Functions/Get-SCEPCertificate.ps1

<#
    .SYNOPSIS
    Requests a Certificate from an SCEP 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 SCEP Server.
    If using SSL, this must match the SCEP 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 CertificateTemplate
    Specifies the Object Identifier of a Certificate Template to be written into the Certificate Template Information Extension of the Certificate Request.
 
    .PARAMETER Eku
    Specifies one or more Enhanced Key Usages to be included in the Certificate Request.
    They get identified by their Friendly Name.
 
    .PARAMETER AppPolicy
    Specifies one or more Application Policies to be included in the Certificate Request.
    They get identified by their Friendly Name.
 
    .PARAMETER KeyUsage
    Specifies the Key Usage to be included in the Certificate Request.
    Unlike New-CertificateRequest, no Key Usage Extension is included unless specified.
 
    .PARAMETER Smime
    Specifies the S/MIME Capabilities the requestor supports.
 
    .PARAMETER Sid
    Specifies a Security Identifier to be written into the szOID_NTDS_CA_SECURITY_EXT Extension of the Certificate Request.
 
    .PARAMETER ChallengePassword
    Specifies the Challenge Password used to authenticate to the SCEP Server.
    Not necessary if the SCEP 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 SCEP 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 KeyAlgorithm
    Specifies the Algorithm to be used when creating the Key Pair.
    Defaults to "RSA".
 
    .PARAMETER KeyLength
    Specifies the Key Length for the Key pair of the Certificate.
    Gets applied only when KeyAlgorithm is "RSA".
    Defaults to 3072 Bits.
 
    .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 SCEP Server to be used.
    Only necessary if your SCEP 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".
 
    .NOTES
    CertificateTemplate, Eku, AppPolicy, KeyUsage, Smime and Sid only add Extensions to the Certificate Request.
    Whether they make it into the issued Certificate is up to the SCEP Server and the CA behind it.
    They cannot be combined with SigningCert, as a Renewal inherits its Extensions from that Certificate.
 
    .OUTPUTS
    System.Security.Cryptography.X509Certificates.X509Certificate. Returns the issued Certificate returned by the SCEP Server.
#>


