Functions/Get-NDESCertificate.ps1
<#
.SYNOPSIS Requests a Certificate from an NDES Server via the SCEP Protocol. This works on Windows 8.1 and newer Operating Systems. .PARAMETER ComputerName Specifies the Host Name or IP Address of the NDES Server. If using SSL, this must match the NDES Server's identity as specified in its SSL Server Certificate. .PARAMETER MachineContext By default, the Key for Certificate Request gets created in the current User's Context. By specifying this Parameter, it will be created as a Machine Key. You must execute the Command with Elevation (Run as Administrator) then. .PARAMETER Subject Specifies the Subject DN for the Certificate. May be left empty if you specify a DnsName, Upn or IP instead. .PARAMETER Dns Specifies one or more DNS Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request. May be left Empty if you specify a Subject, Upn or IP instead. .PARAMETER Upn Specifies one or more User Principal Names to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request. May be left Empty if you specify a Subject, DnsName or IP instead. .PARAMETER Email Specifies one or more E-Mail addresses (RFC 822) to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request. May be left Empty if you specify a Subject, DnsName, Upn or IP instead. .PARAMETER IP Specifies or more IP Addresses to be written into the Subject Alternative Name (SAN) Extension of the Certificate Request. May be left Empty if you specify a Subject, DnsName or Upn instead. .PARAMETER ChallengePassword Specifies the Challenge Password used to authenticate to the NDES Server. Not necessary if the NDES Server doesn't require a Password, or if you specify a SigningCert. .PARAMETER SigningCert Specifies the Signing Certificate used to sign the SCEP Certificate Request. Can be passed to the Command via the Pipeline. Use this when you already have a Certificate issued by the NDES Server and just want to renew it. Subject Information will be taken from this Certificate as otherwise NDES would deny the Request if there is a mismatch. .PARAMETER Ksp Specifies the Cryptographic Service Provider (CSP) or Key Storage Provider (KSP) to be used for the Private Key of the Certificate. You can specify any CSP or KSP that is installed on the System. Defaults to the Microsoft Software Key Storage Provider. .PARAMETER KeyLength Specifies the Key Length for the Key pair of the Certificate. Defaults to 2048 Bits RSA. ECC is not implemented as of now. .PARAMETER PrivateKeyExportable Specifies if the Private Key of the Certificate shall be marked as exportable. Defaults to the Key being not marked as exportable. .PARAMETER UseSSL Forces the connection to use SSL Encryption. Not necessary from a security perspective, as the SCEP Message's confidential partsd are encrypted with the NDES RA Certificates anyway. .PARAMETER Port Specifies the Network Port of the NDES Server to be used. Only necessary if your NDES Server is running on a non-default Port for some reason. Defaults to Port 80 without SSL and 443 with SSL. .PARAMETER Method Specifies if the Certificate Submission shall be done with HTTP "GET" or "POST". Defaults to "POST". .OUTPUTS System.Security.Cryptography.X509Certificates.X509Certificate. Returns the issued Certificate returned by the NDES Server. #> Function Get-NDESCertificate { [cmdletbinding()] param( [Parameter(Mandatory=$True)] [String] $ComputerName, [Alias("Machine")] [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [Switch] $MachineContext = $False, [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [ValidateNotNullOrEmpty()] [String] $Subject, [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [Alias("DnsName")] [ValidateNotNullOrEmpty()] [ValidateScript({ $_ | ForEach-Object -Process { [System.Uri]::CheckHostName($_) -eq [System.UriHostnameType]::Dns } })] [String[]] $Dns, [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [Alias("UserPrincipalName")] [ValidateNotNullOrEmpty()] [mailaddress[]] $Upn, [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [Alias("RFC822Name")] [Alias("E-Mail")] [ValidateNotNullOrEmpty()] [mailaddress[]] $Email, [Alias("IPAddress")] [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [System.Net.IPAddress[]] $IP, [Parameter( ParameterSetName="NewRequest", Mandatory=$False )] [ValidateNotNullOrEmpty()] [String] $ChallengePassword, [Parameter( ParameterSetName="RenewalRequest", ValuefromPipeline = $True, Mandatory=$False )] [ValidateScript({($_.HasPrivateKey) -and ($null -ne $_.PSParentPath)})] [System.Security.Cryptography.X509Certificates.X509Certificate2] $SigningCert, [Alias("KeyStorageProvider")] [Parameter(Mandatory=$False)] [ValidateScript({ $Ksp = $_ [bool](Get-KeyStorageProvider | Where-Object { $_.Name -eq $Ksp })} )] [String] $Ksp = "Microsoft Software Key Storage Provider", [Parameter(Mandatory=$False)] [ValidateSet(512,1024,2048,3072,4096,8192)] [Int] $KeyLength = 2048, [Alias("Exportable")] [Parameter(Mandatory=$False)] [Switch] $PrivateKeyExportable = $False, [Alias("SSL")] [Parameter(Mandatory=$False)] [Switch] $UseSSL = $False, [Parameter(Mandatory=$False)] [ValidateRange(1,65535)] [Int] $Port, [Parameter(Mandatory=$False)] [ValidateSet("GET","POST")] [String] $Method = "POST", [Parameter(Mandatory=$False)] [ValidateNotNullOrEmpty()] [String] $Suffix = "certsrv/mscep/mscep.dll" ) begin { Add-Type -AssemblyName System.Security # This hides the Status Indicators of the Invoke-WebRequest Calls later on $ProgressPreference = 'SilentlyContinue' # Assembling the Configuration String, which is the SCEP URL in this Case If ($UseSSL) { $Protocol = "https" } Else { $Protocol = "http" } If ($Port) { $PortString = ":$($Port)" } Else { $PortString = [String]::Empty } $ConfigString = "$($Protocol)://$($ComputerName)$($PortString)/$($Suffix)/pkiclient.exe" Write-Verbose -Message "Configuration String: $ConfigString" # SCEP GetCACaps Operation Try { $GetCACaps = (Invoke-WebRequest -uri "$($ConfigString)?operation=GetCACaps").Content } Catch { Write-Error -Message $PSItem.Exception.Message return } # SCEP GetCACert Operation Try { $GetCACert = (Invoke-WebRequest -uri "$($ConfigString)?operation=GetCACert").Content # Decoding the CMS (PKCS#7 Message that was returned from the NDES Server) $Pkcs7CaCert = New-Object System.Security.Cryptography.Pkcs.SignedCms $Pkcs7CaCert.Decode($GetCACert) } Catch { Write-Error -Message $PSItem.Exception.Message return } } process { # Skip pipeline processing if the preparation steps failed If (-not $GetCACaps) { return } If (-not $Pkcs7CaCert.Certificates) { return } # Ensuring the Code will be executed on a supported Operating System # Operating Systems prior to Windows 8.1 don't contain the IX509SCEPEnrollment Interface If ([int32](Get-WmiObject Win32_OperatingSystem).BuildNumber -lt $BUILD_NUMBER_WINDOWS_8_1) { Write-Error -Message "This must be executed on Windows 8.1/Windows Server 2012 R2 or newer!" return } # Ensuring we work with Elevation when messing with the Computer Certificate Store # As we want to inherit Key Settings from the Signing Certificate, we must also check its Certificate Store If ($MachineContext.IsPresent -or ($SigningCert -and ($SigningCert.PSParentPath -match "Machine"))) { If (-not ( [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent() ).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) { Write-Error -Message "This must be run with Elevation (Run as Administrator) when using the Machine Context!" return } } $CertificateRequestObject = New-Object -ComObject "X509Enrollment.CX509CertificateRequestPkcs10" # Determining if we create an entirely new Certificate Request or inherit Settings from an old one If ($SigningCert) { # Certificate Renewal Request If ($GetCACaps -match "Renewal") { $InheritOptions = $X509RequestInheritOptions.InheritDefault $InheritOptions += $X509RequestInheritOptions.InheritSubjectAltNameFlag $InheritOptions += $X509RequestInheritOptions.InheritExtensionsFlag $InheritOptions += $X509RequestInheritOptions.InheritSubjectFlag $CertificateRequestObject.InitializeFromCertificate( [int]($SigningCert.PSParentPath -match "Machine")+1, [Convert]::ToBase64String($SigningCert.RawData), $EncodingType.XCN_CRYPT_STRING_BASE64, $InheritOptions ) <# https://tools.ietf.org/html/draft-nourse-scep-23#section-2.3 A client that is performing certificate renewal as per Appendix D SHOULD send an empty challenge password (i.e. use the empty string as the challenge password) but MAY send the originally distributed challenge password in the challengePassword attribute. #> $CertificateRequestObject.ChallengePassword = [String]::Empty } Else { Write-Error -Message "The Server does not support Renewal!" return } } Else { # New Certificate Request If ((-not $Dns) -and (-not $Upn) -and (-not $Email) -and (-not $IP) -and ((-not $Subject) -or ($Subject -eq "CN="))) { Write-Error -Message "You must provide an Identity, either in Form ob a Subject or Subject Alternative Name!" return } $CertificateRequestObject.Initialize( [int]($MachineContext.IsPresent)+1 ) Try { # To Do: implement Validation of the Subject RDN $SubjectDnObject = New-Object -ComObject "X509Enrollment.CX500DistinguishedName" $SubjectDnObject.Encode($Subject) $CertificateRequestObject.Subject = $SubjectDnObject } Catch { Write-Error -Message "Invalid Subject DN supplied!" return } # Set the Subject Alternative Names Extension if specified as Argument If ($Upn -or $Email -or $Dns -or $IP) { $SubjectAlternativeNamesExtension = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames $Sans = New-Object -ComObject X509Enrollment.CAlternativeNames # https://msdn.microsoft.com/en-us/library/aa374981(VS.85).aspx Foreach ($Entry in $Upn) { $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName $AlternativeNameObject.InitializeFromString( $AlternativeNameType.XCN_CERT_ALT_NAME_USER_PRINCIPLE_NAME, $Entry ) $Sans.Add($AlternativeNameObject) [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject)) } Foreach ($Entry in $Email) { $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName $AlternativeNameObject.InitializeFromString( $AlternativeNameType.XCN_CERT_ALT_NAME_RFC822_NAME, $Entry ) $Sans.Add($AlternativeNameObject) [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject)) } Foreach ($Entry in $Dns) { $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName $AlternativeNameObject.InitializeFromString( $AlternativeNameType.XCN_CERT_ALT_NAME_DNS_NAME, $Entry ) $Sans.Add($AlternativeNameObject) [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject)) } Foreach ($Entry in $IP) { $AlternativeNameObject = New-Object -ComObject X509Enrollment.CAlternativeName $AlternativeNameObject.InitializeFromRawData( $AlternativeNameType.XCN_CERT_ALT_NAME_IP_ADDRESS, $EncodingType.XCN_CRYPT_STRING_BASE64, [Convert]::ToBase64String($Entry.GetAddressBytes()) ) $Sans.Add($AlternativeNameObject) [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($AlternativeNameObject)) } $SubjectAlternativeNamesExtension.Critical = $True $SubjectAlternativeNamesExtension.InitializeEncode($Sans) # Adding the Extension to the Certificate $CertificateRequestObject.X509Extensions.Add($SubjectAlternativeNamesExtension) } If ($ChallengePassword) { <# https://tools.ietf.org/html/draft-nourse-scep-23#section-2.2 PKCS#10 [RFC2986] specifies a PKCS#9 [RFC2985] challengePassword attribute to be sent as part of the enrollment request. Inclusion of the challengePassword by the SCEP client is OPTIONAL and allows for unauthenticated authorization of enrollment requests. #> $CertificateRequestObject.ChallengePassword = $ChallengePassword } } # Configuring the private Key of the Certificate $CertificateRequestObject.PrivateKey.Length = $KeyLength $CertificateRequestObject.PrivateKey.ExportPolicy = [int]($PrivateKeyExportable.IsPresent) $CertificateRequestObject.PrivateKey.ProviderName = $Ksp <# Identify the Root CA Certificate that was delivered with the Chain https://tools.ietf.org/html/rfc5280#section-6.1 A certificate is self-issued if the same DN appears in the subject and issuer fields #> $RootCaCert = $Pkcs7CaCert.Certificates | Where-Object { $_.Subject -eq $_.Issuer } # Initialize the IX509SCEPEnrollment Interface # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nn-certenroll-ix509scepenrollment $SCEPEnrollmentInterface = New-Object -ComObject "X509Enrollment.CX509SCEPEnrollment" # Let's try to build a SCEP Enrollment Message now... Try { # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-initialize $SCEPEnrollmentInterface.Initialize( $CertificateRequestObject, (Get-CertificateHash -Bytes $RootCaCert.RawData -HashAlgorithm "MD5"), $EncodingType.XCN_CRYPT_STRING_HEX, [Convert]::ToBase64String($GetCACert), $EncodingType.XCN_CRYPT_STRING_BASE64 ) } Catch { Write-Error -Message $PSItem.Exception.Message return } # Sets the preferred hash and encryption algorithms for the request. # If you do not set this property, then the default hash and encryption algorithms will be used. # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-put_servercapabilities $SCEPEnrollmentInterface.ServerCapabilities = $GetCACaps <# https://tools.ietf.org/html/draft-nourse-scep-23#section-2.2 If the requester does not have an appropriate existing certificate, then a locally generated self-signed certificate MUST be used instead. The self-signed certificate MUST use the same subject name as in the PKCS#10 request. https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-put_signercertificate To create a renewal request, you must set this property prior to calling the CreateRequestMessage method. Otherwise, the CreateRequestMessage method will create a new request and generate a self-signed certificate using the same private key as the inner PKCSV10 reqeust. #> If ($SigningCert) { $SignerCertificate = New-Object -ComObject 'X509Enrollment.CSignerCertificate' # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-isignercertificate-initialize $SignerCertificate.Initialize( [int]($SigningCert.PSParentPath -match "Machine"), $X509PrivateKeyVerify.VerifyNone, # We did this already during Parameter Validation $EncodingType.XCN_CRYPT_STRING_BASE64, [Convert]::ToBase64String($SigningCert.RawData) ) $SCEPEnrollmentInterface.SignerCertificate = $SignerCertificate } # Building the PKCS7 Message for the SCEP Enrollment # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-createrequestmessage $SCEPRequestMessage = $SCEPEnrollmentInterface.CreateRequestMessage( $EncodingType.XCN_CRYPT_STRING_BASE64 ) # Submission to the NDES Server Try { If ($Method -eq "POST") { If ($GetCACaps -match "POSTPKIOperation") { $SCEPResponse = Invoke-WebRequest ` -Body ([Convert]::FromBase64String($SCEPRequestMessage)) ` -Method 'POST' ` -Uri "$($ConfigString)?operation=PKIOperation" ` -Headers @{'Content-Type' = 'application/x-pki-message'} } Else { Write-Warning -Message "The Server indicates that it doesnt support the 'POST' Method. Falling back to 'GET'." $Method = "GET" } } If ($Method -eq "GET") { $SCEPResponse = Invoke-WebRequest ` -Method 'GET' ` -Uri "$($ConfigString)?operation=PKIOperation&message=$([uri]::EscapeDataString($SCEPRequestMessage))" ` -Headers @{'Content-Type' = 'application/x-pki-message'} } $SCEPResponse = [Convert]::ToBase64String($ScepResponse.Content) } Catch { Write-Error -Message $PSItem.Exception.Message return } Try { # Process a response message and return the disposition of the message. # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-processresponsemessage $Disposition = $SCEPEnrollmentInterface.ProcessResponseMessage( $SCEPResponse, $EncodingType.XCN_CRYPT_STRING_BASE64 ) # https://docs.microsoft.com/en-us/windows/win32/api/certpol/ne-certpol-x509scepdisposition Switch ($Disposition) { $X509SCEPDisposition.SCEPDispositionFailure { $ErrorMessage = '' $ErrorMessage += "The NDES Server rejected the Certificate Request!`n" # The Failinfo Method is only present in Windows 10 # Windows 8.1 / 2012 R2 Users therefore won't get any fancy error message, sadly If ([int32](Get-WmiObject Win32_OperatingSystem).BuildNumber -ge $BUILD_NUMBER_WINDOWS_10) { $FailInfo = ($SCEPFailInfo | Where-Object { $_.Code -eq $SCEPEnrollmentInterface.FailInfo() }) $ErrorMessage += "SCEP Failure Information: $($FailInfo.Message) ($($FailInfo.Code)) $($FailInfo.Description)`n" $ErrorMessage += "Additional Information returned by the Server: $($SCEPEnrollmentInterface.Status().Text)`n" If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.CERT_E_WRONG_USAGE) { $ErrorMessage += "Possible reason(s): The Challenge Password has been used already." } If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.TRUST_E_CERT_SIGNATURE) { $ErrorMessage += "Possible reason(s): The NDES Server requires a Challenge Password but none was supplied." } If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.ERROR_NOT_FOUND) { $ErrorMessage += "Possible reason(s): The Challenge Password supplied is unknown to the NDES Server, or it has been used already." } If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.CERTSRV_E_BAD_REQUESTSUBJECT) { $ErrorMessage += "Possible reason(s): The CA denied your request because an invalid Subject was requested." } If ($SCEPEnrollmentInterface.Status().Text -match $NDESErrorCode.RPC_S_SERVER_UNAVAILABLE) { $ErrorMessage += "Possible reason(s): The NDES Server was unable to contact the Certification Authority." } } Write-Error -Message $ErrorMessage } $X509SCEPDisposition.SCEPDispositionPending { Write-Warning -Message "The Enrollment was successful with Status ScepDispositionPending, which is not yet implemented!" } $X509SCEPDisposition.SCEPDispositionPendingChallenge { Write-Warning -Message "The Enrollment was successful with Status ScepDispositionPendingChallenge, which is not yet implemented!" } $X509SCEPDisposition.SCEPDispositionUnknown { Write-Error -Message "The Enrollment failed for an unknown Reason." } $X509SCEPDisposition.SCEPDispositionSuccess { # We load the Certificate into an X509Certificate2 Object # https://docs.microsoft.com/en-us/windows/win32/api/certenroll/nf-certenroll-ix509scepenrollment-get_certificate $CertificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 $CertificateObject.Import( [Convert]::FromBase64String( $SCEPEnrollmentInterface.Certificate($EncodingType.XCN_CRYPT_STRING_BASE64) ) ) # Return the resulting Certificate If ($MachineContext.IsPresent -or ($SigningCert -and ($SigningCert.PSParentPath -match "Machine"))) { Get-ChildItem -Path "Cert:\LocalMachine\My\$($CertificateObject.Thumbprint)" } Else { Get-ChildItem -Path "Cert:\CurrentUser\My\$($CertificateObject.Thumbprint)" } } } } Catch { Write-Error -Message $PSItem.Exception.Message return } # Cleaning up the COM Objects, avoiding any User Errors to be reported $CertificateRequestObject, $SubjectDnObject, $SubjectAlternativeNamesExtension, $Sans, $SCEPEnrollmentInterface, $SignerCertificate | ForEach-Object -Process { Try { [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($_)) } Catch { # we don't want to return anything here } } } end {} } # SIG # Begin signature block # MIIfUQYJKoZIhvcNAQcCoIIfQjCCHz4CAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB # gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR # AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQU3/MinZ8JMESF23TcEZA1bkyO # YN2gghk4MIIFQDCCBCigAwIBAgIRAI8ql/xeLmzwWijNkBrZWykwDQYJKoZIhvcN # AQELBQAwfDELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3Rl # cjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQw # IgYDVQQDExtTZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0EwHhcNMjAxMTIwMDAw # MDAwWhcNMjMxMTIwMjM1OTU5WjCBhzELMAkGA1UEBhMCREUxDjAMBgNVBBEMBTkx # NjAyMR0wGwYDVQQHDBREw7xycndhbmdlbiBIYWxzYmFjaDEVMBMGA1UECQwMV2Vp # aGVyd2VnIDE1MRgwFgYDVQQKDA9Vd2UgR3JhZGVuZWdnZXIxGDAWBgNVBAMMD1V3 # ZSBHcmFkZW5lZ2dlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOd8 # GJf9qC1WQbcxgVa4XpKLzh/oy12qkfG3K11BLRs2UuZoZXelefKJYirHWpzNlhkb # RoGv3sNUCgKpRDtyz1kHf+jvk+nsB9SCctMccmb987BA8kq/togGWjqlHcQFfETr # lv3zxiQkd560Ttrx9OO8/mgIvUubGW4jttet+AUV8PeHJeCQKwetoEn3obcgqjua # AS41nc/f+NaX6wkD8iKGpXy+CrHbflhACasvUychBf/BlmxsZKP8sf6dZNN0I7TU # 9kjO5A8NiWAp7J9oTz0tfKuHGurGaqlAMQUJdD9RNDzsz+CN1w/LjbkhfJawnoI8 # XR7g8nIBOH2df+YImPUCAwEAAaOCAa8wggGrMB8GA1UdIwQYMBaAFA7hOqhTOjHV # ir7Bu61nGgOFrTQOMB0GA1UdDgQWBBQpnALCRSXWP6gLMr77GCxcPejdmjAOBgNV # HQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAKBggrBgEFBQcDAzAR # BglghkgBhvhCAQEEBAMCBBAwSgYDVR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAj # BggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEMG # A1UdHwQ8MDowOKA2oDSGMmh0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1JT # QUNvZGVTaWduaW5nQ0EuY3JsMHMGCCsGAQUFBwEBBGcwZTA+BggrBgEFBQcwAoYy # aHR0cDovL2NydC5zZWN0aWdvLmNvbS9TZWN0aWdvUlNBQ29kZVNpZ25pbmdDQS5j # cnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMB0GA1UdEQQW # MBSBEnV3ZUBncmFkZW5lZ2dlci5ldTANBgkqhkiG9w0BAQsFAAOCAQEAhEOjCx9s # SaMpTP9RFRnJx8dcn0eDdCk6TGZlB3gyh24VWu+VECUXd/1svZJ6apPDRpz2kvFz # TlIEfAORKDuXY72X6eCS7VFTjNvEyNFPmr67T6JUB7Qka6W9dpAqhufxOQ0DRS/a # kytP3J4JF0BYiZ3IxfgAH1ji/uXuMyD1jFSWsDyhSMk+O0ugYw+TaKb4j8XCWN7k # N8uVhaqXmDFi9XKTKQturbxEG3nCSxludZt5fDImj7cYnorhI3vGKZSXQTjgQ1Tv # jUyb4YjoToTNjZ6fz3HamALoi6QHL9npHB6ekLLwVsUW8G9t5o54tQ4qbngap/fB # Qk0JDQ0C2+ikbjCCBfUwggPdoAMCAQICEB2iSDBvmyYY0ILgln0z02owDQYJKoZI # hvcNAQEMBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpOZXcgSmVyc2V5MRQw # EgYDVQQHEwtKZXJzZXkgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3 # b3JrMS4wLAYDVQQDEyVVU0VSVHJ1c3QgUlNBIENlcnRpZmljYXRpb24gQXV0aG9y # aXR5MB4XDTE4MTEwMjAwMDAwMFoXDTMwMTIzMTIzNTk1OVowfDELMAkGA1UEBhMC # R0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9y # ZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtTZWN0aWdvIFJT # QSBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCGIo0yhXoYn0nwli9jCB4t3HyfFM/jJrYlZilAhlRGdDFixRDtsocnppnLlTDA # VvWkdcapDlBipVGREGrgS2Ku/fD4GKyn/+4uMyD6DBmJqGx7rQDDYaHcaWVtH24n # lteXUYam9CflfGqLlR5bYNV+1xaSnAAvaPeX7Wpyvjg7Y96Pv25MQV0SIAhZ6DnN # j9LWzwa0VwW2TqE+V2sfmLzEYtYbC43HZhtKn52BxHJAteJf7wtF/6POF6YtVbC3 # sLxUap28jVZTxvC6eVBJLPcDuf4vZTXyIuosB69G2flGHNyMfHEo8/6nxhTdVZFu # ihEN3wYklX0Pp6F8OtqGNWHTAgMBAAGjggFkMIIBYDAfBgNVHSMEGDAWgBRTeb9a # qitKz1SA4dibwJ3ysgNmyzAdBgNVHQ4EFgQUDuE6qFM6MdWKvsG7rWcaA4WtNA4w # DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI # KwYBBQUHAwMGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBH # MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy # dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF # BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1 # c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w # DQYJKoZIhvcNAQEMBQADggIBAE1jUO1HNEphpNveaiqMm/EAAB4dYns61zLC9rPg # Y7P7YQCImhttEAcET7646ol4IusPRuzzRl5ARokS9At3WpwqQTr81vTr5/cVlTPD # oYMot94v5JT3hTODLUpASL+awk9KsY8k9LOBN9O3ZLCmI2pZaFJCX/8E6+F0ZXkI # 9amT3mtxQJmWunjxucjiwwgWsatjWsgVgG10Xkp1fqW4w2y1z99KeYdcx0BNYzX2 # MNPPtQoOCwR/oEuuu6Ol0IQAkz5TXTSlADVpbL6fICUQDRn7UJBhvjmPeo5N9p8O # Hv4HURJmgyYZSJXOSsnBf/M6BZv5b9+If8AjntIeQ3pFMcGcTanwWbJZGehqjSkE # And8S0vNcL46slVaeD68u28DECV3FTSK+TbMQ5Lkuk/xYpMoJVcp+1EZx6ElQGqE # V8aynbG8HArafGd+fS7pKEwYfsR7MUFxmksp7As9V1DSyt39ngVR5UR43QHesXWY # DVQk/fBO4+L4g71yuss9Ou7wXheSaG3IYfmm8SoKC6W59J7umDIFhZ7r+YMp08Ys # fb06dy6LN0KgaoLtO0qqlBCk4Q34F8W2WnkzGJLjtXX4oemOCiUe5B7xn1qHI/+f # pFGe+zmAEc3btcSnqIBv5VPU4OOiwtJbGvoyJi1qV3AcPKRYLqPzW0sH3DJZ84en # Gm1YMIIG7DCCBNSgAwIBAgIQMA9vrN1mmHR8qUY2p3gtuTANBgkqhkiG9w0BAQwF # ADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcT # C0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAs # BgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN # MTkwNTAyMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjB9MQswCQYDVQQGEwJHQjEbMBkG # A1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRgwFgYD # VQQKEw9TZWN0aWdvIExpbWl0ZWQxJTAjBgNVBAMTHFNlY3RpZ28gUlNBIFRpbWUg # U3RhbXBpbmcgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDIGwGv # 2Sx+iJl9AZg/IJC9nIAhVJO5z6A+U++zWsB21hoEpc5Hg7XrxMxJNMvzRWW5+adk # FiYJ+9UyUnkuyWPCE5u2hj8BBZJmbyGr1XEQeYf0RirNxFrJ29ddSU1yVg/cyeNT # mDoqHvzOWEnTv/M5u7mkI0Ks0BXDf56iXNc48RaycNOjxN+zxXKsLgp3/A2UUrf8 # H5VzJD0BKLwPDU+zkQGObp0ndVXRFzs0IXuXAZSvf4DP0REKV4TJf1bgvUacgr6U # nb+0ILBgfrhN9Q0/29DqhYyKVnHRLZRMyIw80xSinL0m/9NTIMdgaZtYClT0Bef9 # Maz5yIUXx7gpGaQpL0bj3duRX58/Nj4OMGcrRrc1r5a+2kxgzKi7nw0U1BjEMJh0 # giHPYla1IXMSHv2qyghYh3ekFesZVf/QOVQtJu5FGjpvzdeE8NfwKMVPZIMC1Pvi # 3vG8Aij0bdonigbSlofe6GsO8Ft96XZpkyAcSpcsdxkrk5WYnJee647BeFbGRCXf # BhKaBi2fA179g6JTZ8qx+o2hZMmIklnLqEbAyfKm/31X2xJ2+opBJNQb/HKlFKLU # rUMcpEmLQTkUAx4p+hulIq6lw02C0I3aa7fb9xhAV3PwcaP7Sn1FNsH3jYL6uckN # U4B9+rY5WDLvbxhQiddPnTO9GrWdod6VQXqngwIDAQABo4IBWjCCAVYwHwYDVR0j # BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFBqh+GEZIA/DQXdF # KI7RNV8GEgRVMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMG # A1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBQBgNVHR8ESTBH # MEWgQ6BBhj9odHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQ2Vy # dGlmaWNhdGlvbkF1dGhvcml0eS5jcmwwdgYIKwYBBQUHAQEEajBoMD8GCCsGAQUF # BzAChjNodHRwOi8vY3J0LnVzZXJ0cnVzdC5jb20vVVNFUlRydXN0UlNBQWRkVHJ1 # c3RDQS5jcnQwJQYIKwYBBQUHMAGGGWh0dHA6Ly9vY3NwLnVzZXJ0cnVzdC5jb20w # DQYJKoZIhvcNAQEMBQADggIBAG1UgaUzXRbhtVOBkXXfA3oyCy0lhBGysNsqfSoF # 9bw7J/RaoLlJWZApbGHLtVDb4n35nwDvQMOt0+LkVvlYQc/xQuUQff+wdB+PxlwJ # +TNe6qAcJlhc87QRD9XVw+K81Vh4v0h24URnbY+wQxAPjeT5OGK/EwHFhaNMxcyy # UzCVpNb0llYIuM1cfwGWvnJSajtCN3wWeDmTk5SbsdyybUFtZ83Jb5A9f0VywRsj # 1sJVhGbks8VmBvbz1kteraMrQoohkv6ob1olcGKBc2NeoLvY3NdK0z2vgwY4Eh0k # hy3k/ALWPncEvAQ2ted3y5wujSMYuaPCRx3wXdahc1cFaJqnyTdlHb7qvNhCg0MF # pYumCf/RoZSmTqo9CfUFbLfSZFrYKiLCS53xOV5M3kg9mzSWmglfjv33sVKRzj+J # 9hyhtal1H3G/W0NdZT1QgW6r8NDT/LKzH7aZlib0PHmLXGTMze4nmuWgwAxyh8Fu # TVrTHurwROYybxzrF06Uw3hlIDsPQaof6aFBnf6xuKBlKjTg3qj5PObBMLvAoGMs # /FwWAKjQxH/qEZ0eBsambTJdtDgJK0kHqv3sMNrxpy/Pt/360KOE2See+wFmd7lW # EOEgbsausfm2usg1XTN2jvF8IAwqd661ogKGuinutFoAsYyr4/kKyVRd1LlqdJ69 # SK6YMIIHBzCCBO+gAwIBAgIRAIx3oACP9NGwxj2fOkiDjWswDQYJKoZIhvcNAQEM # BQAwfTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQ # MA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSUwIwYD # VQQDExxTZWN0aWdvIFJTQSBUaW1lIFN0YW1waW5nIENBMB4XDTIwMTAyMzAwMDAw # MFoXDTMyMDEyMjIzNTk1OVowgYQxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh # dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3Rp # Z28gTGltaXRlZDEsMCoGA1UEAwwjU2VjdGlnbyBSU0EgVGltZSBTdGFtcGluZyBT # aWduZXIgIzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCRh0ssi8Hx # HqCe0wfGAcpSsL55eV0JZgYtLzV9u8D7J9pCalkbJUzq70DWmn4yyGqBfbRcPlYQ # gTU6IjaM+/ggKYesdNAbYrw/ZIcCX+/FgO8GHNxeTpOHuJreTAdOhcxwxQ177MPZ # 45fpyxnbVkVs7ksgbMk+bP3wm/Eo+JGZqvxawZqCIDq37+fWuCVJwjkbh4E5y8O3 # Os2fUAQfGpmkgAJNHQWoVdNtUoCD5m5IpV/BiVhgiu/xrM2HYxiOdMuEh0FpY4G8 # 9h+qfNfBQc6tq3aLIIDULZUHjcf1CxcemuXWmWlRx06mnSlv53mTDTJjU67MximK # IMFgxvICLMT5yCLf+SeCoYNRwrzJghohhLKXvNSvRByWgiKVKoVUrvH9Pkl0dPyO # rj+lcvTDWgGqUKWLdpUbZuvv2t+ULtka60wnfUwF9/gjXcRXyCYFevyBI19UCTgq # YtWqyt/tz1OrH/ZEnNWZWcVWZFv3jlIPZvyYP0QGE2Ru6eEVYFClsezPuOjJC77F # hPfdCp3avClsPVbtv3hntlvIXhQcua+ELXei9zmVN29OfxzGPATWMcV+7z3oUX5x # rSR0Gyzc+Xyq78J2SWhi1Yv1A9++fY4PNnVGW5N2xIPugr4srjcS8bxWw+StQ8O3 # ZpZelDL6oPariVD6zqDzCIEa0USnzPe4MQIDAQABo4IBeDCCAXQwHwYDVR0jBBgw # FoAUGqH4YRkgD8NBd0UojtE1XwYSBFUwHQYDVR0OBBYEFGl1N3u7nTVCTr9X05rb # nwHRrt7QMA4GA1UdDwEB/wQEAwIGwDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM # MAoGCCsGAQUFBwMIMEAGA1UdIAQ5MDcwNQYMKwYBBAGyMQECAQMIMCUwIwYIKwYB # BQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMEQGA1UdHwQ9MDswOaA3oDWG # M2h0dHA6Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1JTQVRpbWVTdGFtcGluZ0NB # LmNybDB0BggrBgEFBQcBAQRoMGYwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQuc2Vj # dGlnby5jb20vU2VjdGlnb1JTQVRpbWVTdGFtcGluZ0NBLmNydDAjBggrBgEFBQcw # AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIBAEoD # eJBCM+x7GoMJNjOYVbudQAYwa0Vq8ZQOGVD/WyVeO+E5xFu66ZWQNze93/tk7OWC # t5XMV1VwS070qIfdIoWmV7u4ISfUoCoxlIoHIZ6Kvaca9QIVy0RQmYzsProDd6aC # ApDCLpOpviE0dWO54C0PzwE3y42i+rhamq6hep4TkxlVjwmQLt/qiBcW62nW4SW9 # RQiXgNdUIChPynuzs6XSALBgNGXE48XDpeS6hap6adt1pD55aJo2i0OuNtRhcjwO # hWINoF5w22QvAcfBoccklKOyPG6yXqLQ+qjRuCUcFubA1X9oGsRlKTUqLYi86q50 # 1oLnwIi44U948FzKwEBcwp/VMhws2jysNvcGUpqjQDAXsCkWmcmqt4hJ9+gLJTO1 # P22vn18KVt8SscPuzpF36CAT6Vwkx+pEC0rmE4QcTesNtbiGoDCni6GftCzMwBYj # yZHlQgNLgM7kTeYqAT7AXoWgJKEXQNXb2+eYEKTx6hkbgFT6R4nomIGpdcAO39Bo # lHmhoJ6OtrdCZsvZ2WsvTdjePjIeIOTsnE1CjZ3HM5mCN0TUJikmQI54L7nu+i/x # 8Y/+ULh43RSW3hwOcLAqhWqxbGjpKuQQK24h/dN8nTfkKgbWw/HXaONPB3mBCBP+ # smRe6bE85tB4I7IJLOImYr87qZdRzMdEMoGyr8/fMYIFgzCCBX8CAQEwgZEwfDEL # MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE # BxMHU2FsZm9yZDEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSQwIgYDVQQDExtT # ZWN0aWdvIFJTQSBDb2RlIFNpZ25pbmcgQ0ECEQCPKpf8Xi5s8FoozZAa2VspMAkG # BSsOAwIaBQCgeDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJ # AzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMCMG # CSqGSIb3DQEJBDEWBBRzKLZCnfYQZIPtL4otikHZHRCbIDANBgkqhkiG9w0BAQEF # AASCAQA4K2UkV6famsO6vNH0IHASRuUXopcAAvIx/gENo5w7U7e8YicohjV9jjsY # Ka9A/OODwr5QJ0Vr4JTa1tQ5KA8yhty/IlUSkgwtYuMuPD70nti1tXBgFJDySoCZ # QkAK/omKKV1LOCSmg6U8sgTrlT9lqWZcrvh6BdvdDkP0JRrNSJDgOOisvSSm5+QP # SlFBc4pRxtvT7FfaV5uj49b1pVeHWG2WiOEF9wX8R5hjl0I+sfyEoX62FUOESoN2 # bfRx25X/5bJRrZ2Kk9uF56f5Ir70JQgjpQBq9UnwA60DgJuiKDdlGXep8uzB6sI5 # mDxMVbyxChrBaQ3rzBawvi5G7TnboYIDTDCCA0gGCSqGSIb3DQEJBjGCAzkwggM1 # AgEBMIGSMH0xCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0 # ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEl # MCMGA1UEAxMcU2VjdGlnbyBSU0EgVGltZSBTdGFtcGluZyBDQQIRAIx3oACP9NGw # xj2fOkiDjWswDQYJYIZIAWUDBAICBQCgeTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcN # AQcBMBwGCSqGSIb3DQEJBTEPFw0yMTA1MDYxMTQ2NTRaMD8GCSqGSIb3DQEJBDEy # BDDIfXz9pR2C9Ia/6syRhAqRtEjIzUIEKRogTAeJaUILN4BYMtSgkOjNTRVF2bJU # B10wDQYJKoZIhvcNAQEBBQAEggIANEcPPXjZrU9m4qpDtKF+9mKOOtdbZjg2TZl4 # l1m61WCsjHFRap70lqjDJpIP9XHdwzUsvOHjCbNNZ8LEp0bcw6NTjCp/GjqG++HC # aHrYvCEcTSMRUqjzjsLMqAc6sZsAxUlYZJdC6s7R+ylTGBmu/HlS1Xgnq2mMPgd5 # I+gsAP9jPGFFwOtCCdKQ1zi5OZHiomWMbiBWv96/ppNG7/ZNg071b9KIhwGHAfnz # aRFpjheCqUk1f2lI6yaBrDEfDwXgIJa3NxH1vbXd7zUxKVvNq0/2O/By3Kw7BAhm # eD1oraGACzStG3aF32puoPiN76j3/fqXV75AkFM5EB0pH8TmqCh6rwuc/t+t6rCC # 2RJThYeQaMLf5ttHcm8pUMSyrOnNLqTiHmeYK0kR6Ed9lZMDF02L4monEIDF4O7n # 3QVIUI/tsC43RMQDtZpVrJLz73SxUvqk8x5V7RMj50sfmTooQSSDXI1VfumafRm9 # UfVngpJgto1L9XQbwPNLGQ3gFsXoGOeCJbr+xiNShVtF75xHgQRjtDeHRxKAgofo # b+EuOwA+TwjwoZMxkoAMKFlYpQrNv/4XgAWK86Dp4rNq4wUKyIzeNRfpCNJK3TZ8 # /NEyFhnpKuBsQqZlI25Z5hSsizatK1BtdmBwo1hkoxsin4CeI2V5rFynVEE+wGWg # CGv7iko= # SIG # End signature block |