<#
.SYNOPSIS
  Vergleicht einen E-Voting Image USB Stick mit einem Referenz-Image und prüft ob sämtliche Dateien darauf vertrauenswürdig sind

.DESCRIPTION
  Prüft einen E-Voting Image USB Stick, in dem er ihn mit einem bekannten unmodifizierten Microsoft Windows ISO vergleicht,
  sowie Signaturen und Hash-Werte prüft.
  Dateien erfüllen die Prüfung, falls sie einer der folgenden drei Kriterien erfüllen: Sie sind identisch auf der originalen
  Microsoft ISO vorhanden, sie sind mit einem vertrauenswürdigen Zertifikat signiert, oder ihr Hash hat einen bekannten
  korrekten Wert.

.PARAMETER ReferenceISO
  Pfad zu einer unmodifizierten Windows LTSC 2021 Deutsch ISO Datei

.PARAMETER ImageUSB
  Laufwerksbuchstabe des USB Sticks, der geprüft werden soll

.PARAMETER DisplayPositiveResults
  Falls dieser Parameter gesetzt ist, werden auch erfolgreich geprüfte Dateien in der Konsole angezeigt

.INPUTS
  None

.OUTPUTS
  Eine Datei namens 'evoting_imagecheck.csv' wird im Dokumente-Ordner erstellt

.NOTES
  Version:        1.11
  Author:         Ontrex AG - Athman Boukhaoua
  Creation Date:  20.10.2022
  Purpose/Change: Script erstellt

.LINK  
  www.ontrex.ch
#>


param(
    [Parameter(Mandatory=$true)][string]$ReferenceISO,
    [Parameter(Mandatory=$true)][string]$ImageUSB,
    [switch]$DisplayPositiveResults = $false
)

# A list of certificate CNs we trust to sign executables
$trusted_signers = @(
    'CN=Ontrex AG, OU=CTO, O=Ontrex AG, L=Bruettisellen, S=Zuerich, C=CH'
    'CN="Open Source Developer, Dominik Reichl", O=Open Source Developer, L=Metzingen, S=Baden-Württemberg, C=DE'
    'E=don.h@free.fr, CN="NOTEPAD++", O="NOTEPAD++", L=Paris, S=Île-de-France, C=FR'
    'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
    'CN=Microsoft Windows, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
    'CN=.NET, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
    'CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
    'CN=Microsoft Windows Publisher, O=Microsoft Corporation, L=Redmond, S=Washington, C=US'
    'CN=Ghisler Software GmbH, O=Ghisler Software GmbH, S=Bern, C=CH'
    'CN=A.E.T. Europe B.V., O=A.E.T. Europe B.V., L=Arnhem, S=Gelderland, C=NL'
    'CN=HP Inc., O=HP Inc., L=Palo Alto, S=California, C=US'
    'CN=HP Inc., OU=HP Cybersecurity, O=HP Inc., L=Palo Alto, S=California, C=US'
    'CN=Lenovo, OU=G10, O=Lenovo, L=Morrisville, S=North Carolina, C=US'
    'CN=Lenovo, OU=G11, O=Lenovo, L=Morrisville, S=North Carolina, C=US'
    'CN=Lenovo, O=Lenovo, L=Morrisville, S=North Carolina, C=US'
)

