AzStackHciConnectivity/TestXmlSigning.ps1

<###################################################
 # #
 # Copyright (c) Microsoft. All rights reserved. #
 # #
 ##################################################>


<#
.DESCRIPTION
    Ensure XML is signed by Microsoft.
 
.PARAMETER XmlPath
    Path to XML File
 
.EXAMPLE
    .\BuildEndpointTargets.ps1 -TargetDirectory .
    Build XML from all json services under current directory (.)
#>


[CmdletBinding()]
param (
    [Parameter()]
    [System.String]
    $XmlPath
)

function Test-XMLSignatureByMicrosoft
{
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [System.String]
        $XmlPath
    )

    # Read the xml file so we can test the signature.
    try
    {
        $XmlDocument = New-Object -TypeName System.Xml.XmlDocument
        $XmlDocument.PreserveWhitespace = $true
        $xmlTextReader = New-Object -TypeName System.Xml.XmlTextReader -ArgumentList $XmlPath
        $XmlDocument.Load($xmlTextReader)
        $xmlTextReader.Dispose()
    }
    catch
    {
        throw ($LocalizedStrings.OEMMetadataInvalid -f $XmlPath)
    }

    $validSignature = $false
    $isSignedByMicrosoft = $false
    Write-Verbose "Testing $XmlPath"
    $signatures = $XmlDocument.GetElementsByTagName('Signature')
    if (-not [System.String]::IsNullOrEmpty($signatures))
    {

        foreach($signature in $signatures)
        {
            # Get the signed XML to validate the signature.
            Add-Type -AssemblyName System.Security
            $signedXml = New-Object System.Security.Cryptography.Xml.SignedXml -ArgumentList $XmlDocument
            $signedXml.LoadXml([System.Xml.XmlElement]$signature)

            $x509certificates = $signature.KeyInfo.x509Data
            if (-not [System.String]::IsNullOrEmpty($x509certificates))
            {
                # Find the signing certificate, and add intermediate certificate to enable disconnected validation
                foreach($x509certificate in $x509certificates.X509Certificate)
                {
                    $certBytes = [System.Convert]::FromBase64String($x509certificate)
                    $certificate = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $certBytes,$null
                    Write-Verbose $certificate.Thumbprint
                    if ($signedXml.CheckSignature($certificate,$true))
                    {
                        # This is the signing certificate
                        Write-Verbose "This is the signing certificate $($certificate.Thumbprint)"
                        Write-Verbose "$XmlPath,$($certificate.Thumbprint)"
                        $signingCertificate = $certificate
                    }
                    elseif (Get-ChildItem -Path Cert:\LocalMachine\Root | Where-Object {$_.Thumbprint -eq $certificate.Thumbprint})
                    {
                        # This is an existing trusted root
                        Write-Verbose "This is an existing trusted root $($certificate.Thumbprint)"
                    }
                    else
                    {
                        # This is not the signing certificate or an existing trusted root, add it to Intermediate CAs...
                        # ...this allows IsMicrosoftCertificate and x509Chain.Build to function, even when disconnected.
                        Write-Verbose "$($certificate.Thumbprint)"
                        if (Get-ChildItem -Path Cert:\LocalMachine\CA | Where-Object {$_.Thumbprint -eq $certificate.Thumbprint})
                        {
                            Write-Verbose "existing $($certificate.Thumbprint)"
                        }
                        else
                        {
                            Write-Verbose "Add $($certificate.Thumbprint)"
                            $x509Store = New-Object System.Security.Cryptography.X509Certificates.X509Store('CA','LocalMachine')
                            $x509Store.Open('ReadWrite')
                            $x509Store.Add($certificate)
                            $x509Store.Dispose()
                        }
                    }
                }

                # Test that the signing certificate is a trusted certificate.
                if ($signingCertificate)
                {
                    if (Test-MicrosoftCertificate -Certificate $signingCertificate)
                    {
                        Write-Verbose "Valid and msft $XmlPath,$($signingCertificate.Thumbprint)"
                        $validSignature = $true
                        $isSignedByMicrosoft = $true
                    }
                    elseif (Test-AlternateRoot -Certificate $signingCertificate)
                    {
                        Write-Verbose "Alt $XmlPath,$($signingCertificate.Thumbprint)"
                        $validSignature = $true
                        $isSignedByMicrosoft = $true
                    }
                    else
                    {
                        Write-Warning "Untrusted $XmlPath,$($signingCertificate.Thumbprint)"
                    }
                }
                else
                {
                    # We did not find a signing certificate, so the signature is not valid.
                    Write-Verbose "Invalid $XmlPath"
                }
            }
        }
    }
    else
    {
        Write-Warning ($LocalizedStrings.OEMPackageUnsigned -f $XmlPath)
    }

    # Fail if the package is unsigned or the signature is invalid or untrusted.
    if (-not $validSignature)
    {
        throw ("OEMPackageInvalid -f $XmlPath")
    }

    return $isSignedByMicrosoft
}

