Functions/Get-IssuedCertificate.ps1

<#
    .SYNOPSIS
    Allows for Submission of a Certificate Request to a Certification Authority.
    Allows for retrieval of a previously issued Certificate from a Certification Authority.
 
    .PARAMETER CertificateRequest
    The BASE64 encoded Certificate Request to be submitted to the Certification Authority.
 
    .PARAMETER RequestId
    The Request Identifier that was given to a previously submitted Certificate Request.
 
    .PARAMETER ConfigString
    The Configuration String for the Certificate Authority to connect to, either
    in the Form of "<Hostname>\<Common-Name-of-CA>" for a RPC/DCOM Enrollment or
    in for Form of "https://<Hostname>/<Common-Name-of-CA>_CES_<Authentication-Type>/service.svc/CES"
    for a WSTEP (Certificate Enrollment Web Service) Enrollment.
 
    .PARAMETER CertificateTemplate
    Optional: The name of the Certificate Template to request a Certificate from.
    Must be used if the Certificate request does not contain this information.
 
    .PARAMETER Credential
    Credentials when performing a WSTEP Enrollment with Username/Password Authentication.
 
    .PARAMETER ClientCertificate
    Thumbprint of an authentication Certificate when performing a WSTEP Enrollment with Client Certificate Authentication.
 
    .PARAMETER MachineContext
    Uses the machine's identity for submitting the certificate request.
 
    .OUTPUTS
    An object representing the Enrollment/Retrieval result.
#>