# A list of known hash values of files we have customized that aren't possible to sign
$trusted_hashes = @{
    'de-de_windows_10_enterprise_ltsc_2021_x64_dvd_71796d33.iso' = '710D8854127054B696152388C8527EF5D526ED5ECDFFF8B664F4C9EC809F6053'
    'de-de_windows_11_enterprise_ltsc_2024_x64_dvd_4f136f69.iso' = '1175FE9681F93C56F1A54A4363F801785CEC95DEFF1E980F2F4120AD567C4803'
    'autounattend.xml' = 'CE88B4A068DDE6E164F95E4C29DBC61903994E828D13B2559E5DCEEB7C829A1B'
    'gmp.dll' = '74970AC1F9570B301D22788E62BF5D51CB885001A3CB630BA2C9DB798D5DEC30'
    '7z2501-x64.msi' = 'E7EB0B7ED5EFA4E087B7B17F191797F7AF5B7F442D1290C66F3A21777005EF57'
    'openssl-3.6.0-win64.zip' = '4B074F2D6797F802D3A5851440CB1C3696F2E627F97BD87A48B04A9A506FBA30'
    'vmgj.zip' = '486DB645F8FF5E7223E37E412D5C6F2C45ECADD813EE14ADDBC93E3D8A142D67'
    'kse-560-setup.exe' = '656D03DD7BDBC862162389DB9BF63331D4B855D68A6156D3834098508ECB1BC8'
    'npp.8.8.5.Installer.x64.exe' = 'C6D1E5AACBF69AA18DF4CAF1346FD69638491A5AD0085729BAE91C662D1C62BB'
    'credentialguard.txt' = '9B2926AB458C37018AFC42158E087C42EDCAADE269B8E3CDDC13EEE41C0335F8'
    'ie_user.txt' = '93A751DDEEF902B3C300089BEC2F55F5DE8E67BDDF0FA1DB4F872962C6624036'
    'user.txt' = '1182AE66BDFE6796B3364DEC63DD2F82EC6DE19BE42E0B14B167390902350C16'
    'ie_computer.txt' = '961750F0FF1923BD084843C6771D0F212367BF1F19A1E9C70734E6212301B123'
    'defender.txt' = '016E13150DA8573CF55DDA319C4E7C14480921C6233E1078D46704FFC24983DD'
    'computer.txt' = '8D9277777FE7FD61C97A08A0BD14676977DE6D202067E64EAFAF243DD33E6B46'
    'bitlocker.txt' = '9B38454AA10CF67183C60980E8301917A3480D371C1B77A965872439AEFAC199'
    'edge.txt' = 'D942E516992B88A119093E3D23A1D77371B1822AFE211BF10290FF26968D1880'
    'cis.txt' = '6DFCFDF9FFC433D2E73FDF3097EF1F90764F0158C02518CBD47444777B806F05'
    'custom.txt' = 'F9D754E445A49AD0851EDBAE2EA4E8C2FA0FCDD8E345C041D46DCD1846DFE2FA'
    'code128.ttf' = '2998DE8D2EBED4F31BC7CE8F1A0414342D35068149A6A52C14BCE8EC8BCCB0DB'
    'OB______.TTF' = '82E335C05518655E045CE0584DF3A1B2F209EA43F3EE743AA82F48FE42FC1C05'
    'RobotoMono-Bold.ttf' = '3F4E0CD7747DF32A34748A66C1274D76712CAB429C75E75F5F0167319B97FCCB'
    'LayoutModification.xml' = '88D640375DC4C2122C32718A2EAD4EA05BAD9A8924F7AB833F92E86C6B562C6C'
    'timechangeforusers.inf' = 'CE632B7D6C65D15D3E398C180644E019ED83368C2DE84A2F4DF8F7FB71895CE9'
}


# Check if a file is signed, and if yes, whether the signing authority is in the list of trusted signers
function check-signature($file_name)
{
    # Get the signature of this file
    $signature = Get-AuthenticodeSignature $file_name

    # Verify if it's valid
    if ($signature.Status -eq [System.Management.Automation.SignatureStatus]::Valid) {
        # If it's valid, get the identity of the signer, and check if it's in our accepted list of signers
        $certificate = $signature.SignerCertificate
        if ($trusted_signers -contains $certificate.Subject) {
            # Only if the signature is valid and from an approved certificate, we return true
            return @{Result=$true; Signer=$certificate.Subject.Split(',')[0]}
        }
        else {
            Write-Host "$($certificate.Subject) is untrusted"
        }
    }

    # In any other case, return false
    return @{Result=$false; Signer="unsigned"}
}

# Calculate the hash of a file, and check if it matches a known trusted value
function check-hash($file_name)
{
    # Get the SHA-256 hash of the file
    $hash = (Get-FileHash $file_name).Hash

    # See if it's in our table of safe hashes
    if ($trusted_hashes[(Split-Path $file_name -Leaf)] -eq $hash) {
        # Return true if it is in there
        return @{Result=$true; Hash=$hash}
    }

    # And false if it couldn't be found, or wasn't equal
    return @{Result=$false; Hash=$hash}
}

# Mount an ISO file and return the drive letter it was mounted to
function mount-iso($path)
{
    # First find out which CD ROM drives already exist
    [array]$old_drives = (Get-Volume | ? DriveType -eq 'CD-ROM').DriveLetter

    # Then mount the ISO file and get another list of CD ROM drives
    $mount_info = Mount-DiskImage $ReferenceISO
    [array]$new_drives = (Get-Volume | ? DriveType -eq 'CD-ROM').DriveLetter

    # Then find out which CD ROM drive has just newly appeared and return that one's drive letter
    $r = ''
    $new_drives | % { if ($old_drives -notcontains $_) { $r = $_ } }

    $r
}