Function Get-SCEPCertificate {

    [cmdletbinding()]
    [Alias("Get-NDESCertificate")]
    param(
        [Parameter(Mandatory=$True)]
        [String]
        $ComputerName,

        [Alias("Machine")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [Switch]
        $MachineContext,

        [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
            )]
        [ValidatePattern("^([0-2])((\.0)|(\.[1-9][0-9]*))*$")]
        [String]
        $CertificateTemplate,

        [Alias("EnhancedKeyUsage")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateSet(
            "EnrollmentAgent",
            "ClientAuthentication",
            "CodeSigning",
            "LifeTimeSigning",
            "DocumentSigning",
            "DocumentEncryption",
            "EncryptingFileSystem",
            "FileRecovery",
            "IPSecEndSystem",
            "IPSecIKEIntermediate",
            "IPSecTunnelEndpoint",
            "IPSecUser",
            "KeyRecovery",
            "KDCAuthentication",
            "SecureEmail",
            "ServerAuthentication",
            "SmartCardLogon",
            "TimeStamping",
            "OCSPSigning",
            "RemoteDesktopAuthentication",
            "PrivateKeyArchival"
            )]
        [String[]]
        $Eku,

        [Alias("ApplicationPolicy")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateSet(
            "EnrollmentAgent",
            "ClientAuthentication",
            "CodeSigning",
            "LifeTimeSigning",
            "DocumentSigning",
            "DocumentEncryption",
            "EncryptingFileSystem",
            "FileRecovery",
            "IPSecEndSystem",
            "IPSecIKEIntermediate",
            "IPSecTunnelEndpoint",
            "IPSecUser",
            "KeyRecovery",
            "KDCAuthentication",
            "SecureEmail",
            "ServerAuthentication",
            "SmartCardLogon",
            "TimeStamping",
            "OCSPSigning",
            "RemoteDesktopAuthentication",
            "PrivateKeyArchival"
            )]
        [String[]]
        $AppPolicy,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateSet(
            "CrlSign",
            "DataEncipherment",
            "DecipherOnly",
            "DigitalSignature",
            "EncipherOnly",
            "KeyAgreement",
            "KeyCertSign",
            "KeyEncipherment",
            "None",
            "NonRepudiation"
            )]
        [String[]]
        $KeyUsage,

        [Alias("SmimeCapabilities")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateSet(
            "des",
            "des3",
            "rc2",
            "rc4",
            "des3wrap",
            "rc2wrap",
            "aes128",
            "aes192",
            "aes256",
            "aes128wrap",
            "aes192wrap",
            "aes256wrap",
            "md5",
            "sha1",
            "sha256",
            "sha384",
            "sha512"
            )]
        [String[]]
        $Smime,

        [Alias("SecurityIdentifier")]
        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateNotNullOrEmpty()]
        [ValidatePattern("^S-1-5-21-[0-9]*-[0-9]*-[0-9]*-[0-9]*$")]
        [String]
        $Sid,

        [Parameter(
            ParameterSetName="NewRequest",
            Mandatory=$False
            )]
        [ValidateNotNullOrEmpty()]
        [String]
        $ChallengePassword,

        [Parameter(
            ParameterSetName="RenewalRequest",
            ValuefromPipeline = $True,
            Mandatory=$False
            )]
        [ValidateScript({($_.HasPrivateKey) -and ($null -ne $_.PSParentPath)})]
        [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(
            "RSA",
            "ECDSA_P256",
            "ECDSA_P384",
            "ECDSA_P521",
            "ECDH_P256",
            "ECDH_P384",
            "ECDH_P521",
            "ML-DSA:44",
            "ML-DSA:65",
            "ML-DSA:87"
            )]
        [String]
        $KeyAlgorithm = "RSA",

        [Alias("KeySize")]
        [Parameter(Mandatory=$False)]
        [ValidateSet(512,1024,2048,3072,4096,8192)]
        [Int]
        $KeyLength = 3072,

        [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",

        [Parameter(Mandatory=$False)]
        [ValidateScript({$_.Subject -eq $_.Issuer})]
        [System.Security.Cryptography.X509Certificates.X509Certificate]
        $RootCaCert,

        [ValidateSet(
            "POSTPKIOperation",
            "Renewal",
            "SHA-512",
            "SHA-256",
            "SHA-1",
            "AES",
            "DES3")]
        [String[]]
        $CaCapabilites
    )

    begin  {

        # 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
        if ($CaCapabilites) {
            $GetCACaps = $CaCapabilites -join [Environment]::NewLine
        }
        Else {
            Try {
                $GetCACaps = (Invoke-WebRequest -Uri "$($ConfigString)?operation=GetCACaps" -UseBasicParsing).Content
            }
            Catch {
                Write-Error -Message $PSItem.Exception.Message
                return
            }
        }

        # SCEP GetCACert Operation
        Try {
            $GetCACert = (Invoke-WebRequest -Uri "$($ConfigString)?operation=GetCACert" -UseBasicParsing).Content

            # Decoding the CMS (PKCS#7 Message that was returned from the SCEP Server)
            $Pkcs7CaCert = New-Object -TypeName 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 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
            }
        }

        $CertificateRequestPkcs10 = 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

                $CertificateRequestPkcs10.InitializeFromCertificate(
                    [int]($SigningCert.PSParentPath -match "Machine")+1,
                    [Convert]::ToBase64String($SigningCert.RawData),
                    $EncodingType.XCN_CRYPT_STRING_BASE64,
                    $InheritOptions
                )

                $CertificateRequestPkcs10.PrivateKey.Length = $KeyLength
                $CertificateRequestPkcs10.PrivateKey.ExportPolicy = [int]($PrivateKeyExportable.IsPresent)
                $CertificateRequestPkcs10.PrivateKey.ProviderName = $Ksp

                <#
                    RFC 8894
                    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.
                #>

                $CertificateRequestPkcs10.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)) {
                Write-Error -Message "You must provide an Identity, either in Form ob a Subject or Subject Alternative Name!"
                return
            }

            $PrivateKey = New-Object -ComObject X509Enrollment.CX509PrivateKey
            $PrivateKey.ProviderName = $Ksp
            $PrivateKey.MachineContext = [int]($MachineContext.IsPresent)
            $PrivateKey.ExportPolicy = [int]($PrivateKeyExportable.IsPresent)

            If ($KeyAlgorithm -ne "RSA") {

                $Algorithm = New-Object -ComObject X509Enrollment.CObjectId
    
                $Algorithm.InitializeFromAlgorithmName(
                    $ObjectIdGroupId.XCN_CRYPT_PUBKEY_ALG_OID_GROUP_ID,
                    $ObjectIdPublicKeyFlags.XCN_CRYPT_OID_INFO_PUBKEY_ANY,
                    $AlgorithmFlags.AlgorithmFlagsNone,
                    $KeyAlgorithm
                )
    
                $PrivateKey.Algorithm = $Algorithm
    
                [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($Algorithm))
            }
    
            # Key Length is only relevant when Key Type is "RSA"
            If ($KeyAlgorithm -eq "RSA") {
                $PrivateKey.Length = $KeyLength
            }
    
            Try {
                $PrivateKey.Create()
            }
            Catch {
                [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($PrivateKey))
                Write-Error -Message $PSItem.Exception.Message
                return
            }

            $CertificateRequestPkcs10.InitializeFromPrivateKey(
                [int]($MachineContext.IsPresent)+1,
                $PrivateKey, 
                [String]::Empty
            )

            Try {
                # To Do: implement Validation of the Subject RDN
                $SubjectDnObject = New-Object -ComObject "X509Enrollment.CX500DistinguishedName"
                $SubjectDnObject.Encode($Subject)
                $CertificateRequestPkcs10.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
        
                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
                $CertificateRequestPkcs10.X509Extensions.Add($SubjectAlternativeNamesExtension)
        
            }

            $X509Extensions = @{}

            If ($CertificateTemplate) {
                $X509Extensions.Add($Oid.szOID_CERTIFICATE_TEMPLATE, $(New-TemplateExtension -ObjectIdentifier $CertificateTemplate))
            }

            If ($KeyUsage) {
                $X509Extensions.Add($Oid.szOID_KEY_USAGE, $(New-KeyUsageExtension -KeyUsage $KeyUsage))
            }

            If ($Eku) {
                $X509Extensions.Add($Oid.XCN_OID_ENHANCED_KEY_USAGE, $(New-ExtendedKeyUsageExtension -Eku $Eku))
            }

            If ($AppPolicy) {
                $X509Extensions.Add($Oid.szOID_APPLICATION_CERT_POLICIES, $(New-ApplicationPoliciesExtension -ApplicationPolicies $AppPolicy))
            }

            If ($Smime) {
                $X509Extensions.Add($Oid.SmimeCapabilities, $(New-SmimeCapabilitiesExtension -Smime $Smime))
            }

            If ($Sid) {
                $X509Extensions.Add($Oid.szOID_NTDS_CA_SECURITY_EXT, $(New-SidExtension -Sid $Sid))
            }

            $X509Extensions.GetEnumerator() | ForEach-Object -Process {

                $X509Extension = New-Object -ComObject X509Enrollment.CX509Extension
                $X509ExtensionOid = New-Object -ComObject X509Enrollment.CObjectId

                try {
                    $X509ExtensionOid.InitializeFromValue($_.Key)
                    $X509Extension.Critical = $False
                    $X509Extension.Initialize($X509ExtensionOid, $EncodingType.XCN_CRYPT_STRING_BASE64, $_.Value)
                    $CertificateRequestPkcs10.X509Extensions.Add($X509Extension)
                }
                finally {
                    $X509Extension | Unregister-ComObject
                    $X509ExtensionOid | Unregister-ComObject
                }
            }

            If ($ChallengePassword) {
                <#
                    RFC 8894
                    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.
                #>

                $CertificateRequestPkcs10.ChallengePassword = $ChallengePassword
            }

        }

        <#
            Identify the Root CA Certificate that was delivered with the Chain
            A certificate is self-issued if the same DN appears in the subject and issuer fields
        #>

        if ($null -eq $RootCaCert) {
            $RootCaCert = $Pkcs7CaCert.Certificates | Where-Object { $_.Subject -eq $_.Issuer }
        }
        else {
            # This is a workaround for the case where the SCEP server doesnt provide the Root CA certificate. In this case we must fool the Microsoft API and inject the user-provided one.
            $CertificateCollection = $Pkcs7CaCert.Certificates
            [void]$CertificateCollection.Add([System.Security.Cryptography.X509Certificates.X509Certificate2]::New($RootCaCert.RawData))
            $GetCACert = $CertificateCollection.Export(5)
        }

        # Initialize the IX509SCEPEnrollment Interface
        $SCEPEnrollmentInterface = New-Object -ComObject "X509Enrollment.CX509SCEPEnrollment"

        # Let's try to build a SCEP Enrollment Message now...
        Try {

            $SCEPEnrollmentInterface.Initialize(
                $CertificateRequestPkcs10,
                (Get-Hash -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.
        $SCEPEnrollmentInterface.ServerCapabilities = $GetCACaps

        <#
            RFC 8894
            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.
 
            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

            $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
        $SCEPRequestMessage = $SCEPEnrollmentInterface.CreateRequestMessage(
            $EncodingType.XCN_CRYPT_STRING_BASE64
            )
        
        # Submission to the SCEP 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'} `
                        -UseBasicParsing
                }
                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'} `
                    -UseBasicParsing
            }

            $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.
            $Disposition = $SCEPEnrollmentInterface.ProcessResponseMessage(
                $SCEPResponse,
                $EncodingType.XCN_CRYPT_STRING_BASE64
                )

            Switch ($Disposition) {

                $X509SCEPDisposition.SCEPDispositionFailure {

                    $ErrorMessage = ''
                    $ErrorMessage += "The SCEP Server rejected the Certificate Request!`n"

                    $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 SCEP 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 SCEP 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 SCEP 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
                    $CertificateObject = [Security.Cryptography.X509Certificates.X509Certificate2]::new([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
        $CertificateRequestPkcs10,
        $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
# MIInYwYJKoZIhvcNAQcCoIInVDCCJ1ACAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCMO/NAx3z3P5V4
# 8YHZwEvtZTm6vYxlgJLOfon2Cwd6L6CCIBMwggZCMIIEKqADAgECAhBpEmNtaQD5
# xRtKmVz7/u/QMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQK
# ExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2Rl
# IFNpZ25pbmcgMjAyMSBDQTAeFw0yNjAzMTgwNzQ5NDRaFw0yNzA2MjAwNzQ5NDNa
# MGgxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIDAZCYXllcm4xFDASBgNVBAcMC0TDvHJy
# d2FuZ2VuMRgwFgYDVQQKDA9Vd2UgR3JhZGVuZWdnZXIxGDAWBgNVBAMMD1V3ZSBH
# cmFkZW5lZ2dlcjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAM2hKwhe
# E1F2z3bW4sx0w3zQoHm6QC3uXPWzhQ9slqAzgu4PHaIRE22OqlABXYtXq+iu2kh6
# PZxkim0QEdq1vtuHOKBnD1XEOBUx/NIi+PxZ02AaRulDO685tLUOrnupohxaG4qq
# 6C/Seyab8/7tXzMEhv/PsOGl1N4m3YOLJjUslMVhkLoNc12T/PzF6qTZThBRiKeD
# N0tlQo5EraLhghZ3jFKkpCH6ckGEVolBNwqg0BBJiT6mQtVlcZmlJK2c1rNq9Apw
# IvN9bA+5A/w9T3yhbIlz0nuoIqdTaFq0DUH2SFQdXZP6xEPuAICJCDaDrc3hL4WF
# gLc4Tw5SzwVKLawFeYhzCbq22CvA6+c4dGgMyLY99UXtIiHB52UQEmL50tkMRxWw
# Hsonxy2/H380mrVQus2/lM1X9xYcQrxHcjoDjQSi4JCClZekVYPUxgd9lxYQBd8+
# PpdRucjAzKmOx0uc5+tddVRzMYYoc/xQSWj06aTr2zDQu+dpchWFJHEirQIDAQAB
# o4IBeDCCAXQwDAYDVR0TAQH/BAIwADA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8v
# Y2NzY2EyMDIxLmNybC5jZXJ0dW0ucGwvY2NzY2EyMDIxLmNybDBzBggrBgEFBQcB
# AQRnMGUwLAYIKwYBBQUHMAGGIGh0dHA6Ly9jY3NjYTIwMjEub2NzcC1jZXJ0dW0u
# Y29tMDUGCCsGAQUFBzAChilodHRwOi8vcmVwb3NpdG9yeS5jZXJ0dW0ucGwvY2Nz
# Y2EyMDIxLmNlcjAfBgNVHSMEGDAWgBTddF1MANt7n6B0yrFu9zzAMsBwzTAdBgNV
# HQ4EFgQUwj1KxaiWz3BWxuN8zTWx+dWip28wSwYDVR0gBEQwQjAIBgZngQwBBAEw
# NgYLKoRoAYb2dwIFAQQwJzAlBggrBgEFBQcCARYZaHR0cHM6Ly93d3cuY2VydHVt
# LnBsL0NQUzATBgNVHSUEDDAKBggrBgEFBQcDAzAOBgNVHQ8BAf8EBAMCB4AwDQYJ
# KoZIhvcNAQELBQADggIBADrSbHhlYMa9ixnpIWBgVhL76qdlK5iPN35rlMHgK89n
# O9afz8EYTK7UExehOZxHtpLqO/hJu4eIQmjzC+tyUDii/3+IPoL1R9NlxAgoPxMc
# 3voLsX0xwTkl+R6dO6Q8RM3EDsknyUtVpjBggCPZ0pZsNumV1BXdIPPzdA1Rxm3F
# 6zcOGaXAJH37EWtbnc2e3X4EIxRFPm2EP5oiEYVEi90B3lcmo5p3iJG6zNSr+apG
# neN4AWuoGMbYBT7Ms5CdmbaM6uhuq73OqP6x47VjyeXpfuEVxvLSBfL24AI73//3
# 8sq2gH//j4qE8Ic4hV8NIBsHLvHuFH06z2EqWoEI0dKz2C92S86hqw+OGAcgLTVE
# StRppJXgtJwwxusm9OiJPIfDFY7kQxSGRq4B1YR1GGaUm1p4s2+819H8sYM+RGbM
# MCrY4C8EQNeCJedXZeCIXyWFDRizK7BB6B24DC0a7XR7cedQOMwMy/m9kZRsSt6X
# 7c84iOhCEL3Degnv8V4/KJSDtaOMVQUm6vRyFdQEfkVCHCaOuM6i4lQwKu38nOx+
# vNkCOSm3LWrYJGMxk1/KcPL5T+nR8WIR9SaS2vEGEvZmie71Q6qdug8cmPibxIs6
# N8wM2NJ+fDBHhoZl6as2VmDvLhqkbJaC0Piz82UWi6lGAfrhs4sLjOPIRvSauJTe
# MIIGuTCCBKGgAwIBAgIRAJmjgAomVTtlq9xuhKaz6jkwDQYJKoZIhvcNAQEMBQAw
# gYAxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBT
# LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAi
# BgNVBAMTG0NlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EgMjAeFw0yMTA1MTkwNTMy
# MThaFw0zNjA1MTgwNTMyMThaMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3Nl
# Y28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25p
# bmcgMjAyMSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAJ0jzwQw
# IzvBRiznM3M+Y116dbq+XE26vest+L7k5n5TeJkgH4Cyk74IL9uP61olRsxsU/WB
# AElTMNQI/HsE0uCJ3VPLO1UufnY0qDHG7yCnJOvoSNbIbMpT+Cci75scCx7UsKK1
# fcJo4TXetu4du2vEXa09Tx/bndCBfp47zJNsamzUyD7J1rcNxOw5g6FJg0ImIv7n
# CeNn3B6gZG28WAwe0mDqLrvU49chyKIc7gvCjan3GH+2eP4mYJASflBTQ3HOs6JG
# driSMVoD1lzBJobtYDF4L/GhlLEXWgrVQ9m0pW37KuwYqpY42grp/kSYE4BUQrbL
# gBMNKRvfhQPskDfZ/5GbTCyvlqPN+0OEDmYGKlVkOMenDO/xtMrMINRJS5SY+jWC
# i8PRHAVxO0xdx8m2bWL4/ZQ1dp0/JhUpHEpABMc3eKax8GI1F03mSJVV6o/nmmKq
# DE6TK34eTAgDiBuZJzeEPyR7rq30yOVw2DvetlmWssewAhX+cnSaaBKMEj9O2GgY
# kPJ16Q5Da1APYO6n/6wpCm1qUOW6Ln1J6tVImDyAB5Xs3+JriasaiJ7P5KpXeiVV
# /HIsW3ej85A6cGaOEpQA2gotiUqZSkoQUjQ9+hPxDVb/Lqz0tMjp6RuLSKARsVQg
# ETwoNQZ8jCeKwSQHDkpwFndfCceZ/OfCUqjxAgMBAAGjggFVMIIBUTAPBgNVHRMB
# Af8EBTADAQH/MB0GA1UdDgQWBBTddF1MANt7n6B0yrFu9zzAMsBwzTAfBgNVHSME
# GDAWgBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0l
# BAwwCgYIKwYBBQUHAwMwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5jZXJ0
# dW0ucGwvY3RuY2EyLmNybDBsBggrBgEFBQcBAQRgMF4wKAYIKwYBBQUHMAGGHGh0
# dHA6Ly9zdWJjYS5vY3NwLWNlcnR1bS5jb20wMgYIKwYBBQUHMAKGJmh0dHA6Ly9y
# ZXBvc2l0b3J5LmNlcnR1bS5wbC9jdG5jYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0g
# ADAmMCQGCCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZI
# hvcNAQEMBQADggIBAHWIWA/lj1AomlOfEOxD/PQ7bcmahmJ9l0Q4SZC+j/v09CD2
# csX8Yl7pmJQETIMEcy0VErSZePdC/eAvSxhd7488x/Cat4ke+AUZZDtfCd8yHZgi
# kGuS8mePCHyAiU2VSXgoQ1MrkMuqxg8S1FALDtHqnizYS1bIMOv8znyJjZQESp9R
# T+6NH024/IqTRsRwSLrYkbFq4VjNn/KV3Xd8dpmyQiirZdrONoPSlCRxCIi54vQc
# qKiFLpeBm5S0IoDtLoIe21kSw5tAnWPazS6sgN2oXvFpcVVpMcq0C4x/CLSNe0Xc
# kmmGsl9z4UUguAJtf+5gE8GVsEg/ge3jHGTYaZ/MyfujE8hOmKBAUkVa7NMxRSB1
# EdPFpNIpEn/pSHuSL+kWN/2xQBJaDFPr1AX0qLgkXmcEi6PFnaw5T17UdIInA58r
# Tu3mefNuzUtse4AgYmxEmJDodf8NbVcU6VdjWtz0e58WFZT7tST6EWQmx/OoHPel
# E77lojq7lpsjhDCzhhp4kfsfszxf9g2hoCtltXhCX6NqsqwTT7xe8LgMkH4hVy8L
# 1h2pqGLT2aNCx7h/F95/QvsTeGGjY7dssMzq/rSshFQKLZ8lPb8hFTmiGDJNyHga
# 5hZ59IGynk08mHhBFM/0MLeBzlAQq1utNjQprztZ5vv/NJy8ua9AGbwkMWkOMIIF
# yTCCBLGgAwIBAgIQG7WPJSrfIwBJKMmuPX7tJzANBgkqhkiG9w0BAQwFADB+MQsw
# CQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEn
# MCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIwIAYDVQQD
# ExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMB4XDTIxMDUzMTA2NDMwNloXDTI5
# MDkxNzA2NDMwNlowgYAxCzAJBgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRl
# Y2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBB
# dXRob3JpdHkxJDAiBgNVBAMTG0NlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EgMjCC
# AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL35ePjm1YAMZJ2GG5ZkZz8i
# Oh51AX3v+1xnjMnMXGupkea5QuUgS5vam3u5mV3Zm4BL14RAKyfT6Lowuz4JGqdJ
# le8rQCTCl8en7psl76gKAJeFWqqd3CnJ4jUH63BNStbBs1a4oUE4m9H7MX+P4F/h
# sT8PjhZJYNcGjRj5qiYQqyrT0NFnjRtGvkcw1S5y0cVj2udjeUR+S2MkiYYuND8p
# TFKLKqfA4pEoibnAW/kd2ecnrf+aApfBxlCSmwIsvam5NFkKv4RK/9/+s5/r2Z7g
# mCPspmt3FirbzK07HKSH3EZzXhliaEVX5JCCQrtC1vBh4MGjPWajXfQY7ojJjRdF
# KZkydQIx7ikmyGsC5rViRX83FVojaInUPt5OJ7DwQAy8TRfLTaKzHtAGWt32k89X
# dZn1+oYaZ3izv5b+NNy951JW5bPldXvXQZEF3F1p45UNQ7n8g5Y5lXtsgFpPE3LG
# 130pekS6UqQq1UFGCSD+IqC2WzCNvIkM1ddw+IdS/drvrFEuB7NO/tAJ2nDvmPpW
# 5m3btVdL3OUsJRXIni54TvjanJ6GLMpX8xrlyJKLGoKWesO8UBJp2A5aRos66yb6
# I8m2sIG+QgCk+Nb+MC7H0kb25Y51/fLMudCHW8wGEGC7gzW3XmfeR+yZSPGkoRX+
# rYxijjlVTzkWubFjnf+3AgMBAAGjggE+MIIBOjAPBgNVHRMBAf8EBTADAQH/MB0G
# A1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAfBgNVHSMEGDAWgBQIds3LB/8k
# 9sXN7buQvOKEN0Z19zAOBgNVHQ8BAf8EBAMCAQYwLwYDVR0fBCgwJjAkoCKgIIYe
# aHR0cDovL2NybC5jZXJ0dW0ucGwvY3RuY2EuY3JsMGsGCCsGAQUFBwEBBF8wXTAo
# BggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVtLmNvbTAxBggrBgEF
# BQcwAoYlaHR0cDovL3JlcG9zaXRvcnkuY2VydHVtLnBsL2N0bmNhLmNlcjA5BgNV
# HSAEMjAwMC4GBFUdIAAwJjAkBggrBgEFBQcCARYYaHR0cDovL3d3dy5jZXJ0dW0u
# cGwvQ1BTMA0GCSqGSIb3DQEBDAUAA4IBAQBRwqFYFiIQi/yGMdTCMtNc+EuiL2o+
# TfirCB7t1ej65wgN7LfGHg6ydQV6sQv613RqAAYfpM6q8mt92BHAEQjUDk1hxTqo
# +rHh45jq4mP9QfWTfQ28XZI7kZplutBfTL5MjWgDEBbV8dAEioUz+TfnWy4maUI8
# us281HrpTZ3a50P7Y1KAhQTEJZVV8H6nnwHFWyj44M6GcKYnOzn7OC6YU2UidS3X
# 9t0iIpGW691o7T+jGZfTOyWI7DYSPal+zgKNBZqSpyduRbKcYoY3DaQzjteoTtBK
# F0NMxfGnbNIeWGwUUX6KVKH27595el2BmhaQD+G78UoA+fndvu2q7M4KMIIGuTCC
# BKGgAwIBAgIRAOf/acc7Nc5LkSbYdHxopYcwDQYJKoZIhvcNAQEMBQAwgYAxCzAJ
# BgNVBAYTAlBMMSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScw
# JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxJDAiBgNVBAMT
# G0NlcnR1bSBUcnVzdGVkIE5ldHdvcmsgQ0EgMjAeFw0yMTA1MTkwNTMyMDdaFw0z
# NjA1MTgwNTMyMDdaMFYxCzAJBgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0
# YSBTeXN0ZW1zIFMuQS4xJDAiBgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAy
# MSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAOkSHwQ17bldesWm
# lUG+imV/TnfRbSV102aO2/hhKH9/t4NAoVoipzu0ePujH67y8iwlmWuhqRR4xLeL
# dPxolEL55CzgUXQaq+Qzr5Zk7ySbNl/GZloFiYwuzwWS2AVgLPLCZd5DV8QTF+V5
# 7Y6lsdWTrrl5dEeMfsxhkjM2eOXabwfLy6UH2ZHzAv9bS/SmMo1PobSx+vHWST7c
# 4aiwVRvvJY2dWRYpTipLEu/XqQnqhUngFJtnjExqTokt4HyzOsr2/AYOm8YOcoJQ
# xgvc26+LAfXHiBkbQkBdTfHak4DP3UlYolICZHL+XSzSXlsRgqiWD4MypWGU4A13
# xiHmaRBZowS8FET+QAbMiqBaHDM3Y6wohW07yZ/mw9ZKu/KmVIAEBhrXesxifPB+
# DTyeWNkeCGq4IlgJr/Ecr1px6/1QPtj66yvXl3uauzPPGEXUk6vUym6nZyE1IGXI
# 45uGVI7XqvCt99WuD9LNop9Kd1LmzBGGvxucOo0lj1M3IRi8FimAX3krunSDguC5
# HgD75nWcUgdZVjm/R81VmaDPEP25Wj+C1reicY5CPckLGBjHQqsJe7jJz1CJXBMU
# tZs10cVKMEK3n/xD2ku5GFWhx0K6eFwe50xLUIZD9GfT7s/5/MyBZ1Ep8Q6H+GMu
# udDwF0mJitk3G8g6EzZprfMQMc3DAgMBAAGjggFVMIIBUTAPBgNVHRMBAf8EBTAD
# AQH/MB0GA1UdDgQWBBS+VAIvv0Bsc0POrAklTp5DRBru4DAfBgNVHSMEGDAWgBS2
# oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYI
# KwYBBQUHAwgwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL2NybC5jZXJ0dW0ucGwv
# Y3RuY2EyLmNybDBsBggrBgEFBQcBAQRgMF4wKAYIKwYBBQUHMAGGHGh0dHA6Ly9z
# dWJjYS5vY3NwLWNlcnR1bS5jb20wMgYIKwYBBQUHMAKGJmh0dHA6Ly9yZXBvc2l0
# b3J5LmNlcnR1bS5wbC9jdG5jYTIuY2VyMDkGA1UdIAQyMDAwLgYEVR0gADAmMCQG
# CCsGAQUFBwIBFhhodHRwOi8vd3d3LmNlcnR1bS5wbC9DUFMwDQYJKoZIhvcNAQEM
# BQADggIBALiTWXfJTBX9lAcIoKd6oCzwQZOfARQkt0OmiQ390yEqMrStHmpfycgg
# fPGlBHdMDDYhHDVTGyvY+WIbdsIWpJ1BNRt9pOrpXe8HMR5sOu71AWOqUqfEIXaH
# WOEs0UWmVs8mJb4lKclOHV8oSoR0p3GCX2tVO+XF8Qnt7E6fbkwZt3/AY/C5KYzF
# ElU7TCeqBLuSagmM0X3Op56EVIMM/xlWRaDgRna0hLQze5mYHJGv7UuTCOO3wC1b
# zeZWdlPJOw5v4U1/AljsNLgWZaGRFuBwdF62t6hOKs86v+jPIMqFPwxNJN/ou22D
# qzpP+7TyYNbDocrThlEN9D2xvvtBXyYqA7jhYY/fW9edUqhZUmkUGM++Mvz9lyT/
# nBdfaKqM5otK0U5H8hCSL4SGfjOVyBWbbZlUIE8X6XycDBRRKEK0q5JTsaZksoKa
# bFAyRKJYgtObwS1UPoDGcmGirwSeGMQTJSh+WR5EXZaEWJVA6ZZPBlGvjgjFYaQ0
# kLq1OitbmuXZmX7Z70ks9h/elK0A8wOg8oiNVd3o1bb59ms1QF4OjZ45rkWfsGuz
# 8ctB9/leCuKzkx5Rt1WAOsXy7E7pws+9k+jrePrZKw2DnmlNaT19QgX2I+hFtvhC
# 6uOhj/CgjVEA4q1i1OJzpoAmre7zdEg+kZcFIkrDHgokA5mcIMK1MIIGgjCCBGqg
# AwIBAgIQKPB3wRw2vf5fdDJHcCcuAzANBgkqhkiG9w0BAQwFADBWMQswCQYDVQQG
# EwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMSQwIgYDVQQD
# ExtDZXJ0dW0gVGltZXN0YW1waW5nIDIwMjEgQ0EwHhcNMjYwMzExMDczNDU0WhcN
# MzYwMjI3MDczNDU0WjBQMQswCQYDVQQGEwJQTDEhMB8GA1UECgwYQXNzZWNvIERh
# dGEgU3lzdGVtcyBTLkEuMR4wHAYDVQQDDBVDZXJ0dW0gVGltZXN0YW1wIDIwMjYw
# ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC4vc3wcPsSNdoYthfbjUAT
# Tkk5EyItd37odw4lsmyOd/dmwXycOrTu8w7O1Kj/63o1X+MRU1N1zTj7LjhZD+Uj
# xbJ1sJ91SS/jYTYbLro72LELWkJ7zaNcJOOq3k4MLNS/DhRHSmsYMqk+MzkMfNZi
# 8DWUqlzVPUa2/aACViReDMnc/gtXm7tA9Pr4DN7agEPE1NtN36oCgj6iHR5aGhah
# /XskfvLZ6ZstoZ5zefWTrZrLh3kcH+YkzoZYX9Hf6qqrizkiBj4BlS9R4+VwVKMd
# jhO7UEa/pf8cTWy+jrsATuAGthG7sWIN+3KV7+Ytv5Uy+DQEgf3bn/VuH4wN0aPh
# j/mwueJ9jmIjNwqvM/dno8fBeR1jtnuP++XgveQfbTMP3qu9dPRg8ltvtrreQZ9K
# PDFyUxEZMsrLVm6nJ1JKJgPe6n4gwsL6VrjjHX0zpLF3vUvsQ8TiWgm4sk4r4D7p
# cXE/rX0E0Vwa+VMLT73PiDZ2nzhIpc1RwNdbb/qR3Mpa8sQXNPHFIoX/7bapGUtG
# 5sd1cUGsvLqIWk6dP/xAgPb2BludUinSTCYV7ysiHQS8vFmDXIU7fMkSE7/QHcYP
# Sahro4fk5z9W1t2kIxbZRJe0s4DXiPDlQPwiQFllLkU9wLvU6DqR8v35a65J4TeI
# XhMO/+iCzL+B0rI9GGeKLQIDAQABo4IBUDCCAUwwdQYIKwYBBQUHAQEEaTBnMDsG
# CCsGAQUFBzAChi9odHRwOi8vc3ViY2EucmVwb3NpdG9yeS5jZXJ0dW0ucGwvY3Rz
# Y2EyMDIxLmNlcjAoBggrBgEFBQcwAYYcaHR0cDovL3N1YmNhLm9jc3AtY2VydHVt
# LmNvbTAfBgNVHSMEGDAWgBS+VAIvv0Bsc0POrAklTp5DRBru4DAMBgNVHRMBAf8E
# AjAAMDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9zdWJjYS5jcmwuY2VydHVtLnBs
# L2N0c2NhMjAyMS5jcmwwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDgYDVR0PAQH/
# BAQDAgeAMCIGA1UdIAQbMBkwCAYGZ4EMAQQCMA0GCyqEaAGG9ncCBQELMB0GA1Ud
# DgQWBBQjOWooq5oSp6Sn8h/5RZq/jf6CAzANBgkqhkiG9w0BAQwFAAOCAgEAZv6T
# m6wL3k6mBTwkrYcTVcAR01uE37gUGNihgnTJR+gC41T2H9lwETRjE10nEdCUNv3N
# i8S6aBx4UcMRX93fd9w4RUteua2I+oj0kCpuNa3PQDKUwozHZmotWivaPO9KTs08
# y0YVhVSMZvuUH/reFec9eLT6FLAFnX0Sg9Wc7833uQB5RPa8TmXBkTolC8bNxHX+
# 2SfEWSNI8w/Y7o9qBF9l0uwVSrjQitVtIdZo2qb9NvMqqPFLWYef9SG+PGMqfPAQ
# 2EoYeT0hlFLkubWF1X3HbiDwXtz3TU2EWHU+VTcZMC4IzMyHK/+kh9n3oxSQ45ws
# Y71y7mqxKyYPyHSPoV3RiAQ1Thr9c65BeJLaELxWSKeQyAGIdBsMlIXPO6qp+VGm
# E49vosogQ0jYe2hgq5LgJ6oO0Ie364V/kITBnifUqS6Zxu+qjfOYS8o72EeoEWIi
# 04/BuH8Y6leNNP27j8NKwaPciWcqv/HBnQjizzmH/aqXn03K2SnjvaYPlCR8fFAA
# W2k6os0cZvLFEhMnHHAghYSIrdwCP98BrkjgA3ogOu+jXEO/nbD9OGL873Te6U2T
# coOu9lqQQyXYNHiLR5eMqJrzXiDlodarOEKjlukyPDnLIuLkg0y6K8S1A5wU8CkM
# 86cXdWFHLRIEYd9kdCfRZBZHhK7iVPeEZYxa9bgxggamMIIGogIBATBqMFYxCzAJ
# BgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAi
# BgNVBAMTG0NlcnR1bSBDb2RlIFNpZ25pbmcgMjAyMSBDQQIQaRJjbWkA+cUbSplc
# +/7v0DANBglghkgBZQMEAgEFAKCBiDAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIB
# BDAcBgkqhkiG9w0BCQUxDxcNMjYxMDA3MTQyMTU0WjAcBgorBgEEAYI3AgELMQ4w
# DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgB9E56ChZWvAN7Co5gqZP8k5K
# sTdHSIsRQopvcyMNdBwwDQYJKoZIhvcNAQEBBQAEggGAbq5P40GrzfE9k7lZ6V8v
# unCBibowNRzsoeuny6hAb0pNXoYsW2emYw7Hmu2DpLlf/UiE+8+qEpWepd1vUQ+U
# WzCgWrqEnqHy2eNbNiT+I3NaIyRv8LYyPJkChLPY5SDDl7i8H/QNI69Y5+6MwTU7
# WfcJS+HKNs3QUKLb6n8ZiNr/IbaG8qMqpVa6UJlSY/JQYRHzgzEHhET+Ba+JrDxD
# MOKKlER5pZ3YOnNhCHXIqgwEjHIVSf9y3ykD00PFDheTOD/HgMNYDRTqYW33TTKp
# CxaBc2jQ4wNg+0TsQJBrdvQxnrdlRvD1nHUZfepiLsQHyWfwQ4Dq4vHkXqbXISxh
# awzcntptsYjarGWwB1kusjIPYTYpBNQ3+QHpfb4cS/p8ZWcbhazaha5iMOql5+kj
# zSPjRRf1eilHvtZxk/DKgRKuM7nUQqLk9gFSGZfIfZtgmWDBHey8xo07J34eJmtR
# hRmtHWeML+FNSZDZ2yVRkJ9KsAw1iznMehxeCxquEgtzoYIEAjCCA/4GCSqGSIb3
# DQEJBjGCA+8wggPrAgEBMGowVjELMAkGA1UEBhMCUEwxITAfBgNVBAoTGEFzc2Vj
# byBEYXRhIFN5c3RlbXMgUy5BLjEkMCIGA1UEAxMbQ2VydHVtIFRpbWVzdGFtcGlu
# ZyAyMDIxIENBAhAo8HfBHDa9/l90MkdwJy4DMA0GCWCGSAFlAwQCAgUAoIIBVjAa
# BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MTAw
# NzE0MjE1NVowNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQghb6Q4QrSQ418ySi2r0iw
# mrIIF3zs+LASbFjTkQUlxDwwPwYJKoZIhvcNAQkEMTIEMAu1uwwFOLXFy4KYzLHo
# Pv4pOFrGGmPii2doOw4laboMZDkwZaqD26Z+/O9ldLvZBjCBnwYLKoZIhvcNAQkQ
# AgwxgY8wgYwwgYkwgYYEFFcUaEEMqFrzQk75FkpRNhD0042YMG4wWqRYMFYxCzAJ
# BgNVBAYTAlBMMSEwHwYDVQQKExhBc3NlY28gRGF0YSBTeXN0ZW1zIFMuQS4xJDAi
# BgNVBAMTG0NlcnR1bSBUaW1lc3RhbXBpbmcgMjAyMSBDQQIQKPB3wRw2vf5fdDJH
# cCcuAzANBgkqhkiG9w0BAQEFAASCAgBK50Y2IMoBuUmPGdeNLupRpk0ikzXm+iDN
# qEGCBx4q1zx1YpdsSMJo7OFMv4gB7yLnzwA4g/nOeO+QtHHqO6QUc6xQZvS45i+2
# iI374NA1ce3Wr4OHmY7kDWk1dGFLv6nvudmTxzmf8XKfrqXqNzYtJZcAkVwE8gtZ
# jVprvaSe8+W1XKZZLoPDzEkAoRGTvFuPtfCTDw/AimwUO32tMG5CRWbpedCzjh0X
# W/I8QvK0SWsoILZL51knl2KpS7utfGYZC7p+H8JKSiJi98bT7oyUJpqPI/YymIjf
# 0B0gSxlburqoyrbDtfsNvPoqUAhwpgGc6jEYwG5Od2KdDCMjUA7EbJ7OzUGhDjW+
# AdfmvcuHfw2nvPTDgyryMt+78QtCOvV/OPU2O3uQ9eplT+VDcSGmiMGmO4unzScc
# wrs2f7fuEhCLBkp4GPAjisRsN+QNM1ky6lywYt3xcSC+w2Q5VN8PSidFlqBZC9iQ
# jtTellQI++vpFr8h0PsFNmwIcefVlt7cvXxRLcU8yLdQsF+8hbzxlLP8hdLAdP+q
# pu+/09R7J00NRyFMB/MrLSZmUZUXC1TV6t1tt1RHq5ne7cWxO4/zmVelqiLEKTRi
# jC7AjfZ4t+G6BE0Z9a62VmZvebVDTQ4psp+ZggaSw6Yt98UezfGbu9sCVuW1LUOR
# KQqQY7GsYg==
# SIG # End signature block