Server/Install-CertificationAuthority.ps1
function Install-CertificationAuthority { <# .ExternalHelp PSPKI.Help.xml #> [OutputType('SysadminsLV.PKI.Utils.IServiceOperationResult')] [CmdletBinding( DefaultParameterSetName = 'NewKeySet', ConfirmImpact = 'High', SupportsShouldProcess = $true )] param( [Parameter(ParameterSetName = 'NewKeySet')] [string]$CAName, [Parameter(ParameterSetName = 'NewKeySet')] [string]$CADNSuffix, [Parameter(ParameterSetName = 'NewKeySet')] [ValidateSet("Standalone Root","Standalone Subordinate","Enterprise Root","Enterprise Subordinate")] [string]$CAType, [Parameter(ParameterSetName = 'NewKeySet')] [string]$ParentCA, [Parameter(ParameterSetName = 'NewKeySet')] [string]$CSP, [Parameter(ParameterSetName = 'NewKeySet')] [int]$KeyLength, [Parameter(ParameterSetName = 'NewKeySet')] [string]$HashAlgorithm, [Parameter(ParameterSetName = 'NewKeySet')] [int]$ValidForYears = 5, [Parameter(ParameterSetName = 'NewKeySet')] [string]$RequestFileName, [Parameter(Mandatory = $true, ParameterSetName = 'PFXKeySet')] [IO.FileInfo]$CACertFile, [Parameter(Mandatory = $true, ParameterSetName = 'PFXKeySet')] [Security.SecureString]$Password, [Parameter(Mandatory = $true, ParameterSetName = 'ExistingKeySet')] [string]$Thumbprint, [string]$DBDirectory = $(Join-Path $env:SystemRoot "System32\CertLog"), [string]$LogDirectory = $(Join-Path $env:SystemRoot "System32\CertLog"), [switch]$OverwriteExisting, [switch]$AllowCSPInteraction, [switch]$Force ) #region OS and existing CA checking # check if script running on Windows Server 2008 or Windows Server 2008 R2 $OS = Get-WmiObject Win32_OperatingSystem -Property ProductType if ($OSVersion.Major -lt 6) { Write-Error -Category NotImplemented -ErrorId "NotSupportedException" ` -Message "Windows XP, Windows Server 2003 and Windows Server 2003 R2 are not supported!" return } if ($OS.ProductType -eq 1) { Write-Error -Category NotImplemented -ErrorId "NotSupportedException" ` -Message "Client operating systems are not supported!" return } $CertConfig = New-Object -ComObject CertificateAuthority.Config try {$ExistingDetected = $CertConfig.GetConfig(3)} catch {} if ($ExistingDetected) { Write-Error -Category ResourceExists -ErrorId "ResourceExistsException" ` -Message "Certificate Services are already installed on this computer. Only one Certification Authority instance per computer is supported." return } #endregion #region Binaries checking and installation if necessary if ($OSVersion.Major -eq 6 -and $OSVersion.Minor -eq 0) { cmd /c "servermanagercmd -install AD-Certificate 2> null" | Out-Null } else { try {Import-Module ServerManager -ErrorAction Stop} catch { ocsetup 'ServerManager-PSH-Cmdlets' /quiet | Out-Null Start-Sleep 1 Import-Module ServerManager -ErrorAction Stop } $status = (Get-WindowsFeature -Name AD-Certificate).Installed # if still no, install binaries, otherwise do nothing if (!$status) {$retn = Add-WindowsFeature -Name AD-Certificate -ErrorAction Stop if (!$retn.Success) { Write-Error -Category NotInstalled -ErrorId "NotInstalledException" ` -Message "Unable to install ADCS installation packages due of the following error: $($retn.breakCode)" return } } } try {$CASetup = New-Object -ComObject CertOCM.CertSrvSetup.1} catch { Write-Error -Category NotImplemented -ErrorId "NotImplementedException" ` -Message "Unable to load necessary interfaces. Your Windows Server operating system is not supported!" return } # initialize setup binaries try {$CASetup.InitializeDefaults($true, $false)} catch { Write-Error -Category InvalidArgument -ErrorId ParameterIncorrectException ` -ErrorAction Stop -Message "Cannot initialize setup binaries!" } #endregion #region Property enums $CATypesByName = @{"Enterprise Root" = 0; "Enterprise Subordinate" = 1; "Standalone Root" = 3; "Standalone Subordinate" = 4} $CATypesByVal = @{} $CATypesByName.keys | ForEach-Object {$CATypesByVal.Add($CATypesByName[$_],$_)} $CAPRopertyByName = @{"CAType"=0;"CAKeyInfo"=1;"Interactive"=2;"ValidityPeriodUnits"=5; "ValidityPeriod"=6;"ExpirationDate"=7;"PreserveDataBase"=8;"DBDirectory"=9;"Logdirectory"=10; "ParentCAMachine"=12;"ParentCAName"=13;"RequestFile"=14;"WebCAMachine"=15;"WebCAName"=16 } $CAPRopertyByVal = @{} $CAPRopertyByName.keys | ForEach-Object {$CAPRopertyByVal.Add($CAPRopertyByName[$_],$_)} $ValidityUnitsByName = @{"years" = 6} $ValidityUnitsByVal = @{6 = "years"} #endregion $ofs = ", " #region Key set processing functions #region NewKeySet function NewKeySet ($CAName, $CADNSuffix, $CAType, $ParentCA, $CSP, $KeyLength, $HashAlgorithm, $ValidForYears, $RequestFileName, $AllowCSPInteraction) { #region CSP, key length and hashing algorithm verification $CAKey = $CASetup.GetCASetupProperty(1) if ($AllowCSPInteraction) {$CASetup.SetCASetupProperty(0x2,$true)} if ($CSP -ne "") { if ($CASetup.GetProviderNameList() -notcontains $CSP) { # TODO add available CSP list Write-Error -Category InvalidArgument -ErrorId "InvalidCryptographicServiceProviderException" ` -ErrorAction Stop -Message "Specified CSP '$CSP' is not valid!" } else { $CAKey.ProviderName = $CSP } } else { $CAKey.ProviderName = "RSA#Microsoft Software Key Storage Provider" } if ($KeyLength -ne 0) { if ($CASetup.GetKeyLengthList($CAKey.ProviderName).Length -eq 1) { $CAKey.Length = $CASetup.GetKeyLengthList($CAKey.ProviderName)[0] } else { if ($CASetup.GetKeyLengthList($CAKey.ProviderName) -notcontains $KeyLength) { Write-Error -Category InvalidArgument -ErrorId "InvalidKeyLengthException" ` -ErrorAction Stop -Message @" The specified key length '$KeyLength' is not supported by the selected CSP '$($CAKey.ProviderName)' The following key lengths are supported by this CSP: $($CASetup.GetKeyLengthList($CAKey.ProviderName)) "@ } $CAKey.Length = $KeyLength } } if ($HashAlgorithm -ne "") { if ($CASetup.GetHashAlgorithmList($CAKey.ProviderName) -notcontains $HashAlgorithm) { Write-Error -Category InvalidArgument -ErrorId "InvalidHashAlgorithmException" ` -ErrorAction Stop -Message @" The specified hash algorithm is not supported by the selected CSP '$($CAKey.ProviderName)' The following hash algorithms are supported by this CSP: $($CASetup.GetHashAlgorithmList($CAKey.ProviderName)) "@ } $CAKey.HashAlgorithm = $HashAlgorithm } $CASetup.SetCASetupProperty(1,$CAKey) #endregion #region Setting CA type if ($CAType) { $SupportedTypes = $CASetup.GetSupportedCATypes() $SelectedType = $CATypesByName[$CAType] if ($SupportedTypes -notcontains $CATypesByName[$CAType]) { Write-Error -Category InvalidArgument -ErrorId "InvalidCATypeException" ` -ErrorAction Stop -Message @" Selected CA type: '$CAType' is not supported by current Windows Server installation. The following CA types are supported by this installation: $([int[]]$CASetup.GetSupportedCATypes() | %{$CATypesByVal[$_]}) "@ } else {$CASetup.SetCASetupProperty($CAPRopertyByName.CAType,$SelectedType)} } #endregion #region setting CA certificate validity if ($SelectedType -eq 0 -or $SelectedType -eq 3 -and $ValidForYears -ne 0) { try{$CASetup.SetCASetupProperty(6,$ValidForYears)} catch { Write-Error -Category InvalidArgument -ErrorId "InvalidCAValidityException" ` -ErrorAction Stop -Message "The specified CA certificate validity period '$ValidForYears' is invalid." } } #endregion #region setting CA name if ($CAName -ne "") { if ($CADNSuffix -ne "") {$Subject = "CN=$CAName" + ",$CADNSuffix"} else {$Subject = "CN=$CAName"} $DN = New-Object -ComObject X509Enrollment.CX500DistinguishedName # validate X500 name format try {$DN.Encode($Subject,0x0)} catch { Write-Error -Category InvalidArgument -ErrorId "InvalidX500NameException" ` -ErrorAction Stop -Message "Specified CA name or CA name suffix is not correct X.500 Distinguished Name." } $CASetup.SetCADistinguishedName($Subject, $true, $true, $true) } #endregion #region set parent CA/request file properties if ($CASetup.GetCASetupProperty(0) -eq 1 -and $ParentCA) { [void]($ParentCA -match "^(.+)\\(.+)$") try {$CASetup.SetParentCAInformation($ParentCA)} catch { Write-Error -Category ObjectNotFound -ErrorId "ObjectNotFoundException" ` -ErrorAction Stop -Message @" The specified parent CA information '$ParentCA' is incorrect. Make sure if parent CA information is correct (you must specify existing CA) and is supplied in a 'CAComputerName\CASanitizedName' form. "@ } } elseif ($CASetup.GetCASetupProperty(0) -eq 1 -or $CASetup.GetCASetupProperty(0) -eq 4 -and $RequestFileName -ne "") { $CASetup.SetCASetupProperty(14,$RequestFileName) } #endregion } #endregion #region PFXKeySet function PFXKeySet ($CACertFile, $Password) { $FilePath = Resolve-Path $CACertFile -ErrorAction Stop try {[void]$CASetup.CAImportPFX( $FilePath.Path, [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)), $true) } catch {Write-Error $_ -ErrorAction Stop} } #endregion #region ExistingKeySet function ExistingKeySet ($Thumbprint) { $ExKeys = $CASetup.GetExistingCACertificates() | Where-Object { ([Security.Cryptography.X509Certificates.X509Certificate2]$_.ExistingCACertificate).Thumbprint -eq $Thumbprint } if (!$ExKeys) { Write-Error -Category ObjectNotFound -ErrorId "ElementNotFoundException" ` -ErrorAction Stop -Message "The system cannot find a valid CA certificate with thumbprint: $Thumbprint" } else {$CASetup.SetCASetupProperty(1,@($ExKeys)[0])} } #endregion #endregion #region set database settings if ($DBDirectory -ne "" -and $LogDirectory -ne "") { try {$CASetup.SetDatabaseInformation($DBDirectory,$LogDirectory,$null,$OverwriteExisting)} catch { Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" ` -ErrorAction Stop -Message "Specified path to either database directory or log directory is invalid." } } elseif ($DBDirectory -ne "" -and $LogDirectory -eq "") { Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" ` -ErrorAction Stop -Message "CA Log file directory cannot be empty." } elseif ($DBDirectory -eq "" -and $LogDirectory -ne "") { Write-Error -Category InvalidArgument -ErrorId "InvalidPathException" ` -ErrorAction Stop -Message "CA database directory cannot be empty." } #endregion # process parametersets. switch ($PSCmdlet.ParameterSetName) { "ExistingKeySet" {ExistingKeySet $Thumbprint} "PFXKeySet" {PFXKeySet $CACertFile $Password} "NewKeySet" {NewKeySet $CAName $CADNSuffix $CAType $ParentCA $CSP $KeyLength $HashAlgorithm $ValidForYears $RequestFileName $AllowCSPInteraction} } try { Write-Verbose "Installing Certification Authority role on $env:computername ..." -ForegroundColor Cyan if ($Force -or $PSCmdlet.ShouldProcess($env:COMPUTERNAME, "Install Certification Authority")) { $CASetup.Install() $PostRequiredMsg = @" Certification Authority role was successfully installed, but not completed. To complete installation submit request file '$($CASetup.GetCASetupProperty(14))' to parent Certification Authority and install issued certificate by running the following command: certutil -installcert 'PathToACertFile' "@ if ($CASetup.GetCASetupProperty(0) -eq 1 -and $ParentCA -eq "") { Write-Warning $PostRequiredMsg } elseif ($CASetup.GetCASetupProperty(0) -eq 1 -and $PSCmdlet.ParameterSetName -eq "NewKeySet" -and $ParentCA -ne "") { $CASName = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration).Active $SetupStatus = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration\$CASName).SetupStatus $RequestID = (Get-ItemProperty HKLM:\System\CurrentControlSet\Services\CertSvc\Configuration\$CASName).RequestID if ($SetupStatus -ne 1) { Write-Warning $PostRequiredMsg } } elseif ($CASetup.GetCASetupProperty(0) -eq 4) { Write-Warning $PostRequiredMsg } else {New-Object SysadminsLV.PKI.Utils.ServiceOperationResult 0} } } catch {New-Object SysadminsLV.PKI.Utils.ServiceOperationResult $_.Exception.HResult} Remove-Module ServerManager -ErrorAction SilentlyContinue } # SIG # Begin signature block # MIIcgAYJKoZIhvcNAQcCoIIccTCCHG0CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCPTIx5EjytWljF # 2XinppWVuPHP0X/kcINUJ6VHT/eLL6CCF4owggUTMIID+6ADAgECAhAJwnVp5a70 # RHscglFEfEqLMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV # BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcN # MTcwNDE3MDAwMDAwWhcNMjAwNDIxMTIwMDAwWjBQMQswCQYDVQQGEwJMVjENMAsG # A1UEBxMEUmlnYTEYMBYGA1UEChMPU3lzYWRtaW5zIExWIElLMRgwFgYDVQQDEw9T # eXNhZG1pbnMgTFYgSUswggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo # NCCuzEogktL+1+lvPHu7ctNtCD7wA5Nalebh0FaKz3v1944APtg7A5oQfh6c20f7 # xYyTw4wVuo6L6S3dlMUa+bfXvTXIco0ilTIz0uqUKW8WGYwJtbFpu6PvCs0LHDRD # rD8sEFgGHQhbz+J4gtV8BI7OID+yNfgbUk4JeSBGNzgeqZMdf/xceMoLx+fHi9tU # OdTtgs/dXQYg3M3J+rGxFdpxOO7JmUZ8nqVALlnU9cHBGKUY4hDvDxfp7EukhnHv # RpkhacZB1RBw0q8q+ekvLVCZwpG4N1Pnq2ksHiBzqRWQQE89iV+UwgRnLx2igywk # 2kX+JPSZYsQCbDGo4DqBAgMBAAGjggHFMIIBwTAfBgNVHSMEGDAWgBRaxLl7Kgqj # pepxA8Bg+S32ZXUOWDAdBgNVHQ4EFgQU9Mh+66y4uf1WQl9FmsWMHdk2HrswDgYD # VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGA1UdHwRwMG4wNaAz # oDGGL2h0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEu # Y3JsMDWgM6Axhi9odHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVk # LWNzLWcxLmNybDBMBgNVHSAERTBDMDcGCWCGSAGG/WwDATAqMCgGCCsGAQUFBwIB # FhxodHRwczovL3d3dy5kaWdpY2VydC5jb20vQ1BTMAgGBmeBDAEEATCBhAYIKwYB # BQUHAQEEeDB2MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20w # TgYIKwYBBQUHMAKGQmh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dFNIQTJBc3N1cmVkSURDb2RlU2lnbmluZ0NBLmNydDAMBgNVHRMBAf8EAjAAMA0G # CSqGSIb3DQEBCwUAA4IBAQCfpLMUerP0WXkcb9+dunMLt3jowZEd8X6ISxxzdsdB # 8jOZ92L88qKqjWD1I9HBceba4tdJZCLV33S9a3eoxUunIlJH4GmYH/HSrc2qgNxg # PyobmWf556c7Wd3q6ZUKgos0bw++TtLqb/jvoKN19epTEkwQDIwVFzOAxZ4T+sYr # jmFhd9KeaRhTLZRBVdKNTKtXaoWFrfNSQTp8NcNYdkEM05cUnEUMDOoeLSmxPnIv # pl8KbripxtVQ591rCLJN2uMtrtSE1nvjiYfSFQI00EiB33ZoI2T1eCNuP1M6c+ex # KzQQC8UDp7J+duzl1j605TwSfLS/MJsaiwftNzc3FfgSMIIFMDCCBBigAwIBAgIQ # BAkYG1/Vu2Z1U0O1b5VQCDANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEV # MBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29t # MSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTMxMDIy # MTIwMDAwWhcNMjgxMDIyMTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMM # RGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQD # EyhEaWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMIIBIjAN # BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+NOzHH8OEa9ndwfTCzFJGc/Q+0WZ # sTrbRPV/5aid2zLXcep2nQUut4/6kkPApfmJ1DcZ17aq8JyGpdglrA55KDp+6dFn # 08b7KSfH03sjlOSRI5aQd4L5oYQjZhJUM1B0sSgmuyRpwsJS8hRniolF1C2ho+mI # LCCVrhxKhwjfDPXiTWAYvqrEsq5wMWYzcT6scKKrzn/pfMuSoeU7MRzP6vIK5Fe7 # SrXpdOYr/mzLfnQ5Ng2Q7+S1TqSp6moKq4TzrGdOtcT3jNEgJSPrCGQ+UpbB8g8S # 9MWOD8Gi6CxR93O8vYWxYoNzQYIH5DiLanMg0A9kczyen6Yzqf0Z3yWT0QIDAQAB # o4IBzTCCAckwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYD # VR0lBAwwCgYIKwYBBQUHAwMweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhho # dHRwOi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNl # cnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEG # A1UdHwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2Vy # dEFzc3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0 # LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwTwYDVR0gBEgwRjA4Bgpg # hkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv # bS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYEFFrEuXsqCqOl6nEDwGD5LfZldQ5Y # MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBCwUA # A4IBAQA+7A1aJLPzItEVyCx8JSl2qB1dHC06GsTvMGHXfgtg/cM9D8Svi/3vKt8g # VTew4fbRknUPUbRupY5a4l4kgU4QpO4/cY5jDhNLrddfRHnzNhQGivecRk5c/5Cx # GwcOkRX7uq+1UcKNJK4kxscnKqEpKBo6cSgCPC6Ro8AlEeKcFEehemhor5unXCBc # 2XGxDI+7qPjFEmifz0DLQESlE/DmZAwlCEIysjaKJAL+L3J+HNdJRZboWR3p+nRk # a7LrZkPas7CM1ekN3fYBIM6ZMWM9CBoYs4GbT8aTEAb8B4H6i9r5gkn3Ym6hU/oS # lBiFLpKR6mhsRDKyZqHnGKSaZFHvMIIGajCCBVKgAwIBAgIQAwGaAjr/WLFr1tXq # 5hfwZjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhE # aWdpQ2VydCBBc3N1cmVkIElEIENBLTEwHhcNMTQxMDIyMDAwMDAwWhcNMjQxMDIy # MDAwMDAwWjBHMQswCQYDVQQGEwJVUzERMA8GA1UEChMIRGlnaUNlcnQxJTAjBgNV # BAMTHERpZ2lDZXJ0IFRpbWVzdGFtcCBSZXNwb25kZXIwggEiMA0GCSqGSIb3DQEB # AQUAA4IBDwAwggEKAoIBAQCjZF38fLPggjXg4PbGKuZJdTvMbuBTqZ8fZFnmfGt/ # a4ydVfiS457VWmNbAklQ2YPOb2bu3cuF6V+l+dSHdIhEOxnJ5fWRn8YUOawk6qhL # LJGJzF4o9GS2ULf1ErNzlgpno75hn67z/RJ4dQ6mWxT9RSOOhkRVfRiGBYxVh3lI # RvfKDo2n3k5f4qi2LVkCYYhhchhoubh87ubnNC8xd4EwH7s2AY3vJ+P3mvBMMWSN # 4+v6GYeofs/sjAw2W3rBerh4x8kGLkYQyI3oBGDbvHN0+k7Y/qpA8bLOcEaD6dpA # oVk62RUJV5lWMJPzyWHM0AjMa+xiQpGsAsDvpPCJEY93AgMBAAGjggM1MIIDMTAO # BgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEF # BQcDCDCCAb8GA1UdIASCAbYwggGyMIIBoQYJYIZIAYb9bAcBMIIBkjAoBggrBgEF # BQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzCCAWQGCCsGAQUFBwIC # MIIBVh6CAVIAQQBuAHkAIAB1AHMAZQAgAG8AZgAgAHQAaABpAHMAIABDAGUAcgB0 # AGkAZgBpAGMAYQB0AGUAIABjAG8AbgBzAHQAaQB0AHUAdABlAHMAIABhAGMAYwBl # AHAAdABhAG4AYwBlACAAbwBmACAAdABoAGUAIABEAGkAZwBpAEMAZQByAHQAIABD # AFAALwBDAFAAUwAgAGEAbgBkACAAdABoAGUAIABSAGUAbAB5AGkAbgBnACAAUABh # AHIAdAB5ACAAQQBnAHIAZQBlAG0AZQBuAHQAIAB3AGgAaQBjAGgAIABsAGkAbQBp # AHQAIABsAGkAYQBiAGkAbABpAHQAeQAgAGEAbgBkACAAYQByAGUAIABpAG4AYwBv # AHIAcABvAHIAYQB0AGUAZAAgAGgAZQByAGUAaQBuACAAYgB5ACAAcgBlAGYAZQBy # AGUAbgBjAGUALjALBglghkgBhv1sAxUwHwYDVR0jBBgwFoAUFQASKxOYspkH7R7f # or5XDStnAs0wHQYDVR0OBBYEFGFaTSS2STKdSip5GoNL9B6Jwcp9MH0GA1UdHwR2 # MHQwOKA2oDSGMmh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRENBLTEuY3JsMDigNqA0hjJodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln # aUNlcnRBc3N1cmVkSURDQS0xLmNybDB3BggrBgEFBQcBAQRrMGkwJAYIKwYBBQUH # MAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBBBggrBgEFBQcwAoY1aHR0cDov # L2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEQ0EtMS5jcnQw # DQYJKoZIhvcNAQEFBQADggEBAJ0lfhszTbImgVybhs4jIA+Ah+WI//+x1GosMe06 # FxlxF82pG7xaFjkAneNshORaQPveBgGMN/qbsZ0kfv4gpFetW7easGAm6mlXIV00 # Lx9xsIOUGQVrNZAQoHuXx/Y/5+IRQaa9YtnwJz04HShvOlIJ8OxwYtNiS7Dgc6aS # wNOOMdgv420XEwbu5AO2FKvzj0OncZ0h3RTKFV2SQdr5D4HRmXQNJsQOfxu19aDx # xncGKBXp2JPlVRbwuwqrHNtcSCdmyKOLChzlldquxC5ZoGHd2vNtomHpigtt7BIY # vfdVVEADkitrwlHCCkivsNRu4PQUCjob4489yq9qjXvc2EQwggbNMIIFtaADAgEC # AhAG/fkDlgOt6gAK6z8nu7obMA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjEx # MTAwMDAwMDBaFw0yMTExMTAwMDAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMTCCASIwDQYJKoZIhvcNAQEBBQAD # ggEPADCCAQoCggEBAOiCLZn5ysJClaWAc0Bw0p5WVFypxNJBBo/JM/xNRZFcgZ/t # LJz4FlnfnrUkFcKYubR3SdyJxArar8tea+2tsHEx6886QAxGTZPsi3o2CAOrDDT+ # GEmC/sfHMUiAfB6iD5IOUMnGh+s2P9gww/+m9/uizW9zI/6sVgWQ8DIhFonGcIj5 # BZd9o8dD3QLoOz3tsUGj7T++25VIxO4es/K8DCuZ0MZdEkKB4YNugnM/JksUkK5Z # ZgrEjb7SzgaurYRvSISbT0C58Uzyr5j79s5AXVz2qPEvr+yJIvJrGGWxwXOt1/HY # zx4KdFxCuGh+t9V3CidWfA9ipD8yFGCV/QcEogkCAwEAAaOCA3owggN2MA4GA1Ud # DwEB/wQEAwIBhjA7BgNVHSUENDAyBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUF # BwMDBggrBgEFBQcDBAYIKwYBBQUHAwgwggHSBgNVHSAEggHJMIIBxTCCAbQGCmCG # SAGG/WwAAQQwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNv # bS9zc2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBB # AG4AeQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBh # AHQAZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBj # AGUAIABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABT # ACAAYQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABB # AGcAcgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBh # AGIAaQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBh # AHQAZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAu # MAsGCWCGSAGG/WwDFTASBgNVHRMBAf8ECDAGAQH/AgEAMHkGCCsGAQUFBwEBBG0w # azAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUF # BzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVk # SURSb290Q0EuY3J0MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp # Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRw # Oi8vY3JsNC5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3Js # MB0GA1UdDgQWBBQVABIrE5iymQftHt+ivlcNK2cCzTAfBgNVHSMEGDAWgBRF66Kv # 9JLLgjEtUYunpyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEARlA+ybcoJKc4HbZb # Ka9Sz1LpMUerVlx71Q0LQbPv7HUfdDjyslxhopyVw1Dkgrkj0bo6hnKtOHisdV0X # FzRyR4WUVtHruzaEd8wkpfMEGVWp5+Pnq2LN+4stkMLA0rWUvV5PsQXSDj0aqRRb # poYxYqioM+SbOafE9c4deHaUJXPkKqvPnHZL7V/CSxbkS3BMAIke/MV5vEwSV/5f # 4R68Al2o/vsHOE8Nxl2RuQ9nRc3Wg+3nkg2NsWmMT/tZ4CMP0qquAHzunEIOz5HX # J7cW7g/DvXwKoO4sCFWFIrjrGBpN/CohrUkxg0eVd3HcsRtLSxwQnHcUwZ1PL1qV # CCkQJjGCBEwwggRIAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp # Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERp # Z2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0ECEAnCdWnlrvRE # exyCUUR8SoswDQYJYIZIAWUDBAIBBQCggYQwGAYKKwYBBAGCNwIBDDEKMAigAoAA # oQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4w # DAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgSldWwul/sMEdE1TJvn6kwxCH # CVYrxN1qP/LBKhuvwFcwDQYJKoZIhvcNAQEBBQAEggEAljwohWmEQ93XizQzgr0O # hqld0WN+YvxiPuvQPG4OdXbUK1ngvwMMMqlcA7agEqrJzn7Z6OIrByuna2WLhR4I # QeyN5gOsbcEs+cZizVBdiJD9JI/mKoR3T9seXZvOmbfpczJlg3+4UkA90/jxOgct # NsJfIwjcJFUrRyqADMTCeR2tU7fiq34UiUQGLrLUXKyJhyls8DiDW88NtssCfKr7 # HmcFlr4qZDOS/VIHULYe8sKYyXy8L5hjhDxXkFA3ZlEA3xw3tATRjku5A2agU11Z # 342/nkP3j3NiahHqGVEaJfi9NT8stjCvjn99uavLZCYmV7aOUAYwgZrVmrDwD3pp # I6GCAg8wggILBgkqhkiG9w0BCQYxggH8MIIB+AIBATB2MGIxCzAJBgNVBAYTAlVT # MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j # b20xITAfBgNVBAMTGERpZ2lDZXJ0IEFzc3VyZWQgSUQgQ0EtMQIQAwGaAjr/WLFr # 1tXq5hfwZjAJBgUrDgMCGgUAoF0wGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAc # BgkqhkiG9w0BCQUxDxcNMTgxMDIyMTYyNTA3WjAjBgkqhkiG9w0BCQQxFgQUkggc # 4aU7EbaN3dynPCoi4ntcIxYwDQYJKoZIhvcNAQEBBQAEggEASU5kDP4E1wHYMatY # 260z6+kfqRuLPnxgnEtOSxK4oG+FLn2I42GwM3+u0cpDJCmmQRRUFNpxl33Z75Kc # Q5zUlQHSzJyJ/CcXJKowJTykG9XWdTIdLvg3ZeKJ3tzHw5TDEXPAfUv8209FyjC+ # bGGCu1DgNJ/zoNn4T2rBQZxjsbqo+0TmsPstDDk4TjWlwILpzr8g7rznJ3lhn59I # UFArP2kUk3OjHemE8ORnr8tCeVjDlUDj/VuVODKkf3TXpfnoqxPtWhVOwmaPQMCH # 1Pr47j5HOG8WFwEU0g0i6j+V8jNetgWi6bVgf3ZwkhaaCV40Ka9NjPjp83JaI1Pz # 7siqcw== # SIG # End signature block |