function process-result($filename, $result, $reason, $info)
{
    # Write a summary of the result to the console
    if ($result -eq 'ok') {
        if ($DisplayPositiveResults) {
            switch ($reason) {
                'original' {
                    Write-Host "$filename ok because original" -ForegroundColor Green
                }
                'signature' {
                    Write-Host "$filename ok by signature" -ForegroundColor Green
                }
                'hash' {
                    Write-Host "$filename ok by hash" -ForegroundColor Green
                }
            }
        }
    }
    else {
        Write-Host "$filename not ok" -ForegroundColor Red
    }

    # Format the results as an object so we can later output everything in a table
    New-Object PSObject -Property @{
        FileName = $filename
        Result = $result
        Reason = $reason
        Info = $info
    }
}





Write-Host "Verifying integrity of the reference ISO file"
$isofile = Get-FileHash $ReferenceISO
if ($isofile.Hash -ne $trusted_hashes['de-de_windows_10_enterprise_ltsc_2021_x64_dvd_71796d33.iso'] -and $isofile.Hash -ne $trusted_hashes['de-de_windows_11_enterprise_ltsc_2024_x64_dvd_4f136f69.iso']) {
    Write-Host "Reference ISO file does not have the correct hash value" -ForegroundColor Red
    exit 1
}
Write-Host "  ISO file is ok"





Write-Host "Mounting reference ISO file"
$reference_drive = mount-iso $ReferenceISO

if (-not $reference_drive) {
    Write-Host "  Could not mount $ReferenceISO" -ForegroundColor Red
    exit 1
}
Write-Host "  Mounted to drive $reference_drive"




$verification_results = @()

ls $ImageUSB -File -Force -Recurse | % {
    $file_to_check = $_.FullName

    # Construct the name of the file to compare it with by removing the drive letter of the customized image
    # and instead adding the one from the original ISO
    $reference_file = $reference_drive + $file_to_check.Substring(1)

    if (Test-Path $reference_file) {
        # If this file also exists on the original Microsoft ISO image, then compare its hash with the original
        $reference_hash = Get-FileHash $reference_file
        $check_hash = Get-FileHash $file_to_check

        if ($check_hash.Hash -eq $reference_hash.Hash) {
            $verification_results += process-result $file_to_check "ok" "original" $check_hash.Hash
        }
        else {
            $verification_results += process-result $file_to_check "failed" "original" $check_hash.Hash
        }
    }
    else {
        # This file doesn't exist on the original ISO, so we have to check its signature

        $signature_check = check-signature $file_to_check

        if ($signature_check.Result) {
            $verification_results += process-result $file_to_check "ok" "signature" $signature_check.Signer
        }
        else {
            # If the file doesn't have a signature, then check the hash instead
            $hash_check = check-hash $file_to_check

            if ($hash_check.Result) {
                $verification_results += process-result $file_to_check "ok" "hash" $hash_check.Hash
            }
            else {
                $verification_results += process-result $file_to_check "failed" "hash" $hash_check.Hash
            }
        }


    }
}

$result_filename = Join-Path ([Environment]::GetFolderPath(“mydocuments”)) "evoting_imagecheck.csv"
$verification_results | Export-Csv $result_filename -NoTypeInformation -Encoding UTF8
Write-Host "Results of the scan have been written to:`n$result_filename"

Write-Host "Unmounting reference image"
Dismount-DiskImage $ReferenceISO | Out-Null

