(C) Ondrej Sevecek, 2019 - www.sevecek.com, ondrej@sevecek.com
#$global:outClass = 'main' $libDir = Split-Path -parent $MyInvocation.MyCommand.Definition & "$libDir\lib-common.ps1" -defaultConfig -rootDir $libDir -outFile caLib & "$libDir\lib-modifyActions.ps1" & "$libDir\lib-buildup.ps1" $vmName = $args[0] DBG ("AD CS Installation library") Redirect-TempToOutput Load-VMConfig Find-MarkedVolumes $appTag = 'ca' $appConfig = $vmConfig.$appTag $firstAppHost = Get-FirstAppHostInInstance $appTag $appConfig.instance 'waitParams' $firstAppHostInInstance = Check-FirstAppHostInInstance $appTag $appConfig.instance #==================== #==================== #========================= DBG ("Copying CAPOLICY.INF") Copy-Item -Path "$global:rootDir\AD-CS\capolicy.inf" -Destination "$env:SystemRoot" -Force -EV er -EA SilentlyContinue DBGER $MyInvocation.MyCommand.Name $er #========================= DBG ("Going to install AD CS with: {0} | CN={1},{2} | {3} | {4} | {5} | {6}" -f $appConfig.pkitype, $appConfig.instance, $appConfig.dn, $appConfig.provider, $appConfig.algo, $appConfig.keyLength, $appConfig.validity) if ($thisOSVersion -like '5.2.*') { DBG ("Doing 5.2 installation of Certificate Services by using SYSOCMGR.") $sysocmgrFile = Get-DataFileApp 'certsrvSetup' $null '.ini' # Note: CADistinguishedName, nor other variants such as Locality, State, Country etc. are supported on 2k3 $argReplacement = 'CAType${0}|Name$"{1}"|CADistinguishedName$"{2}"|CSPProvider$"{3}"|HashAlgorithm${4}|KeyLength${5}|ValidityPeriod${6}' -f (Escape-ForMultiValue $appConfig.pkitype, $appConfig.instance, $appConfig.dn, $appConfig.provider, $appConfig.algo, $appConfig.keyLength, $appConfig.validity) Replace-ArgumentsInFile "$global:rootDir\AD-CS\install-CertSrv.ini" $argReplacement $sysocmgrFile ASCII Run-Process "sysocmgr" "/i:`"$env:SystemRoot\inf\sysoc.inf`" /u:`"$sysocmgrFile`" /r /q" } elseif ($global:thisOSVersionNumber -ge 6.2) { DBG ("Doing 6.2+ installation of AD CS by using the powershell cmdlet") Install-AdcsCertificationAuthority -AllowAdministratorInteraction:$false -CACommonName $appConfig.instance -CADistinguishedNameSuffix $appConfig.dn -CAType ('{0}CA' -f $appConfig.pkitype) -CryptoProviderName $appConfig.provider -HashAlgorithmName $appConfig.algo -IgnoreUnicode:$false -KeyLength $appConfig.keyLength -OverwriteExistingCAinDS -OverwriteExistingDatabase -OverwriteExistingKey:$false -ValidityPeriod Years -ValidityPeriodUnits $appConfig.validity -Confirm:$false -EV er -EA SilentlyContinue DBGER $MyInvocation.MyCommand.Name $er } else { DBG ("Doing 6.0 and 6.1 installation of AD CS by using .VBS script.") switch ($appConfig.pkitype) { "EnterpriseRoot" { $typeSwitch = '/IE' } "StandaloneRoot" { $typeSwitch = '/IS' } "EnterpriseSubordinate" { $typeSwitch = '/IF' } "StandaloneSubordinate" { $typeSwitch = '/IT' } default { $typeSwitch = '/IE' } } $scriptParams = "//NoLogo `"$global:rootDir\AD-CS\install-AD-CS.vbs`" /SP `"$($appConfig.provider)`" /SK `"$($appConfig.keyLength)`" /SA `"$($appConfig.algo)`" /SN `"$($appConfig.instance)`" /DN `"$($appConfig.dn)`" /SV `"$($appConfig.validity)`" $typeSwitch" DBG ('Will install the CA with the following script: {0}' -f $scriptParams) # if ($global:thisOSVersionNumber -eq 6.0) { Read-Host DOITMANUALLY } if ($global:thisOSVersionNumber -eq 6.0) { # On Windows 2008 RTM there is the hang/deadlock if we assume the output to come back - it hangs on the g_oCASetup.Install() call Run-Process 'cscript' $scriptParams -doNotRedirOut $true } else { Run-Process 'cscript' $scriptParams } } $caBaseRegKey = 'HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration\{0}' -f $appConfig.instance DBG ('CA base registry key: {0}' -f $caBaseRegKey) #========================= DBG ("Default CA config") DBG ("Setting default CERSRV registry parameters") Run-Process 'CERTUTIL' '-setreg Policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2' Run-Process 'CERTUTIL' '-setreg CA\ValidityPeriodUnits 7' Run-Process 'CERTUTIL' '-setreg Policy\EditFlags +EDITF_ENABLELDAPREFERRALS' if ($global:thisOSVersionNumber -ge 6.1) { Run-Process 'CERTUTIL' '-setreg DBFlags +DBFLAGS_ENABLEVOLATILEREQUESTS' } Run-Process 'CERTUTIL' '-setreg CA\AuditFilter 127' Enable-Auditing 'Object Access' 'Certification Services' -verify DBG ('Should we change the CNGHashAlgorithm: {0} | {1}' -f (Is-ValidString $appConfig.cngHash), $appConfig.cngHash) if (Is-ValidString $appConfig.cngHash) { DBGSTART [string] $currentCngHash = (Get-ItemProperty -Path (Join-Path $caBaseRegKey CSP) -Name CNGHashAlgorithm).CNGHashAlgorithm DBGER $MyInvocation.MyCommand.Name $error DBGEND DBG ('Current CNG hash algo: {0}' -f $currentCngHash) DBGIF $MyInvocation.MyCommand.Name { Is-Null $currentCngHash } DBG ('Changing CNG hash algo: {0} | {1}' -f $currentCngHash, $appConfig.cngHash) DBGSTART Set-ItemProperty -Path (Join-Path $caBaseRegKey CSP) -Name CNGHashAlgorithm -Value $appConfig.cngHash DBGER $MyInvocation.MyCommand.Name $error DBGEND } if ($thisOSVersion -like '6.0.*') { # Note: this shity OS doesn't allow Administrators full control to the registry keys # TrustedInstaller is owner and Administrators are granted only Read permission Take-RegOwnership 'Software\Classes\AppId\{D99E6E74-FC88-11D0-B498-00A0C90312F3}' Set-RegPermissions 'Software\Classes\AppId\{D99E6E74-FC88-11D0-B498-00A0C90312F3}' "Administrators" } DBG ('Adjust static DCOM port: {0}' -f (Is-ValidString $appConfig.staticPort)) if (Is-ValidString $appConfig.staticPort) { Run-Process 'CERTUTIL' '-setreg CA\InterfaceFlags +IF_NORPCICERTREQUEST' Set-RegistryValue 'HKLM:\Software\Classes\AppID\{D99E6E74-FC88-11D0-B498-00A0C90312F3}' EndPoints ('ncacn_ip_tcp,0,{0}' -f $appConfig.staticPort) MultiString } # This can only be set if all the clients are at least Vista/2008 #Run-Process 'CERTUTIL' '-setreg CA\CSP\AlternateSignatureAlgorithm 1' #Run-Process 'CERTUTIL' '-setreg CA\EncryptionCSP\CNGEncryptionAlgorithm AES' #Run-Process 'CERTUTIL' '-setreg CA\EncryptionCSP\SymmetricKeySize 128' #Run-Process 'CERTUTIL' '-setreg CA\EncryptionCSP\CNGPublicKeyAlorithm ECDH_P256' #Run-Process 'CERTUTIL' '-setreg CA\EncryptionCSP\KeySize 256' if (($thisOSVersionNumber -ge 6) -and ($appConfig.pkitype -like 'Standalone*')) { # Note: this is not necessary for enterprise CAs that use certificate templates # The logic is that the CA checks the template OR the EditFlags for presence of this attribute # and if at least one says to omit CRL/AIA paths, it does as instructed Run-Process 'CERTUTIL' '-setreg Policy\EditFlags +EDITF_ENABLEOCSPREVNOCHECK' } Set-RegistrySD ($caBaseRegKey) 'Security' ('O:BAG:BAD:AI(A;OICI;0x200;;;AU)(A;OICI;CC;;;{0}\{1})(A;OICI;DC;;;{0}\{1})S:(AU;SAFA;0xFFFF;;;WD)(AU;SAFA;0xFFFF;;;AN)' -f $appConfig.app.iDomain, $appConfig.app.aGroup) [System.Collections.ArrayList] $deList = @() $rootDSE = Get-DE 'RootDSE' ([ref] $deList) $configDN = GDES $rootDSE configurationNamingContext DBG ("Importing Autoenrollment rights GUID") # Note: you cannot use #configurationNamingContext with Windows 2003 LDIFDE Run-Process 'LDIFDE' "-i -f `"$global:rootDir\AD-CS\autoenrollment-rights-guid.ldf`" -c `"cn=configuration,dc=x`" `"$configDN`"" -ignoreExitCodes @(5010) #==================== DBG ("Importing OIDs") Run-Process 'LDIFDE' "-i -f `"$global:rootDir\AD-CS\cert-templates-oids.ldf`" -c `"cn=configuration,dc=x`" `"$configDN`"" #==================== DBG ('Updating macros in templates.LDF') $templatesLDF = Get-DataFileApp 'templates' $null '.ldf' $argReplacement = 'namePrefix${0}' -f (Escape-ForMultiValue $appConfig.templateNamePrefix) Replace-ArgumentsInFile (Join-Path $global:rootDir 'AD-CS\templates.ldf') $argReplacement $templatesLDF ASCII DBG ('Importing templates') Run-Process 'LDIFDE' ('-i -f "{0}" -c "cn=configuration,dc=x" "{1}"' -f $templatesLDF, $configDN) #==================== DBG ("Going to set CRL and AIA paths") $certEnrollPath = "$env:SystemRoot\system32\CertSrv\CertEnroll" #$publicDNS = Strip-ValueFlags ([string] $appConfig.SelectSingleNode('./fs[@appTag="target"]/@dns').'#text') [string] $publicDNS = Get-ServiceOrMachineDnsFQDNs $appConfig -assertSingleName $true [string] $virtDir = Strip-ValueFlags ([string] $appConfig.SelectSingleNode('./fs[@appTag="target"]/@iis').'#text') if (Is-ValidString $publicDNS) { DBG ("Will publish on public DNS: {0} / {1}" -f $publicDNS, $virtDir) $crlPublicDNSURL = '6:http://{0}/{1}/%3%8%9.crl\n' -f $publicDNS, $virtDir $aiaPublicDNSURL = '2:http://{0}/{1}/%3%4.crt\n' -f $publicDNS, $virtDir } else { DBG ('No public DNS for CRL') } if (-not (Parse-BoolSafe $appConfig.noLDAPpaths)) { DBG ('Should add LDAP paths for CRL') $ldapCRL = '79:ldap:///CN=%7%8,CN=%2,CN=CDP,CN=Public Key Services,CN=Services,%6%10\n' $ldapAIA = '3:ldap:///CN=%7,CN=AIA,CN=Public Key Services,CN=Services,%6%11\n' } else { DBG ('No LDAP paths for CRL') $ldapCRL = '' $ldapAIA = '' } Run-Process 'CERTUTIL' ('-setreg CA\CRLPublicationURLs "65:{0}\%3%8%9.crl\n{1}{2}"' -f $certEnrollPath, $crlPublicDNSURL, $ldapCRL) Run-Process 'CERTUTIL' ('-setreg CA\CACertPublicationURLs "1:{0}\%3%4.crt\n{1}{2}"' -f $certEnrollPath, $aiaPublicDNSURL, $ldapAIA) #DBG ("Copying the original CA .CRT name") #Rename-Item -Path ("$env:SystemRoot\System32\CertSrv\CertEnroll\{0}.{1}_{2}.crt" -f $thisComputerHost, $thisComputerDomain, $appConfig.instance) -NewName ('{0}.crt' -f $appConfig.instance) -EV er -EA SilentlyContinue #DBGSTART #$cmdOutput = & "$global:rootDir\AD-CS\sevecek-publish-AIA-CDP.ps1" "$env:SystemRoot\System32\CertSrv\CertEnroll" $appConfig.instance #DBGER $MyInvocation.MyCommand.Name $er #DBG ('Copy AIA .CRT result: {0}' -f ($cmdOutput | Out-String)) DBG ('Sometimes the CertSvc is not yet fully initialized, so give it some time') Wait-Service CertSvc Wait-CertSvc if ($global:thisOSVersionNumber -ge 6) { DBG ("Setting AD CS to Delayed AutoStart on Win6.x") Run-Process 'SC' 'config CertSvc start= delayed-auto' } #========================= #========================= DBG ("Delegating CA forest administration to: {0}" -f $appConfig.app.aGroup) $pkiDN = 'CN=Public Key Services,CN=Services,{0}' -f $configDN $templatesDN = 'CN=Certificate Templates,{0}' -f $pkiDN $oidsDN = 'CN=OID,{0}' -f $pkiDN $aiaDN = 'CN=AIA,{0}' -f $pkiDN $cdpDN = 'CN={1},CN=CDP,{0}' -f $pkiDN, $global:thisComputerNetBIOS $esDN = 'CN=Enrollment Services,{0}' -f $pkiDN # /P:Y - mark protected # /N - replace ACL instead of editing # /I:T - inherit to all childs # /G - grant # /R - revoke $caMachineLogin = Get-SAMLogin ('{0}$' -f $global:thisComputerNetBIOS) $global:thisComputerDomain Run-Process 'DSACLS' ('"{0}" /P:Y /N /G "{1}:GA" "SYSTEM:GA" "Authenticated Users:GR"' -f $templatesDN, $appConfig.app.aGroup) Run-Process 'DSACLS' ('"{0}" /P:Y /N /I:T /G "{1}:GA" "SYSTEM:GA" "Authenticated Users:GR"' -f $oidsDN, $appConfig.app.aGroup) Run-Process 'DSACLS' ('"{0}" /P:Y /N /I:T /G "{1}:GA" "SYSTEM:GA" "Authenticated Users:GR"' -f $aiaDN, $appConfig.app.aGroup) Run-Process 'DSACLS' ('"{0}" /P:Y /N /I:T /G "{1}:GA" "SYSTEM:GA" "Authenticated Users:GR" "{2}:GA"' -f $cdpDN, $appConfig.app.aGroup, $caMachineLogin) Run-Process 'DSACLS' ('"{0}" /P:Y /N /I:T /G "{1}:GA" "SYSTEM:GA" "Authenticated Users:GR"' -f $esDN, $appConfig.app.aGroup) #========================= DBG ("Searching for certificate TEMPLATES") $searchRes = Get-ADSearch $templatesDN 'oneLevel' '(objectClass=pKICertificateTemplate)' if ($searchRes.found) { #$searchRes[1] = $searchRes[0].FindAll() $searchRes.result | % { $oneDN = GSRS $_ distinguishedName DBG ("Securing template for default PKI admins group: {0}" -f $oneDN) Run-Process 'DSACLS' ('"{0}" /P:Y /R "Enterprise Admins" "Domain Admins" "SYSTEM" /G "Authenticated Users:GR" "{1}:GWWOWD"' -f $oneDN, $appConfig.app.aGroup) } } Dispose-ADSearch ([ref] $searchRes) #========================= DBG ("Searching for OIDs") $searchRes = Get-ADSearch $oidsDN 'oneLevel' '(objectClass=msPKI-Enterprise-OID)' #DBGIF $MyInvocation.MyCommand.Name { Is-Null $searchRes[0] } if ($searchRes.found) { #$searchRes[1] = $searchRes[0].FindAll() $searchRes.result | % { $oneDN = GSRS $_ distinguishedName DBG ("Securing OID: {0}" -f $oneDN) Run-Process 'DSACLS' ('"{0}" /P:Y /R "Enterprise Admins" "Domain Admins" /G "Authenticated Users:GR" "{1}:GA"' -f $oneDN, $appConfig.app.aGroup) } } Dispose-ADSearch ([ref] $searchRes) Dispose-List ([ref] $deList) #========================= DBG ("Finishing AD CS installation by cleaning up and restarting the service and publishing CRL") Remove-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Cryptography\CertificateTemplateCache' -Name 'Timestamp' -EA SilentlyContinue -EV er DBGER $MyInvocation.MyCommand.Name $er Remove-ItemProperty -Path 'HKCU:\SOFTWARE\Microsoft\Cryptography\CertificateTemplateCache' -Name 'Timestamp' -EA SilentlyContinue -EV er DBGER $MyInvocation.MyCommand.Name $er Run-Process 'certutil' '-silent -repairstore my *' # Note: this produces unnecessary "Access denied" errors on some Microsoft root CAs which do not have private keys anyway #Run-Process 'certutil' '-silent -repairstore root *' Restart-Service -Name CertSvc -EV er -EA SilentlyContinue DBGER $MyInvocation.MyCommand.Name $er Wait-Service CertSvc Wait-CertSvc Run-Process 'CERTUTIL' '-crl' DBG ("Enabling default certificate templates") Run-Process 'CERTUTIL' '-SetCATemplates KerberosAuthentication' $publishingScript = 'sevecek-PKI-publish-AIA-CDP' #========================= $cdpSvcNode = $appConfig.SelectSingleNode('./svc[@appTag="jobs"]') #$cdpFsJobNode = $appConfig.SelectSingleNode('./fs[@instance="local" and @appTag="jobs"]') $cdpFsShareNode = $appConfig.SelectSingleNode('./fs[@appTag="target"]') #DBG ('Install CRL/CRT/AIA/CDP publishing script: {0}' -f ((Is-ValidString $cdpSvcNode.login) -and (Is-ValidString $cdpFsJobNode.instance) -and (Is-ValidString $cdpFsShareNode.instance))) DBG ('Install CRL/CRT/AIA/CDP publishing script: {0}' -f ((Is-ValidString $cdpSvcNode.login) -and (Is-ValidString $cdpFsShareNode.instance))) #if ((Is-ValidString $cdpSvcNode.login) -and (Is-ValidString $cdpFsJobNode.instance) -and (Is-ValidString $cdpFsShareNode.instance)) { if ((Is-ValidString $cdpSvcNode.login) -and (Is-ValidString $cdpFsShareNode.instance)) { $targetFSPath = Resolve-ClientFsPath $cdpFsShareNode if ($targetFSPath -like '\\*') { $targetShareTokens = ($targetFSPath).Split('\') #DBG ('Prepare CDP/AIA publishing script to a shared folder: {0}' -f $targetFSPath) #$cdpScriptTemp = Get-DataFileApp $publishingScript $null '.bat' $argReplacement = 'caName${0}|fsServer${1}|fsShare${2}|publishUser${3}@{4}|publishPwd${5}' -f (Escape-ForMultiValue $appConfig.instance, $targetShareTokens[2], $targetShareTokens[3], $cdpSvcNode.login, $cdpSvcNode.domain, $cdpSvcNode.pwd) #Replace-ArgumentsInFile "$global:rootDir\AD-CS\$publishingScript.bat" $argReplacement $cdpScriptTemp ASCII } else { #DBG ('Prepare CDP/AIA publishing script to publish to a local folder: {0}' -f $targetFSPath) #$cdpScriptTemp = Get-DataFileApp $publishingScript $null '.bat' $argReplacement = 'caName${0}|fsServer${1}|fsShare${2}|publishUser${3}@{4}|publishPwd${5}' -f (Escape-ForMultiValue $appConfig.instance, $null, $targetFSPath, $cdpSvcNode.login, $cdpSvcNode.domain, $cdpSvcNode.pwd) #Replace-ArgumentsInFile "$global:rootDir\AD-CS\$publishingScript.bat" $argReplacement $cdpScriptTemp ASCII } <# $cdpScript = Join-Path (Resolve-ClientFsPath $cdpFsJobNode) "$publishingScript.bat" DBG ('Copy CDP script: {0} | {1}' -f $cdpScriptTemp, $cdpScript) Copy-Item -Path $cdpScriptTemp -Destination $cdpScript -Force -EV er -EA SilentlyContinue | Out-Null DBGER $MyInvocation.MyCommand.Name $er $aiaRenameScriptSrc = "$global:rootDir\AD-CS\$publishingScript.ps1" $aiaRenameScriptDst = Join-Path (Resolve-ClientFsPath $cdpFsJobNode) "$publishingScript.ps1" DBG ('Copy AIA script: {0} | {1}' -f $aiaRenameScriptSrc, $aiaRenameScriptDst) Copy-Item -Path $aiaRenameScriptSrc -Destination $aiaRenameScriptDst -Force -EV er -EA SilentlyContinue | Out-Null DBGER $MyInvocation.MyCommand.Name $er #> $cdpScript = Install-ScheduledJob -vmConfig $vmConfig -appTag ca -sourceScriptName $publishingScript -sourceFolder AD-CS -argReplacement $argReplacement if ($global:thisOSVersionNumber -ge 6) { DBG ('Build scheduled task for event 4872') Schedule-Task $publishingScript $cdpScript 'NT AUTHORITY\System' $null 'ONEVENT /EC Security /MO "*[System/EventID=4872 or System/EventID=4895]"' $true } else { Schedule-Task $publishingScript $cdpScript $null $null 'SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA "Win32_NTLogEvent" AND TargetInstance.LogFile = "Security" AND (TargetInstance.EventCode = "776" OR TargetInstance.EventCode = "784")' $true } } DBG ('Finally publish CRL again to test the copy-script execution') # Note: the script does not wait for the FS instance to finish # so don't rely on this too much Run-Process 'CERTUTIL' '-crl' #========================= # Just a matter of debugging info obtained if ($global:thisOSVersionNumber -ge 6.1) { Run-Process 'CERTUTIL' '-ADTemplate' } else { Run-Process 'CERTUTIL' '-Template' } #========================= #========================= $certTemplApps = $xmlConfig.SelectNodes('./VMs/MACHINE[vm/@do="true"]//cert[translate(@instance,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz")="{0}"]' -f $appConfig.instance.ToLower()) DBG ('Application requested certificate templates: {0}' -f (Get-CountSafe $certTemplApps)) foreach ($oneCertApp in $certTemplApps) { DBG ('Application asks for a template: {0} | {1}' -f $oneCertApp.template, $oneCertApp.who) $oneAppTemplate = $oneCertApp.template.Replace('$namePrefix$', $appConfig.templateNamePrefix) DBG ('Enabling certificate template: {0}' -f $oneAppTemplate) Run-Process 'CERTUTIL' ('-SetCATemplates +{0}' -f $oneAppTemplate) $appTemplateDN = 'CN={0},{1}' -f $oneAppTemplate, $templatesDN foreach ($oneWho in (Split-MultiValue $oneCertApp.who)) { DBG ('Ellow Enroll permission for one: {0}' -f $oneWho) $appEnrolleeBase = Strip-ValueFlags $oneWho if ($appEnrolleeBase -eq $global:emptyValueMarker) { $appEnrollee = Get-MachineSAMLogin $oneCertApp } else { $appEnrollee = Get-SAMLogin $appEnrolleeBase } DBGIF ('Did not find enrollee account: {0}' -f $oneWho) { Is-EmptyString $appEnrollee } if (Is-ValidString $appEnrollee) { #DBGSTART #$appEnrolleSID = (New-Object Security.Principal.NTAccount $appEnrollee).Translate([Security.Principal.SecurityIdentifier]).Value #DBGER $MyInvocation.MyCommand.Name $Error #DBGEND #DBG ('Secure template for enrollee: {0} | {1}' -f $appEnrollee, $appEnrolleSID) #DBGIF $MyInvocation.MyCommand.Name { Is-EmptyString $appEnrolleSID } Assert-AccountExists $appEnrollee 'Secure template for enrollee' Run-Process 'DSACLS' ('"{0}" /G "{1}:CA;Enroll"' -f $appTemplateDN, $appEnrollee) if (Has-ValueFlags $oneWho 'A') { Run-Process 'DSACLS' ('"{0}" /G "{1}:CA;AutoEnrollment"' -f $appTemplateDN, $appEnrollee) } } } } # SIG # Begin signature block # MIIc/QYJKoZIhvcNAQcCoIIc7jCCHOoCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBHI3u+5iig3Crv # 8NewbFK5UrRppDWTKyaguxLv8rk4I6CCGAQwggTlMIIDzaADAgECAhA5vUKe0oFu # utW8yQO0umXnMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNVBAYTAklMMRYwFAYDVQQK # Ew1TdGFydENvbSBMdGQuMSkwJwYDVQQLEyBTdGFydENvbSBDZXJ0aWZpY2F0aW9u # IEF1dGhvcml0eTEjMCEGA1UEAxMaU3RhcnRDb20gQ2xhc3MgMiBPYmplY3QgQ0Ew # HhcNMTYxMjAxMTU1MTEzWhcNMTgxMjAxMTU1MTEzWjBRMQswCQYDVQQGEwJDWjEa # MBgGA1UECAwRSmlob21vcmF2c2t5IEtyYWoxDTALBgNVBAcMBEJybm8xFzAVBgNV # BAMMDk9uZHJlaiBTZXZlY2VrMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC # AQEAr9E9hNj06bash9JX97kpsqK9Z/ciOBC6trI4nvlW9CPwhKBTb5wArhxLYZBG # 9jWPWrdy1nL/cm5qMqBb/mogYwMwvEYWMvsIOOVn6HD9lVhNAovD6PHz0ziBBKIs # zXTjyUPQaoIlIELovz967m78HJdUZJGxqhluAsS9o9/fEzA7XXUhUuqRKsetuZV/ # Asfh5sOveeoRsbeW4daTWvtz3TJuULL0w43LNVYJkd6LL8cegvLPVZUe1N7skvid # EvntdlowQsJlqFdrH3SGKIPKA6ObcY8SZWkEQSbVBF8Kum1UT+jN0gm+84FwOg5W # qKx+VvTK2ljVWnPrCD0Zzu2oIQIDAQABo4IBkzCCAY8wDgYDVR0PAQH/BAQDAgeA # MBMGA1UdJQQMMAoGCCsGAQUFBwMDMAkGA1UdEwQCMAAwHQYDVR0OBBYEFG2vSo3N # hQWILeUs0oN9XzHTejcfMB8GA1UdIwQYMBaAFD5ik5rXxxnuPo9JEIVVFSDjlIQc # MG0GCCsGAQUFBwEBBGEwXzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Auc3RhcnRz # c2wuY29tMDcGCCsGAQUFBzAChitodHRwOi8vYWlhLnN0YXJ0c3NsLmNvbS9jZXJ0 # cy9zY2EuY29kZTIuY3J0MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuc3Rh # cnRzc2wuY29tL3NjYS1jb2RlMi5jcmwwIwYDVR0SBBwwGoYYaHR0cDovL3d3dy5z # dGFydHNzbC5jb20vMFEGA1UdIARKMEgwCAYGZ4EMAQQBMDwGCysGAQQBgbU3AQIF # MC0wKwYIKwYBBQUHAgEWH2h0dHBzOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kw # DQYJKoZIhvcNAQELBQADggEBAJuRiEvHtIYSpsmMkPhTz4QOOShN3p5KWdf8vm71 # A33CR9fds10d8D2B2aE+vjmHJ69GY0bbfg5oZY2Lsq2euL7Da5/hS8+6T3MEtD4h # njfHV7mxmoSfFuy/KDipoV6uwhI+ksqchXYdUH+5uCQO0MOO8ITjAgzUQsnZ4UIB # HBGeP+e+3ljxSYSXWdPIrgxdR971P/HhWSVfKNlmBgEKMQM5Jy0aAd4jxSl/AzdY # t0+6pliFJ1peGhdFni2Fm8fu5oN68aTIrNtc5WY7Lzgf+sRTVeWORWS37+1zAD0m # jzd8gyfBLxRuaRSfjYxny0rLXelAwfiA3ze2DU2Bfg9/rfcwggXYMIIDwKADAgEC # AhBsO9J+3TyUnpWOKKmzx1egMA0GCSqGSIb3DQEBCwUAMH0xCzAJBgNVBAYTAklM # MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh # bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMSkwJwYDVQQDEyBTdGFydENvbSBDZXJ0aWZp # Y2F0aW9uIEF1dGhvcml0eTAeFw0xNTEyMTYwMTAwMDVaFw0zMDEyMTYwMTAwMDVa # MHUxCzAJBgNVBAYTAklMMRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSkwJwYDVQQL # EyBTdGFydENvbSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEjMCEGA1UEAxMaU3Rh # cnRDb20gQ2xhc3MgMiBPYmplY3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw # ggEKAoIBAQC5FARY97LFhiwIMmCtCCbAgXe5aBnZFSsdGGnk2hqWBZcuZHkaqT1R # M1rQd2r0ApNBw466cBur2Ht0b5jo17mpPmh2pImgIqwX1in4u7hhn9IH0GYOMEcg # K3ACHv5zCRxxNLXifqmsqKfxjjpABnaSyvd4bO9YBXN9f4NQ6aJVAuMArpanxsJk # e+P4WECVLk17v92CAN5JVaczI+baT/lgo5NVcTEkloCViSbIfU6ILeyhOSQZvpom # MYk8eJqI0nimOTJJfmXangNDsrX8np+3lXD0+6rCZisXRWIaeffyTMHZ31Qj1D50 # WYdRtX5yev4WgaXoKJQN3lkgXUcytvyHAgMBAAGjggFaMIIBVjAOBgNVHQ8BAf8E # BAMCAQYwEwYDVR0lBAwwCgYIKwYBBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAy # BgNVHR8EKzApMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0c3NsLmNvbS9zZnNjYS5j # cmwwZgYIKwYBBQUHAQEEWjBYMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5zdGFy # dHNzbC5jb20wMAYIKwYBBQUHMAKGJGh0dHA6Ly9haWEuc3RhcnRzc2wuY29tL2Nl # cnRzL2NhLmNydDAdBgNVHQ4EFgQUPmKTmtfHGe4+j0kQhVUVIOOUhBwwHwYDVR0j # BBgwFoAUTgvvGqRAW6UXaYcwyjRoQ9BBrvIwPwYDVR0gBDgwNjA0BgRVHSAAMCww # KgYIKwYBBQUHAgEWHmh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeTANBgkq # hkiG9w0BAQsFAAOCAgEAY6U81bNtJyjY67pTrzAL6kpdEtX5mspw+kxjjNdNVH5G # 6lLnhaEkIxqdpvY/Wdw+UdNtExs+N8efKPSwh2m/BxXj2fSeLMwXcwHFookScEER # 8ez0quCNzioqNHac7LCXPEnQzbtG2FHlePKNDWh8eU6KxiAzNzIrIxPthinHGgLT # BOACHQM2YTlD8YoU5oN3dLmBOqtH0BDMZoLcjEIoEW1zC+TnVb3yU1G0xub6gnN7 # lP50vbAiHJYrnywQiXaloBV8B9YYfe6ZgvjqxwufwFcMVyE3UmCuDTsOpjqDEKpJ # 25s+FUdkie5VqCS1aaudLo31X+9UvP45pfgyRqzyfUnVEhH4ZXxlBWZMzj2Xov5+ # m/+H3kxYuFA5xdqdshj/Zx00S7PkCSF+8M1NCcvFgQwjIw61bZAjDBl3P3a8xNTX # sb2CjFdiNKbT3LD6IGeIf0b/EbPf0FXdvBrxm0ofMOhnngdPolPYCtoOGtZPAVe/ # xeu+/ZyKv6TSHlshaUO0iYfsmbXnZ51vvt/kkjwms9/qPFxSuE0fjEfF7aQazwRE # Df2hiVPR0pAhvShtM3oU4XreEFEUWEYHs25fYV4WMmxkUKSgmSmwRq45tvtGH4LT # b5+cd+iLqK8rBQL0E6xaUjjGfsYx7bueIvqTvCkrQvoxMbn/qDHCiypowDVq6TAw # ggZqMIIFUqADAgECAhADAZoCOv9YsWvW1ermF/BmMA0GCSqGSIb3DQEBBQUAMGIx # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3 # dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0Et # MTAeFw0xNDEwMjIwMDAwMDBaFw0yNDEwMjIwMDAwMDBaMEcxCzAJBgNVBAYTAlVT # MREwDwYDVQQKEwhEaWdpQ2VydDElMCMGA1UEAxMcRGlnaUNlcnQgVGltZXN0YW1w # IFJlc3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKNkXfx8 # s+CCNeDg9sYq5kl1O8xu4FOpnx9kWeZ8a39rjJ1V+JLjntVaY1sCSVDZg85vZu7d # y4XpX6X51Id0iEQ7Gcnl9ZGfxhQ5rCTqqEsskYnMXij0ZLZQt/USs3OWCmejvmGf # rvP9Enh1DqZbFP1FI46GRFV9GIYFjFWHeUhG98oOjafeTl/iqLYtWQJhiGFyGGi5 # uHzu5uc0LzF3gTAfuzYBje8n4/ea8EwxZI3j6/oZh6h+z+yMDDZbesF6uHjHyQYu # RhDIjegEYNu8c3T6Ttj+qkDxss5wRoPp2kChWTrZFQlXmVYwk/PJYczQCMxr7GJC # kawCwO+k8IkRj3cCAwEAAaOCAzUwggMxMA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMB # Af8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIw # ggGhBglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdp # Y2VydC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBl # ACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBu # AHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0 # AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0 # AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBl # AG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5 # ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABl # AHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwD # FTAfBgNVHSMEGDAWgBQVABIrE5iymQftHt+ivlcNK2cCzTAdBgNVHQ4EFgQUYVpN # JLZJMp1KKnkag0v0HonByn0wfQYDVR0fBHYwdDA4oDagNIYyaHR0cDovL2NybDMu # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcmwwOKA2oDSGMmh0 # dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRENBLTEuY3Js # MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRBc3N1cmVkSURDQS0xLmNydDANBgkqhkiG9w0BAQUFAAOCAQEAnSV+ # GzNNsiaBXJuGziMgD4CH5Yj//7HUaiwx7ToXGXEXzakbvFoWOQCd42yE5FpA+94G # AYw3+puxnSR+/iCkV61bt5qwYCbqaVchXTQvH3Gwg5QZBWs1kBCge5fH9j/n4hFB # pr1i2fAnPTgdKG86Ugnw7HBi02JLsOBzppLA044x2C/jbRcTBu7kA7YUq/OPQ6dx # nSHdFMoVXZJB2vkPgdGZdA0mxA5/G7X1oPHGdwYoFenYk+VVFvC7Cqsc21xIJ2bI # o4sKHOWV2q7ELlmgYd3a822iYemKC23sEhi991VUQAOSK2vCUcIKSK+w1G7g9BQK # Ohvjjz3Kr2qNe9zYRDCCBs0wggW1oAMCAQICEAb9+QOWA63qAArrPye7uhswDQYJ # KoZIhvcNAQEFBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu # YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQg # QXNzdXJlZCBJRCBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTIxMTExMDAwMDAw # MFowYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE # CxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNlcnQgQXNzdXJlZCBJ # RCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA6IItmfnKwkKV # pYBzQHDSnlZUXKnE0kEGj8kz/E1FkVyBn+0snPgWWd+etSQVwpi5tHdJ3InECtqv # y15r7a2wcTHrzzpADEZNk+yLejYIA6sMNP4YSYL+x8cxSIB8HqIPkg5QycaH6zY/ # 2DDD/6b3+6LNb3Mj/qxWBZDwMiEWicZwiPkFl32jx0PdAug7Pe2xQaPtP77blUjE # 7h6z8rwMK5nQxl0SQoHhg26Ccz8mSxSQrllmCsSNvtLOBq6thG9IhJtPQLnxTPKv # mPv2zkBdXPao8S+v7Iki8msYZbHBc63X8djPHgp0XEK4aH631XcKJ1Z8D2KkPzIU # YJX9BwSiCQIDAQABo4IDejCCA3YwDgYDVR0PAQH/BAQDAgGGMDsGA1UdJQQ0MDIG # CCsGAQUFBwMBBggrBgEFBQcDAgYIKwYBBQUHAwMGCCsGAQUFBwMEBggrBgEFBQcD # CDCCAdIGA1UdIASCAckwggHFMIIBtAYKYIZIAYb9bAABBDCCAaQwOgYIKwYBBQUH # AgEWLmh0dHA6Ly93d3cuZGlnaWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5o # dG0wggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0 # AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1 # AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABp # AGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBl # AGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBo # AGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAg # AGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAg # AGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZIAYb9bAMVMBIGA1UdEwEB # /wQIMAYBAf8CAQAweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRwOi8v # b2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRzLmRp # Z2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1UdHwR6 # MHgwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E # aWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwHQYDVR0OBBYEFBUAEisTmLKZB+0e # 36K+Vw0rZwLNMB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqG # SIb3DQEBBQUAA4IBAQBGUD7Jtygkpzgdtlspr1LPUukxR6tWXHvVDQtBs+/sdR90 # OPKyXGGinJXDUOSCuSPRujqGcq04eKx1XRcXNHJHhZRW0eu7NoR3zCSl8wQZVann # 4+erYs37iy2QwsDStZS9Xk+xBdIOPRqpFFumhjFiqKgz5Js5p8T1zh14dpQlc+Qq # q8+cdkvtX8JLFuRLcEwAiR78xXm8TBJX/l/hHrwCXaj++wc4Tw3GXZG5D2dFzdaD # 7eeSDY2xaYxP+1ngIw/Sqq4AfO6cQg7PkdcntxbuD8O9fAqg7iwIVYUiuOsYGk38 # KiGtSTGDR5V3cdyxG0tLHBCcdxTBnU8vWpUIKRAmMYIETzCCBEsCAQEwgYkwdTEL # MAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKTAnBgNVBAsTIFN0 # YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSMwIQYDVQQDExpTdGFydENv # bSBDbGFzcyAyIE9iamVjdCBDQQIQOb1CntKBbrrVvMkDtLpl5zANBglghkgBZQME # AgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJAzEM # BgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqG # SIb3DQEJBDEiBCCYEvT04HmTNacN8tE1fnRJVTu11z2Vp+a6Fkmws8PVnDANBgkq # hkiG9w0BAQEFAASCAQBP9ZCjMyi6bJ+BV8JZbFjeaKXF5HEfY4r1Z0rQ+m04nrf/ # 52oUUYhEvhxE1wnpYnT6brdG41m7Z1E3/GnV1B5gJJoHazrhGFuYhmp6wyEUCEGz # kwWfjZEIE9K9HRDUKF5ZEuMFMBHTg0aFnQOmaLDKqpRtU4hK3p7B2PfBwApUSsUa # D96b/ZO5w5rwZ5YG2h9o5T3MINt1tkrdJZ9U+hg6qKmgQH13yvUTJBiFHEGOOmHm # ZneQQIkP0kl+V40FHS1updwepVJZv0krbqqV08h/waCjOcZgNF+v/aCVQ8eE+ZOx # mpgLp1DocDmYkDnd7PceaRkssikMz73e9gufBh0uoYICDzCCAgsGCSqGSIb3DQEJ # BjGCAfwwggH4AgEBMHYwYjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0 # IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEhMB8GA1UEAxMYRGlnaUNl # cnQgQXNzdXJlZCBJRCBDQS0xAhADAZoCOv9YsWvW1ermF/BmMAkGBSsOAwIaBQCg # XTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0xODA4 # MjExNjM5MDNaMCMGCSqGSIb3DQEJBDEWBBQhr/2IQS+C/aGpcZD3+sba3L202zAN # BgkqhkiG9w0BAQEFAASCAQCgi7ceZ8MippaUjd1MfMQjX6qlbBQa7oSIn8Z+EfG2 # YaeGqEvpbhUl7KCa7LRe0r8yItNZCfHslRuB8cC6n997eUTdLc94Tmy3cJkPnhb3 # jIXVm1m6B0J5PAhRoHlJziPaQ+mvy0IfU33m1AeckYTqDw9395dBJvYdoWUCYrKS # pkAJlZ4jr1PVDcK9VJod4qfRoFZPaL1DjJieD1otKAFI2Y9N1p7UvScVOcDWvyJb # YKt5ncFOcI8grYctCXzQzidKATTZZMIticxwU95MwYoDdIW8A5AkL1jHtWq6wS6V # 4YX1TJ9g1BaBpTxtaR2WiqGKsMGqVe9tdvrB4QkrEG4u # SIG # End signature block