Private/Add-ADFSTkSPRelyingPartyTrust.ps1
function Add-ADFSTkSPRelyingPartyTrust { param ( [Parameter(Mandatory = $true, Position = 0)] $sp ) $Continue = $true ### EntityId $entityID = $sp.entityID $rpParams = @{ Identifier = $sp.entityID EncryptionCertificateRevocationCheck = 'None' SigningCertificateRevocationCheck = 'None' ClaimsProviderName = @("Active Directory") ErrorAction = 'Stop' SignatureAlgorithm = Get-ADFSTkSecureHashAlgorithm -EntityId $entityID -CertificateSignatureAlgorithm $SigningCertificate.SignatureAlgorithm.Value IssuanceAuthorizationRules = Get-ADFSTkIssuanceAuthorizationRules -EntityId $entityID SamlResponseSignature = Get-ADFSTkSamlResponseSignature -EntityId $entityID } Write-ADFSTkLog (Get-ADFSTkLanguageText addRPAddingRP -f $entityId) -EntryType Information -EventID 41 ### Name, DisplayName $Name = (Split-Path $sp.entityID -NoQualifier).TrimStart('/') -split '/' | select -First 1 #region Token Encryption Certificate Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPGettingEncryptionert) $CertificateString = ($sp.SPSSODescriptor.KeyDescriptor | ? use -eq "encryption" | select -ExpandProperty KeyInfo).X509Data.X509Certificate if ($CertificateString -eq $null) { #Check if any certificates without 'use'. Should we use this? Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPEncryptionCertNotFound) $CertificateString = ($sp.SPSSODescriptor.KeyDescriptor | ? use -ne "signing" | select -ExpandProperty KeyInfo).X509Data.X509Certificate #or shoud 'use' not be present? } if ($CertificateString -ne $null) { $rpParams.EncryptionCertificate = $null try { #May be more certificates! #If more than one, choose the one with furthest end date. $CertificateString | % { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPConvertingEncrytionCert) $EncryptionCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $CertificateBytes = [system.Text.Encoding]::UTF8.GetBytes($_) $EncryptionCertificate.Import($CertificateBytes) if ($rpParams.EncryptionCertificate -eq $null) { $rpParams.EncryptionCertificate = $EncryptionCertificate } elseif ($rpParams.EncryptionCertificate.NotAfter -lt $EncryptionCertificate.NotAfter) { $rpParams.EncryptionCertificate = $EncryptionCertificate } Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPConvertionEncryptionCertDone) } if ($CertificateString -is [Object[]]) { #Just for logging! Write-ADFSTkLog (Get-ADFSTkLanguageText addRPMultipleEncryptionCertsFound -f $EncryptionCertificate.Thumbprint) -EntryType Warning -EventID 30 } } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText addRPCouldNotImportEncrytionCert) -EntryType Error -EventID 21 $Continue = $false } } #endregion #region Token Signing Certificate #Add all signing certificates if there are more than one Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPGetSigningCert) #$rpParams.SignatureAlgorithm = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" $CertificateString = ($sp.SPSSODescriptor.KeyDescriptor | ? use -eq "signing" | select -ExpandProperty KeyInfo).X509Data.X509Certificate if ($CertificateString -eq $null) { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPSigningCertNotFound) $CertificateString = ($sp.SPSSODescriptor.KeyDescriptor | ? use -ne "encryption" | select -ExpandProperty KeyInfo).X509Data.X509Certificate #or shoud 'use' not be present? } if ($CertificateString -ne $null) { #foreach insted create $SigningCertificates array try { $rpParams.RequestSigningCertificate = @() $CertificateString | % { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPConvertingSigningCert) $CertificateBytes = [system.Text.Encoding]::UTF8.GetBytes($_) $SigningCertificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $SigningCertificate.Import($CertificateBytes) $rpParams.RequestSigningCertificate += $SigningCertificate #if ($SigningCertificate.SignatureAlgorithm.Value -eq '1.2.840.113549.1.1.11') #Check if Signature Algorithm is SHA256 #{ # $rpParams.SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" #} } Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPConvertionSigningCertDone) } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText addRPCouldNotImportSigningCert) -EntryType Error -EventID 22 $Continue = $false } } #endregion #region Get SamlEndpoints Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPGetSamlEndpoints) $rpParams.SamlEndpoint = @() $rpParams.SamlEndpoint += $sp.SPSSODescriptor.AssertionConsumerService | % { if ($_.Binding -eq "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST") { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPHTTPPostFound) New-ADFSSamlEndpoint -Binding POST -Protocol SAMLAssertionConsumer -Uri $_.Location -Index $_.index } elseif ($_.Binding -eq "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact") { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPHTTPArtifactFound) New-ADFSSamlEndpoint -Binding Artifact -Protocol SAMLAssertionConsumer -Uri $_.Location -Index $_.index } elseif ($_.Binding -eq "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect") { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPHTTPRedirectFound) New-ADFSSamlEndpoint -Binding Redirect -Protocol SAMLAssertionConsumer -Uri $_.Location -Index $_.index } else { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPUnhandledEndpointFound -f $_.Binding, $entityID) } } if ($rpParams.SamlEndpoint.Count -eq 0) { Write-ADFSTkLog (Get-ADFSTkLanguageText addRPNoSamlEndpointsFound) -EntryType Error -EventID 23 $Continue = $false } #endregion #region Get LogoutEndpoints Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPGetLogoutEndpoints) $rpParams.SamlEndpoint += $sp.SPSSODescriptor.SingleLogoutService | % { if ($_.Binding -eq "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST") { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPLogoutPostFound) New-ADFSSamlEndpoint -Binding POST -Protocol SAMLLogout -ResponseUri $_.Location -Uri ("https://{0}/adfs/ls/?wa=wsignout1.0" -f $Settings.configuration.staticValues.ADFSExternalDNS) } elseif ($_.Binding -eq "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect") { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPLogoutRedirectFound) New-ADFSSamlEndpoint -Binding Redirect -Protocol SAMLLogout -ResponseUri $_.Location -Uri ("https://{0}/adfs/ls/?wa=wsignout1.0" -f $Settings.configuration.staticValues.ADFSExternalDNS) } } #endregion #region Get Issuance Transform Rules from Entity Categories Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPGetEntityCategories) $EntityCategories = @() $EntityCategories += $sp.Extensions.EntityAttributes.Attribute | ? Name -eq "http://macedir.org/entity-category" | select -ExpandProperty AttributeValue | % { if ($_ -is [string]) { $_ } elseif ($_ -is [System.Xml.XmlElement]) { $_."#text" } } Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPFollowingECFound -f ($EntityCategories -join ',')) if ($ForcedEntityCategories) { $EntityCategories += $ForcedEntityCategories Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPAddedForcedEC -f ($ForcedEntityCategories -join ',')) } $rpParams.IssuanceTransformRules = Get-ADFSTkIssuanceTransformRules $EntityCategories -EntityId $entityID ` -RequestedAttribute $sp.SPSSODescriptor.AttributeConsumingService.RequestedAttribute ` -RegistrationAuthority $sp.Extensions.RegistrationInfo.registrationAuthority ` -NameIdFormat $sp.SPSSODescriptor.NameIDFormat #endregion if ((Get-ADFSRelyingPartyTrust -Identifier $entityID) -eq $null) { $NamePrefix = $Settings.configuration.MetadataPrefix $Sep = $Settings.configuration.MetadataPrefixSeparator $NameWithPrefix = "$NamePrefix$Sep$Name" if ((Get-ADFSRelyingPartyTrust -Name $NameWithPrefix) -ne $null) { $n = 1 Do { $n++ $NameWithPrefix = "$NamePrefix$Sep$Name ($n)" } Until ((Get-ADFSRelyingPartyTrust -Name $NameWithPrefix) -eq $null) Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPRPAlreadyExistsChangingNameTo -f $NameWithPrefix) } $rpParams.Name = $NameWithPrefix if ($Continue) { try { Write-ADFSTkVerboseLog (Get-ADFSTkLanguageText addRPAddingRP -f $entityID) # Invoking the following command leverages 'splatting' for passing the switches for commands # for details, see: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_splatting?view=powershell-6 # (that's what it's @rpParams and not $rpParams) Add-ADFSRelyingPartyTrust @rpParams Write-ADFSTkLog (Get-ADFSTkLanguageText addRPSuccefullyAddedRP -f $entityId) -EntryType Information -EventID 42 Add-ADFSTkEntityHash -EntityID $entityId } catch { Write-ADFSTkLog (Get-ADFSTkLanguageText addRPCouldNotAddRP -f $entityId, $_) -EntryType Error -EventID 24 Add-ADFSTkEntityHash -EntityID $entityId } } else { #There were some error with certificate or endpoints with this SP. Let's only try again if it changes... Add-ADFSTkEntityHash -EntityID $entityId } } else { Write-ADFSTkLog (Get-ADFSTkLanguageText addRPRPAlreadyExists -f $entityId) -EntryType Warning -EventID 25 } } # SIG # Begin signature block # MIIRbgYJKoZIhvcNAQcCoIIRXzCCEVsCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU/CwhMzvGlWH3P7FqTf51hLj1 # ABWggg51MIIEfTCCA2WgAwIBAgIDG+cVMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNV # BAYTAlVTMSEwHwYDVQQKExhUaGUgR28gRGFkZHkgR3JvdXAsIEluYy4xMTAvBgNV # BAsTKEdvIERhZGR5IENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN # MTQwMTAxMDcwMDAwWhcNMzEwNTMwMDcwMDAwWjCBgzELMAkGA1UEBhMCVVMxEDAO # BgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdv # RGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRpZmlj # YXRlIEF1dGhvcml0eSAtIEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAv3FiCPH6WTT3G8kYo/eASVjpIoMTpsUgQwE7hPHmhUmfJ+r2hBtOoLTbcJjH # MgGxBT4HTu70+k8vWTAi56sZVmvigAf88xZ1gDlRe+X5NbZ0TqmNghPktj+pA4P6 # or6KFWp/3gvDthkUBcrqw6gElDtGfDIN8wBmIsiNaW02jBEYt9OyHGC0OPoCjM7T # 3UYH3go+6118yHz7sCtTpJJiaVElBWEaRIGMLKlDliPfrDqBmg4pxRyp6V0etp6e # MAo5zvGIgPtLXcwy7IViQyU0AlYnAZG0O3AqP26x6JyIAX2f1PnbU21gnb8s51ir # uF9G/M7EGwM8CetJMVxpRrPgRwIDAQABo4IBFzCCARMwDwYDVR0TAQH/BAUwAwEB # /zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFDqahQcQZyi27/a9BUFuIMGU2g/e # MB8GA1UdIwQYMBaAFNLEsNKR1EwRcbNhyz2h/t2oatTjMDQGCCsGAQUFBwEBBCgw # JjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDIGA1UdHwQr # MCkwJ6AloCOGIWh0dHA6Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LmNybDBGBgNV # HSAEPzA9MDsGBFUdIAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2Rh # ZGR5LmNvbS9yZXBvc2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEAWQtTvZKGEack # e+1bMc8dH2xwxbhuvk679r6XUOEwf7ooXGKUwuN+M/f7QnaF25UcjCJYdQkMiGVn # OQoWCcWgOJekxSOTP7QYpgEGRJHjp2kntFolfzq3Ms3dhP8qOCkzpN1nsoX+oYgg # HFCJyNwq9kIDN0zmiN/VryTyscPfzLXs4Jlet0lUIDyUGAzHHFIYSaRt4bNYC8nY # 7NmuHDKOKHAN4v6mF56ED71XcLNa6R+ghlO773z/aQvgSMO3kwvIClTErF0UZzds # yqUvMQg3qm5vjLyb4lddJIGvl5echK1srDdMZvNhkREg5L4wn3qkKQmw4TRfZHcY # QFHfjDCmrzCCBNAwggO4oAMCAQICAQcwDQYJKoZIhvcNAQELBQAwgYMxCzAJBgNV # BAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMRow # GAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UEAxMoR28gRGFkZHkgUm9v # dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjAeFw0xMTA1MDMwNzAwMDBaFw0z # MTA1MDMwNzAwMDBaMIG0MQswCQYDVQQGEwJVUzEQMA4GA1UECBMHQXJpem9uYTET # MBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UEChMRR29EYWRkeS5jb20sIEluYy4x # LTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzEz # MDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eSAt # IEcyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAueDLENSvdr3Uk2Lr # MGS4gQhswwTZYheOL/8+Zc+PzmLmPFIc2hZFS1WreGtjg2KQzg9pbJnIGhSLTMxF # M+qI3J6jryv+gGGdeVfEzy70PzA8XUf8mha8wzeWQVGOEUtU+Ci+0Iy+8DA4HvOw # JvhmR2Nt3nEmR484R1PRRh2049wA6kWsvbxx2apvANvbzTA6eU9fTEf4He9bwsSd # YDuxskOR2KQzTuqz1idPrSWKpcb01dCmrnQFZFeItURV1C0qOj74uL3pMgoClGTE # FjpQ8Uqu53kzrwwgB3/o3wQ5wmkCbGNS+nfBG8h0h8i5kxhQVDVLaU68O9NJLh/c # wdJS+wIDAQABo4IBGjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC # AQYwHQYDVR0OBBYEFEDCvSeOzDSDMKIz1/tss/C0LIDOMB8GA1UdIwQYMBaAFDqa # hQcQZyi27/a9BUFuIMGU2g/eMDQGCCsGAQUFBwEBBCgwJjAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZ29kYWRkeS5jb20vMDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6 # Ly9jcmwuZ29kYWRkeS5jb20vZ2Ryb290LWcyLmNybDBGBgNVHSAEPzA9MDsGBFUd # IAAwMzAxBggrBgEFBQcCARYlaHR0cHM6Ly9jZXJ0cy5nb2RhZGR5LmNvbS9yZXBv # c2l0b3J5LzANBgkqhkiG9w0BAQsFAAOCAQEACH5skxDIOLiWqZBL/6FfTwTvbD6c # iAbJUI+mc/dXMRu+vOQv2/i601vgtOfmeWIODKLXamNzMbX1qEikOwgtol2Q17R8 # JU8RVjDEtkSdeyyd5V7m7wxhqr/kKhvuhJ64g33BQ85EpxNwDZEf9MgTrYNg2dhy # qHMkHrWsIg7KF4liWEQbq4klAQAPzcQbYttRtNMPUSqb9Lxz/HbONqTN2dgs6q6b # 9SqykNFNdRiKP4pBkCN9W0v+pANYm0ayw2Bgg/h9UEHOwqGQw7vvAi/SFVTuRBXZ # Cq6nijPtsS12NibcBOuf92EfFdyHb+5GliitoSZ9CgmnLgSjjbz4vAQwATCCBRww # ggQEoAMCAQICCDeMqUwECkf0MA0GCSqGSIb3DQEBCwUAMIG0MQswCQYDVQQGEwJV # UzEQMA4GA1UECBMHQXJpem9uYTETMBEGA1UEBxMKU2NvdHRzZGFsZTEaMBgGA1UE # ChMRR29EYWRkeS5jb20sIEluYy4xLTArBgNVBAsTJGh0dHA6Ly9jZXJ0cy5nb2Rh # ZGR5LmNvbS9yZXBvc2l0b3J5LzEzMDEGA1UEAxMqR28gRGFkZHkgU2VjdXJlIENl # cnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTIwMDEwODExMjIyNFoXDTIxMDMw # ODE4NTgwMFowXjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNV # BAcTBk90dGF3YTEVMBMGA1UEChMMQ0FOQVJJRSBJbmMuMRUwEwYDVQQDEwxDQU5B # UklFIEluYy4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZhfCjFqiT # mN1uLoySixnwaOjf/ZAL9P6SvjlCaBA2mutoorEgnzUP8HnOIcvMRgEMPmpaZ8eg # M93Bmx9d41xoarsQpCN3DhYOo+b3fWnPucVtpxbul2OFePv63mw/uvr+dqkv4b/f # 3Tg+ilQbpsNonbvh9MKEFv8Pn9koj0ySV+qxz34PxTVAe6g//pel3/3i9fqilCnI # Ecx4zg/+NKBeOWROSs4oXo3IvBjVrunmz+YuieSr78TqIE6hD8JF2q1wKwfMB3+x # 7dEXZAus9WtIU/qITATtEfO9QAgrrYL4F1MLN+osSp8my5eCOjnLTQc47q574V3z # QhsIHW7yBXLdAgMBAAGjggGFMIIBgTAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoG # CCsGAQUFBwMDMA4GA1UdDwEB/wQEAwIHgDA1BgNVHR8ELjAsMCqgKKAmhiRodHRw # Oi8vY3JsLmdvZGFkZHkuY29tL2dkaWcyczUtNS5jcmwwXQYDVR0gBFYwVDBIBgtg # hkgBhv1tAQcXAjA5MDcGCCsGAQUFBwIBFitodHRwOi8vY2VydGlmaWNhdGVzLmdv # ZGFkZHkuY29tL3JlcG9zaXRvcnkvMAgGBmeBDAEEATB2BggrBgEFBQcBAQRqMGgw # JAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmdvZGFkZHkuY29tLzBABggrBgEFBQcw # AoY0aHR0cDovL2NlcnRpZmljYXRlcy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5L2dk # aWcyLmNydDAfBgNVHSMEGDAWgBRAwr0njsw0gzCiM9f7bLPwtCyAzjAdBgNVHQ4E # FgQUUPnMg2nmYS8l7rmax3weVkrgz5AwDQYJKoZIhvcNAQELBQADggEBAIYabiAR # aY4KhO6oWgNHPOBjoHuqUH7NwRGN/ztYJznRBZbdD50smoK5GR0FvUZ8TXhYoZOa # zXe4NlFM4e6YcudU+EA/OF+sZHFBWziz1VS6U3sS+cGyJcxvelSoid0q3W3i9/Zy # 6Nv2kk/DEJp49O47mPNovpL15yykX3Vo26GwC9peo4s/cKMzthmgrcF2uLkT+LW4 # 4xKhaL7nBTGDMhjno+a3t00SWCId7wzgQadIJ1QlFOKm0xgmuiW3LIqCG0apvaOf # vWKTPKq68q+FbDPOO48oKrvw1c9K/m8gcnBLz6PX1REVIs5u3pvdOYBCz6uXyKxn # t+Q5jDEK0NskLu0xggJjMIICXwIBATCBwTCBtDELMAkGA1UEBhMCVVMxEDAOBgNV # BAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoTEUdvRGFk # ZHkuY29tLCBJbmMuMS0wKwYDVQQLEyRodHRwOi8vY2VydHMuZ29kYWRkeS5jb20v # cmVwb3NpdG9yeS8xMzAxBgNVBAMTKkdvIERhZGR5IFNlY3VyZSBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgLSBHMgIIN4ypTAQKR/QwCQYFKw4DAhoFAKB4MBgGCisGAQQB # gjcCAQwxCjAIoAKAAKECgAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYK # KwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwIwYJKoZIhvcNAQkEMRYEFJP6YmHH # MOE7WkdJ3HBeZWmcnNgiMA0GCSqGSIb3DQEBAQUABIIBACRfPlUJT8f3gKgkKcHn # qTMZ9zf/enp+PSxjt5RRvzeFHy/5Xo17YqgoP1037eebjPYemvMKrqNuY9AVXPtJ # 97FjACyHc/BAo4Irt11eVQSg6Zg3rtw1juIWpqTg1i69dGMRx5O2GuFxwcR7BG3/ # JTf3jJ+v9cKVyuGEQIIrEsPN+4GOd7kX0lyWQW3d0h9q4/yYCV82fpYAGa0/qg07 # qmpqvdcKtrEpu//2LriZcTVK96dx8Da4CY4AJNjZxRxw24GBXfVNMR1Rss+3Zjj7 # EcY6v2LQMhJWwuxxmDBq0ILJw9ah6VfC02lkJaSoRhTRb/H1wCn93L71wjUd6fZr # 7p8= # SIG # End signature block |