Get-ADWHfBKeys.ps1
# # Get-ADWHfBKeys.ps1 # # Copyright 2019 Microsoft. All rights reserved. # <# Get-ADWHfBKeys #> function Get-ADWHfBKeys { <#.SYNOPSIS Reads Windows Hello for Business (WHfB) keys from Active Directory. .DESCRIPTION Reads Windows Hello for Business (WHfB) keys from Active Directory. Two modes are supported: read all keys from a specific AD domain, or all keys from a specific AD user. Any keys found are checked to see if they are vulnerable to the ROCA vulnerability. Any keys found are also checked to see if they are linked to a valid device object in the forest; any key that is not linked to a valid device object is deemed "orphaned". This cmdlet uses the current user to authenticate to Active Directory. To ensure the most accurate results, a privileged account such as a Domain Admin should be used to run this cmdlet. Lesser-privileged accounts may not have sufficient permissions to query users and/or their WHfB keys. .PARAMETER Domain Specify this parameter to read all keys from a specific domain, or a specific domain\user combination. .PARAMETER SamAccountName Specify this parameter to read all keys from a specific user. .PARAMETER SkipCheckForOrphanedKeys Optional. This switch is used to suppress checking each key to see if it is linked to a valid device object. This option requires additional network queries to check therefore increasing run time of the command. .PARAMETER Report Optional. This switch will cause a summary report to be printed to console and log. .PARAMETER Logging Optional. This switch will enable additional diagnostic logging to a file. .INPUTS None. You cannot pipe objects to Get-ADWHfBKeys. .OUTPUTS Custom type representing WHfB key. Get-ADWHfBKeys returns zero or more based on results. .EXAMPLE PS C:\>Get-ADWHfBKeys -Domain contoso.com Scan the contoso.com AD domain for all WHfB keys and display summary report. .EXAMPLE PS C:\>Get-ADWHfBKeys -Report -Domain contoso.com -SkipCheckForOrphanedKeys Scan the contoso.com AD domain for all WHfB keys, without performing orphaned key checks, and display summary report. .EXAMPLE PS C:\>Get-ADWHfBKeys -Report -Domain contoso.com -SamAccountName TestUser Scan the contoso.com\TestUser AD user account for its WHfB keys and display summary report. .EXAMPLE PS C:\>Get-ADWHfBKeys -Logging -Report -Domain contoso.com | Export-Csv "contoso_whfb_keys.csv" Scan the contoso.com AD domain for all WHfB keys, pipe the results to a CSV file, emit diagnostic logging to file, and display summary report. #> [CmdletBinding()] param ( [CmdletBinding()] [Parameter( Mandatory=$true, ParameterSetName='DomainUser' )] [Parameter( Mandatory=$true, ParameterSetName='Domain' )] [string]$Domain, [Parameter( Mandatory=$true, ParameterSetName='DomainUser' )] [string]$SamAccountName, [Parameter( Mandatory=$false )] [Switch]$SkipCheckForOrphanedKeys, [Parameter( Mandatory=$false )] [Switch]$Report, [Parameter( Mandatory=$false )] [Switch]$Logging ) Begin { ImportActiveDirectoryModuleIfNeeded if ($Logging) { $timestamp = Get-TimeStamp $script:Logfile = "WHfBTools_$($timestamp).log" DiagLog "Get-ADWHfBKeys starting" -logOnly } else { $script:Logfile = $null } # Reset summary report counters $script:totalADUsers = 0 $script:totalADUsersWithWHfBKeys = 0 $script:totalADWHfBKeys = 0 $script:totalADRocaVulnerableKeys = 0 $script:totalADOrphanedKeys = 0 $script:stopwatch = [System.Diagnostics.Stopwatch]::StartNew() } Process { $domainController = Get-ADDomainController -Domain $Domain -Discover if (!$SkipCheckForOrphanedKeys) { $deviceContainerInfo = Get-ADDeviceRegistrationServiceContainerInfo -Domain $domainController.Domain if ($deviceContainerInfo) { $deviceContainerDC = Get-ADDomainController -Domain $deviceContainerInfo.DeviceContainerDomain -Discover $deviceContainerInfo = [PSCustomObject]@{ DeviceContainerDC = $deviceContainerDC.Name DeviceContainerDomain = $deviceContainerInfo.DeviceContainerDomain DeviceContainerDN = $deviceContainerInfo.DeviceContainerDN } if ($Logging) { $output = "Device container domain: " + $deviceContainerInfo.DeviceContainerDomain DiagLog $output -logOnly $output = "Device container DN: " + $deviceContainerInfo.DeviceContainerDN DiagLog $output -logOnly $output = "Device container domain controller: " + $deviceContainerInfo.DeviceContainerDC DiagLog $output -logOnly } } else { DiagLog "Error: failed to locate device container - forest may not be correctly configured." -foregroundcolor Yellow Exit-PSHostProcess } } else { if ($Logging) { $output = "-SkipCheckForOrphanedKey was specified, not checking for orphaned keys" DiagLog $output -logOnly } $deviceContainerInfo = $null } if ($SamAccountName) { $LDAPFilter = "(samAccountName=$SamAccountName)" } else { $LDAPFilter = "(objectClass=*)" } if ($Logging) { $output = "Ready to start query" DiagLog $output -logOnly $output = "Domain controller: " + $domainController.Name DiagLog $output -logOnly $output = "LDAP search filter: " + $LDAPFilter DiagLog $output -logOnly } Update-GetADWHfBKeysProgress $SkipCheckForOrphanedKeys # Start the query pipeline Get-ADUser ` -Server $domainController.Name ` -LDAPFilter $LDAPFilter ` -Properties "msds-KeyCredentialLink" | Get-ADWHfBKeysFromADUser -Domain $domainController.Domain -SkipCheckForOrphanedKeys $SkipCheckForOrphanedKeys -DeviceContainerInfo $deviceContainerInfo -Logging $Logging } End { if ($Report) { DiagLog "Report of summary results:" -foregroundcolor yellow DiagLog "Users scanned: $script:totalADUsers" -foregroundcolor yellow DiagLog "Users with WHfB keys: $script:totalADUsersWithWHfBKeys" -foregroundcolor yellow DiagLog "Total WHfB Keys: $script:totalADWHfBKeys" -foregroundcolor yellow DiagLog "Total ROCA vulnerable keys: $script:totalADRocaVulnerableKeys" -foregroundcolor yellow if (!$SkipCheckForOrphanedKeys) { DiagLog "Total orphaned keys: $script:totalADOrphanedKeys" -foregroundcolor yellow } } if ($Logging) { DiagLog "Get-ADWHfBKeys ending" -logOnly } } } <# Update-GetADWHfBKeysProgress #> function Update-GetADWHfBKeysProgress { <#.SYNOPSIS Updates the progress bar with current status. .DESCRIPTION Updates the progress bar with current status. .PARAMETER SkipCheckForOrphanedKeys Specifies whether skip-orphaned-key-checks was specified by the user. #> [CmdletBinding()] param ( [Parameter( Mandatory=$true )] [bool]$SkipCheckForOrphanedKeys ) $activity = "Get-ADWHfBKeys - " + $script:stopwatch.Elapsed.ToString("dd\:hh\:mm\:ss") $progressDescription = "Scanning Active Directory and Compiling Statistics" $progressResults = "$script:totalADUsers users scanned | $script:totalADWHfBKeys WHfB keys found | $script:totalADRocaVulnerableKeys ROCA vulnerable keys" if (!$SkipCheckForOrphanedKeys) { $progressResults = $progressResults + " | $script:totalADOrphanedKeys orphaned keys" } Write-Progress -Id 1 -Activity $activity -Status $progressDescription -PercentComplete -1 -CurrentOperation $progressResults } <# Get-ADWHfBKeysFromADUser #> function Get-ADWHfBKeysFromADUser { <#.SYNOPSIS Reads WHfB keys from the specified Active Directory user object. .DESCRIPTION Reads WHfB keys from the specified Active Directory user object. .PARAMETER User A user object returned from the Get-ADUser PowerShell cmdlet. .PARAMETER Domain The AD domain that contains User. .PARAMETER SkipCheckForOrphanedKeys This switch is used to suppress checking each key to see if it is linked to a valid device object. This option requires additional network queries to check therefore increasing run time of the command. .PARAMETER DeviceContainerInfo PSObject containing information about the device container in the current forest as as well which domain controller in that domain to use for queries. .PARAMETER Logging This switch will enable additional diagnostic logging to a file. .INPUTS AD user object returned from Get-ADUser. .OUTPUTS Array of ADWHfBKey objects from the user object, or $null if none exist. #> [CmdletBinding()] param ( [Parameter( ValueFromPipeline=$true )] [PSObject]$User, [Parameter( Mandatory=$false )] [string]$Domain, [Parameter( Mandatory=$false )] [bool]$SkipCheckForOrphanedKeys, [Parameter( Mandatory=$false )] [PSObject]$DeviceContainerInfo, [Parameter( Mandatory=$false )] [bool]$Logging ) Begin { } Process { # Increment total # of users seen $script:totalADUsers += 1 # Noop if user does not have any keys if (!$User.PropertyNames.Contains("msds-KeyCredentialLink")) { return } # Increment total # of users with WHfB keys $script:totalADUsersWithWHfBKeys += 1 $rawKeys = $User.'msds-KeyCredentialLink' foreach ($rawKey in $rawKeys) { # Parse the raw value $key = Get-ADWHfBKeyFromValue -RawValue $rawKey # Parsing failures result in a null result. Sometimes seen due # to malformed or test key values. if (!$key) { if ($Logging) { $output = "Unable to parse key from user '$User.SamAccountName' $User.DistinguishedName" DiagLog $output -logOnly $output = "Unparseable key raw value: " + $rawKey DiagLog $output -logOnly } continue; } if ($key.KeyUsage -ne "NGC") { # Currently we are only focused on NGC keys which are intended for # authentication. Ignore all other key types for now. $output = "Ignoring non-NGC key ($key.KeyUsage) from user $User.SamAccountName $User.DistinguishedName" DiagLog $output -logOnly $output = "Ignored key raw value: " + $rawKey DiagLog $output -logOnly continue; } # Increment total # of WHfB keys seen $script:totalADWHfBKeys += 1 # Add user identifying data to the key object $key.UserDomain = $Domain $key.UserSamAccountName = $User.SamAccountName $key.UserDistinguishedName = $User.DistinguishedName # Do post-parsing key validation checks # Always check whether key is ROCA-vulnerable $rawKeyBytes = [System.Convert]::FromBase64String($key.KeyMaterial); $key.ROCAVulnerable = Probe-KeyForRocaVulnerability $rawKeyBytes if ($key.ROCAVulnerable) { # Increment total # of ROCA-vulnerable WHfB keys $script:totalADRocaVulnerableKeys += 1 } # Optionally check whether key is soft-linked to a device object if (!$SkipCheckForOrphanedKeys) { if ($deviceContainerInfo) { $hasValidDeviceObject = DoesDeviceObjectExistAD ` $DeviceContainerInfo.DeviceContainerDC ` $DeviceContainerInfo.DeviceContainerDomain ` $DeviceContainerInfo.DeviceContainerDN ` $key.KeyDeviceId ` $Logging $key.OrphanedKey = !$hasValidDeviceObject } else { $key.OrphanedKey = $true } if ($key.OrphanedKey) { $script:totalADOrphanedKeys += 1 } } else { $key.OrphanedKey = "Not checked" } Update-GetADWHfBKeysProgress $SkipCheckForOrphanedKeys # Write keys to the pipeline as we finish them Write-Output $key } } End { } } # SIG # Begin signature block # MIIjhQYJKoZIhvcNAQcCoIIjdjCCI3ICAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA2vcDG509RJfx7 # mNi/k/gg6CudpJnXPgvxRG3QFmDz0KCCDYEwggX/MIID56ADAgECAhMzAAABUZ6N # j0Bxow5BAAAAAAFRMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMTkwNTAyMjEzNzQ2WhcNMjAwNTAyMjEzNzQ2WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQCVWsaGaUcdNB7xVcNmdfZiVBhYFGcn8KMqxgNIvOZWNH9JYQLuhHhmJ5RWISy1 # oey3zTuxqLbkHAdmbeU8NFMo49Pv71MgIS9IG/EtqwOH7upan+lIq6NOcw5fO6Os # +12R0Q28MzGn+3y7F2mKDnopVu0sEufy453gxz16M8bAw4+QXuv7+fR9WzRJ2CpU # 62wQKYiFQMfew6Vh5fuPoXloN3k6+Qlz7zgcT4YRmxzx7jMVpP/uvK6sZcBxQ3Wg # B/WkyXHgxaY19IAzLq2QiPiX2YryiR5EsYBq35BP7U15DlZtpSs2wIYTkkDBxhPJ # IDJgowZu5GyhHdqrst3OjkSRAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUV4Iarkq57esagu6FUBb270Zijc8w # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDU0MTM1MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAWg+A # rS4Anq7KrogslIQnoMHSXUPr/RqOIhJX+32ObuY3MFvdlRElbSsSJxrRy/OCCZdS # se+f2AqQ+F/2aYwBDmUQbeMB8n0pYLZnOPifqe78RBH2fVZsvXxyfizbHubWWoUf # NW/FJlZlLXwJmF3BoL8E2p09K3hagwz/otcKtQ1+Q4+DaOYXWleqJrJUsnHs9UiL # crVF0leL/Q1V5bshob2OTlZq0qzSdrMDLWdhyrUOxnZ+ojZ7UdTY4VnCuogbZ9Zs # 9syJbg7ZUS9SVgYkowRsWv5jV4lbqTD+tG4FzhOwcRQwdb6A8zp2Nnd+s7VdCuYF # sGgI41ucD8oxVfcAMjF9YX5N2s4mltkqnUe3/htVrnxKKDAwSYliaux2L7gKw+bD # 1kEZ/5ozLRnJ3jjDkomTrPctokY/KaZ1qub0NUnmOKH+3xUK/plWJK8BOQYuU7gK # YH7Yy9WSKNlP7pKj6i417+3Na/frInjnBkKRCJ/eYTvBH+s5guezpfQWtU4bNo/j # 8Qw2vpTQ9w7flhH78Rmwd319+YTmhv7TcxDbWlyteaj4RK2wk3pY1oSz2JPE5PNu # Nmd9Gmf6oePZgy7Ii9JLLq8SnULV7b+IP0UXRY9q+GdRjM2AEX6msZvvPCIoG0aY # HQu9wZsKEK2jqvWi8/xdeeeSI9FN6K1w4oVQM4Mwggd6MIIFYqADAgECAgphDpDS # AAAAAAADMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0 # ZSBBdXRob3JpdHkgMjAxMTAeFw0xMTA3MDgyMDU5MDlaFw0yNjA3MDgyMTA5MDla # MH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdS # ZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMT # H01pY3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTEwggIiMA0GCSqGSIb3DQEB # AQUAA4ICDwAwggIKAoICAQCr8PpyEBwurdhuqoIQTTS68rZYIZ9CGypr6VpQqrgG # OBoESbp/wwwe3TdrxhLYC/A4wpkGsMg51QEUMULTiQ15ZId+lGAkbK+eSZzpaF7S # 35tTsgosw6/ZqSuuegmv15ZZymAaBelmdugyUiYSL+erCFDPs0S3XdjELgN1q2jz # y23zOlyhFvRGuuA4ZKxuZDV4pqBjDy3TQJP4494HDdVceaVJKecNvqATd76UPe/7 # 4ytaEB9NViiienLgEjq3SV7Y7e1DkYPZe7J7hhvZPrGMXeiJT4Qa8qEvWeSQOy2u # M1jFtz7+MtOzAz2xsq+SOH7SnYAs9U5WkSE1JcM5bmR/U7qcD60ZI4TL9LoDho33 # X/DQUr+MlIe8wCF0JV8YKLbMJyg4JZg5SjbPfLGSrhwjp6lm7GEfauEoSZ1fiOIl # XdMhSz5SxLVXPyQD8NF6Wy/VI+NwXQ9RRnez+ADhvKwCgl/bwBWzvRvUVUvnOaEP # 6SNJvBi4RHxF5MHDcnrgcuck379GmcXvwhxX24ON7E1JMKerjt/sW5+v/N2wZuLB # l4F77dbtS+dJKacTKKanfWeA5opieF+yL4TXV5xcv3coKPHtbcMojyyPQDdPweGF # RInECUzF1KVDL3SV9274eCBYLBNdYJWaPk8zhNqwiBfenk70lrC8RqBsmNLg1oiM # CwIDAQABo4IB7TCCAekwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFEhuZOVQ # BdOCqhc3NyK1bajKdQKVMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1Ud # DwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFHItOgIxkEO5FAVO # 4eqnxzHRI4k0MFoGA1UdHwRTMFEwT6BNoEuGSWh0dHA6Ly9jcmwubWljcm9zb2Z0 # LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcmwwXgYIKwYBBQUHAQEEUjBQME4GCCsGAQUFBzAChkJodHRwOi8vd3d3Lm1p # Y3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dDIwMTFfMjAxMV8wM18y # Mi5jcnQwgZ8GA1UdIASBlzCBlDCBkQYJKwYBBAGCNy4DMIGDMD8GCCsGAQUFBwIB # FjNodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2RvY3MvcHJpbWFyeWNw # cy5odG0wQAYIKwYBBQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AcABvAGwAaQBjAHkA # XwBzAHQAYQB0AGUAbQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAGfyhqWY # 4FR5Gi7T2HRnIpsLlhHhY5KZQpZ90nkMkMFlXy4sPvjDctFtg/6+P+gKyju/R6mj # 82nbY78iNaWXXWWEkH2LRlBV2AySfNIaSxzzPEKLUtCw/WvjPgcuKZvmPRul1LUd # d5Q54ulkyUQ9eHoj8xN9ppB0g430yyYCRirCihC7pKkFDJvtaPpoLpWgKj8qa1hJ # Yx8JaW5amJbkg/TAj/NGK978O9C9Ne9uJa7lryft0N3zDq+ZKJeYTQ49C/IIidYf # wzIY4vDFLc5bnrRJOQrGCsLGra7lstnbFYhRRVg4MnEnGn+x9Cf43iw6IGmYslmJ # aG5vp7d0w0AFBqYBKig+gj8TTWYLwLNN9eGPfxxvFX1Fp3blQCplo8NdUmKGwx1j # NpeG39rz+PIWoZon4c2ll9DuXWNB41sHnIc+BncG0QaxdR8UvmFhtfDcxhsEvt9B # xw4o7t5lL+yX9qFcltgA1qFGvVnzl6UJS0gQmYAf0AApxbGbpT9Fdx41xtKiop96 # eiL6SJUfq/tHI4D1nvi/a7dLl+LrdXga7Oo3mXkYS//WsyNodeav+vyL6wuA6mk7 # r/ww7QRMjt/fdW1jkT3RnVZOT7+AVyKheBEyIXrvQQqxP/uozKRdwaGIm1dxVk5I # RcBCyZt2WwqASGv9eZ/BvW1taslScxMNelDNMYIVWjCCFVYCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAVGejY9AcaMOQQAAAAABUTAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgqbTb3gCu # 2bHXsX0Y0YpDLKu8R0NBz5i4mZf9C3OURDUwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQBMrC/u3tpldRn+ExiMtCMjITI3Yt0g46IZZAAIardl # F2la5i7yh88CDaFKFmApViVuBDZDGLxHlGcPrNuCz99HHQF+XZAsjZXBIVPIih/c # Xjz1JWAUEdU9PDFd2u60nH9vY38VnvxrxlAPC0Tcz/wUZSeP61rRtoQgn2uL4Gml # MYGIzpILrvSBJi4bgc5mbRseAC9J+5fLeptevK0DGBoK84Mf5DPXcgZTnWGS+30t # vuZbEo+43/ncQac/68ESUlYxctTLLVuOQ12YKW8gmiggHxdNgGA/WqrBZfzuJNry # NiUktCWbgqhgqLEgjx0313bWloAnyaOuEd/I/FlXQpjioYIS5DCCEuAGCisGAQQB # gjcDAwExghLQMIISzAYJKoZIhvcNAQcCoIISvTCCErkCAQMxDzANBglghkgBZQME # AgEFADCCAVAGCyqGSIb3DQEJEAEEoIIBPwSCATswggE3AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIEWBBs67mJnZjQb608k0clpLa34SJ4OwrIGe/C6r # p4sxAgZdtfNcnjMYEjIwMTkxMjA0MTQxMjEzLjA3WjAEgAIB9KCB0KSBzTCByjEL # MAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJ # cmVsYW5kIE9wZXJhdGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBF # U046M0JENC00QjgwLTY5QzMxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w # IFNlcnZpY2Wggg48MIIE8TCCA9mgAwIBAgITMwAAAQvk+b6Pb0wd0AAAAAABCzAN # BgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDAeFw0x # OTEwMjMyMzE5MTVaFw0yMTAxMjEyMzE5MTVaMIHKMQswCQYDVQQGEwJVUzELMAkG # A1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBD # b3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9zb2Z0IElyZWxhbmQgT3BlcmF0aW9u # cyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjozQkQ0LTRCODAtNjlD # MzElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZTCCASIwDQYJ # KoZIhvcNAQEBBQADggEPADCCAQoCggEBAJcC1Z1GMUG4z4PaeFQotW5a/1xlyrX/ # x6bKRAGmUOKLwOrDAI2cPTMmHPuf3ha1aMWxzkov90XyApZMxEfkxVNrl3EIm7pW # 1mhtz6zO0z7Qk8zlWZxv/sP4CUUREYCRAYbE79nh/EcfX8Rxn+LBSKbNp9eME6Uh # DdFLFQCP3zSWK4DI0KuPwl26cZHedVJG/Em1alRm+UhSthjgsOYkmwWwjyCxyHcu # tyGY94GSjGy/LtGkqFw5C1NhpwPjy/Pt/NPZyJyImoBfFm3t+2HyyCoqJRREJW5K # VxQpcFeb/V1xgIqo6hTPZga7aLS3gr9fXslZnmN03W/GrNJBr0/g8fECAwEAAaOC # ARswggEXMB0GA1UdDgQWBBStH9nqHYoenOCYDVBEZf/3bV7e7zAfBgNVHSMEGDAW # gBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8v # Y3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNUaW1TdGFQQ0Ff # MjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRw # Oi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0YVBDQV8yMDEw # LTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsGAQUFBwMIMA0G # CSqGSIb3DQEBCwUAA4IBAQAm6KOdqe82tLrd7zsIrSDAiYjwLgl2HEss+cDqb+lR # JdZ6X0oJre33k1E07fo2B6YPGGyTPutUeJSKBvWkl2b5MHlKGDYOU+LVSF0JNo3m # VNZn6scAV8MjiLaB0o7B3K6DvebmNrZ2p8NOXYOLlrHBwGAO8axkt8Gb5oa63a9Q # YEGDVCMwp+pAaowkJjBc8Z0ebBE3VQ3kyk5EGROaTYMRZaNGbQspDX95XgpiJTlx # XgYLT/z+r9fvXBuvB3IfZnK+HaYg4T7hP2ZlzsfQLNnxB2pMd3bFtNPUZI1F55hi # WdORaUKIQuNiQicdR/C6YLWkK5kx/ghM3DsqN44Y/IoNMIIGcTCCBFmgAwIBAgIK # YQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNV # BAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jv # c29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlm # aWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcNMjUwNzAxMjE0 # NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UE # BxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYD # VQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIwDQYJKoZIhvcN # AQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0VBDVpQoAgoX7 # 7XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEwRA/xYIiEVEMM # 1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQedGFnkV+BVLHP # k0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKxXf13Hz3wV3Ws # vYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4GkbaICDXoeByw # 6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEAAaOCAeYwggHi # MBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7fEYbxTNoWoVt # VTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0T # AQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvXzpoYxDBWBgNV # HR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9w # cm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYIKwYBBQUHAQEE # TjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2Nl # cnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0gAQH/BIGVMIGS # MIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93d3cubWljcm9z # b2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYBBQUHAgIwNB4y # IB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUAbQBlAG4AdAAu # IB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOhIW+z66bM9TG+ # zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS+7lTjMz0YBKK # dsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlKkVIArzgPF/Uv # eYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon/VWvL/625Y4z # u2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOiPPp/fZZqkHim # bdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/fmNZJQ96LjlX # dqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCIIYdqwUB5vvfHh # AN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0cs0d9LiFAR6A # +xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7aKLixqduWsqdC # osnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQcdeh0sVV42ne # V8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+NR4Iuto229Nf # j950iEkSoYICzjCCAjcCAQEwgfihgdCkgc0wgcoxCzAJBgNVBAYTAlVTMQswCQYD # VQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENv # cnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVyYXRpb25z # IExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjNCRDQtNEI4MC02OUMz # MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloiMKAQEwBwYF # Kw4DAhoDFQDx/fkdMWpT3PCKEj2S2aw+CnAwUqCBgzCBgKR+MHwxCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBU # aW1lLVN0YW1wIFBDQSAyMDEwMA0GCSqGSIb3DQEBBQUAAgUA4ZHhczAiGA8yMDE5 # MTIwNDE1NDAzNVoYDzIwMTkxMjA1MTU0MDM1WjB3MD0GCisGAQQBhFkKBAExLzAt # MAoCBQDhkeFzAgEAMAoCAQACAhCgAgH/MAcCAQACAhHbMAoCBQDhkzLzAgEAMDYG # CisGAQQBhFkKBAIxKDAmMAwGCisGAQQBhFkKAwKgCjAIAgEAAgMHoSChCjAIAgEA # AgMBhqAwDQYJKoZIhvcNAQEFBQADgYEAkl0SzAtkFTe1T1w7EXVAuo3rVBAegt84 # yCE4Z+SP/nDQM8kd2jLpwvQYv4CpxYQNOfFNSktD5cGMtWPjEsplBhBjdHENqxbu # 9TgXlxrKmBBR7MMVihlaSZiWwydEBexLWd6JYoaQNITpm1C+s1CSfW8YZoZoQR1w # 3wZmTwWBRKwxggMNMIIDCQIBATCBkzB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK # V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0 # IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg # MjAxMAITMwAAAQvk+b6Pb0wd0AAAAAABCzANBglghkgBZQMEAgEFAKCCAUowGgYJ # KoZIhvcNAQkDMQ0GCyqGSIb3DQEJEAEEMC8GCSqGSIb3DQEJBDEiBCDGeAjqLamc # Gudr7kYRLoU2wlNng7tIxobJZ6XHedQMOjCB+gYLKoZIhvcNAQkQAi8xgeowgecw # geQwgb0EIDSP0M4gUz46JJfxcCRcBeK9FHQs8cDpxVT8BMATXHOIMIGYMIGApH4w # fDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl # ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMd # TWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAEL5Pm+j29MHdAAAAAA # AQswIgQgZrEqn2Tba/C2eAVBjYDtfsmboozAciWDePHDPDx9ck8wDQYJKoZIhvcN # AQELBQAEggEAk8JitspfMhnhPylrzWSQRansvw7ya3uUHxtSUyw+fHZCTG4LfW1h # itHiEHUQ2VLrkvEkkk0oOoGpMdL6lZtBmwBUITjRpd35UcK0uq5oGnjptgq1Rm55 # lczqofqo/mV9kQx99FvvMQIp73m867gKkIL7CN3J61NNYllQ3a7S+pSdBcyuPITe # rku3qcALcl4+/zbC+oe8Kv8szecwVw1Q/KDbvNAUZmOC3LEwtBLN27sc8j1bEe+9 # fZqVMg/GiaeWWKiZHlrqaeAc4cW5bZ4NxrcjFrwEix75B5dLZI6EOfXk3+UxTM0j # E6Wq1rUr7KsigbXicRpu1hTuke0KHkQChg== # SIG # End signature block |