PSPKI.psm1

#region assembly import
Add-Type -Path $PSScriptRoot\Library\SysadminsLV.Asn1Parser.dll -ErrorAction Stop
Add-Type -Path $PSScriptRoot\Library\SysadminsLV.PKI.dll -ErrorAction Stop
Add-Type -Path $PSScriptRoot\Library\SysadminsLV.PKI.Win.dll -ErrorAction Stop
Add-Type -Path $PSScriptRoot\Library\SysadminsLV.PKI.OcspClient.dll -ErrorAction Stop
Add-Type -AssemblyName System.Security -ErrorAction Stop
#endregion

#region global variable section
[bool]$PsIsCore = if ($PSVersionTable.PSEdition -like "*core*") {$true} else {$false}

# compatibility
[bool]$NoDomain = $true # computer is a member of workgroup
try {
    # check if any domain controller is reachable
    [void][System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain()
    # then read configuration naming context path
    $Domain = ([ADSI]"LDAP://RootDSE").ConfigurationNamingContext
    $PkiConfigContext = "CN=Public Key Services,CN=Services,$Domain"
    $NoDomain = $false
} catch {
    $NoDomain = $true
    Write-Warning @'
Current machine is not joined to AD DS forest. Commands that depend on Active Directory will not run.
'@

}

[bool]$NoCAPI = $true   # CertAdm.dll server managemend library is missing
if (Test-Path $PSScriptRoot\Server) {
    try {
        $CertAdmin = New-Object -ComObject CertificateAuthority.Admin
        $NoCAPI = $false
    } catch {
        $NoCAPI = $true
        Write-Warning @'
Active Directory Certificate Services remote administration tools (RSAT) are not installed and only
client-side functionality will be available.
'@

    }
}


# warning messages
$RestartRequired = @"
New {0} are set, but will not be applied until Certification Authority service is restarted.
In future consider to use '-RestartCA' switch for this cmdlet to restart Certification Authority service immediatelly when new settings are set.
 
See more: Start-CertificationAuthority, Stop-CertificationAuthority and Restart-CertificationAuthority cmdlets.
"@

$NothingIsSet = @"
Input object was not modified since it was created. Nothing is written to the CA configuration.
"@

#endregion

#region helper functions
$PREREQ_ADDS = "ADDS"
$PREREQ_RSAT = "RSAT"
function Assert-CommandRequirement {
[CmdletBinding()]
    param([string[]]$requirement)

    # return immediately if no requirements are asked
    if (!$requirement) {
        return
    }

    $Caller = (Get-PSCallStack)[1].FunctionName -replace "\<.*"
    $result = $requirement | %{
        switch($_) {
            $PREREQ_ADDS {
                if ($NoDomain) {"'AD DS Domain Membership'"}
            }
            $PREREQ_RSAT {
                if ($NoCAPI) {"'AD CS RSAT tools'"}
            }
        }
    }

    # if '$result' is null, then all assertions are passed, good to go
    if (!$result) {
        return
    }
    # otherwise fire error
    Write-Error ("'{0}' command cannot run on this system, because it fails one or more requirements: {1}" -f $Caller, ($result -join ", "))
}

function Clear-ComObject($ComObject) {
    [SysadminsLV.PKI.Utils.CryptographyUtils]::ReleaseCom($ComObject)
}
function Export-Binary([System.IO.FileInfo]$OutPath, [byte[]]$data) {
    if ($PsIsCore) {
        Set-Content -Path $OutPath -Value $data -AsByteStream
    } else {
        Set-Content -Path $OutPath -Value $data -Encoding Byte
    }
}
function Ping-ICertAdmin ($ConfigString) {
    $success = $true
    try {
        $CertAdmin = New-Object -ComObject CertificateAuthority.Admin
        $var = $CertAdmin.GetCAProperty($ConfigString,0x6,0,4,0)
    } catch {$success = $false}
    $success
}

function Write-ErrorMessage {
    param (
        [SysadminsLV.PKI.Utils.PSErrorSourceEnum]$Source,
        $ComputerName,
        $ExtendedInformation
    )
$DCUnavailable = @"
"Active Directory domain could not be contacted.
"@

$CAPIUnavailable = @"
Unable to locate required assemblies. This can be caused if attempted to run this module on a client machine where AdminPack/RSAT (Remote Server Administration Tools) are not installed.
"@

$WmiUnavailable = @"
Unable to connect to CA server '$ComputerName'. Make sure if Remote Registry service is running and you have appropriate permissions to access it.
Also this error may indicate that Windows Remote Management protocol exception is not enabled in firewall.
"@

$XchgUnavailable = @"
Unable to retrieve any 'CA Exchange' certificates from '$ComputerName'. This error may indicate that target CA server do not support key archival. All requests which require key archival will immediately fail.
"@

    switch ($source) {
        DCUnavailable {
            Write-Error -Category ObjectNotFound -ErrorId "ObjectNotFoundException" `
            -Message $DCUnavailable
        }
        CAPIUnavailable {
            Write-Error -Category NotImplemented -ErrorId "NotImplementedException" `
            -Message $NoCAPI; exit
        }
        CAUnavailable {
            Write-Error -Category ResourceUnavailable -ErrorId ResourceUnavailableException `
            -Message "Certificate Services are either stopped or unavailable on '$ComputerName'."
        }
        WmiUnavailable {
            Write-Error -Category ResourceUnavailable -ErrorId ResourceUnavailableException `
            -Message $WmiUnavailable
        }
        WmiWriteError {
            try {$text = Get-ErrorMessage $ExtendedInformation}
            catch {$text = "Unknown error '$code'"}
            Write-Error -Category NotSpecified -ErrorId NotSpecifiedException `
            -Message "An error occured during CA configuration update: $text"
        }
        ADKRAUnavailable {
            Write-Error -Category ObjectNotFound -ErrorId "ObjectNotFoundException" `
            -Message "No KRA certificates found in Active Directory."
        }
        ICertAdminUnavailable {
            Write-Error -Category ResourceUnavailable -ErrorId ResourceUnavailableException `
            -Message "Unable to connect to management interfaces on '$ComputerName'"
        }
        NoXchg {
            Write-Error -Category ObjectNotFound -ErrorId ObjectNotFoundException `
            -Message $XchgUnavailable
        }
        NonEnterprise {
            Write-Error -Category NotImplemented -ErrorAction NotImplementedException `
            -Message "Specified Certification Authority type is not supported. The CA type must be either 'Enterprise Root CA' or 'Enterprise Standalone CA'."
        }
    }
}
#endregion

#region module installation stuff
# dot-source all function files
Get-ChildItem -Path $PSScriptRoot -Include *.ps1 -Recurse | Foreach-Object { . $_.FullName }

# DS-dependent aliases
New-Alias -Name Add-AdCrl                   -Value Add-AdCertificateRevocationList -Force
New-Alias -Name Remove-AdCrl                -Value Remove-AdCertificateRevocationList -Force
New-Alias -Name Get-CA                      -Value Get-CertificationAuthority -Force
New-Alias -Name Get-KRAFlag                 -Value Get-KeyRecoveryAgentFlag -Force
New-Alias -Name Enable-KRAFlag              -Value Enable-KeyRecoveryAgentFlag -Force
New-Alias -Name Disable-KRAFlag             -Value Disable-KeyRecoveryAgentFlag -Force
New-Alias -Name Restore-KRAFlagDefault      -Value Restore-KeyRecoveryAgentFlagDefault -Force
New-Alias -Name Connect-CA                  -Value Connect-CertificationAuthority -Force

# RSAT-dependent aliases
New-Alias -Name Add-AIA                     -Value Add-AuthorityInformationAccess -Force
New-Alias -Name Get-AIA                     -Value Get-AuthorityInformationAccess -Force
New-Alias -Name Remove-AIA                  -Value Remove-AuthorityInformationAccess -Force
New-Alias -Name Set-AIA                     -Value Set-AuthorityInformationAccess -Force

New-Alias -Name Add-CDP                     -Value Add-CRLDistributionPoint -Force
New-Alias -Name Get-CDP                     -Value Get-CRLDistributionPoint -Force
New-Alias -Name Remove-CDP                  -Value Remove-CRLDistributionPoint -Force
New-Alias -Name Set-CDP                     -Value Set-CRLDistributionPoint -Force
    
New-Alias -Name Get-CRLFlag                 -Value Get-CertificateRevocationListFlag -Force
New-Alias -Name Enable-CRLFlag              -Value Enable-CertificateRevocationListFlag -Force
New-Alias -Name Disable-CRLFlag             -Value Disable-CertificateRevocationListFlag -Force
New-Alias -Name Restore-CRLFlagDefault      -Value Restore-CertificateRevocationListFlagDefault -Force
    
New-Alias -Name Remove-Request              -Value Remove-AdcsDatabaseRow -Force
    
New-Alias -Name Get-CAACL                   -Value Get-CertificationAuthorityAcl -Force
New-Alias -Name Add-CAACL                   -Value Add-CertificationAuthorityAcl -Force
New-Alias -Name Remove-CAACL                -Value Remove-CertificationAuthorityAcl -Force
New-Alias -Name Set-CAACL                   -Value Set-CertificationAuthorityAcl -Force

New-Alias -Name Get-OCSPACL                 -Value Get-OnlineResponderAcl -Force
New-Alias -Name Add-OCSPACL                 -Value Add-OnlineResponderAcl -Force
New-Alias -Name Remove-OCSPACL              -Value Remove-OnlineResponderAcl -Force
New-Alias -Name Set-OCSPACL                 -Value Set-OnlineResponderAcl -Force

# compat/rename aliases
New-Alias -Name Get-CASecurityDescriptor    -Value Get-CertificationAuthorityAcl -Force
New-Alias -Name Set-CASecurityDescriptor    -Value Set-CertificationAuthorityAcl -Force
New-Alias -Name Add-CAAccessControlEntry    -Value Add-CertificationAuthorityAcl -Force
New-Alias -Name Remove-CAAccessControlEntry -Value Remove-CertificationAuthorityAcl -Force

New-Alias -Name oid                         -Value Get-ObjectIdentifier -Force
New-Alias -Name oid2                        -Value Get-ObjectIdentifierEx -Force
New-Alias -Name Get-Csp                     -Value Get-CryptographicServiceProvider -Force
New-Alias -Name Get-CRL                     -Value Get-CertificateRevocationList -Force
New-Alias -Name Show-CRL                    -Value Show-CertificateRevocationList -Force
New-Alias -Name Get-CTL                     -Value Get-CertificateTrustList -Force
New-Alias -Name Show-CTL                    -Value Show-CertificateTrustList -Force

# export all functions and aliases, filter by PSD1
Export-ModuleMember -Function * -Alias *

# conditional type data
if ($PSVersionTable.PSVersion.Major -eq 5) {
    Update-TypeData -AppendPath $PSScriptRoot\Types\PSPKI.PS5Types.ps1xml
}
# SIG # Begin signature block
# MIIvDQYJKoZIhvcNAQcCoIIu/jCCLvoCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCeFEU1aWMjJJYe
# 79nN9nuHuA0kXI7NsjBhYUFxbAaqdqCCE5kwggWQMIIDeKADAgECAhAFmxtXno4h
# MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z
# ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
# AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z
# G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ
# anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s
# Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL
# 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb
# BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3
# JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c
# AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx
# YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0
# viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL
# T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud
# EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf
# Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk
# aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS
# PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK
# 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB
# cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp
# 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg
# dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri
# RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7
# 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5
# nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3
# i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H
# EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G
# CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ
# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0
# IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C
# 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce
# 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da
# E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T
# SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA
# FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh
# D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM
# 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z
# 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05
# huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY
# mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP
# /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T
# AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD
# VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG
# A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY
# aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj
# ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV
# HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN
# BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry
# sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL
# IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf
# Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh
# OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh
# dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV
# 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j
# wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH
# Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC
# XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l
# /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW
# eE4wggdNMIIFNaADAgECAhAObby6tbZ0sFYtkajicQ8aMA0GCSqGSIb3DQEBDAUA
# MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE
# AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz
# ODQgMjAyMSBDQTEwHhcNMjYwMjA2MDAwMDAwWhcNMjkwMjI3MjM1OTU5WjBVMQsw
# CQYDVQQGEwJMVjEOMAwGA1UEBwwFUsSrZ2ExGjAYBgNVBAoMEUlLICJTeXNhZG1p
# bnMgTFYiMRowGAYDVQQDDBFJSyAiU3lzYWRtaW5zIExWIjCCAiIwDQYJKoZIhvcN
# AQEBBQADggIPADCCAgoCggIBAKwGGasrfMfwdc37W1d3/vgvVZ5Wgfmk8Rd4sb3e
# f1vZ4D2kA0sLNU1AwbwfLjnnRT0brMbrI2y/MSt10oqOFSnR7nw9AkhW/1PVZS9l
# rxRYX/g/RjO+lG5TnxRTsaWUiw7clvhRipxBgWJuxky8MuUD/eTyMLu1rn6He7p/
# cp4kg6nu6ZsaPxsEY9EBTAdXzlyYS/U3NJMk8GjrLdVAlZpoONXnoB9yChIly409
# yh2xWczWIUv9ku2SFrZbB6l3YhY2inDAPKpAKyCd0xeQPKSeRoC+JXAnA1dSSRJ9
# 557LFFBfnR4XFh4E1OHuKRfTk18UjfwQqdF4cdmH5I4rR5Pqhy2shwBP8XrT26em
# OhpfUAWVfJWIWcoQPq9JV/3dr8tPZgCW97dZpmu0/q3TlHS/sPASNO279diN2o/f
# H0fsNPBzFSe85BCtUk3muyEhVHU3R//Lg1MSFB0BRFeAafhlsm/VvhIQ8tQvb7it
# a7UB7gacdB795+XhpY0MLc0fFsrSTENxXeH5N7sIlNa3zao4l3IiNmR6lwvm6IMf
# L8aRBPWg6PicLK2sXa10PDQLxee533dHuuvvpaVdpyvcEpaCHlaSKxeFhwur339D
# yuaWQ37rospo/pS8oaG05edihaF7O4LRiqeVDx1RL9Yd4uPH02J284seLMKTZ7wa
# Tle1AgMBAAGjggIDMIIB/zAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfRO
# QjAdBgNVHQ4EFgQU8Tdc7JEZ0WMWKjWL7tfz8hanUtgwPgYDVR0gBDcwNTAzBgZn
# gQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BT
# MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGt
# MIGqMFOgUaBPhk1odHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVz
# dGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZN
# aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNp
# Z25pbmdSU0E0MDk2U0hBMzg0MjAyMUNBMS5jcmwwgZQGCCsGAQUFBwEBBIGHMIGE
# MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUH
# MAKGUGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRH
# NENvZGVTaWduaW5nUlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAw
# DQYJKoZIhvcNAQEMBQADggIBAIRcHe3iWZ4t2G3pttGtw01+okbWPPachOEYxiGL
# 2Gp7DBP3Pvfw1qEHnwULtPs0hBG/Rd8+TtKkTpyZO0E2EfIYfe/EVmXjr+6jrOnU
# beRiVDMahp7ym37FhrRPzzDEihFmyzz/Ec8YmE4oeEH+0ZTKT+7F7VThVmVGWQ6x
# YIGqSL3k6/Af1P1gdK+1MdQtB/E1mg+7aDqiOxCRRsfwXwLjB+LSi0GflBQZeeHf
# pvogtHPWM6yMEZVZkY6sxF9jo9ewhVc9DJB86KQSxJ14vkM0OAu7Q83L8N+exia2
# XuC3C+7nuVdHB7+HHu3z/Cz1aftWuHLnVRYrhJZCZ+46YvjRFQxf+GIjqyopBfDh
# DX6Oq4GlOSrJPnSnyRgNu4Mr4nOWJ2LuTzFmgJu+GmeHSLH+U2uudNdagjkjRnWQ
# TOZ4hdnqG0WlhMazHMf0RGx8s3DRIX9kjttDQ3RbYUJRqMq9KVf5K+CdNYKRyqET
# 4tn+ixidYWazVTgsaQi1ZxmdxmS784F5CQxLlg87xWIUlWyIA2fWWnqePxGaLZrB
# pDr0KkKT6gF3z2+Bs9q3o1sOAvjP7SvaBLJHuBmC5oeKnbZa+iuVEJFQShEdfl28
# Khk3jA3RU0cOK+CJMup5FXo4mdydO2ItLKZ62vC4f2m3IinXfyh7MfUyZQ0heZMi
# Who4MYIayjCCGsYCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl
# cnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWdu
# aW5nIFJTQTQwOTYgU0hBMzg0IDIwMjEgQ0ExAhAObby6tbZ0sFYtkajicQ8aMA0G
# CWCGSAFlAwQCAQUAoIGEMBgGCisGAQQBgjcCAQwxCjAIoAKAAKECgAAwGQYJKoZI
# hvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcC
# ARUwLwYJKoZIhvcNAQkEMSIEIGnxMLsQ6kWe926eHN6Y+MqFJChf1TXPvUcIv78/
# 2fvdMA0GCSqGSIb3DQEBAQUABIICAACxLYm2G5oY8jgMJoDiDvZrriry55+i+7Mw
# t3c8535hAOWYv0kyHPoVG19lppozjkd2g9JxJfmxfL9OBP0Ov0BUHhDX1rGFBwGQ
# Tbqt23JdXq4RTTE7gU6DlUWROuY6oFjdY0vQuY6ocnZdlbFYMkCZHYaE8MxAa96/
# TzhVH5TUTJvwBEkxByscN+XMoppwoDAd7gK8OsP/sZzSp2eDKoJ9PNAbPl4Ac/5C
# WYVsQNcNFdsac5cUip48V9NF8wwJtr8PL36JNQKvswkUO+iYkwIcyVNQiPaiJXfc
# C7usIbsAccqUmt1WK0jQ3Vm/OEZVRs720KGGlPdsdMY/8+VPQvPsRIObgqfEXtzm
# q5+lhOIWhu0D7pjRwZka0/KSiJV38dDw4/TMPO50YiqlMCz8+PAIu9913YB+OuDO
# e7D55u0/Jfws0SmrM+wBs1EkfHBY43Thf3uTXiiKN6Z8DDEjJ1FzzgzaKFsdNP6D
# LIMIF4R8+H4NFmJZRNYJ5yX0ZMjRvRrK3rud+c3yoLgc8peiXxUAE7E4SuSLn7Cv
# V9xkoPbxQ2eiBkqguqVQBEvDbmv0KlJHChcc0lydEvbMVVlVR8ifDPpAIejanin0
# AGPWGtppH/LYmIBuJk//+/Ec5d2T3wz+xiX7Yanrr1+RTbcl6eUZLOyTd7x5moXs
# HFsRRox5oYIXlzCCF5MGCisGAQQBgjcDAwExgheDMIIXfwYJKoZIhvcNAQcCoIIX
# cDCCF2wCAQMxDzANBglghkgBZQMEAgIFADCBhwYLKoZIhvcNAQkQAQSgeAR2MHQC
# AQEGCWCGSAGG/WwHATBBMA0GCWCGSAFlAwQCAgUABDApagbfRnFbgYKcUAsWt1ca
# an0HHe3XkuH6lkXL6vWD+eQtrElygfxPoBcODFkFYI4CEFz9A4IYTZ048YtQrx83
# kasYDzIwMjYwNjA4MjExNjE2WqCCEzowggbtMIIE1aADAgECAhAMIENJ+dD3WfuY
# LeQIG4h7MA0GCSqGSIb3DQEBDAUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5E
# aWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1l
# U3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwHhcNMjUwNjA0MDAwMDAw
# WhcNMzYwOTAzMjM1OTU5WjBjMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNl
# cnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFNIQTM4NCBSU0E0MDk2IFRpbWVz
# dGFtcCBSZXNwb25kZXIgMjAyNSAxMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEA2zlS+4t0t+XJDVHY+vNJxpv794sM3O4UQycmKRXmYLs+YRfztyl8QJ7n
# /UqxNTKWmjdFDWGv43+a2oiJ41yxOe0sLoFx8F1az2JRTZc7dhAxbne+byd5bf2S
# EZlCruGxxWSqbpUY6dAGRCCyBOaiFaoXhkn+L15efcomDSrTnA5Vgd9pvMO+7bM+
# tSW4JzAiIbO2mIPyCEdKYscmPl+YBuenSP7NJw9icL1tWpn61uM6WyUNv4RcyBAz
# +NvJbNf5kTM7F46cvBwp0lZYisZR985y5sYj4e4yUBbPBxyrT5aNMZ++5tis8GDm
# HCpqyVLQ4eLHwpim5iwR49TREfETtlEFORWTkJ2hOO1zzVAWs6jtdep12VtFZoQO
# hIwdUfPHSsAw39xFVevFEFf2u+DVr1sOV7JACY+xcG8hWIeqPGVUwkiyBRUTgA7H
# eAxJb0iQl4GDBC6ZBA4wGN/ahMxF4fuJsOs1zwkPBSnXmHkm18HwHgIPKk287dMI
# chZyjm7zGcCYZ4bisoUYWL9oTga9JCfFMTc9yl26XDB0zl9rdSwviOmaYSlaRanF
# 84oxAYnqgBy6Z89ykPgWnb7SRi31NyP359Whok+36fkyxTPjSrCWvMK7pzbRg8tf
# IRlUnxl7G5bIrkPqMbD9zJoB79MHFgLr5ljU7rrcLwy+cEfpzFMCAwEAAaOCAZUw
# ggGRMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFWeuednyJEQSbQ2Uo15tyTFPy34
# MB8GA1UdIwQYMBaAFO9vU0rp5AZ8esrikFb2L9RJ7MtOMA4GA1UdDwEB/wQEAwIH
# gDAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDCBlQYIKwYBBQUHAQEEgYgwgYUwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBdBggrBgEFBQcwAoZR
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0VGlt
# ZVN0YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3J0MF8GA1UdHwRYMFYwVKBS
# oFCGTmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNFRp
# bWVTdGFtcGluZ1JTQTQwOTZTSEEyNTYyMDI1Q0ExLmNybDAgBgNVHSAEGTAXMAgG
# BmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQEMBQADggIBABt+CySH2Alq
# xUHnUWnZJI7rpdAqo0PcikyV48Ltk5QWFgxpHP9WtjR3lskEAOk3TszmuNyMid7V
# uxHlQJl4KcdTr5cQ2YLy+l560peBgM7kA4HCJqGqdQdzjXyrlg3YCdfnjs9w/7BO
# 8xUmlAaq/D+PTZZO+Mnxa3/IoyYsF+L9gWX4VJxZLljVs5JKmpSonnysMYv7Caqk
# QpBDmJWU2F68mLLZXfU0wXbDy9QQTskgcHviyQDeB1l6jl/WwOQiSNTNafYQUR2Z
# sJ5rPJu1NPzO1htKwdiUjWenHwq5BRK1BR7+D+TwG97UHX4V0W+JvFZp8z3d3G5s
# A7Pt9qO5/6AWZ+0yf8nN58D+HAAShHmny25t6W7qF6VSRZCIpGr8hbAjfbBhO4MY
# 8G2U9zwVKp6SljuKknxd2buihO33dioCGsB6trX++xQKf4QlYSggFvD9ZWSG4ysJ
# PYOx+hbsBTEONFtr99x6OgJnnyVkDoudIn+gmV+Bq+a2G++BLU5AXOVclExpuoUQ
# XUZF5p3sUrd21QjF9Ra0x4RD02gS4XwgzN+tvuY+tjhPICwXmH3ERL+fPIoxZT0X
# gwVP+17UqUbi5Zpe4YdadG5WjCTBvtmlM4JVovGYRvyAyfmYJJx0/0T+qK05wRJp
# g4q81vOKuCQPaE9H99JCVvfCDBm4KjrEMIIGtDCCBJygAwIBAgIQDcesVwX/IZku
# QEMiDDpJhjANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM
# RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQD
# ExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwHhcNMjUwNTA3MDAwMDAwWhcNMzgw
# MTE0MjM1OTU5WjBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIElu
# Yy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgVGltZVN0YW1waW5nIFJT
# QTQwOTYgU0hBMjU2IDIwMjUgQ0ExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAtHgx0wqYQXK+PEbAHKx126NGaHS0URedTa2NDZS1mZaDLFTtQ2oRjzUX
# MmxCqvkbsDpz4aH+qbxeLho8I6jY3xL1IusLopuW2qftJYJaDNs1+JH7Z+QdSKWM
# 06qchUP+AbdJgMQB3h2DZ0Mal5kYp77jYMVQXSZH++0trj6Ao+xh/AS7sQRuQL37
# QXbDhAktVJMQbzIBHYJBYgzWIjk8eDrYhXDEpKk7RdoX0M980EpLtlrNyHw0Xm+n
# t5pnYJU3Gmq6bNMI1I7Gb5IBZK4ivbVCiZv7PNBYqHEpNVWC2ZQ8BbfnFRQVESYO
# szFI2Wv82wnJRfN20VRS3hpLgIR4hjzL0hpoYGk81coWJ+KdPvMvaB0WkE/2qHxJ
# 0ucS638ZxqU14lDnki7CcoKCz6eum5A19WZQHkqUJfdkDjHkccpL6uoG8pbF0LJA
# QQZxst7VvwDDjAmSFTUms+wV/FbWBqi7fTJnjq3hj0XbQcd8hjj/q8d6ylgxCZSK
# i17yVp2NL+cnT6Toy+rN+nM8M7LnLqCrO2JP3oW//1sfuZDKiDEb1AQ8es9Xr/u6
# bDTnYCTKIsDq1BtmXUqEG1NqzJKS4kOmxkYp2WyODi7vQTCBZtVFJfVZ3j7OgWmn
# hFr4yUozZtqgPrHRVHhGNKlYzyjlroPxul+bgIspzOwbtmsgY1MCAwEAAaOCAV0w
# ggFZMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFO9vU0rp5AZ8esrikFb2
# L9RJ7MtOMB8GA1UdIwQYMBaAFOzX44LScV1kTN8uZz/nupiuHA9PMA4GA1UdDwEB
# /wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDCDB3BggrBgEFBQcBAQRrMGkwJAYI
# KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1
# aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZFJvb3RH
# NC5jcnQwQwYDVR0fBDwwOjA4oDagNIYyaHR0cDovL2NybDMuZGlnaWNlcnQuY29t
# L0RpZ2lDZXJ0VHJ1c3RlZFJvb3RHNC5jcmwwIAYDVR0gBBkwFzAIBgZngQwBBAIw
# CwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4ICAQAXzvsWgBz+Bz0RdnEwvb4L
# yLU0pn/N0IfFiBowf0/Dm1wGc/Do7oVMY2mhXZXjDNJQa8j00DNqhCT3t+s8G0iP
# 5kvN2n7Jd2E4/iEIUBO41P5F448rSYJ59Ib61eoalhnd6ywFLerycvZTAz40y8S4
# F3/a+Z1jEMK/DMm/axFSgoR8n6c3nuZB9BfBwAQYK9FHaoq2e26MHvVY9gCDA/JY
# sq7pGdogP8HRtrYfctSLANEBfHU16r3J05qX3kId+ZOczgj5kjatVB+NdADVZKON
# /gnZruMvNYY2o1f4MXRJDMdTSlOLh0HCn2cQLwQCqjFbqrXuvTPSegOOzr4EWj7P
# tspIHBldNE2K9i697cvaiIo2p61Ed2p8xMJb82Yosn0z4y25xUbI7GIN/TpVfHIq
# Q6Ku/qjTY6hc3hsXMrS+U0yy+GWqAXam4ToWd2UQ1KYT70kZjE4YtL8Pbzg0c1ug
# MZyZZd/BdHLiRu7hAWE6bTEm4XYRkA6Tl4KSFLFk43esaUeqGkH/wyW4N7Oigizw
# JWeukcyIPbAvjSabnf7+Pu0VrFgoiovRDiyx3zEdmcif/sYQsfch28bZeUz2rtY/
# 9TCA6TD8dC3JE3rYkrhLULy7Dc90G6e8BlqmyIjlgp2+VqsS9/wQD7yFylIz0scm
# bKvFoW2jNrbM1pD2T7m3XDCCBY0wggR1oAMCAQICEA6bGI750C3n79tQ4ghAGFow
# DQYJKoZIhvcNAQEMBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0
# IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNl
# cnQgQXNzdXJlZCBJRCBSb290IENBMB4XDTIyMDgwMTAwMDAwMFoXDTMxMTEwOTIz
# NTk1OVowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgVHJ1c3Rl
# ZCBSb290IEc0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv+aQc2je
# u+RdSjwwIjBpM+zCpyUuySE98orYWcLhKac9WKt2ms2uexuEDcQwH/MbpDgW61bG
# l20dq7J58soR0uRf1gU8Ug9SH8aeFaV+vp+pVxZZVXKvaJNwwrK6dZlqczKU0RBE
# EC7fgvMHhOZ0O21x4i0MG+4g1ckgHWMpLc7sXk7Ik/ghYZs06wXGXuxbGrzryc/N
# rDRAX7F6Zu53yEioZldXn1RYjgwrt0+nMNlW7sp7XeOtyU9e5TXnMcvak17cjo+A
# 2raRmECQecN4x7axxLVqGDgDEI3Y1DekLgV9iPWCPhCRcKtVgkEy19sEcypukQF8
# IUzUvK4bA3VdeGbZOjFEmjNAvwjXWkmkwuapoGfdpCe8oU85tRFYF/ckXEaPZPfB
# aYh2mHY9WV1CdoeJl2l6SPDgohIbZpp0yt5LHucOY67m1O+SkjqePdwA5EUlibaa
# RBkrfsCUtNJhbesz2cXfSwQAzH0clcOP9yGyshG3u3/y1YxwLEFgqrFjGESVGnZi
# fvaAsPvoZKYz0YkH4b235kOkGLimdwHhD5QMIR2yVCkliWzlDlJRR3S+Jqy2QXXe
# eqxfjT/JvNNBERJb5RBQ6zHFynIWIgnffEx1P2PsIV/EIFFrb7GrhotPwtZFX50g
# /KEexcCPorF+CiaZ9eRpL5gdLfXZqbId5RsCAwEAAaOCATowggE2MA8GA1UdEwEB
# /wQFMAMBAf8wHQYDVR0OBBYEFOzX44LScV1kTN8uZz/nupiuHA9PMB8GA1UdIwQY
# MBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA4GA1UdDwEB/wQEAwIBhjB5BggrBgEF
# BQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBD
# BggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# QXNzdXJlZElEUm9vdENBLmNydDBFBgNVHR8EPjA8MDqgOKA2hjRodHRwOi8vY3Js
# My5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMBEGA1Ud
# IAQKMAgwBgYEVR0gADANBgkqhkiG9w0BAQwFAAOCAQEAcKC/Q1xV5zhfoKN0Gz22
# Ftf3v1cHvZqsoYcs7IVeqRq7IviHGmlUIu2kiHdtvRoU9BNKei8ttzjv9P+Aufih
# 9/Jy3iS8UgPITtAq3votVs/59PesMHqai7Je1M/RQ0SbQyHrlnKhSLSZy51PpwYD
# E3cnRNTnf+hZqPC/Lwum6fI0POz3A8eHqNJMQBk1RmppVLC4oVaO7KTVPeix3P0c
# 2PR3WlxUjG/voVA9/HYJaISfb8rbII01YBwCA8sgsKxYoA5AY8WYIsGyWfVVa88n
# q2x2zm8jLfR+cWojayL/ErhULSd+2DrZ8LaHlv1b0VysGMNNn3O3AamfV6peKOK5
# lDGCA4wwggOIAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0
# LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IFRpbWVTdGFtcGlu
# ZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMQIQDCBDSfnQ91n7mC3kCBuIezANBglg
# hkgBZQMEAgIFAKCB4TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZI
# hvcNAQkFMQ8XDTI2MDYwODIxMTYxNlowKwYLKoZIhvcNAQkQAgwxHDAaMBgwFgQU
# crz9oBB/STSwBxxhD+bXllAAmHcwNwYLKoZIhvcNAQkQAi8xKDAmMCQwIgQgMvPj
# sb2i17JtTx0bjN29j4uEdqF4ntYSzTyqep7/NcIwPwYJKoZIhvcNAQkEMTIEMNfF
# fpfmnFapf70BCuNqcsbW3oYTY0z8f/STkxEZXvAmZ3CHaMgdQ2uv5JMsl4pywzAN
# BgkqhkiG9w0BAQEFAASCAgBz50IkokLZf4QNKJ0e9bmA/75VhdJHBJ/QQ2O8XRP3
# DK7TA83N3to8xJX9uNRmOnaFQ7g6fUCNvHQt6LRJ4XCdBBrWgVDxWwejsXhEM4sN
# 5oyovS3Lg/LyGOGZr9/FL1S/vytJQjUhKff7erWdlmzS5IgN9zxhEpXg5XEiYMEf
# zADC63WlCt8T/j9yexw1JQPJ+PtvOCJGuTrvXB6BN98za455nilKWWZ5NR4udzMe
# S9/tzm5nIBIX/sWpr75+F6C1tiOUsl0AYDAD79rk5OzNxt3nuwcuKIZinXT4+X78
# +/vqt3liMDQ4A4EHUs6rhdE+TfY58Ga0qXA21cQJ9pgRZmAmInKRisE7teGZHCtC
# yn8o8vvGnk5g5U4l49mDsvjZ1JiOmd6cFMpMdXGZ5gDTjWsIR+aLRYYF4HW8Gnzz
# Q8jUlqF7xRAq3K7Cq78LpEpL/tg73/g26dDuzp6my+KyjzuCcJx96qYJvF86SLe+
# Hr4aqtxhfVqOuOtASsTaCFeuydqibA4p2dDF5sduC25pCI//HP+n4eWtgoUe1uaK
# YAEp0lQawImw59aDGr1Ur9PsXjf1gd1zP9rEWuaqVgdNBMPpHN3rVDcbvw7jY36F
# LcUyFihQjeetaeKWX2lVUR5TfNWIaw3/Gy/rfpSTlJRNl9C9rhhlilvuu1QsiVDU
# /g==
# SIG # End signature block