# SIG # Begin signature block
# MIIpaAYJKoZIhvcNAQcCoIIpWTCCKVUCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCBT9lybwtmSdBMu
# qfkk9VzKlnEfBtjoWmb/PPTJtnx7+qCCDh0wggawMIIEmKADAgECAhAIrUCyYNKc
# TJ9ezam9k67ZMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV
# BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0z
# NjA0MjgyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
# ggIKAoICAQDVtC9C0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0
# JAfhS0/TeEP0F9ce2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJr
# Q5qZ8sU7H/Lvy0daE6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhF
# LqGfLOEYwhrMxe6TSXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+F
# LEikVoQ11vkunKoAFdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh
# 3K3kGKDYwSNHR7OhD26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJ
# wZPt4bRc4G/rJvmM1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQay
# g9Rc9hUZTO1i4F4z8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbI
# YViY9XwCFjyDKK05huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchAp
# QfDVxW0mdmgRQRNYmtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRro
# OBl8ZhzNeDhFMJlP/2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IB
# WTCCAVUwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+
# YXsIiGX0TkIwHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0P
# AQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAk
# BggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAC
# hjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9v
# dEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAED
# MAgGBmeBDAEEATANBgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql
# +Eg08yy25nRm95RysQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFF
# UP2cvbaF4HZ+N3HLIvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1h
# mYFW9snjdufE5BtfQ/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3Ryw
# YFzzDaju4ImhvTnhOE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5Ubdld
# AhQfQDN8A+KVssIhdXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw
# 8MzK7/0pNVwfiThV9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnP
# LqR0kq3bPKSchh/jwVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatE
# QOON8BUozu3xGFYHKi8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bn
# KD+sEq6lLyJsQfmCXBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQji
# WQ1tygVQK+pKHJ6l/aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbq
# yK+p/pQd52MbOoZWeE4wggdlMIIFTaADAgECAhAFEg3W08Ss3uSAihKAChYEMA0G
# CSqGSIb3DQEBCwUAMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwg
# SW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcg
# UlNBNDA5NiBTSEEzODQgMjAyMSBDQTEwHhcNMjUwNjEyMDAwMDAwWhcNMjgwNjI5
# MjM1OTU5WjBtMQswCQYDVQQGEwJDSDEQMA4GA1UECBMHWnVlcmljaDEWMBQGA1UE
# BxMNQnJ1ZXR0aXNlbGxlbjESMBAGA1UEChMJT250cmV4IEFHMQwwCgYDVQQLEwND
# VE8xEjAQBgNVBAMTCU9udHJleCBBRzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC
# AgoCggIBAOeaXMlEzCcl/YFheOTiqcGlcahquUGqGwoqChBXqGeoKL8nB46vNgMd
# eKm6ivXxGf7uvlOdfcIVn0PB74qeqdRtnzG/E6mGTV+UaNsvaEaRNT7vUFQQ9o+y
# oYgwGJGtrlt9O58+i+A2fUkG/yZnXPSD3RdTLECoyuiYl5taxrcUEII5V00lH3kQ
# Ah88or51ET7Pxv7rY4ZQ9ikfaG4uvTpTqqqjYP1z+3PyLlBPQjgAMvOxM8IWjNfC
# TB38Fd+Eo8D1sMTXOs4Ts27KL0rPns/awzlDBNuDWBJGxLtl2bb9VizgLVHEHuPr
# TPaTTR5arhSQdU+x9oX0kX8jjUWQE+HDVqexqoi+X+JJGHCX4S+rEGokOlcqq0L6
# fMWeD2HpFVIMq131ibMT0vlM0t3X0twotGTm5S28tubyT19u7+JQ9Rta4PDu5+JW
# iZiulV5aSIjkCjIan/RMKAGzTee6wZnI0eeHKSnliZr1nqhEt4d4NQrLP35EHsxx
# Ss/DC4gf/gIQknh7u1c/SsWn4RJf65fMUhERjqInybek+0FiNM/IHb0Wy0mciuBK
# aolqUPuwCt4A36sCEuyE5Vw9Ic2jhLMHXhzo/LiH8gpFveFU6mwpOl/xyTdGRnPj
# V+Kia16yfQlSdSXgkWH5oexILdWHwRaQ/H5xQF4VHrLdCM/shWE9AgMBAAGjggID
# MIIB/zAfBgNVHSMEGDAWgBRoN+Drtjv4XxGG+/5hewiIZfROQjAdBgNVHQ4EFgQU
# MGoSLq8bMCN/OIbK12YRP+XXyl8wPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggr
# BgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ1BTMA4GA1UdDwEB/wQE
# AwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1o
# dHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2ln
# bmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQu
# ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2
# U0hBMzg0MjAyMUNBMS5jcmwwgZQGCCsGAQUFBwEBBIGHMIGEMCQGCCsGAQUFBzAB
# hhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wXAYIKwYBBQUHMAKGUGh0dHA6Ly9j
# YWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFRydXN0ZWRHNENvZGVTaWduaW5n
# UlNBNDA5NlNIQTM4NDIwMjFDQTEuY3J0MAkGA1UdEwQCMAAwDQYJKoZIhvcNAQEL
# BQADggIBAHs0iImarS84t4jRD/4IttOIYGtvJGCe5AAqCvInI42VLeUkeq6IfNI8
# 6y5YsgrYm0WBnl+AN5IX/QZJtzX75N347jjVawZbmcs0JXKmmQyEgUaAuhfpIn8Z
# WB1+UZ8/dhSJD9FcgR6G/mzJh5uEEkGHxJMp1K3AbpJYWm1XqpJHlFYEEN/Te2RZ
# ek7V+W9NnCJKeSSWksvKbHXoXphm3Y6+8gSkMJw3TxR44R/MsrNRJwUABMmaTBOa
# xRkLlHYaOcZ1nyPnD25dy80WBKjnNP/QifKJtKVy9kkxy8BH3w2Q5gdqJB4Y74xf
# zqHAQxEqBasnf1gWVxeWMNW//Ct0SUI60vyrspmhSNJ830omaogy/6g/pzQ0AxWl
# oPlyvV6ipoJZ5KDZkD8iGNS59PmUwNv/rL/0/O50ggUdC4QfLBiLUavMbYbI685f
# sYK/RrV1bt0C8ux2oVigDrQLaGriLq2/wU0ywuV9FUDWurlXHSALcFnHMbmbmw9t
# a4+XcJiZ3F7qlTvwYUXW0SO2O8C7XKu47TwFFNeWe8glUKeSm60oSGcFA0GXtGCo
# asIlrlR3FTaJgfmkyiughotZtlFO3O7WPbbIiPmY66nLQcJP7rQ5F7gXSBN4abIB
# fCDOaEZZwFhycRGS+5wMSPR3l3wS9R49Gec/gu+N1o6df716shRmMYIaoTCCGp0C
# AQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xQTA/
# BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQgQ29kZSBTaWduaW5nIFJTQTQwOTYg
# U0hBMzg0IDIwMjEgQ0ExAhAFEg3W08Ss3uSAihKAChYEMA0GCWCGSAFlAwQCAQUA
# oHwwEAYKKwYBBAGCNwIBDDECMAAwGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIL1C
# XHR8rCMQr37vxi9V7m8rpraNsaw6at2qahKEgXTjMA0GCSqGSIb3DQEBAQUABIIC
# AJb6RCBlx4lqlNgHbd5LZXE5oBwDFCJYxD++nvt3PGnLj3kLVXnRTF0VLHBpPXps
# 5Ts8TDr5LbPbgYclgH5H/ZN0EFaz2U4XX38eEEbdfE0JXlebl/Uis2k5n4Q9ITxC
# jj+0u0sEenWWsT2+t0Xsni+1VIKZJuoKLx6P9/nh/NdA22wuNIVHYLN26yNt6yx0
# 1M4vLAu65sZ7SMb1jNiT+CHR/97asyqtzuY8oCD6mNQCJWMiQX1l/V2rJtTg1Tz/
# Tfm4268PpjDKozgxXJXp/fVMLruu/ZOOttqpqo6kjJuMAJYVQZKYSK/eYcCa1kFz
# 1WyR7Yf7Up6YM7oKdzgAOAOzJKnVA1EbTW98kC9dQriY3+u3nDqc4NvFdVYWHlmK
# zowo8GEzNUT3Kg4LettH2OMORTnS/hL8yAwEtFy7Ng/YGkkuRkytvbRKPw5/0Hva
# rpqzBwo/xzETg+pxy+gXcFvSu5VDIciq2LY6J9pSvm01cQBNZoWElOYPnIE7fB7I
# KsVYmHq1Hrrf+GEnQOo1TnrNary7wSoOUptZpJulV1pQMcUQ/47UmB6QoGeH0Lym
# AwWjfOE80C7n+/sYGWlECZBJiWikJU1y4Aejy8GNQa/n/3xP7o+sfmxu7CECowLq
# m0trzzZwsv4PuI0BeEV94yJr7CKM+w2P7qB9Le5E+56joYIXdzCCF3MGCisGAQQB
# gjcDAwExghdjMIIXXwYJKoZIhvcNAQcCoIIXUDCCF0wCAQMxDzANBglghkgBZQME
# AgEFADB4BgsqhkiG9w0BCRABBKBpBGcwZQIBAQYJYIZIAYb9bAcBMDEwDQYJYIZI
# AWUDBAIBBQAEIKRe3M+fJbjtYpFz1waVl4Qq0k11D6DXexo4LB4yBdTFAhEA83rW
# Zd+NSVfscXPsHnzUeBgPMjAyNTEyMDIxMDUwMjRaoIITOjCCBu0wggTVoAMCAQIC
# EAqA7xhLjfEFgtHEdqeVdGgwDQYJKoZIhvcNAQELBQAwaTELMAkGA1UEBhMCVVMx
# FzAVBgNVBAoTDkRpZ2lDZXJ0LCBJbmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVz
# dGVkIEc0IFRpbWVTdGFtcGluZyBSU0E0MDk2IFNIQTI1NiAyMDI1IENBMTAeFw0y
# NTA2MDQwMDAwMDBaFw0zNjA5MDMyMzU5NTlaMGMxCzAJBgNVBAYTAlVTMRcwFQYD
# VQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQgU0hBMjU2IFJT
# QTQwOTYgVGltZXN0YW1wIFJlc3BvbmRlciAyMDI1IDEwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQDQRqwtEsae0OquYFazK1e6b1H/hnAKAd/KN8wZQjBj
# MqiZ3xTWcfsLwOvRxUwXcGx8AUjni6bz52fGTfr6PHRNv6T7zsf1Y/E3IU8kgNke
# ECqVQ+3bzWYesFtkepErvUSbf+EIYLkrLKd6qJnuzK8Vcn0DvbDMemQFoxQ2Dsw4
# vEjoT1FpS54dNApZfKY61HAldytxNM89PZXUP/5wWWURK+IfxiOg8W9lKMqzdIo7
# VA1R0V3Zp3DjjANwqAf4lEkTlCDQ0/fKJLKLkzGBTpx6EYevvOi7XOc4zyh1uSqg
# r6UnbksIcFJqLbkIXIPbcNmA98Oskkkrvt6lPAw/p4oDSRZreiwB7x9ykrjS6GS3
# NR39iTTFS+ENTqW8m6THuOmHHjQNC3zbJ6nJ6SXiLSvw4Smz8U07hqF+8CTXaETk
# VWz0dVVZw7knh1WZXOLHgDvundrAtuvz0D3T+dYaNcwafsVCGZKUhQPL1naFKBy1
# p6llN3QgshRta6Eq4B40h5avMcpi54wm0i2ePZD5pPIssoszQyF4//3DoK2O65Uc
# k5Wggn8O2klETsJ7u8xEehGifgJYi+6I03UuT1j7FnrqVrOzaQoVJOeeStPeldYR
# NMmSF3voIgMFtNGh86w3ISHNm0IaadCKCkUe2LnwJKa8TIlwCUNVwppwn4D3/Pt5
# pwIDAQABo4IBlTCCAZEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU5Dv88jHt/f3X
# 85FxYxlQQ89hjOgwHwYDVR0jBBgwFoAU729TSunkBnx6yuKQVvYv1Ensy04wDgYD
# VR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIGVBggrBgEFBQcB
# AQSBiDCBhTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMF0G
# CCsGAQUFBzAChlFodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkRzRUaW1lU3RhbXBpbmdSU0E0MDk2U0hBMjU2MjAyNUNBMS5jcnQwXwYD
# VR0fBFgwVjBUoFKgUIZOaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
# VHJ1c3RlZEc0VGltZVN0YW1waW5nUlNBNDA5NlNIQTI1NjIwMjVDQTEuY3JsMCAG
# A1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOC
# AgEAZSqt8RwnBLmuYEHs0QhEnmNAciH45PYiT9s1i6UKtW+FERp8FgXRGQ/YAavX
# zWjZhY+hIfP2JkQ38U+wtJPBVBajYfrbIYG+Dui4I4PCvHpQuPqFgqp1PzC/ZRX4
# pvP/ciZmUnthfAEP1HShTrY+2DE5qjzvZs7JIIgt0GCFD9ktx0LxxtRQ7vllKluH
# WiKk6FxRPyUPxAAYH2Vy1lNM4kzekd8oEARzFAWgeW3az2xejEWLNN4eKGxDJ8WD
# l/FQUSntbjZ80FU3i54tpx5F/0Kr15zW/mJAxZMVBrTE2oi0fcI8VMbtoRAmaasl
# NXdCG1+lqvP4FbrQ6IwSBXkZagHLhFU9HCrG/syTRLLhAezu/3Lr00GrJzPQFnCE
# H1Y58678IgmfORBPC1JKkYaEt2OdDh4GmO0/5cHelAK2/gTlQJINqDr6JfwyYHXS
# d+V08X1JUPvB4ILfJdmL+66Gp3CSBXG6IwXMZUXBhtCyIaehr0XkBoDIGMUG1dUt
# wq1qmcwbdUfcSYCn+OwncVUXf53VJUNOaMWMts0VlRYxe5nK+At+DI96HAlXHAL5
# SlfYxJ7La54i71McVWRP66bW+yERNpbJCjyCYG2j+bdpxo/1Cy4uPcU3AWVPGrbn
# 5PhDBf3Froguzzhk++ami+r3Qrx5bIbY3TVzgiFI7Gq3zWcwgga0MIIEnKADAgEC
# AhANx6xXBf8hmS5AQyIMOkmGMA0GCSqGSIb3DQEBCwUAMGIxCzAJBgNVBAYTAlVT
# MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
# b20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0yNTA1MDcw
# MDAwMDBaFw0zODAxMTQyMzU5NTlaMGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5E
# aWdpQ2VydCwgSW5jLjFBMD8GA1UEAxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBUaW1l
# U3RhbXBpbmcgUlNBNDA5NiBTSEEyNTYgMjAyNSBDQTEwggIiMA0GCSqGSIb3DQEB
# AQUAA4ICDwAwggIKAoICAQC0eDHTCphBcr48RsAcrHXbo0ZodLRRF51NrY0NlLWZ
# loMsVO1DahGPNRcybEKq+RuwOnPhof6pvF4uGjwjqNjfEvUi6wuim5bap+0lgloM
# 2zX4kftn5B1IpYzTqpyFQ/4Bt0mAxAHeHYNnQxqXmRinvuNgxVBdJkf77S2uPoCj
# 7GH8BLuxBG5AvftBdsOECS1UkxBvMgEdgkFiDNYiOTx4OtiFcMSkqTtF2hfQz3zQ
# Sku2Ws3IfDReb6e3mmdglTcaarps0wjUjsZvkgFkriK9tUKJm/s80FiocSk1VYLZ
# lDwFt+cVFBURJg6zMUjZa/zbCclF83bRVFLeGkuAhHiGPMvSGmhgaTzVyhYn4p0+
# 8y9oHRaQT/aofEnS5xLrfxnGpTXiUOeSLsJygoLPp66bkDX1ZlAeSpQl92QOMeRx
# ykvq6gbylsXQskBBBnGy3tW/AMOMCZIVNSaz7BX8VtYGqLt9MmeOreGPRdtBx3yG
# OP+rx3rKWDEJlIqLXvJWnY0v5ydPpOjL6s36czwzsucuoKs7Yk/ehb//Wx+5kMqI
# MRvUBDx6z1ev+7psNOdgJMoiwOrUG2ZdSoQbU2rMkpLiQ6bGRinZbI4OLu9BMIFm
# 1UUl9VnePs6BaaeEWvjJSjNm2qA+sdFUeEY0qVjPKOWug/G6X5uAiynM7Bu2ayBj
# UwIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU729T
# SunkBnx6yuKQVvYv1Ensy04wHwYDVR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4c
# D08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMIMHcGCCsGAQUF
# BwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEG
# CCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRU
# cnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5k
# aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAgBgNVHSAEGTAX
# MAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggIBABfO+xaA
# HP4HPRF2cTC9vgvItTSmf83Qh8WIGjB/T8ObXAZz8OjuhUxjaaFdleMM0lBryPTQ
# M2qEJPe36zwbSI/mS83afsl3YTj+IQhQE7jU/kXjjytJgnn0hvrV6hqWGd3rLAUt
# 6vJy9lMDPjTLxLgXf9r5nWMQwr8Myb9rEVKChHyfpzee5kH0F8HABBgr0UdqirZ7
# bowe9Vj2AIMD8liyrukZ2iA/wdG2th9y1IsA0QF8dTXqvcnTmpfeQh35k5zOCPmS
# Nq1UH410ANVko43+Cdmu4y81hjajV/gxdEkMx1NKU4uHQcKfZxAvBAKqMVuqte69
# M9J6A47OvgRaPs+2ykgcGV00TYr2Lr3ty9qIijanrUR3anzEwlvzZiiyfTPjLbnF
# RsjsYg39OlV8cipDoq7+qNNjqFzeGxcytL5TTLL4ZaoBdqbhOhZ3ZRDUphPvSRmM
# Thi0vw9vODRzW6AxnJll38F0cuJG7uEBYTptMSbhdhGQDpOXgpIUsWTjd6xpR6oa
# Qf/DJbg3s6KCLPAlZ66RzIg9sC+NJpud/v4+7RWsWCiKi9EOLLHfMR2ZyJ/+xhCx
# 9yHbxtl5TPau1j/1MIDpMPx0LckTetiSuEtQvLsNz3Qbp7wGWqbIiOWCnb5WqxL3
# /BAPvIXKUjPSxyZsq8WhbaM2tszWkPZPubdcMIIFjTCCBHWgAwIBAgIQDpsYjvnQ
# Lefv21DiCEAYWjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UE
# ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYD
# VQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIwODAxMDAwMDAw
# WhcNMzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdp
# Q2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
# AoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Yq3aaza57G4QN
# xDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lXFllVcq9ok3DC
# srp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxeTsiT+CFhmzTr
# BcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbuyntd463JT17l
# Necxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I9YI+EJFwq1WC
# QTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmgZ92kJ7yhTzm1
# EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse5w5jrubU75KS
# Op493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKyEbe7f/LVjHAs
# QWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwhHbJUKSWJbOUO
# UlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/Y+whX8QgUWtv
# sauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwIDAQABo4IBOjCC
# ATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4c
# D08wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYDVR0PAQH/BAQD
# AgGGMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGln
# aWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5j
# b20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+MDwwOqA4oDaG
# NGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RD
# QS5jcmwwEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUAA4IBAQBwoL9D
# XFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSId229GhT0E0p6
# Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7Uz9FDRJtDIeuW
# cqFItJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxAGTVGamlUsLih
# Vo7spNU96LHc/RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAIDyyCwrFigDkBj
# xZgiwbJZ9VVrzyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW/VvRXKwYw02f
# c7cBqZ9Xql4o4rmUMYIDfDCCA3gCAQEwfTBpMQswCQYDVQQGEwJVUzEXMBUGA1UE
# ChMORGlnaUNlcnQsIEluYy4xQTA/BgNVBAMTOERpZ2lDZXJ0IFRydXN0ZWQgRzQg
# VGltZVN0YW1waW5nIFJTQTQwOTYgU0hBMjU2IDIwMjUgQ0ExAhAKgO8YS43xBYLR
# xHanlXRoMA0GCWCGSAFlAwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B
# CRABBDAcBgkqhkiG9w0BCQUxDxcNMjUxMjAyMTA1MDI0WjArBgsqhkiG9w0BCRAC
# DDEcMBowGDAWBBTdYjCshgotMGvaOLFoeVIwB/tBfjAvBgkqhkiG9w0BCQQxIgQg
# w2qpvZkkXMzLxc3/05lWNF58NeE9D2MYn01rbW+R2fkwNwYLKoZIhvcNAQkQAi8x
# KDAmMCQwIgQgSqA/oizXXITFXJOPgo5na5yuyrM/420mmqM08UYRCjMwDQYJKoZI
# hvcNAQEBBQAEggIARrb9qzHgb137DQeyY7Tbdn0KMEQPZn31M62+0UX4yFvbSTeb
# cxSdJCVS/rWJasm5Y8W+iWoa07dpxqa9ftzYbcA774tgIomm5F9Mvi1dXZmMc9cP
# 8gPtLp+S2jWil6d1JVj0489elyTw2vKLKybaihLjtkzo2GO127yGwlQRLnUT26Sl
# 0crdjxQyy4T9jYApQsWUFeGNSXBbsE5PwwgAfdIKATMC5M8ZEf1j3bF/o9/XAUzG
# ZXYWQcpscAYKJM9ARUBWFIgMFjAaE4JAVHQxVxMBfjc9X7Wg9YBTYDpQdt+Q1mU+
# GytFThIrgJ0eA1IcmoGccaosOJ7fmeSco7aAFn0ZnI63Qd1QZ7EM7G3udC8OHbff
# JXmkwXu4+IliuZYmjXCeW/izo3mt9fEN+Fm5sPJ0pYwFXXzcD+zDkAwQpPx4bsAS
# pFHbnqLw3zaXD7jiA7+HyCu7N57MWZECAV5XqzfcVoODKPxiJzCrUN87nQSTRV9/
# 58fQyV/xaQG4tLWK3y0AkMRia5L56zjiPK4d/D6mmCVzIZsFIXcsx/+Mb4OIdOOX
# 0fPpduFBV4ddOdfM+O4K/PVAkKAe9BlaIabI0nwLCap29qWScLi3Vg4XWtM46rd6
# D4TuVc0rXFkCNs2EYC/doZUL9hzY6eBMpxpo00K3xlbOAq0joKipLrZNzGs=
# SIG # End signature block