# this function is based on code from PowerShellGet
function Test-MicrosoftCertificate
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param (
        [Parameter(Mandatory = $true)]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]
        $Certificate
    )

    try
    {
        $requiredAssembly = @( [System.Management.Automation.PSCmdlet].Assembly.FullName,
                               [System.Net.IWebProxy].Assembly.FullName,
                               [System.Uri].Assembly.FullName )
        $source = @"
using System;
using System.Net;
using System.Management.Automation;
using Microsoft.Win32.SafeHandles;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
 
namespace Microsoft.PowerShell.CodeSigning
{
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct CERT_CHAIN_POLICY_PARA {
        public CERT_CHAIN_POLICY_PARA(int size) {
            cbSize = (uint) size;
            dwFlags = 0;
            pvExtraPolicyPara = IntPtr.Zero;
        }
        public uint cbSize;
        public uint dwFlags;
        public IntPtr pvExtraPolicyPara;
    }
 
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct CERT_CHAIN_POLICY_STATUS {
        public CERT_CHAIN_POLICY_STATUS(int size) {
            cbSize = (uint) size;
            dwError = 0;
            lChainIndex = IntPtr.Zero;
            lElementIndex = IntPtr.Zero;
            pvExtraPolicyStatus = IntPtr.Zero;
        }
        public uint cbSize;
        public uint dwError;
        public IntPtr lChainIndex;
        public IntPtr lElementIndex;
        public IntPtr pvExtraPolicyStatus;
    }
 
    public class Helper
    {
        [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public extern static
        bool CertVerifyCertificateChainPolicy(
            [In] IntPtr pszPolicyOID,
            [In] SafeX509ChainHandle pChainContext,
            [In] ref CERT_CHAIN_POLICY_PARA pPolicyPara,
            [In,Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);
 
        [DllImport("Crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)]
        public static extern
        SafeX509ChainHandle CertDuplicateCertificateChain(
            [In] IntPtr pChainContext);
 
        public static bool IsMicrosoftCertificate([In] SafeX509ChainHandle pChainContext)
        {
            const uint MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG = 0x00010000;
 
            CERT_CHAIN_POLICY_PARA PolicyPara = new CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_PARA)));
            CERT_CHAIN_POLICY_STATUS PolicyStatus = new CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(CERT_CHAIN_POLICY_STATUS)));
            int CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7;
 
            PolicyPara.dwFlags = (uint) MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG;
 
            if(!CertVerifyCertificateChainPolicy(new IntPtr(CERT_CHAIN_POLICY_MICROSOFT_ROOT),
                                                 pChainContext,
                                                 ref PolicyPara,
                                                 ref PolicyStatus))
            {
                return false;
            }
 
            return (PolicyStatus.dwError == 0);
        }
    }
}
"@

        Add-Type -ReferencedAssemblies $requiredAssembly -TypeDefinition $source -Language CSharp -ErrorAction Stop
    }
    catch
    {
        Write-Verbose "Error $($_.ToString())"
        return $false
    }

    try
    {
        $X509Chain = New-Object System.Security.Cryptography.X509Certificates.X509Chain
        $null = $X509Chain.Build($Certificate)
    }
    catch
    {
        Write-Verbose "eror $($_.ToString())"
        return $false
    }

    $SafeX509ChainHandle = [Microsoft.PowerShell.CodeSigning.Helper]::CertDuplicateCertificateChain($X509Chain.ChainContext)
    return [Microsoft.PowerShell.CodeSigning.Helper]::IsMicrosoftCertificate($SafeX509ChainHandle)
}





