AttestationReport/AttestationReport.psm1
# Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. # Creation of an attestation report class to have meaningful data and formatting class AttestationReport { [DateTime] $Time [string] $HostName [string] $AttestationOperationMode [string] $AttestationStatus [string] $AttestationSubStatus [string] $AuthorizedHostGroup [string] $EndorsementKeyHash } #region Constants $script:AttestationEventProviderName = "Microsoft-Windows-HostGuardianService-Attestation" # The telling event that an attestation request passed. $script:TcgLogValidationEventId = 1203 # AD based attestation status events $script:AttestationAdStatusEvents = @{ 1519 = "Passed"; 1524 = "UnauthorizedHost" } $script:AttestationTpmSubStatusEvents = @{ 1500 = "NoInformation"; 1508 = "SecureBoot"; 1510 = "DebugMode"; 1513 = "CodeIntegrityPolicy"; 1523 = "NoInformation"; 1533 = "Iommu"; 1534 = "VirtualSecureMode"; 1535 = "PagefileEncryption"; 1536 = "BitLocker"; 1537 = "HypervisorEnforcedCodeIntegrityPolicy"; 1538 = "CodeIntegrityPolicy"; 1539 = "HibernationEnabled"; 1540 = "DumpsEnabled"; 1541 = "DumpEncryption"; 1542 = "DumpEncryptionKey" } $script:AttestationTpmStatusEvents = @{ 1500 = "UnauthorizedHost"; 1508 = "InsecureHostConfiguration"; 1510 = "InsecureHostConfiguration"; 1513 = "InsecureHostConfiguration"; 1523 = "Passed"; 1533 = "InsecureHostConfiguration"; 1534 = "InsecureHostConfiguration"; 1535 = "InsecureHostConfiguration"; 1536 = "InsecureHostConfiguration"; 1537 = "InsecureHostConfiguration"; 1538 = "InsecureHostConfiguration"; 1539 = "InsecureHostConfiguration"; 1540 = "InsecureHostConfiguration"; 1541 = "InsecureHostConfiguration"; 1542 = "InsecureHostConfiguration"; } #endregion <# .Synopsis Generates a report of attestation requests done by an HGS server .DESCRIPTION The Get-HgsAttestationReport cmdlet obtains events from the HostGuardianService-Attestation event provider, and parses them to find the past attestation requests handled by this HGS Server. When running this cmdlet on or target in an HGS server that is a member of a cluster, it will attempt to find relevant events from all nodes. If -AD or -TPM is not passed through, it will report attestation requests of the current operation mode. .EXAMPLE Get-HgsAttestationReport -AD -Tpm -StartTime (Get-Date).AddDays(-7) Generates a report of all AD and TPM based attestation requests handled by the targeted HGS server for the past seven days. .EXAMPLE $cred = Get-Credential Get-HgsAttestationReport -ComputerName HgsServer.Contoso.Com -Credential $cred Generates a report of all attestation requests of the current operation mode handled by the targeted HGS server as far back as the event logs go. #> function Get-HgsAttestationReport { [CmdletBinding(DefaultParameterSetName = 'LocalComputer')] param ( # Specifies the earliest date to look for events [Parameter(Mandatory = $false)] [Alias("NotBefore")] [DateTime] $StartTime = [System.DateTime]::MinValue, # Specifies the latest date to look for events [Parameter(Mandatory = $false)] [Alias("NotAfter")] [DateTime] $EndTime = [System.DateTime]::MaxValue, # Specifies if the parser should look for AD based attestation requests. If both -AD and -Tpm are not present, the search defaults to the target's current Attestation Operation Mode. [Alias("ParseADRequests")] [Parameter(Mandatory = $false)] [Switch] $AD, # Specifies if the parser should look for Tpm based attestation requests. If both -AD and -Tpm are not present, the search defaults to the target's current Attestation Operation Mode. [Parameter(Mandatory = $false)] [Alias("ParseTpmRequests")] [switch] $Tpm, # The name of the target computer. [Parameter(Mandatory = $true, ParameterSetName = "RemoteComputer")] [String] $ComputerName, # Credentials for invoking commands on the target computer [Parameter(Mandatory = $true, ParameterSetName = "RemoteComputer")] [PSCredential] $Credential, # PSSession Configuration Name for invoking commands [Parameter(Mandatory = $false)] [Alias("ConfigurationName")] [String] $EndpointName = "Microsoft.PowerShell" ) if ($PSCmdlet.ParameterSetName -eq "LocalComputer") { try { $HgsServerInfo = Get-HgsServer -ErrorAction Stop } catch [Exception] { Write-Error $_ break } } else { try { $HgsServerInfo = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ConfigurationName $EndpointName -ScriptBlock {Get-HgsServer} -ErrorAction Stop } catch [Exception] { Write-Error $_ break } } # In the case of multiple nodes $HgsServerNodeNames = @() switch ($PSCmdlet.ParameterSetName) { "LocalComputer" { $HgsServerNodeNames += (Get-ClusterNode | Where-Object {$_.State -eq "Up"}).Name } "RemoteComputer" {$HgsServerNodeNames += (Invoke-Command -ComputerName $ComputerName -Credential $Credential -ConfigurationName $EndpointName -ScriptBlock {Get-ClusterNode}).Name} } if ($HgsServerNodeNames.Count -gt 1) { switch ($PSCmdlet.ParameterSetName) { "LocalComputer" { Write-Warning ("This host is not the only member of the Host Guardian Service instance '{0}'. To collect all attestation requests handled by this instance, run this script targeting all of the machines of this instance: {1}" -f $HgsServerInfo.AttestationUrl[0].Host, ($HgsServerNodeNames -join "; ")) } "RemoteComputer" { # This will still give the netBIOS name even if the input computername is the netBIOS Write-Warning ("The host '{0}' is not the only member of the Host Guardian Service instance '{1}'. To collect all attestation requests handled by this instance, run this script targeting all of the machines of this instance: {2}" -f $ComputerName,$HgsServerInfo.AttestationUrl[0].Host, ($HgsServerNodeNames -join "; ")) } } } if (!$Tpm -and !$AD) { # If we can get the current attestation operation mode, use that. if ($HgsServerInfo.AttestationOperationMode.Value -eq "Tpm" -or $HgsServerInfo.AttestationOperationMode -eq "Tpm") { $Tpm = $true } else { $AD = $true } } $EventIds = @() if ($AD) { $EventIds += $script:AttestationAdStatusEvents.Keys } if ($Tpm) { $TpmEventIDs = $script:AttestationTpmStatusEvents.Keys + $script:TcgLogValidationEventId $EventIds += $TpmEventIds } $AttestationEvents = @() switch ($PSCmdlet.ParameterSetName) { "LocalComputer" { $AttestationEvents += Get-WinEvent -ProviderName $script:AttestationEventProviderName -ErrorAction Stop| Where-Object {($EventIds -contains $_.Id) -and ($_.TimeCreated -gt $StartTime) -and ($_.TimeCreated -le $EndTime)} } "RemoteComputer" { $AttestationEvents += Get-WinEvent -ProviderName $script:AttestationEventProviderName -ComputerName $ComputerName -Credential $Credential -ErrorAction Stop| Where-Object {($EventIds -contains $_.Id) -and ($_.TimeCreated -gt $StartTime) -and ($_.TimeCreated -le $EndTime)} } } $AttestationRequests = @() if ($Tpm) { $TpmEvents = $AttestationEvents | Where-Object {$TpmEventIds -contains $_.Id} if ($PSCmdlet.ParameterSetName -eq "RemoteComputer") { $TpmBasedAttestationRequests = FindTpmRequests -Events $TpmEvents -ComputerName $ComputerName -Credential $Credential -ConfigurationName $EndpointName -UseRemote } else { $TpmBasedAttestationRequests = FindTpmRequests -Events $TpmEvents } $AttestationRequests += $TpmBasedAttestationRequests } if ($AD) { $AdEvents = $AttestationEvents | Where-Object {$script:AttestationAdStatusEvents.Keys -contains $_.Id} if ($PSCmdlet.ParameterSetName -eq "RemoteComputer") { $AdBasedAttestationRequests = FindADRequests -Events $AdEvents -ComputerName $ComputerName -Credential $Credential -ConfigurationName $EndpointName -UseRemote } else { $AdBasedAttestationRequests = FindADRequests -Events $AdEvents } $AttestationRequests += $AdBasedAttestationRequests } # Re-sort by time $AttestationRequests = $AttestationRequests | Sort-Object -Property Time -Descending Write-Output $AttestationRequests } <# Parse events into AD based attestation requests #> function FindADRequests { param( [System.Array] $Events, [switch] $UseRemote, [string] $ComputerName, [PSCredential] $Credential, [String] $ConfigurationName ) if ($UseRemote) { $AuthorizedADHostGroups = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ConfigurationName $ConfigurationName -ScriptBlock {Get-HgsAttestationHostGroup -WarningAction Ignore -ErrorAction Stop} -ErrorAction Stop } else { $AuthorizedADHostGroups = Get-HgsAttestationHostGroup -WarningAction Ignore } $ADAttestationEventGroups = GroupEvents $Events $AdBasedAttestationRequests = @() foreach ($ActivityId in $ADAttestationEventGroups.Keys) { $AttestationRequest = [AttestationReport]::new() $AttestationRequest.AttestationOperationMode = "AD" $AttestationRequest.EndorsementKeyHash = "NotApplicable" $EventList = $ADAttestationEventGroups[$ActivityId] | Sort-Object TimeCreated # Use time of earliest event $AttestationRequest.Time = ($EventList)[0].TimeCreated foreach ($event in $EventList) { if ($AttestationAdStatusEvents.ContainsKey($event.Id)) { $AttestationRequest.AttestationStatus = $script:AttestationAdStatusEvents[$event.Id] if ($AttestationRequest.AttestationStatus -eq "Passed") { $AttestationRequest.AttestationSubStatus = "NoInformation" $AttestationRequest.HostName = $event.Properties.Value # Check if it can't be cast into a SID. If it can, then its the HostGroup Identifier. Otherwise, it should be used as the Host Name # Known issue with this approach: if the SAM account name is somehow in the form of a SID, but this should not be possible. foreach ($prop in $Event.Properties) { try { $sid = New-Object System.Security.Principal.SecurityIdentifier -ArgumentList $prop.Value $hostGroup = $AuthorizedADHostGroups | Where-Object {$_.Identifier -eq $sid.Value} if ($hostGroup -ne $null) { $AttestationRequest.AuthorizedHostGroup = $hostGroup.Name } else { $AttestationRequest.AuthorizedHostGroup = $sid.Value } } catch { $AttestationRequest.HostName = $prop.Value } } } else { # Otherwise, the only property associated with this event is the machine SID of the attesting client $AttestationRequest.HostName = $event.Properties.Value $AttestationRequest.AuthorizedHostGroup = "NotApplicable" } $AdBasedAttestationRequests += ,$AttestationRequest } } } return $AdBasedAttestationRequests } <# Parse events into TPM requests #> function FindTpmRequests { param( [System.Array] $Events, [switch] $UseRemote, [string] $ComputerName, [PSCredential] $Credential, [string] $ConfigurationName ) if ($UseRemote) { # Only need to get settings from one node $AuthorizedTpmHosts = Invoke-Command -ComputerName $ComputerName -Credential $Credential -ConfigurationName $ConfigurationName -ScriptBlock {Get-HgsAttestationTpmHost -WarningAction Ignore -ErrorAction Stop} -ErrorAction Stop } else { $AuthorizedTpmHosts = Get-HgsAttestationTpmHost -WarningAction Ignore -ErrorAction Stop } $TpmAttestationEventGroups = GroupEvents $Events $TpmBasedAttestationRequests = @() # Iterate through attestation groups, generating an AttestationReport object foreach ($ActivityId in $TpmAttestationEventGroups.Keys) { $AttestationRequest = [AttestationReport]::new() $AttestationRequest.AttestationOperationMode = "Tpm" $AttestationRequest.AuthorizedHostGroup = "NotApplicable" $tpmEventList = $TpmAttestationEventGroups[$ActivityId] | Sort-Object TimeCreated # Get earliest event $AttestationRequest.Time = ($tpmEventList)[0].TimeCreated $HostNameFound = $false foreach ($event in $tpmEventList) { # Not all attestation failure events have the host EK attached to it. Instead, use the ID from the event corresponding to starting the TCG log verification if ($event.Id -eq $script:TcgLogValidationEventId -and -not $HostNameFound) { $AttestationRequest.EndorsementKeyHash = $Event.Properties.Value $Hostname = ($AuthorizedTpmHosts | Where-Object {$_.Identifier -eq $event.Properties.value}).Name if ($Hostname) { $AttestationRequest.HostName = $HostName } $HostNameFound = $true } if($AttestationTpmStatusEvents.ContainsKey($Event.Id)) { $AttestationRequest.AttestationStatus = $AttestationTpmStatusEvents[$event.Id] # Account for multiple substatus reasons if ($AttestationRequest.AttestationSubStatus -ne $AttestationTpmSubStatusEvents[$event.Id]) { $AttestationRequest.AttestationSubStatus += $AttestationTpmSubStatusEvents[$event.Id] } if (-not $HostNameFound -and $AttestationRequest.AttestationStatus -eq "UnauthorizedHost") { $AttestationRequest.HostName = 'UnauthorizedHost' $AttestationRequest.EndorsementKeyHash = $Event.Properties.Value $HostNameFound = $true } } } $TpmBasedAttestationRequests += ,$AttestationRequest } return $TpmBasedAttestationRequests } # Group an array of events into a dictionary based on their Activity ID's. function GroupEvents([System.Array] $Events) { $EventGroups = [ordered] @{} # Form groups based on the correlation Activity ID (on the HGS server, these all properly map to identical attestation requests) foreach ($event in $Events) { if ($EventGroups.Contains($event.ActivityId)) { $EventGroups[$event.ActivityId] += ($event) } else { $EventGroups.Add($event.ActivityId, @($event)) } } return $EventGroups } # SIG # Begin signature block # MIIkGgYJKoZIhvcNAQcCoIIkCzCCJAcCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCn1XrRfqS8kb1V # yw/L7Vj0Y0m7xigSh+9DCeqkFl1YQKCCDYMwggYBMIID6aADAgECAhMzAAAAxOmJ # +HqBUOn/AAAAAADEMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTcwODExMjAyMDI0WhcNMTgwODExMjAyMDI0WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCIirgkwwePmoB5FfwmYPxyiCz69KOXiJZGt6PLX4kvOjMuHpF4+nypH4IBtXrL # GrwDykbrxZn3+wQd8oUK/yJuofJnPcUnGOUoH/UElEFj7OO6FYztE5o13jhwVG87 # 7K1FCTBJwb6PMJkMy3bJ93OVFnfRi7uUxwiFIO0eqDXxccLgdABLitLckevWeP6N # +q1giD29uR+uYpe/xYSxkK7WryvTVPs12s1xkuYe/+xxa8t/CHZ04BBRSNTxAMhI # TKMHNeVZDf18nMjmWuOF9daaDx+OpuSEF8HWyp8dAcf9SKcTkjOXIUgy+MIkogCy # vlPKg24pW4HvOG6A87vsEwvrAgMBAAGjggGAMIIBfDAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUy9ZihM9gOer/Z8Jc0si7q7fDE5gw # UgYDVR0RBEswSaRHMEUxDTALBgNVBAsTBE1PUFIxNDAyBgNVBAUTKzIzMDAxMitj # ODA0YjVlYS00OWI0LTQyMzgtODM2Mi1kODUxZmEyMjU0ZmMwHwYDVR0jBBgwFoAU # SG5k5VAF04KqFzc3IrVtqMp1ApUwVAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL3d3 # dy5taWNyb3NvZnQuY29tL3BraW9wcy9jcmwvTWljQ29kU2lnUENBMjAxMV8yMDEx # LTA3LTA4LmNybDBhBggrBgEFBQcBAQRVMFMwUQYIKwYBBQUHMAKGRWh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvY2VydHMvTWljQ29kU2lnUENBMjAxMV8y # MDExLTA3LTA4LmNydDAMBgNVHRMBAf8EAjAAMA0GCSqGSIb3DQEBCwUAA4ICAQAG # Fh/bV8JQyCNPolF41+34/c291cDx+RtW7VPIaUcF1cTL7OL8mVuVXxE4KMAFRRPg # mnmIvGar27vrAlUjtz0jeEFtrvjxAFqUmYoczAmV0JocRDCppRbHukdb9Ss0i5+P # WDfDThyvIsoQzdiCEKk18K4iyI8kpoGL3ycc5GYdiT4u/1cDTcFug6Ay67SzL1BW # XQaxFYzIHWO3cwzj1nomDyqWRacygz6WPldJdyOJ/rEQx4rlCBVRxStaMVs5apao # pIhrlihv8cSu6r1FF8xiToG1VBpHjpilbcBuJ8b4Jx/I7SCpC7HxzgualOJqnWmD # oTbXbSD+hdX/w7iXNgn+PRTBmBSpwIbM74LBq1UkQxi1SIV4htD50p0/GdkUieeN # n2gkiGg7qceATibnCCFMY/2ckxVNM7VWYE/XSrk4jv8u3bFfpENryXjPsbtrj4Ns # h3Kq6qX7n90a1jn8ZMltPgjlfIOxrbyjunvPllakeljLEkdi0iHv/DzEMQv3Lz5k # pTdvYFA/t0SQT6ALi75+WPbHZ4dh256YxMiMy29H4cAulO2x9rAwbexqSajplnbI # vQjE/jv1rnM3BrJWzxnUu/WUyocc8oBqAU+2G4Fzs9NbIj86WBjfiO5nxEmnL9wl # iz1e0Ow0RJEdvJEMdoI+78TYLaEEAo5I+e/dAs8DojCCB3owggVioAMCAQICCmEO # kNIAAAAAAAMwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVTMRMwEQYDVQQI # EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv # ZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290IENlcnRpZmlj # YXRlIEF1dGhvcml0eSAyMDExMB4XDTExMDcwODIwNTkwOVoXDTI2MDcwODIxMDkw # OVowfjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT # B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UE # AxMfTWljcm9zb2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMTCCAiIwDQYJKoZIhvcN # AQEBBQADggIPADCCAgoCggIBAKvw+nIQHC6t2G6qghBNNLrytlghn0IbKmvpWlCq # uAY4GgRJun/DDB7dN2vGEtgL8DjCmQawyDnVARQxQtOJDXlkh36UYCRsr55JnOlo # XtLfm1OyCizDr9mpK656Ca/XllnKYBoF6WZ26DJSJhIv56sIUM+zRLdd2MQuA3Wr # aPPLbfM6XKEW9Ea64DhkrG5kNXimoGMPLdNAk/jj3gcN1Vx5pUkp5w2+oBN3vpQ9 # 7/vjK1oQH01WKKJ6cuASOrdJXtjt7UORg9l7snuGG9k+sYxd6IlPhBryoS9Z5JA7 # La4zWMW3Pv4y07MDPbGyr5I4ftKdgCz1TlaRITUlwzluZH9TupwPrRkjhMv0ugOG # jfdf8NBSv4yUh7zAIXQlXxgotswnKDglmDlKNs98sZKuHCOnqWbsYR9q4ShJnV+I # 4iVd0yFLPlLEtVc/JAPw0XpbL9Uj43BdD1FGd7P4AOG8rAKCX9vAFbO9G9RVS+c5 # oQ/pI0m8GLhEfEXkwcNyeuBy5yTfv0aZxe/CHFfbg43sTUkwp6uO3+xbn6/83bBm # 4sGXgXvt1u1L50kppxMopqd9Z4DmimJ4X7IvhNdXnFy/dygo8e1twyiPLI9AN0/B # 4YVEicQJTMXUpUMvdJX3bvh4IFgsE11glZo+TzOE2rCIF96eTvSWsLxGoGyY0uDW # iIwLAgMBAAGjggHtMIIB6TAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUSG5k # 5VAF04KqFzc3IrVtqMp1ApUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYD # VR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUci06AjGQQ7kU # BU7h6qfHMdEjiTQwWgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybC5taWNyb3Nv # ZnQuY29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAz # XzIyLmNybDBeBggrBgEFBQcBAQRSMFAwTgYIKwYBBQUHMAKGQmh0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljUm9vQ2VyQXV0MjAxMV8yMDExXzAz # XzIyLmNydDCBnwYDVR0gBIGXMIGUMIGRBgkrBgEEAYI3LgMwgYMwPwYIKwYBBQUH # AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvZG9jcy9wcmltYXJ5 # Y3BzLmh0bTBABggrBgEFBQcCAjA0HjIgHQBMAGUAZwBhAGwAXwBwAG8AbABpAGMA # eQBfAHMAdABhAHQAZQBtAGUAbgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAZ/KG # pZjgVHkaLtPYdGcimwuWEeFjkplCln3SeQyQwWVfLiw++MNy0W2D/r4/6ArKO79H # qaPzadtjvyI1pZddZYSQfYtGUFXYDJJ80hpLHPM8QotS0LD9a+M+By4pm+Y9G6XU # tR13lDni6WTJRD14eiPzE32mkHSDjfTLJgJGKsKKELukqQUMm+1o+mgulaAqPypr # WEljHwlpblqYluSD9MCP80Yr3vw70L01724lruWvJ+3Q3fMOr5kol5hNDj0L8giJ # 1h/DMhji8MUtzluetEk5CsYKwsatruWy2dsViFFFWDgycScaf7H0J/jeLDogaZiy # WYlobm+nt3TDQAUGpgEqKD6CPxNNZgvAs0314Y9/HG8VfUWnduVAKmWjw11SYobD # HWM2l4bf2vP48hahmifhzaWX0O5dY0HjWwechz4GdwbRBrF1HxS+YWG18NzGGwS+ # 30HHDiju3mUv7Jf2oVyW2ADWoUa9WfOXpQlLSBCZgB/QACnFsZulP0V3HjXG0qKi # n3p6IvpIlR+r+0cjgPWe+L9rt0uX4ut1eBrs6jeZeRhL/9azI2h15q/6/IvrC4Dq # aTuv/DDtBEyO3991bWORPdGdVk5Pv4BXIqF4ETIheu9BCrE/+6jMpF3BoYibV3FW # TkhFwELJm3ZbCoBIa/15n8G9bW1qyVJzEw16UM0xghXtMIIV6QIBATCBlTB+MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNy # b3NvZnQgQ29kZSBTaWduaW5nIFBDQSAyMDExAhMzAAAAxOmJ+HqBUOn/AAAAAADE # MA0GCWCGSAFlAwQCAQUAoIHcMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwG # CisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8GCSqGSIb3DQEJBDEiBCBix7Ij # XKMF6sNDwlLNuK9wLBT9xFJXX/x2Z9Qqt7EMyzBwBgorBgEEAYI3AgEMMWIwYKAq # gCgARwB1AGEAcgBkAGUAZAAgAEYAYQBiAHIAaQBjACAAVABvAG8AbABzoTKAMGh0 # dHBzOi8vZ2l0aHViLmNvbS9NaWNyb3NvZnQvR3VhcmRlZEZhYnJpY1Rvb2xzLzAN # BgkqhkiG9w0BAQEFAASCAQBjKAQQ1ZvzgmXw0/yKsoTm9lB8tsiEds9TOEycf3Nk # Y8e++gWhBND958oSlcvNurVm7yzxmRjdPNQRfXSj42QSncXtfy2brAccUYqbnIMZ # 5o5nVHnG64pDhXumfJZpScBpSrJWJctoUiPtwBd8+kuyGEJ5NRcwMFe98Kv9Tw81 # +2hZ2Eo9vDlaRIr09R6Bbs61Q5uebdxLuUThblvQspS7lK8cP8busdR8m1Zre2dg # UNx/On81BQlpMZYHR5JaA4/JxgwR9VEz8kdXsbvGKbOY4itOxaw8O5m+QYvb5LOL # Qfm9zBxcXXDpEzUnt1kwqOTa5AGMgYbZ2LsO3yd5FLgnoYITSTCCE0UGCisGAQQB # gjcDAwExghM1MIITMQYJKoZIhvcNAQcCoIITIjCCEx4CAQMxDzANBglghkgBZQME # AgEFADCCATwGCyqGSIb3DQEJEAEEoIIBKwSCAScwggEjAgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIMVvYV4Kh0yzZ2T8JgRrp3wKwFA20/VnAQwk7z3Q # nsHYAgZaTsE/8lAYEzIwMTgwMTI1MTcyMTI2LjYxMlowBwIBAYACA+eggbikgbUw # gbIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xDDAKBgNVBAsT # A0FPQzEnMCUGA1UECxMebkNpcGhlciBEU0UgRVNOOjg0M0QtMzdGNi1GMTA0MSUw # IwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIOzTCCBnEwggRZ # oAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29mdCBSb290 # IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1NVoXDTI1 # MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x # EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv # bjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwggEiMA0G # CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/aZRrdFQQ # 1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxhMFmxMEQP # 8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhHhjKEHnRh # Z5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tkiVBisV39 # dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox8NpOBpG2 # iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJNAgMBAAGj # ggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIoxkPNDe3xG # G8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG # MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186a # GMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br # aS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsG # AQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29t # L3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAGA1UdIAEB # /wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAGCCsGAQUF # BwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEAdABlAG0A # ZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXEDPZ2joSFv # s+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgrUYJEEvu5 # U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c8pl5SpFS # AK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFwnzJKJ/1V # ry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFtw5yjojz6 # f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk7Pf0v35j # WSUPei45V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9ddJgiCGHa # sFAeb73x4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zGy9iCtHLN # HfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3yKxO2ii4 # sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7cRDyXUHHX # odLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wknHNWzfjUe # CLraNtvTX4/edIhJEjCCBNkwggPBoAMCAQICEzMAAACpVHDZecCEZeIAAAAAAKkw # DQYJKoZIhvcNAQELBQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0 # b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3Jh # dGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcN # MTYwOTA3MTc1NjUzWhcNMTgwOTA3MTc1NjUzWjCBsjELMAkGA1UEBhMCVVMxEzAR # BgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1p # Y3Jvc29mdCBDb3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lw # aGVyIERTRSBFU046ODQzRC0zN0Y2LUYxMDQxJTAjBgNVBAMTHE1pY3Jvc29mdCBU # aW1lLVN0YW1wIFNlcnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCslIUYpuVW053fA2cu25iRR4+ViXJNmnTzNEDeaxGn1MeSfg7/nzU6f6dkjHGb # YcUZWT6UXZEvTsDtwUBuJweR1OWs9h48zlARUydohNLSZqQfbh17KYsm4wmudOdM # /J+Dt0YN2xWpDftX97ObEN4MHKRNGsOWJEY2KZBc3h1H1pc/Qo0H/6gvJ47rEhCx # R0L3BL05NsTFu8DstryOgZzJ3bJAPD2j6xu9MHX+WwVzHRQxEdTwOr/s0RPeRMnE # /kjhV8QueAgVfvNFBjZJtrX9WB0R3YhkA0IQOe+uUxZGEVtcfRJad0h2cClhIRqT # U5wiaW6ctHl6jkw4hBUZbF+hAgMBAAGjggEbMIIBFzAdBgNVHQ4EFgQUD9VB+7vz # nfS+SVLajDdXzmQP830wHwYDVR0jBBgwFoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUw # VgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9j # cmwvcHJvZHVjdHMvTWljVGltU3RhUENBXzIwMTAtMDctMDEuY3JsMFoGCCsGAQUF # BwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3Br # aS9jZXJ0cy9NaWNUaW1TdGFQQ0FfMjAxMC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIw # ADATBgNVHSUEDDAKBggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEACJkYpQeL # L3IkdSyOIIQC/Qqhrw7hsDIRhqrFhiCdu+hEO5XMtTrni0alE9OMIBuoOlccFfdz # bY0LsgdFboZFdiRGunRM8TZvUp225OSUjMkpq4mqvnKC07qbVauggjngGS7YEa1F # iQNLwC/iAJ64e4fbytd1uC4EtIyTN4oeJkTk2UFljtFCuV4TELwZZ3W7zoSp6R+O # e88blLg5XW1XWewKfsbWlQ075/qIL1asVQRQcmc/sgADw47C/D7Ilavg1Ge2pjRt # tGAIskKJ3n9g2lghvNOMODJT8grM298ktwDrk0o/CXo0O0vAc2tqUoRToZsERFlh # Qq1y8EDAbvyasqGCA3cwggJfAgEBMIHioYG4pIG1MIGyMQswCQYDVQQGEwJVUzET # MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV # TWljcm9zb2Z0IENvcnBvcmF0aW9uMQwwCgYDVQQLEwNBT0MxJzAlBgNVBAsTHm5D # aXBoZXIgRFNFIEVTTjo4NDNELTM3RjYtRjEwNDElMCMGA1UEAxMcTWljcm9zb2Z0 # IFRpbWUtU3RhbXAgU2VydmljZaIlCgEBMAkGBSsOAwIaBQADFQBdOr9WveEPKcpy # DmT3dTt4GiLr9KCBwTCBvqSBuzCBuDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldh # c2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEMMAoGA1UECxMDQU9DMScwJQYDVQQLEx5uQ2lwaGVyIE5UUyBF # U046MjY2NS00QzNGLUM1REUxKzApBgNVBAMTIk1pY3Jvc29mdCBUaW1lIFNvdXJj # ZSBNYXN0ZXIgQ2xvY2swDQYJKoZIhvcNAQEFBQACBQDeFCBsMCIYDzIwMTgwMTI1 # MDkyMjUyWhgPMjAxODAxMjYwOTIyNTJaMHcwPQYKKwYBBAGEWQoEATEvMC0wCgIF # AN4UIGwCAQAwCgIBAAICDm4CAf8wBwIBAAICGnYwCgIFAN4VcewCAQAwNgYKKwYB # BAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAaAKMAgCAQACAx6AmKEKMAgCAQACAx6E # gDANBgkqhkiG9w0BAQUFAAOCAQEAiqwTaxFV2WwlbyhIJ9evlBrmbaxCvWijShCq # 2D8NMgXnFZesqh8BpTeLlbejEKZrFWg9WpawNqLRaTldYc1/ptQv/iguuyMSZK9r # RvbqH5X3BfN9jQBK8wJIMTLckb4ov9QiWV3G0SAlJJIy5rGTZXsmddWVloiBNJSb # 9I5sDaQ93hfdBFEE4Jk04BL7nAIA2iZIlige0AdAw3kCZUFv2TzoYNnFefIRR6uY # 7DmfLbh3z2+LJ4nFgCSjP1dnkqL+A4S71ua2A8he8yw9PPltr2dUqwo8ayffBShd # 2qzYulFSiDgOPkP0pJ9mfCdCK6gR+z62u50W81G6axQRzcDM4TGCAvUwggLxAgEB # MIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQH # EwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNV # BAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAAqVRw2XnAhGXi # AAAAAACpMA0GCWCGSAFlAwQCAQUAoIIBMjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN # AQkQAQQwLwYJKoZIhvcNAQkEMSIEIAcz39Yx4ZzDG76ErApS9mi9GR6neQTZ2Ho/ # aQi2uE7GMIHiBgsqhkiG9w0BCRACDDGB0jCBzzCBzDCBsQQUXTq/Vr3hDynKcg5k # 93U7eBoi6/QwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu # Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv # cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAIT # MwAAAKlUcNl5wIRl4gAAAAAAqTAWBBTXGrlYHUIk+5wcpNeuG9ycrVFvXDANBgkq # hkiG9w0BAQsFAASCAQAgew+QV5tOmPHKhusNsI6TUaHcrFc0YMVBZiceDlg77x6W # 3rHKITQLAPLHveh4KBjMuzyVzGfDZnDA8JTzba5OttX64Fqok0HGup6zNqHNJYdl # 6dxZelS5TBFnmHaB3NtP8kSOE8VTzbTTUP8a/X6SaHAjl3ko7ofwpqw8d7R/yiw/ # kbBHvDZikeSfXw8fGi2D5R7K/880wsy75zHVdf8PaxtYNb+Q/8lptJmM1H7TcKPH # MrRRF5tJt3hm6gvRGAvrO2Bfhcm3lGzSmAPon6ivuH5Z/qDQ2RIghW3N42OK3NJD # YpRmCkOO05QnOuhk4OLBrES5uIyZVCbu4QuN87Uc # SIG # End signature block |