Function Get-IssuedCertificate {

    [CmdletBinding()]
    param (

        [Parameter(
            ParameterSetName="Submit",
            Mandatory=$True,
            ValuefromPipeline=$True
            )]
        [ValidateNotNullOrEmpty()]
        [String]
        $CertificateRequest,

        [Parameter(
            ParameterSetName="Retrieve",
            Mandatory=$True
            )]
        [ValidateRange(1, [Int]::MaxValue)]
        [Int]
        $RequestId,

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

        [Alias("Config")]
        [Parameter(Mandatory=$True)]
        [ValidateNotNullOrEmpty()]
        [String]
        $ConfigString,
    
        [Parameter(
            ParameterSetName="Submit",
            Mandatory=$False
            )]
        [ValidateNotNullOrEmpty()]
        [String]
        $CertificateTemplate,
        
        [Parameter(Mandatory=$False)]
        [System.Management.Automation.PSCredential]
        $Credential,

        [Parameter(Mandatory=$False)]
        [ValidatePattern("^[0-9a-fA-F]{40}$")]
        [String]
        $ClientCertificate,

        [Alias("Attrib")]
        [Parameter(
            ParameterSetName="Submit",
            Mandatory=$False
            )]
        [String[]]
        $RequestAttributes
    )
    
    begin {}

    process {

        # Ensuring we work with Elevation when using the machine identity
        If ($MachineContext.IsPresent) {

            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
            }
        }

        # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nn-certcli-icertrequest
        $CertRequest = New-Object -ComObject CertificateAuthority.Request

        # Configuring the Certificate Request Interface when using the WSTEP Protocol
        # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nf-certcli-icertrequest3-setcredential
        If ($ConfigString.StartsWith("https://")) { 

            # WSTEP with Username and Password Authentication
            If ($ConfigString.EndsWith(
                "UsernamePassword/service.svc/CES", 
                [System.StringComparison]::OrdinalIgnoreCase
                )) {

                If ($Credential) {

                    $CertRequest.SetCredential(
                        [Int]$null, # no Window Handle
                        $X509EnrollmentAuthFlags.X509AuthUsername,
                        $Credential.UserName,
                        [Runtime.InteropServices.Marshal]::PtrToStringAuto(
                            [Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.Password)
                        )
                    )

                }
                Else {
                    Write-Error -Message "You must provide Authentication Credentials."
                    return
                }
            }

            # WSTEP with Client Certificate Authentication
            If ($ConfigString.EndsWith(
                "Certificate/service.svc/CES", 
                [System.StringComparison]::OrdinalIgnoreCase
                )) {

                If ($ClientCertificate) {

                    $CertRequest.SetCredential(
                        [Int]$null, # no Window Handle
                        $X509EnrollmentAuthFlags.X509AuthCertificate,
                        $ClientCertificate,
                        [String]::Empty
                    )

                }
                Else {
                    Write-Error -Message "You must provide a Client Authentication Certificate Thumbprint."
                    return
                }
            }

            # WSTEP with Kerberos Authentication
            If ($ConfigString.EndsWith(
                "Kerberos/service.svc/CES", 
                [System.StringComparison]::OrdinalIgnoreCase
                )) {
    
                $CertRequest.SetCredential(
                    [Int]$null, # no Window Handle
                    $X509EnrollmentAuthFlags.X509AuthKerberos,
                    [String]::Empty,
                    [String]::Empty
                )

            }
        }

        # Submit a Certificate Request
        If ($CertificateRequest) {

            # Additional attributes can be specified here

            # https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/certutil
            # Names and values must be colon separated, while multiple name, value pairs must be newline separated.
            # For example: CertificateTemplate:User\nEMail:User@Domain.com where the \n sequence is converted to a newline separator.

            If ($CertificateTemplate) {
                $RequestAttributes += "CertificateTemplate:$($CertificateTemplate)" # Names and values must be colon separated
            }

            $Flags = $RequestFlags.CR_IN_ENCODEANY
            
            If ($MachineContext.IsPresent) {
                $Flags = $Flags -bor $RequestFlags.CR_IN_MACHINE
            }

            Try {
                # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nf-certcli-icertrequest-submit
                $Status = $CertRequest.Submit(
                    $Flags,
                    $CertificateRequest,
                    $($RequestAttributes -join [Environment]::NewLine), # multiple name, value pairs must be newline separated.
                    $ConfigString
                )
            }
            Catch {
                Write-Error -Message $PSItem.Exception.Message
                return
            }
        }

        # Retrieve a pending Certificate Request
        If ($RequestId) {

            Try {
                # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nf-certcli-icertrequest-retrievepending
                $Status = $CertRequest.RetrievePending(
                    $RequestId,
                    $ConfigString
                )
            }
            Catch {
                Write-Error -Message $PSItem.Exception.Message
                return
            }
        }

        # Properly formatting Return Code and translate into a meaningful message
        $StatusCode = "0x" + ('{0:x}' -f $CertRequest.GetLastStatus())
        $StatusCodeInt = $CertRequest.GetLastStatus()
        $StatusMessage = (New-Object System.ComponentModel.Win32Exception($CertRequest.GetLastStatus())).Message

        # Process the Submission Result and return it
        Switch ($Status) {

            $DispositionType.CR_DISP_INCOMPLETE {

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Request is incomplete"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }
           
            $DispositionType.CR_DISP_ERROR {

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "There was an error during submission"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }

            $DispositionType.CR_DISP_DENIED {

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Request was denied"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }

            $DispositionType.CR_DISP_ISSUED {

                # https://docs.microsoft.com/en-us/windows/win32/api/certcli/nf-certcli-icertrequest-getcertificate
                # https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2.import
                $CertificateObject = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
                $CertificateObject.Import(
                    [Convert]::FromBase64String(
                        $CertRequest.GetCertificate($RequestFlags.CR_OUT_BASE64)
                    )
                )

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Certificate was issued"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $CertificateObject
                    RawCertificate = $CertRequest.GetCertificate($RequestFlags.CR_OUT_BASE64HEADER)
                }
            }

            $DispositionType.CR_DISP_ISSUED_OUT_OF_BAND {

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Certificate was issued out of band"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }

            $DispositionType.CR_DISP_UNDER_SUBMISSION {
                
                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Request was taken under submission"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }

            $DispositionType.CR_DISP_REVOKED {

                [PSCustomObject]@{
                    RequestId = $CertRequest.GetRequestId()
                    Disposition = $Status
                    Result = "Certificate has been revoked"
                    StatusCode = $StatusCode
                    StatusCodeInt = $StatusCodeInt
                    StatusMessage = $StatusMessage
                    Certificate = $null
                    RawCertificate = $null
                }
            }

            # This should never happen, but just to be on the safe side
            default{
                Write-Error -Message "Retrieved unsupported Disposition Code $Status from the Certification Authority."
            }

        }

        [void]([System.Runtime.Interopservices.Marshal]::ReleaseComObject($CertRequest))

    }
    
    end {}
    
}
# SIG # Begin signature block
# MIIruQYJKoZIhvcNAQcCoIIrqjCCK6YCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAGZ7ZB5LHA8OYh
# 1tL/e/DDswXFkJJK5eRLlMcMVVIaTKCCJM8wggVvMIIEV6ADAgECAhBI/JO0YFWU
# jTanyYqJ1pQWMA0GCSqGSIb3DQEBDAUAMHsxCzAJBgNVBAYTAkdCMRswGQYDVQQI
# DBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoM
# EUNvbW9kbyBDQSBMaW1pdGVkMSEwHwYDVQQDDBhBQUEgQ2VydGlmaWNhdGUgU2Vy
# dmljZXMwHhcNMjEwNTI1MDAwMDAwWhcNMjgxMjMxMjM1OTU5WjBWMQswCQYDVQQG
# EwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdv
# IFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUA
# A4ICDwAwggIKAoICAQCN55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+s
# hJHjUoq14pbe0IdjJImK/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCD
# J9qaDStQ6Utbs7hkNqR+Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7
# P2bSlDFp+m2zNKzBenjcklDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extme
# me/G3h+pDHazJyCh1rr9gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUz
# T2MuuC3hv2WnBGsY2HH6zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6q
# RT5uWl+PoVvLnTCGMOgDs0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mcz
# mrYI4IAFSEDu9oJkRqj1c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEc
# QNYWFyn8XJwYK+pF9e+91WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2T
# OglmmVhcKaO5DKYwODzQRjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/
# AZwQsRb8zG4Y3G9i/qZQp7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QID
# AQABo4IBEjCCAQ4wHwYDVR0jBBgwFoAUoBEKIz6W8Qfs4q8p74Klf9AwpLQwHQYD
# VR0OBBYEFDLrkpr/NZZILyhAQnAgNpFcF4XmMA4GA1UdDwEB/wQEAwIBhjAPBgNV
# HRMBAf8EBTADAQH/MBMGA1UdJQQMMAoGCCsGAQUFBwMDMBsGA1UdIAQUMBIwBgYE
# VR0gADAIBgZngQwBBAEwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybC5jb21v
# ZG9jYS5jb20vQUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNAYIKwYBBQUHAQEE
# KDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21vZG9jYS5jb20wDQYJKoZI
# hvcNAQEMBQADggEBABK/oe+LdJqYRLhpRrWrJAoMpIpnuDqBv0WKfVIHqI0fTiGF
# OaNrXi0ghr8QuK55O1PNtPvYRL4G2VxjZ9RAFodEhnIq1jIV9RKDwvnhXRFAZ/ZC
# J3LFI+ICOBpMIOLbAffNRk8monxmwFE2tokCVMf8WPtsAO7+mKYulaEMUykfb9gZ
# pk+e96wJ6l2CxouvgKe9gUhShDHaMuwV5KZMPWw5c9QLhTkg4IUaaOGnSDip0TYl
# d8GNGRbFiExmfS9jzpjoad+sPKhdnckcW67Y8y90z7h+9teDnRGWYpquRRPaf9xH
# +9/DUp/mBlXpnYzyOmJRvOwkDynUWICE5EV7WtgwggYUMIID/KADAgECAhB6I67a
# U2mWD5HIPlz0x+M/MA0GCSqGSIb3DQEBDAUAMFcxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxLjAsBgNVBAMTJVNlY3RpZ28gUHVibGljIFRp
# bWUgU3RhbXBpbmcgUm9vdCBSNDYwHhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1
# OTU5WjBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMSww
# KgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNjCCAaIw
# DQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAM2Y2ENBq26CK+z2M34mNOSJjNPv
# IhKAVD7vJq+MDoGD46IiM+b83+3ecLvBhStSVjeYXIjfa3ajoW3cS3ElcJzkyZlB
# nwDEJuHlzpbN4kMH2qRBVrjrGJgSlzzUqcGQBaCxpectRGhhnOSwcjPMI3G0hedv
# 2eNmGiUbD12OeORN0ADzdpsQ4dDi6M4YhoGE9cbY11XxM2AVZn0GiOUC9+XE0wI7
# CQKfOUfigLDn7i/WeyxZ43XLj5GVo7LDBExSLnh+va8WxTlA+uBvq1KO8RSHUQLg
# zb1gbL9Ihgzxmkdp2ZWNuLc+XyEmJNbD2OIIq/fWlwBp6KNL19zpHsODLIsgZ+WZ
# 1AzCs1HEK6VWrxmnKyJJg2Lv23DlEdZlQSGdF+z+Gyn9/CRezKe7WNyxRf4e4bwU
# trYE2F5Q+05yDD68clwnweckKtxRaF0VzN/w76kOLIaFVhf5sMM/caEZLtOYqYad
# tn034ykSFaZuIBU9uCSrKRKTPJhWvXk4CllgrwIDAQABo4IBXDCCAVgwHwYDVR0j
# BBgwFoAU9ndq3T/9ARP/FqFsggIv0Ao9FCUwHQYDVR0OBBYEFF9Y7UwxeqJhQo1S
# gLqzYZcZojKbMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMBMG
# A1UdJQQMMAoGCCsGAQUFBwMIMBEGA1UdIAQKMAgwBgYEVR0gADBMBgNVHR8ERTBD
# MEGgP6A9hjtodHRwOi8vY3JsLnNlY3RpZ28uY29tL1NlY3RpZ29QdWJsaWNUaW1l
# U3RhbXBpbmdSb290UjQ2LmNybDB8BggrBgEFBQcBAQRwMG4wRwYIKwYBBQUHMAKG
# O2h0dHA6Ly9jcnQuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY1RpbWVTdGFtcGlu
# Z1Jvb3RSNDYucDdjMCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNv
# bTANBgkqhkiG9w0BAQwFAAOCAgEAEtd7IK0ONVgMnoEdJVj9TC1ndK/HYiYh9lVU
# acahRoZ2W2hfiEOyQExnHk1jkvpIJzAMxmEc6ZvIyHI5UkPCbXKspioYMdbOnBWQ
# Un733qMooBfIghpR/klUqNxx6/fDXqY0hSU1OSkkSivt51UlmJElUICZYBodzD3M
# /SFjeCP59anwxs6hwj1mfvzG+b1coYGnqsSz2wSKr+nDO+Db8qNcTbJZRAiSazr7
# KyUJGo1c+MScGfG5QHV+bps8BX5Oyv9Ct36Y4Il6ajTqV2ifikkVtB3RNBUgwu/m
# SiSUice/Jp/q8BMk/gN8+0rNIE+QqU63JoVMCMPY2752LmESsRVVoypJVt8/N3qQ
# 1c6FibbcRabo3azZkcIdWGVSAdoLgAIxEKBeNh9AQO1gQrnh1TA8ldXuJzPSuALO
# z1Ujb0PCyNVkWk7hkhVHfcvBfI8NtgWQupiaAeNHe0pWSGH2opXZYKYG4Lbukg7H
# pNi/KqJhue2Keak6qH9A8CeEOB7Eob0Zf+fU+CCQaL0cJqlmnx9HCDxF+3BLbUuf
# rV64EbTI40zqegPZdA+sXCmbcZy6okx/SjwsusWRItFA3DE8MORZeFb6BmzBtqKJ
# 7l939bbKBy2jvxcJI98Va95Q5JnlKor3m0E7xpMeYRriWklUPsetMSf2NvUQa/E5
# vVyefQIwggYaMIIEAqADAgECAhBiHW0MUgGeO5B5FSCJIRwKMA0GCSqGSIb3DQEB
# DAUAMFYxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLTAr
# BgNVBAMTJFNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBSb290IFI0NjAeFw0y
# MTAzMjIwMDAwMDBaFw0zNjAzMjEyMzU5NTlaMFQxCzAJBgNVBAYTAkdCMRgwFgYD
# VQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENv
# ZGUgU2lnbmluZyBDQSBSMzYwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIB
# gQCbK51T+jU/jmAGQ2rAz/V/9shTUxjIztNsfvxYB5UXeWUzCxEeAEZGbEN4QMgC
# sJLZUKhWThj/yPqy0iSZhXkZ6Pg2A2NVDgFigOMYzB2OKhdqfWGVoYW3haT29PST
# ahYkwmMv0b/83nbeECbiMXhSOtbam+/36F09fy1tsB8je/RV0mIk8XL/tfCK6cPu
# YHE215wzrK0h1SWHTxPbPuYkRdkP05ZwmRmTnAO5/arnY83jeNzhP06ShdnRqtZl
# V59+8yv+KIhE5ILMqgOZYAENHNX9SJDm+qxp4VqpB3MV/h53yl41aHU5pledi9lC
# BbH9JeIkNFICiVHNkRmq4TpxtwfvjsUedyz8rNyfQJy/aOs5b4s+ac7IH60B+Ja7
# TVM+EKv1WuTGwcLmoU3FpOFMbmPj8pz44MPZ1f9+YEQIQty/NQd/2yGgW+ufflcZ
# /ZE9o1M7a5Jnqf2i2/uMSWymR8r2oQBMdlyh2n5HirY4jKnFH/9gRvd+QOfdRrJZ
# b1sCAwEAAaOCAWQwggFgMB8GA1UdIwQYMBaAFDLrkpr/NZZILyhAQnAgNpFcF4Xm
# MB0GA1UdDgQWBBQPKssghyi47G9IritUpimqF6TNDDAOBgNVHQ8BAf8EBAMCAYYw
# EgYDVR0TAQH/BAgwBgEB/wIBADATBgNVHSUEDDAKBggrBgEFBQcDAzAbBgNVHSAE
# FDASMAYGBFUdIAAwCAYGZ4EMAQQBMEsGA1UdHwREMEIwQKA+oDyGOmh0dHA6Ly9j
# cmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nUm9vdFI0Ni5j
# cmwwewYIKwYBBQUHAQEEbzBtMEYGCCsGAQUFBzAChjpodHRwOi8vY3J0LnNlY3Rp
# Z28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYucDdjMCMGCCsG
# AQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOC
# AgEABv+C4XdjNm57oRUgmxP/BP6YdURhw1aVcdGRP4Wh60BAscjW4HL9hcpkOTz5
# jUug2oeunbYAowbFC2AKK+cMcXIBD0ZdOaWTsyNyBBsMLHqafvIhrCymlaS98+Qp
# oBCyKppP0OcxYEdU0hpsaqBBIZOtBajjcw5+w/KeFvPYfLF/ldYpmlG+vd0xqlqd
# 099iChnyIMvY5HexjO2AmtsbpVn0OhNcWbWDRF/3sBp6fWXhz7DcML4iTAWS+MVX
# eNLj1lJziVKEoroGs9Mlizg0bUMbOalOhOfCipnx8CaLZeVme5yELg09Jlo8BMe8
# 0jO37PU8ejfkP9/uPak7VLwELKxAMcJszkyeiaerlphwoKx1uHRzNyE6bxuSKcut
# isqmKL5OTunAvtONEoteSiabkPVSZ2z76mKnzAfZxCl/3dq3dUNw4rg3sTCggkHS
# RqTqlLMS7gjrhTqBmzu1L90Y1KWN/Y5JKdGvspbOrTfOXyXvmPL6E52z1NZJ6ctu
# MFBQZH3pwWvqURR8AgQdULUvrxjUYbHHj95Ejza63zdrEcxWLDX6xWls/GDnVNue
# KjWUH3fTv1Y8Wdho698YADR7TNx8X8z2Bev6SivBBOHY+uqiirZtg0y9ShQoPzmC
# cn63Syatatvx157YK9hlcPmVoa1oDE5/L9Uo2bC5a4CH2RwwggY7MIIEo6ADAgEC
# AhB0DwHfMJggnItJs5sO5vT7MA0GCSqGSIb3DQEBDAUAMFQxCzAJBgNVBAYTAkdC
# MRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxKzApBgNVBAMTIlNlY3RpZ28gUHVi
# bGljIENvZGUgU2lnbmluZyBDQSBSMzYwHhcNMjMwMzEzMDAwMDAwWhcNMjYwMzEy
# MjM1OTU5WjBSMQswCQYDVQQGEwJERTEPMA0GA1UECAwGQmF5ZXJuMRgwFgYDVQQK
# DA9Vd2UgR3JhZGVuZWdnZXIxGDAWBgNVBAMMD1V3ZSBHcmFkZW5lZ2dlcjCCAiIw
# DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK8WKgQdO1LSQoL7lLmI8JOgQAc4
# IMJTOsnpfGrL9F57ol8zoAMZBCbJ4dU9Km5+XWBgclFQvGcRCKKmAlMScougIdHl
# 8fk4mj5UNnulC58zBFAcWVpkH62yPECWQgky14k1XKNFa326ILpSluO9U25EeIEH
# mKwDCb+TrhskWh4tcEi8wgmCBTBweSmPQoiN0q0HwUvfIP7/WSnV4aupZfmqaBg4
# 4YQluOHEBeAP4B6Imv8g6HVYP1vpDg/lMO3VgeFfLBiRugzjHKWeiNqDX9XHTWNK
# CnFQZPURUKUd8pSIlsw4r2qiXwTLLiyeXa/TahZVGwYfAAgrEA13LwIEcT8iW7IW
# 4XeWYRBYH6jSzxIjn5JEC2bVWo59f2oIxL+oEJSuUvC8RdYZZtEwDUn5DNZeC9ia
# oREzv6Mmqa5L9BtxCOyYpMpTubj4pPP49klHkdgxmczz9vadfmOIjB2sWBR/SmuO
# 7FtBLGMph+wfrIy3pAKLAX0EL72yWqFHKpEgSvCVZ/hnZBVMB6gxT3nFh6m7AXlA
# daxZ7JLq5xy9P/Nwg9g2OltwUzhqIKtTzcG+v20mffy6pG/AkuUIiyfjuC3u1jY9
# TuM74DnaKRh+EgpkiMAzQK9hyl8AS/YZwaWD8b31MLbUnpWNIZ4M5yXhibAHE+jW
# Ig2iWVcLmu7LiT7NAgMBAAGjggGJMIIBhTAfBgNVHSMEGDAWgBQPKssghyi47G9I
# ritUpimqF6TNDDAdBgNVHQ4EFgQUMk0HbqTvGbbhuicQT46bYGPu3l4wDgYDVR0P
# AQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwSgYD
# VR0gBEMwQTA1BgwrBgEEAbIxAQIBAwIwJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9z
# ZWN0aWdvLmNvbS9DUFMwCAYGZ4EMAQQBMEkGA1UdHwRCMEAwPqA8oDqGOGh0dHA6
# Ly9jcmwuc2VjdGlnby5jb20vU2VjdGlnb1B1YmxpY0NvZGVTaWduaW5nQ0FSMzYu
# Y3JsMHkGCCsGAQUFBwEBBG0wazBEBggrBgEFBQcwAoY4aHR0cDovL2NydC5zZWN0
# aWdvLmNvbS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdDQVIzNi5jcnQwIwYIKwYB
# BQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29tMA0GCSqGSIb3DQEBDAUAA4IB
# gQB2atmLSet4Oun2a17hRlqzc45VdBntzhZSsnRuzWbQHR+sOFLtU8i0ttaIMlJf
# ItJ1YsfOunuTuYnw3HgoefVzZtFQBxl0kNOT2H81NgvOPazW6Ur3rDwRo5pZcOt7
# bdfzGB2U7dXdhnkgmFV8kPpqbYdjVj0N4F/Jih0qIOEe/bEpLoDmsQB88hWwy9zv
# CabzYOU4YAUAFQucSzBEGWnOqjchWVU/vdQYrVx26DDVBsZsNB6iS3sNkUgplEe/
# klRY66z6uhqrspwhN9me1evMm+mwFJRPdtJ+kjTu9e9VfB7qkYS5l7opvyGW+mwr
# 4vpS/z8r4D+qWT/ZsW+D+ZDnOCE3joTMwH4wH+k9rW4SBGMHm5yt4crBHcaIbQjO
# kcrKo9eAU5usaOeKl+L1uQoq0Me8Nppc4s/fwLFTFIhjnAq6bXpZud8BEu3L8sNW
# 06vdC1qzBSCDqGKBEUtDDZgRg0b57Ejv5EOk+LJPMHbFj6jjR4hyFB3Se/cNfLiF
# hGUwggZdMIIExaADAgECAhA6UmoshM5V5h1l/MwS2OmJMA0GCSqGSIb3DQEBDAUA
# MFUxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQxLDAqBgNV
# BAMTI1NlY3RpZ28gUHVibGljIFRpbWUgU3RhbXBpbmcgQ0EgUjM2MB4XDTI0MDEx
# NTAwMDAwMFoXDTM1MDQxNDIzNTk1OVowbjELMAkGA1UEBhMCR0IxEzARBgNVBAgT
# Ck1hbmNoZXN0ZXIxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDEwMC4GA1UEAxMn
# U2VjdGlnbyBQdWJsaWMgVGltZSBTdGFtcGluZyBTaWduZXIgUjM1MIICIjANBgkq
# hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjdFn9MFIm739OEk6TWGBm8PY3EWlYQQ2
# jQae45iWgPXUGVuYoIa1xjTGIyuw3suUSBzKiyG0/c/Yn++d5mG6IyayljuGT9De
# XQU9k8GWWj2/BPoamg2fFctnPsdTYhMGxM06z1+Ft0Bav8ybww21ii/faiy+NhiU
# M195+cFqOtCpJXxZ/lm9tpjmVmEqpAlRpfGmLhNdkqiEuDFTuD1GsV3jvuPuPGKU
# JTam3P53U4LM0UCxeDI8Qz40Qw9TPar6S02XExlc8X1YsiE6ETcTz+g1ImQ1OqFw
# EaxsMj/WoJT18GG5KiNnS7n/X4iMwboAg3IjpcvEzw4AZCZowHyCzYhnFRM4PuNM
# VHYcTXGgvuq9I7j4ke281x4e7/90Z5Wbk92RrLcS35hO30TABcGx3Q8+YLRy6o0k
# 1w4jRefCMT7b5mTxtq5XPmKvtgfPuaWPkGZ/tbxInyNDA7YgOgccULjp4+D56g2i
# uzRCsLQ9ac6AN4yRbqCYsG2rcIQ5INTyI2JzA2w1vsAHPRbUTeqVLDuNOY2gYIoK
# BWQsPYVoyzaoBVU6O5TG+a1YyfWkgVVS9nXKs8hVti3VpOV3aeuaHnjgC6He2CCD
# L9aW6gteUe0AmC8XCtWwpePx6QW3ROZo8vSUe9AR7mMdu5+FzTmW8K13Bt8GX/YB
# FJO7LWzwKAUCAwEAAaOCAY4wggGKMB8GA1UdIwQYMBaAFF9Y7UwxeqJhQo1SgLqz
# YZcZojKbMB0GA1UdDgQWBBRo76QySWm2Ujgd6kM5LPQUap4MhTAOBgNVHQ8BAf8E
# BAMCBsAwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBKBgNV
# HSAEQzBBMDUGDCsGAQQBsjEBAgEDCDAlMCMGCCsGAQUFBwIBFhdodHRwczovL3Nl
# Y3RpZ28uY29tL0NQUzAIBgZngQwBBAIwSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDov
# L2NybC5zZWN0aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1waW5nQ0FSMzYu
# Y3JsMHoGCCsGAQUFBwEBBG4wbDBFBggrBgEFBQcwAoY5aHR0cDovL2NydC5zZWN0
# aWdvLmNvbS9TZWN0aWdvUHVibGljVGltZVN0YW1waW5nQ0FSMzYuY3J0MCMGCCsG
# AQUFBzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOC
# AYEAsNwuyfpPNkyKL/bJT9XvGE8fnw7Gv/4SetmOkjK9hPPa7/Nsv5/MHuVus+aX
# wRFqM5Vu51qfrHTwnVExcP2EHKr7IR+m/Ub7PamaeWfle5x8D0x/MsysICs00xtS
# NVxFywCvXx55l6Wg3lXiPCui8N4s51mXS0Ht85fkXo3auZdo1O4lHzJLYX4RZovl
# VWD5EfwV6Ve1G9UMslnm6pI0hyR0Zr95QWG0MpNPP0u05SHjq/YkPlDee3yYOECN
# MqnZ+j8onoUtZ0oC8CkbOOk/AOoV4kp/6Ql2gEp3bNC7DOTlaCmH24DjpVgryn8F
# MklqEoK4Z3IoUgV8R9qQLg1dr6/BjghGnj2XNA8ujta2JyoxpqpvyETZCYIUjIs6
# 9YiDjzftt37rQVwIZsfCYv+DU5sh/StFL1x4rgNj2t8GccUfa/V3iFFW9lfIJWWs
# vtlC5XOOOQswr1UmVdNWQem4LwrlLgcdO/YAnHqY52QwnBLiAuUnuBeshWmfEb5o
# ieIYMIIGgjCCBGqgAwIBAgIQNsKwvXwbOuejs902y8l1aDANBgkqhkiG9w0BAQwF
# ADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcT
# C0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAs
# BgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcN
# MjEwMzIyMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjBXMQswCQYDVQQGEwJHQjEYMBYG
# A1UEChMPU2VjdGlnbyBMaW1pdGVkMS4wLAYDVQQDEyVTZWN0aWdvIFB1YmxpYyBU
# aW1lIFN0YW1waW5nIFJvb3QgUjQ2MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAiJ3YuUVnnR3d6LkmgZpUVMB8SQWbzFoVD9mUEES0QUCBdxSZqdTkdizI
# CFNeINCSJS+lV1ipnW5ihkQyC0cRLWXUJzodqpnMRs46npiJPHrfLBOifjfhpdXJ
# 2aHHsPHggGsCi7uE0awqKggE/LkYw3sqaBia67h/3awoqNvGqiFRJ+OTWYmUCO2G
# AXsePHi+/JUNAax3kpqstbl3vcTdOGhtKShvZIvjwulRH87rbukNyHGWX5tNK/WA
# BKf+Gnoi4cmisS7oSimgHUI0Wn/4elNd40BFdSZ1EwpuddZ+Wr7+Dfo0lcHflm/F
# DDrOJ3rWqauUP8hsokDoI7D/yUVI9DAE/WK3Jl3C4LKwIpn1mNzMyptRwsXKrop0
# 6m7NUNHdlTDEMovXAIDGAvYynPt5lutv8lZeI5w3MOlCybAZDpK3Dy1MKo+6aEtE
# 9vtiTMzz/o2dYfdP0KWZwZIXbYsTIlg1YIetCpi5s14qiXOpRsKqFKqav9R1R5vj
# 3NgevsAsvxsAnI8Oa5s2oy25qhsoBIGo/zi6GpxFj+mOdh35Xn91y72J4RGOJEoq
# zEIbW3q0b2iPuWLA911cRxgY5SJYubvjay3nSMbBPPFsyl6mY4/WYucmyS9lo3l7
# jk27MAe145GWxK4O3m3gEFEIkv7kRmefDR7Oe2T1HxAnICQvr9sCAwEAAaOCARYw
# ggESMB8GA1UdIwQYMBaAFFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBT2
# d2rdP/0BE/8WoWyCAi/QCj0UJTAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUw
# AwEB/zATBgNVHSUEDDAKBggrBgEFBQcDCDARBgNVHSAECjAIMAYGBFUdIAAwUAYD
# VR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VTRVJUcnVz
# dFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMDUGCCsGAQUFBwEBBCkwJzAl
# BggrBgEFBQcwAYYZaHR0cDovL29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0B
# AQwFAAOCAgEADr5lQe1oRLjlocXUEYfktzsljOt+2sgXke3Y8UPEooU5y39rAARa
# AdAxUeiX1ktLJ3+lgxtoLQhn5cFb3GF2SSZRX8ptQ6IvuD3wz/LNHKpQ5nX8hjsD
# LRhsyeIiJsms9yAWnvdYOdEMq1W61KE9JlBkB20XBee6JaXx4UBErc+YuoSb1SxV
# f7nkNtUjPfcxuFtrQdRMRi/fInV/AobE8Gw/8yBMQKKaHt5eia8ybT8Y/Ffa6HAJ
# yz9gvEOcF1VWXG8OMeM7Vy7Bs6mSIkYeYtddU1ux1dQLbEGur18ut97wgGwDiGin
# CwKPyFO7ApcmVJOtlw9FVJxw/mL1TbyBns4zOgkaXFnnfzg4qbSvnrwyj1NiurMp
# 4pmAWjR+Pb/SIduPnmFzbSN/G8reZCL4fvGlvPFk4Uab/JVCSmj59+/mB2Gn6G/U
# YOy8k60mKcmaAZsEVkhOFuoj4we8CYyaR9vd9PGZKSinaZIkvVjbH/3nlLb0a7SB
# IkiRzfPfS9T+JesylbHa1LtRV9U/7m0q7Ma2CQ/t392ioOssXW7oKLdOmMBl14su
# VFBmbzrt5V5cQPnwtd3UOTpS9oCG+ZZheiIvPgkDmA8FzPsnfXW5qHELB43ET7HH
# FHeRPRYrMBKjkb8/IN7Po0d0hQoF4TeMM+zYAJzoKQnVKOLg8pZVPT8xggZAMIIG
# PAIBATBoMFQxCzAJBgNVBAYTAkdCMRgwFgYDVQQKEw9TZWN0aWdvIExpbWl0ZWQx
# KzApBgNVBAMTIlNlY3RpZ28gUHVibGljIENvZGUgU2lnbmluZyBDQSBSMzYCEHQP
# Ad8wmCCci0mzmw7m9PswDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEK
# MAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3
# AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgoiJ0AkrHG2JxX58o
# UA/Uoy335BhroboepLo6K0sf6HkwDQYJKoZIhvcNAQEBBQAEggIAWs41pE0+cXXf
# TZmT6n06IBPOrSLXMmCyhLXDzDPIeBzhrwBpPztV991Hg1xKFGAuZkW41gKlNd6I
# q/82lf6gL8Sfi+r9IwYZx8L4+osbiCL5Om+S5x8L+/3Kga7Kv3LWekEUuAKSf2Ne
# kZhwUZEtCFZfkfcjmRfwb4qMgiMCxI40zrOBUkl4mkOJR5HS4SeO2r6FPbFufd5M
# yv2eQrzDJwl0yFAo4GTC2WA/4ZxIbLcEL4wegWjHjJSvzU1ijrABb4mmhjZiuvzB
# AEceLOpJ8v2yBJ+F4oPxELWbOZ/+4HhFQfAYeSNar2wKlYZ1l7vbW8Bf/U1EY1MT
# 9SWkXLZS87an2L8tmP/0Gw0STvrJL7kUytBzrqkbl91pt2vsaRMO89Ftwkdznfog
# golHbBXuvevHZUnq8NgQ57JA/jjAMWuHjLqBnw/Soly54nDtJOJPYNbfVrdg20oV
# MPWSZnkm+VRe13FnTJEnuoPKMC3Z7foOYdymr+vU7f3lOYbEebTVqALXPZUq0tjW
# Ed1gpyFcVYf0BoLHkxOBFnkvOt55NIcXyGEPc16CJHljrs1T//Y/asiuvftApfoU
# /7VKLd04tc7n/6bh4/whPYyGrcV8iZblo2eiZ40jyhEhMLSVbIkVusqiSOB5LjkE
# kl/8knB+YHceNLE08wxryR81kn7LRNihggMiMIIDHgYJKoZIhvcNAQkGMYIDDzCC
# AwsCAQEwaTBVMQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVk
# MSwwKgYDVQQDEyNTZWN0aWdvIFB1YmxpYyBUaW1lIFN0YW1waW5nIENBIFIzNgIQ
# OlJqLITOVeYdZfzMEtjpiTANBglghkgBZQMEAgIFAKB5MBgGCSqGSIb3DQEJAzEL
# BgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTI1MDIxMTE1Mjc0MFowPwYJKoZI
# hvcNAQkEMTIEMO46dFMP4pRSB3mCWA7ZMtUAPw5BumAmcf/Nj2IJ5SCxDxlfFzEx
# xbK13ekrZz0OKDANBgkqhkiG9w0BAQEFAASCAgCNy0ZA/A4URhOMr9JJUstWe+Ue
# VqmIVrxDWsh4ehY+WYRhBNSDVBFf37DWfArW1Li0N31qjRAm23EKwf+FFd4ELh4a
# nk/oziynS4/8hlxY/PQiZBumYIKTOKP/xIfUp8Hjcnk8xXZzyFtJjShTzqzaei4l
# o2+ASkrwzMGIm6tWYuuhur6ehn+BVAHEfG/c04zd7OsGv6jjXg672lB/yJaGmHdq
# CDnmrpws1fihx11x2Swc+mt9dea1slS9H0j1fsDW9LOGNyi9fGGwWmje0Y0cI1xo
# ISDxIRmPf9wrynMulyigapat8qSXhk6FZ5Wi7OrXlGQxuvwiL0JwQlmFto9XV94m
# c2REm6BIr9Dw23Rrr1chJ+rShg+H3LCShG+AXCLehlmpBodcfLneXDnELhXEIVW/
# zlLn0ice6YwVYMBQtQvTd84KV0zAtfxYeWVyC6/lBt0hlOMRAxaEGAubDMcs5uWo
# vT0pCUPBChR8QN6oGGX4SuEUCXuHg78asfs0RdtiUn3u92nFqz+ecycQhtYuTSAi
# jkJB2/8zDs9QokX5JoibKerUyYgyMADXzJZbWpnVByB3wfPNRlgU1hiLB1HjLrd6
# 94d4jkXjNN8Xwhtjhq9a4meNAQwwIPMSWOEvWENpvNVHDRpd9qlztTJ12jf4FOdN
# 68xRADxYUJXe7RUucQ==
# SIG # End signature block