function Test-AlternateRoot
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    Param (
        [Parameter(Mandatory = $true)]
        [System.Security.Cryptography.X509Certificates.X509Certificate2]
        $Certificate,

        # Alternate roots are select Microsoft roots published here --> https://www.microsoft.com/pkiops/docs/repository.htm
        [System.String[]]
        $AlternateRoots = @(
            '8F43288AD272F3103B6FB1428485EA3014C0BCFE'
            '3B1EFD3A66EA28B16697394703A72CA340A05BD5'
        )
    )

    $result = $false

    $x509Chain = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Chain
    $null = $x509Chain.Build($Certificate)
    foreach ($alternateRoot in $AlternateRoots)
    {
        if ($x509Chain.ChainElements.Certificate[-1].Thumbprint -eq $alternateRoot)
        {
            $result = $true
        }
    }

    return $result
}

Test-XMLSignatureByMicrosoft -XmlPath $XmlPath
# SIG # Begin signature block
# MIIoKAYJKoZIhvcNAQcCoIIoGTCCKBUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBfHGnPgodyxRpv
# G/St++7Y0eIwAbuTLv/kEWu2O2T3TKCCDXYwggX0MIID3KADAgECAhMzAAADTrU8
# esGEb+srAAAAAANOMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
# bmcgUENBIDIwMTEwHhcNMjMwMzE2MTg0MzI5WhcNMjQwMzE0MTg0MzI5WjB0MQsw
# CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u
# ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy
# b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
# AQDdCKiNI6IBFWuvJUmf6WdOJqZmIwYs5G7AJD5UbcL6tsC+EBPDbr36pFGo1bsU
# p53nRyFYnncoMg8FK0d8jLlw0lgexDDr7gicf2zOBFWqfv/nSLwzJFNP5W03DF/1
# 1oZ12rSFqGlm+O46cRjTDFBpMRCZZGddZlRBjivby0eI1VgTD1TvAdfBYQe82fhm
# WQkYR/lWmAK+vW/1+bO7jHaxXTNCxLIBW07F8PBjUcwFxxyfbe2mHB4h1L4U0Ofa
# +HX/aREQ7SqYZz59sXM2ySOfvYyIjnqSO80NGBaz5DvzIG88J0+BNhOu2jl6Dfcq
# jYQs1H/PMSQIK6E7lXDXSpXzAgMBAAGjggFzMIIBbzAfBgNVHSUEGDAWBgorBgEE
# AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUnMc7Zn/ukKBsBiWkwdNfsN5pdwAw
# RQYDVR0RBD4wPKQ6MDgxHjAcBgNVBAsTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEW
# MBQGA1UEBRMNMjMwMDEyKzUwMDUxNjAfBgNVHSMEGDAWgBRIbmTlUAXTgqoXNzci
# tW2oynUClTBUBgNVHR8ETTBLMEmgR6BFhkNodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
# b20vcGtpb3BzL2NybC9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3JsMGEG
# CCsGAQUFBwEBBFUwUzBRBggrBgEFBQcwAoZFaHR0cDovL3d3dy5taWNyb3NvZnQu
# Y29tL3BraW9wcy9jZXJ0cy9NaWNDb2RTaWdQQ0EyMDExXzIwMTEtMDctMDguY3J0
# MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggIBAD21v9pHoLdBSNlFAjmk
# mx4XxOZAPsVxxXbDyQv1+kGDe9XpgBnT1lXnx7JDpFMKBwAyIwdInmvhK9pGBa31
# TyeL3p7R2s0L8SABPPRJHAEk4NHpBXxHjm4TKjezAbSqqbgsy10Y7KApy+9UrKa2
# kGmsuASsk95PVm5vem7OmTs42vm0BJUU+JPQLg8Y/sdj3TtSfLYYZAaJwTAIgi7d
# hzn5hatLo7Dhz+4T+MrFd+6LUa2U3zr97QwzDthx+RP9/RZnur4inzSQsG5DCVIM
# pA1l2NWEA3KAca0tI2l6hQNYsaKL1kefdfHCrPxEry8onJjyGGv9YKoLv6AOO7Oh
# JEmbQlz/xksYG2N/JSOJ+QqYpGTEuYFYVWain7He6jgb41JbpOGKDdE/b+V2q/gX
# UgFe2gdwTpCDsvh8SMRoq1/BNXcr7iTAU38Vgr83iVtPYmFhZOVM0ULp/kKTVoir
# IpP2KCxT4OekOctt8grYnhJ16QMjmMv5o53hjNFXOxigkQWYzUO+6w50g0FAeFa8
# 5ugCCB6lXEk21FFB1FdIHpjSQf+LP/W2OV/HfhC3uTPgKbRtXo83TZYEudooyZ/A
# Vu08sibZ3MkGOJORLERNwKm2G7oqdOv4Qj8Z0JrGgMzj46NFKAxkLSpE5oHQYP1H
# tPx1lPfD7iNSbJsP6LiUHXH1MIIHejCCBWKgAwIBAgIKYQ6Q0gAAAAAAAzANBgkq
# hkiG9w0BAQsFADCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24x
# EDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlv
# bjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
# IDIwMTEwHhcNMTEwNzA4MjA1OTA5WhcNMjYwNzA4MjEwOTA5WjB+MQswCQYDVQQG
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSgwJgYDVQQDEx9NaWNyb3NvZnQg
# Q29kZSBTaWduaW5nIFBDQSAyMDExMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
# CgKCAgEAq/D6chAcLq3YbqqCEE00uvK2WCGfQhsqa+laUKq4BjgaBEm6f8MMHt03
# a8YS2AvwOMKZBrDIOdUBFDFC04kNeWSHfpRgJGyvnkmc6Whe0t+bU7IKLMOv2akr
# rnoJr9eWWcpgGgXpZnboMlImEi/nqwhQz7NEt13YxC4Ddato88tt8zpcoRb0Rrrg
# OGSsbmQ1eKagYw8t00CT+OPeBw3VXHmlSSnnDb6gE3e+lD3v++MrWhAfTVYoonpy
# 4BI6t0le2O3tQ5GD2Xuye4Yb2T6xjF3oiU+EGvKhL1nkkDstrjNYxbc+/jLTswM9
# sbKvkjh+0p2ALPVOVpEhNSXDOW5kf1O6nA+tGSOEy/S6A4aN91/w0FK/jJSHvMAh
# dCVfGCi2zCcoOCWYOUo2z3yxkq4cI6epZuxhH2rhKEmdX4jiJV3TIUs+UsS1Vz8k
# A/DRelsv1SPjcF0PUUZ3s/gA4bysAoJf28AVs70b1FVL5zmhD+kjSbwYuER8ReTB
# w3J64HLnJN+/RpnF78IcV9uDjexNSTCnq47f7Fufr/zdsGbiwZeBe+3W7UvnSSmn
# Eyimp31ngOaKYnhfsi+E11ecXL93KCjx7W3DKI8sj0A3T8HhhUSJxAlMxdSlQy90
# lfdu+HggWCwTXWCVmj5PM4TasIgX3p5O9JawvEagbJjS4NaIjAsCAwEAAaOCAe0w
# ggHpMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBRIbmTlUAXTgqoXNzcitW2o
# ynUClTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYwDwYD
# VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBRyLToCMZBDuRQFTuHqp8cx0SOJNDBa
# BgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2Ny
# bC9wcm9kdWN0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3JsMF4GCCsG
# AQUFBwEBBFIwUDBOBggrBgEFBQcwAoZCaHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXQyMDExXzIwMTFfMDNfMjIuY3J0MIGfBgNV
# HSAEgZcwgZQwgZEGCSsGAQQBgjcuAzCBgzA/BggrBgEFBQcCARYzaHR0cDovL3d3
# dy5taWNyb3NvZnQuY29tL3BraW9wcy9kb2NzL3ByaW1hcnljcHMuaHRtMEAGCCsG
# AQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAHAAbwBsAGkAYwB5AF8AcwB0AGEAdABl
# AG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQBn8oalmOBUeRou09h0ZyKb
# C5YR4WOSmUKWfdJ5DJDBZV8uLD74w3LRbYP+vj/oCso7v0epo/Np22O/IjWll11l
# hJB9i0ZQVdgMknzSGksc8zxCi1LQsP1r4z4HLimb5j0bpdS1HXeUOeLpZMlEPXh6
# I/MTfaaQdION9MsmAkYqwooQu6SpBQyb7Wj6aC6VoCo/KmtYSWMfCWluWpiW5IP0
# wI/zRive/DvQvTXvbiWu5a8n7dDd8w6vmSiXmE0OPQvyCInWH8MyGOLwxS3OW560
# STkKxgrCxq2u5bLZ2xWIUUVYODJxJxp/sfQn+N4sOiBpmLJZiWhub6e3dMNABQam
# ASooPoI/E01mC8CzTfXhj38cbxV9Rad25UAqZaPDXVJihsMdYzaXht/a8/jyFqGa
# J+HNpZfQ7l1jQeNbB5yHPgZ3BtEGsXUfFL5hYbXw3MYbBL7fQccOKO7eZS/sl/ah
# XJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbSoqKfenoi+kiVH6v7RyOA
# 9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sLgOppO6/8MO0ETI7f33Vt
# Y5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtXcVZOSEXAQsmbdlsKgEhr
# /Xmfwb1tbWrJUnMTDXpQzTGCGggwghoEAgEBMIGVMH4xCzAJBgNVBAYTAlVTMRMw
# EQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVN
# aWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNp
# Z25pbmcgUENBIDIwMTECEzMAAANOtTx6wYRv6ysAAAAAA04wDQYJYIZIAWUDBAIB
# BQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQwHAYKKwYBBAGCNwIBCzEO
# MAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIGTxnPG/fsuRxOYg6xZ73ZLV
# MXq7b9tGjBLalt7Ymi81MEIGCisGAQQBgjcCAQwxNDAyoBSAEgBNAGkAYwByAG8A
# cwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20wDQYJKoZIhvcNAQEB
# BQAEggEAdJj9Ifh/FuQjBhpQsK+EgkSQzchrV+7Sfl0VgV6+BSliocNOdfWm1PvX
# kZzRnz2PocKTBcnhMyyjMwFH+P7f2SaTQ9d0mJiANBuwXJKW8ceCU9Hz0lIATVJR
# CUTlYZZWqrvWjdbcl1vj5F4IMni20ktGbVYDoyY959Mz8HbKBrdj5qhoGVo11kZN
# r8OJgPkMkOT/tWkxJEZgAwyUAWsbU0bNJpzbq64OS1y1g1lPkO0s0xU2d5v1betY
# meEx/bZRadKCUkJxUzY0R6WwVQW7OqFme39zdpFCIeLz6bSyJ4PZcolah/5JRONB
# 8PmGwNtAjoB/ZJ3KSAt/PSNt4FUiF6GCF5IwgheOBgorBgEEAYI3AwMBMYIXfjCC
# F3oGCSqGSIb3DQEHAqCCF2swghdnAgEDMQ8wDQYJYIZIAWUDBAIBBQAwggFQBgsq
# hkiG9w0BCRABBKCCAT8EggE7MIIBNwIBAQYKKwYBBAGEWQoDATAxMA0GCWCGSAFl
# AwQCAQUABCBfIMjHac46oUYJPZtBArWlAVAIirHtw8mMbcWbrsZqiwIGZMvn7DW4
# GBEyMDIzMDgwNzIxMzMzMi43WjAEgAIB9KCB0aSBzjCByzELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoT
# FU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJp
# Y2EgT3BlcmF0aW9uczEnMCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM3MDMtMDVF
# MC1EOTQ3MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNloIIR
# 6jCCByAwggUIoAMCAQICEzMAAAHU5OkDL8CsaawAAQAAAdQwDQYJKoZIhvcNAQEL
# BQAwfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcT
# B1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UE
# AxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwHhcNMjMwNTI1MTkxMjI3
# WhcNMjQwMjAxMTkxMjI3WjCByzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
# b3JhdGlvbjElMCMGA1UECxMcTWljcm9zb2Z0IEFtZXJpY2EgT3BlcmF0aW9uczEn
# MCUGA1UECxMeblNoaWVsZCBUU1MgRVNOOjM3MDMtMDVFMC1EOTQ3MSUwIwYDVQQD
# ExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIICIjANBgkqhkiG9w0BAQEF
# AAOCAg8AMIICCgKCAgEAmFPeLZsCJJd+d0lno9cm1nEgG7vBS8ExLTr8N7lzKWtQ
# 5w1w8G7ZC3PqE/ATbYvLft/E8JLX4KADPTfwTh8k+AqVwdR8J9WGKL7mLo6EFfZJ
# slOg+kLbUyCje32U46DbSISOQgZMEvjJMAsHWjcskr48D72bsR/ETXDjgfAAQ4SR
# /r8P43r/httBxNBsGnd9t8eLgOLS5BNHvcmg+8f7NRd5bezYuO6STBjC6mUAiu1A
# lHlmrlhfcGSDUOOfbUjyHv8SurbS8mB83dw3kUS8UD/+3O6DyTwxYKWxgdh0SWhN
# KbkUQ6Igz+yScWK/kwRMYSNrpWVm4C+An1msMG9S7CZhViR26hq+qNIq1uyKg5H9
# qhGzEU9VlDNeReaAXOS4NfJW97FFu5ET7ysJn2kQZK5opdB/7b9x2MhOgOPdGRRH
# D5Onc2ACnwnt7yqUVROHT6AylZwi1Ey5KtX/6Z7g/2RhydnG7iHq/bpkGLvxc9Qw
# a3gvAkbN8yZuPByEt623i1GLvwvd41SCTpaygL/6pmEcpow5qX82b37xgRlGzqcf
# uKH8KgUy7oQHzuxWc99/DbbIw86t7IkdHD++KfVLjV9U6c+CmSzPBpc2S43t2h3w
# 95rpazyDIqZ1agZJGNdmtrJbGyJY3t7qvAUq4+9uf8BwreB8l1uFoExj4s8hMU0C
# AwEAAaOCAUkwggFFMB0GA1UdDgQWBBQ82ozHcLQGehKAeR3nXLK7tAx2STAfBgNV
# HSMEGDAWgBSfpxVdAF5iXYP05dJlpxtTNRnpcjBfBgNVHR8EWDBWMFSgUqBQhk5o
# dHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NybC9NaWNyb3NvZnQlMjBU
# aW1lLVN0YW1wJTIwUENBJTIwMjAxMCgxKS5jcmwwbAYIKwYBBQUHAQEEYDBeMFwG
# CCsGAQUFBzAChlBodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRz
# L01pY3Jvc29mdCUyMFRpbWUtU3RhbXAlMjBQQ0ElMjAyMDEwKDEpLmNydDAMBgNV
# HRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMA4GA1UdDwEB/wQEAwIH
# gDANBgkqhkiG9w0BAQsFAAOCAgEAtMVDz/srcJLXUYWJWfQZOP2y8yzs6vsHAu1Q
# GkUBxkUviD8lP/Di4laF3KMiiiokUOyvXPdDnTPqi+D4syp0rSwwbFk/nbNYWsjZ
# E8J4VXGXgNRBipTWb3ZU7AlMSeQu8qGUJgPtpaZNODxo3BYR9YBkaYc/rXAzSvwr
# Sifj6xLjY+7IJgaKfyRUHGMpoj/76/nbnaykHkrXE1fVtd3JthQ+Rf11jt+04vhu
# E4NQZFNuUQPrfEQlsvyB7oN662M6lHHVUau1IEZeNGCJEzZ7nKOp8u7xAZlhY3K+
# 0pL6P0FrnjvDQLz9mSn90DH4nZh9cb8cfYfcFVOq7xEPz1CYt6aKWLK0CrqIKYXT
# 6h2eY/TqEPhIwAlH4CZR55/BlWz1t8RqZQpF28hB4XkDXf2t1/9s6UsBETjnMtWG
# nkKrn5RopQH9MuNABSqltkNck29fXEVwaUc22VTvkV1AeAOlC9RNV47c6/2/as/V
# OFDVfMMvGL/9O26d4QBX8QeJp9HPjzvmBb9mLFb2AE1SNpcC/UA0hLfBdEVui3pM
# T3725JlUkcD+qX+QFH5KqKCmuqX6kwp3aRk+9R8opbXpWjIUVLDVZGiswCa1KBEk
# o+7Ez9WRokvSYCPqdwDuX5zIbd5ixzIOvBrM0h+Fst71AyaY1E2C7Wk1pELc+lKm
# Tze1l4YwggdxMIIFWaADAgECAhMzAAAAFcXna54Cm0mZAAAAAAAVMA0GCSqGSIb3
# DQEBCwUAMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4G
# A1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTIw
# MAYDVQQDEylNaWNyb3NvZnQgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAx
# MDAeFw0yMTA5MzAxODIyMjVaFw0zMDA5MzAxODMyMjVaMHwxCzAJBgNVBAYTAlVT
# MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK
# ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1l
# LVN0YW1wIFBDQSAyMDEwMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA
# 5OGmTOe0ciELeaLL1yR5vQ7VgtP97pwHB9KpbE51yMo1V/YBf2xK4OK9uT4XYDP/
# XE/HZveVU3Fa4n5KWv64NmeFRiMMtY0Tz3cywBAY6GB9alKDRLemjkZrBxTzxXb1
# hlDcwUTIcVxRMTegCjhuje3XD9gmU3w5YQJ6xKr9cmmvHaus9ja+NSZk2pg7uhp7
# M62AW36MEBydUv626GIl3GoPz130/o5Tz9bshVZN7928jaTjkY+yOSxRnOlwaQ3K
# Ni1wjjHINSi947SHJMPgyY9+tVSP3PoFVZhtaDuaRr3tpK56KTesy+uDRedGbsoy
# 1cCGMFxPLOJiss254o2I5JasAUq7vnGpF1tnYN74kpEeHT39IM9zfUGaRnXNxF80
# 3RKJ1v2lIH1+/NmeRd+2ci/bfV+AutuqfjbsNkz2K26oElHovwUDo9Fzpk03dJQc
# NIIP8BDyt0cY7afomXw/TNuvXsLz1dhzPUNOwTM5TI4CvEJoLhDqhFFG4tG9ahha
# YQFzymeiXtcodgLiMxhy16cg8ML6EgrXY28MyTZki1ugpoMhXV8wdJGUlNi5UPkL
# iWHzNgY1GIRH29wb0f2y1BzFa/ZcUlFdEtsluq9QBXpsxREdcu+N+VLEhReTwDwV
# 2xo3xwgVGD94q0W29R6HXtqPnhZyacaue7e3PmriLq0CAwEAAaOCAd0wggHZMBIG
# CSsGAQQBgjcVAQQFAgMBAAEwIwYJKwYBBAGCNxUCBBYEFCqnUv5kxJq+gpE8RjUp
# zxD/LwTuMB0GA1UdDgQWBBSfpxVdAF5iXYP05dJlpxtTNRnpcjBcBgNVHSAEVTBT
# MFEGDCsGAQQBgjdMg30BATBBMD8GCCsGAQUFBwIBFjNodHRwOi8vd3d3Lm1pY3Jv
# c29mdC5jb20vcGtpb3BzL0RvY3MvUmVwb3NpdG9yeS5odG0wEwYDVR0lBAwwCgYI
# KwYBBQUHAwgwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0PBAQDAgGG
# MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9lJBb186a
# GMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3Br
# aS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3JsMFoGCCsG
# AQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29t
# L3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwDQYJKoZIhvcN
# AQELBQADggIBAJ1VffwqreEsH2cBMSRb4Z5yS/ypb+pcFLY+TkdkeLEGk5c9MTO1
# OdfCcTY/2mRsfNB1OW27DzHkwo/7bNGhlBgi7ulmZzpTTd2YurYeeNg2LpypglYA
# A7AFvonoaeC6Ce5732pvvinLbtg/SHUB2RjebYIM9W0jVOR4U3UkV7ndn/OOPcbz
# aN9l9qRWqveVtihVJ9AkvUCgvxm2EhIRXT0n4ECWOKz3+SmJw7wXsFSFQrP8DJ6L
# GYnn8AtqgcKBGUIZUnWKNsIdw2FzLixre24/LAl4FOmRsqlb30mjdAy87JGA0j3m
# Sj5mO0+7hvoyGtmW9I/2kQH2zsZ0/fZMcm8Qq3UwxTSwethQ/gpY3UA8x1RtnWN0
# SCyxTkctwRQEcb9k+SS+c23Kjgm9swFXSVRk2XPXfx5bRAGOWhmRaw2fpCjcZxko
# JLo4S5pu+yFUa2pFEUep8beuyOiJXk+d0tBMdrVXVAmxaQFEfnyhYWxz/gq77EFm
# PWn9y8FBSX5+k77L+DvktxW/tM4+pTFRhLy/AsGConsXHRWJjXD+57XQKBqJC482
# 2rpM+Zv/Cuk0+CQ1ZyvgDbjmjJnW4SLq8CdCPSWU5nR0W2rRnj7tfqAxM328y+l7
# vzhwRNGQ8cirOoo6CGJ/2XBjU02N7oJtpQUQwXEGahC0HVUzWLOhcGbyoYIDTTCC
# AjUCAQEwgfmhgdGkgc4wgcsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5n
# dG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9y
# YXRpb24xJTAjBgNVBAsTHE1pY3Jvc29mdCBBbWVyaWNhIE9wZXJhdGlvbnMxJzAl
# BgNVBAsTHm5TaGllbGQgVFNTIEVTTjozNzAzLTA1RTAtRDk0NzElMCMGA1UEAxMc
# TWljcm9zb2Z0IFRpbWUtU3RhbXAgU2VydmljZaIjCgEBMAcGBSsOAwIaAxUALTNd
# lo6NscQObHbswf9x3c2ZokiggYMwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UE
# CBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
# b2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQ
# Q0EgMjAxMDANBgkqhkiG9w0BAQsFAAIFAOh7rFkwIhgPMjAyMzA4MDcxNzQ2MDFa
# GA8yMDIzMDgwODE3NDYwMVowdDA6BgorBgEEAYRZCgQBMSwwKjAKAgUA6HusWQIB
# ADAHAgEAAgI3RzAHAgEAAgISpTAKAgUA6Hz92QIBADA2BgorBgEEAYRZCgQCMSgw
# JjAMBgorBgEEAYRZCgMCoAowCAIBAAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3
# DQEBCwUAA4IBAQByExPLhrjvVK2zW4Ov9KYRPKgJ5ajywfgQLmkCpBquzfxSyG9u
# tW9CnjCU4kLbqklyqDuKGWiJfeHwhsJNXatwb8Fbq7440hRZCtchKh2x1apY4Lbs
# VfsPzI719wXLkQXOTqvtvbuJ0C7a18i6G8dLRY69jcTyxZ3BuE9pvqgbczyj+XxL
# /oq2Vc/gruN32nNrqPPKS+FXGBHtco6kysCJ1nW9New8Y2GoKR6Eqaitvif7ctGQ
# hymJ2y4y+Xyl+FQCCOIx9/w3MAPU8lT9CRgGQhEGX94GXG2o5kRI/PY5RzbDqeYL
# +qlSGZJeaNZmNtDCIrkeymoxDcaxqPd3PKcaMYIEDTCCBAkCAQEwgZMwfDELMAkG
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTACEzMAAAHU5OkDL8CsaawAAQAAAdQwDQYJ
# YIZIAWUDBAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkq
# hkiG9w0BCQQxIgQgcL2723SQt8xuKabWyo77O1DcA1KGgKDCxZ37pDM9kpIwgfoG
# CyqGSIb3DQEJEAIvMYHqMIHnMIHkMIG9BCDM6of62BSlzpc71kucQrT4vWlPnwVJ
# MSK4l6dlkz1iNzCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
# AhMzAAAB1OTpAy/ArGmsAAEAAAHUMCIEIOxDhGTqKJgwb/EpGwy3QW8xp/X052fM
# rNb2cjcqyvtyMA0GCSqGSIb3DQEBCwUABIICAF9iOkB/Dyh0YI1dN1jHwGe+B1jb
# iA135jL4XUpB2tf0boqnUfVC8mi8MD9vH0Ysq2cgH8LginR2EGx9ef7q5gxtf09I
# ouYyo71eBWUGY9ZGwiypKoMssXsdci9sVPRjJgT156MAYrTWvhFw+sFTiwcCXSXz
# CWEBbPcJL5XidNbwU6ZZHhXtZma/F96PKn1BbSt3MCbR1nQAaP+ALwmmz6Z4PyDE
# qtS3d736hDy6hjG5kOkjl38GsLUlos9VM6oGp23f6ij3fD2GWb2IFZ2bB7+OWY1Z
# veXchEOnwXEOGG3orbOty6ETVjlJRczq4g+CVw0wYv34f0iHMOR1mgHhyQtq9MSd
# dUqg4iJnY4q12USFzEHWtxn1X2aYUJmwEgX37bz79W52d2eJC8PrSQvE1XYe6f4A
# +F0xc9Lc64B2yJLcNcA3aMjE/YkEJbI0Lxwfqs5o24akegCHc1SkN62y86cuenY1
# LghViNvsysODfZc1I4C/UcvQdL61kedZr73eOlAh1Uz7ZNJurBbFLgJCQ484VrPt
# iY9bCZQIzJ8wwhFZBMntBRe/xQasOVzPFMLveru2VwJOmxc5Noq7zd3fvCFHl5d1
# 1z2kY1TY0BxX0OK3LC11/2L/hXgtHvDKOOQfdgrfGHRk355FTMdPJfvwF+YitkUe
# EHCDbVtBS0ys8lQW
# SIG # End signature block