public/cisa/exchange/ConvertFrom-MailAuthenticationRecordDmarc.ps1
<#
.SYNOPSIS Returns structured RFC compliant object for a DMARC record .DESCRIPTION Adapted from: - https://cloudbrothers.info/en/powershell-tip-resolve-spf/ - https://github.com/cisagov/ScubaGear/blob/main/PowerShell/ScubaGear/Modules/Providers/ExportEXOProvider.psm1 - https://xkln.net/blog/getting-mx-spf-dmarc-dkim-and-smtp-banners-with-powershell/ - DMARC https://datatracker.ietf.org/doc/html/rfc7489 ``` record : v=DMARC1; p=reject; pct=100; rua=mailto:itex-rua@microsoft.com; ruf=mailto:itex-ruf@microsoft.com; fo=1 valid : True policy : reject policySubdomain : percentage : 100 reportAggregate : {DMARCRecordUri} reportForensic : {DMARCRecordUri} reportFailure : {1} reportFailureFormats : {afrf} reportFrequency : 86400 alignmentDkim : r alignmentSpf : r version : DMARC1 warnings : {sp: No subdomain policy set, adkim: No DKIM alignment set, defaults to relaxed, aspf: No SPF alignment set, defaults to relaxed, ri: No report interval set, defaults to 86400 seconds…} ``` .EXAMPLE ConvertFrom-MailAuthenticationRecordDmarc -DomainName "microsoft.com" Returns [DMARCRecord] or "Failure to obtain record" .LINK https://maester.dev/docs/commands/ConvertFrom-MailAuthenticationRecordDmarc #> function ConvertFrom-MailAuthenticationRecordDmarc { [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Colors are beautiful')] [OutputType([DMARCRecord], [System.String])] [cmdletbinding()] param( [Parameter(Mandatory)] # Domain name to check. [string]$DomainName, # DNS-server to use for lookup. [ipaddress]$DnsServerIpAddress = "1.1.1.1", # Use a shorter timeout value for the DNS lookup. [switch]$QuickTimeout, # Ignore hosts file for domain lookup. [switch]$NoHostsFile ) begin { #[DMARCRecordUri]::new("mailto:itex-ruf@microsoft.com") class DMARCRecordUri { [string]$uri [mailaddress]$mailAddress [string]$reportSizeLimit hidden $option = [Text.RegularExpressions.RegexOptions]::IgnoreCase hidden $matchUri = "(?'uri'mailto:(?'address'[^,!]*)(?:!(?'size'\d+(?:k|m|g|t)))?)(?:,|$)" DMARCRecordUri([string]$uri) { $this.uri = $uri $match = [regex]::Match($uri, $this.matchUri, $this.option) $this.mailAddress = ($match.Groups | Where-Object { $_.Name -eq "address" }).Value $this.reportSizeLimit = ($match.Groups | Where-Object { $_.Name -eq "size" }).Value } } #[DMARCRecord]::new("v=DMARC1; p=reject; pct=100; rua=mailto:itex-rua@microsoft.com; ruf=mailto:itex-ruf@microsoft.com; fo=1") class DMARCRecord { [string]$record [bool]$valid [ValidateSet("none", "quarantine", "reject")] [string]$policy #p [string]$policySubdomain #sp [ValidateRange(0, 100)] [int]$percentage = 100 #pct [DMARCRecordUri[]]$reportAggregate #rua [DMARCRecordUri[]]$reportForensic #ruf [ValidateSet("0", "1", "d", "s")] [string[]]$reportFailure #fo [string[]]$reportFailureFormats = "afrf" #rf [int]$reportFrequency = 86400 #ri [ValidateSet("r", "s")] [string]$alignmentDkim = "r" #adkim [ValidateSet("r", "s")] [string]$alignmentSpf = "r" #aspf [string]$version = "DMARC1" [string[]]$warnings hidden $option = [Text.RegularExpressions.RegexOptions]::IgnoreCase hidden $matchInit = "^v\s*=\s*(?'v'DMARC1)\s*;\s*p\s*=\s*(?'p'none|quarantine|reject)(?:$|\s*;\s*)" hidden $matchSp = "sp\s*=\s*(?'sp'none|quarantine|reject)(?:$|\s*;\s*)" hidden $matchRua = "rua\s*=\s*(?'rua'[^;]+)(?:$|\s*;\s*)" hidden $matchRuf = "ruf\s*=\s*(?'ruf'[^;]+)(?:$|\s*;\s*)" hidden $matchUri = "(?'uri'mailto:(?'address'[^,!]*)(?:!(?'size'\d+(?:k|m|g|t)))?)(?:,|$)" hidden $matchAdkim = "adkim\s*=\s*(?'adkim'r|s)(?:$|\s*;\s*)" hidden $matchAspf = "aspf\s*=\s*(?'aspf'r|s)(?:$|\s*;\s*)" hidden $matchRi = "ri\s*=\s*(?'ri'\d+)(?:$|\s*;\s*)" hidden $matchFo = "fo\s*=\s*(?'fo'.{1})(?:$|\s*;\s*)" hidden $matchOptions = "(?'opt'[^:\s])(?:\s*:|\s*$)" hidden $matchRf = "rf\s*=\s*(?'rf'[^;]+)(?:$|\s*;\s*)" hidden $matchFormat = "(?'format'[^:\s]*)(?:\s*:|\s*$)" hidden $matchPct = "pct\s*=\s*(?'pct'\d{1,3})(?:$|\s*;\s*)" DMARCRecord([string]$record) { $this.record = $record $init = $record -match $this.matchInit $this.valid = $init if (-not $init) { $this.warnings += "v/p: Record version (v) and policy (p) configuration is not proper" exit } $this.version = $Matches["v"] $this.policy = $Matches["p"] $sp = $record -match $this.matchSp if (-not $sp) { $this.warnings += "sp: No subdomain policy set" } else { $this.policySubdomain = $Matches["sp"] } $rua = $record -match $this.matchRua if (-not $rua) { $this.warnings += "rua: No aggregate report URI set" } else { $uris = [regex]::Matches($Matches["rua"], $this.matchUri, $this.option) foreach ($uri in ($uris.Groups | Where-Object { $_.Name -eq "uri" })) { $this.reportAggregate += [DMARCRecordUri]::new("$uri") } if (($uris.Groups | Where-Object { $_.Name -eq "uri" } | Measure-Object).Count -gt 2) { $this.warnings += "ruf: More than 2 URIs set and may be ignored" } } $ruf = $record -match $this.matchRuf if (-not $ruf) { $this.warnings += "ruf: No forensic report URI set" } else { $uris = [regex]::Matches($Matches["ruf"], $this.matchUri, $this.option) foreach ($uri in ($uris.Groups | Where-Object { $_.Name -eq "uri" })) { $this.reportForensic += [DMARCRecordUri]::new("$uri") } if (($uris.Groups | Where-Object { $_.Name -eq "uri" } | Measure-Object).Count -gt 2) { $this.warnings += "ruf: More than 2 URIs set and may be ignored" } } $adkim = $record -match $this.matchAdkim if (-not $adkim) { $this.warnings += "adkim: No DKIM alignment set, defaults to relaxed" } else { $this.alignmentDkim = $Matches["adkim"] } $aspf = $record -match $this.matchAspf if (-not $aspf) { $this.warnings += "aspf: No SPF alignment set, defaults to relaxed" } else { $this.alignmentSpf = $Matches["aspf"] } $ri = $record -match $this.matchRi if (-not $ri) { $this.warnings += "ri: No report interval set, defaults to 86400 seconds" } else { $this.reportFrequency = $Matches["ri"] } $fo = $record -match $this.matchFo if (-not $fo) { $this.reportFailure = "0" $this.warnings += "fo: No failure reporting option specified, default (0) report when all mechanisms fail to pass" } elseif ($fo -and -not $ruf) { $this.warnings += "fo: Failure reporting option specified, but no ruf URI set" } else { $options = [regex]::Matches($Matches["fo"], $this.matchOptions, $this.option) foreach ($option in ($options.Groups | Where-Object { $_.Name -eq "opt" })) { $this.reportFailure += $option } } $rf = $record -match $this.matchRf if (-not $rf) { $this.warnings += "rf: No failure report format specified, defaults to afrf" } else { $formats = [regex]::Matches($Matches["rf"], $this.matchFormat, $this.option) foreach ($format in $formats.Groups | Where-Object { $_.Name -eq "format" }) { switch ($format.Value) { "afrf" { $this.reportFailureFormats += $format.Value } "" {} Default { $this.reportFailureFormats += $format.Value $this.warnings += "rf: Unkown failure report format ($($format.Value)) specified" } } } } $pct = $record -match $this.matchPct if (-not $pct) { $this.warnings += "pct: No percentage of messages specified to apply policy to, defaults to 100" } else { $this.percentage = $Matches["pct"] } } } } process { $dmarcPrefix = "_dmarc." $matchRecord = "^v\s*=\s*(?'v'DMARC1)\s*;\s*p\s*=\s*(?'p'none|quarantine|reject)(?:$|\s*;\s*)" $dmarcSplat = @{ Name = "$dmarcPrefix$DomainName" Type = "TXT" Server = $DnsServerIpAddress NoHostsFile = $NoHostsFile QuickTimeout = $QuickTimeout ErrorAction = "Stop" } try { if ( $isWindows -or $PSVersionTable.PSEdition -eq "Desktop") { $dmarcRecord = [DMARCRecord]::new((Resolve-DnsName @dmarcSplat | ` Where-Object { $_.Type -eq "TXT" } | ` Where-Object { $_.Strings -match $matchRecord }).Strings) } else { $cmdletCheck = Get-Command "Resolve-Dns" -ErrorAction SilentlyContinue if ($cmdletCheck) { $dmarcSplatAlt = @{ Query = $dmarcSplat.Name QueryType = $dmarcSplat.Type NameServer = $dmarcSplat.Server ErrorAction = $dmarcSplat.ErrorAction } $record = ((Resolve-Dns @dmarcSplatAlt).Answers | ` Where-Object { $_.RecordType -eq "TXT" } | ` Where-Object { $_.Text -imatch $matchRecord }).Text if ($record) { $dmarcRecord = [DMARCRecord]::new($record) } else { return "Failure to obtain record" } } else { Write-Verbose "`nFor non-Windows platforms, please install DnsClient-PS module." Write-Verbose "`n Install-Module DnsClient-PS -Scope CurrentUser`n" -ForegroundColor Yellow return "Missing dependency, Resolve-Dns not available" } } } catch [System.Management.Automation.CommandNotFoundException] { Write-Verbose $_ return "Unsupported platform, Resolve-DnsName not available" } catch { Write-Verbose $_ return "Failure to obtain record" } return $dmarcRecord } } # SIG # Begin signature block # MIIuqwYJKoZIhvcNAQcCoIIunDCCLpgCAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAtVzlDdD/9EDsh # LwlFwu1nYt5FpLlvzCrOQx4lbrIowaCCE5QwggWQMIIDeKADAgECAhAFmxtXno4h # MuI5B72nd3VcMA0GCSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNV # BAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9vdCBHNDAeFw0xMzA4MDExMjAwMDBaFw0z # ODAxMTUxMjAwMDBaMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB # AL/mkHNo3rvkXUo8MCIwaTPswqclLskhPfKK2FnC4SmnPVirdprNrnsbhA3EMB/z # G6Q4FutWxpdtHauyefLKEdLkX9YFPFIPUh/GnhWlfr6fqVcWWVVyr2iTcMKyunWZ # anMylNEQRBAu34LzB4TmdDttceItDBvuINXJIB1jKS3O7F5OyJP4IWGbNOsFxl7s # Wxq868nPzaw0QF+xembud8hIqGZXV59UWI4MK7dPpzDZVu7Ke13jrclPXuU15zHL # 2pNe3I6PgNq2kZhAkHnDeMe2scS1ahg4AxCN2NQ3pC4FfYj1gj4QkXCrVYJBMtfb # BHMqbpEBfCFM1LyuGwN1XXhm2ToxRJozQL8I11pJpMLmqaBn3aQnvKFPObURWBf3 # JFxGj2T3wWmIdph2PVldQnaHiZdpekjw4KISG2aadMreSx7nDmOu5tTvkpI6nj3c # AORFJYm2mkQZK37AlLTSYW3rM9nF30sEAMx9HJXDj/chsrIRt7t/8tWMcCxBYKqx # YxhElRp2Yn72gLD76GSmM9GJB+G9t+ZDpBi4pncB4Q+UDCEdslQpJYls5Q5SUUd0 # viastkF13nqsX40/ybzTQRESW+UQUOsxxcpyFiIJ33xMdT9j7CFfxCBRa2+xq4aL # T8LWRV+dIPyhHsXAj6KxfgommfXkaS+YHS312amyHeUbAgMBAAGjQjBAMA8GA1Ud # EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBTs1+OC0nFdZEzf # Lmc/57qYrhwPTzANBgkqhkiG9w0BAQwFAAOCAgEAu2HZfalsvhfEkRvDoaIAjeNk # aA9Wz3eucPn9mkqZucl4XAwMX+TmFClWCzZJXURj4K2clhhmGyMNPXnpbWvWVPjS # PMFDQK4dUPVS/JA7u5iZaWvHwaeoaKQn3J35J64whbn2Z006Po9ZOSJTROvIXQPK # 7VB6fWIhCoDIc2bRoAVgX+iltKevqPdtNZx8WorWojiZ83iL9E3SIAveBO6Mm0eB # cg3AFDLvMFkuruBx8lbkapdvklBtlo1oepqyNhR6BvIkuQkRUNcIsbiJeoQjYUIp # 5aPNoiBB19GcZNnqJqGLFNdMGbJQQXE9P01wI4YMStyB0swylIQNCAmXHE/A7msg # dDDS4Dk0EIUhFQEI6FUy3nFJ2SgXUE3mvk3RdazQyvtBuEOlqtPDBURPLDab4vri # RbgjU2wGb2dVf0a1TD9uKFp5JtKkqGKX0h7i7UqLvBv9R0oN32dmfrJbQdA75PQ7 # 9ARj6e/CVABRoIoqyc54zNXqhwQYs86vSYiv85KZtrPmYQ/ShQDnUBrkG5WdGaG5 # nLGbsQAe79APT0JsyQq87kP6OnGlyE0mpTX9iV28hWIdMtKgK1TtmlfB2/oQzxm3 # i0objwG2J5VT6LaJbVu8aNQj6ItRolb58KaAoNYes7wPD1N1KarqE3fk3oyBIa0H # EEcRrYc9B9F1vM/zZn4wggawMIIEmKADAgECAhAIrUCyYNKcTJ9ezam9k67ZMA0G # CSqGSIb3DQEBDAUAMGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ # bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0 # IFRydXN0ZWQgUm9vdCBHNDAeFw0yMTA0MjkwMDAwMDBaFw0zNjA0MjgyMzU5NTla # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDVtC9C # 0CiteLdd1TlZG7GIQvUzjOs9gZdwxbvEhSYwn6SOaNhc9es0JAfhS0/TeEP0F9ce # 2vnS1WcaUk8OoVf8iJnBkcyBAz5NcCRks43iCH00fUyAVxJrQ5qZ8sU7H/Lvy0da # E6ZMswEgJfMQ04uy+wjwiuCdCcBlp/qYgEk1hz1RGeiQIXhFLqGfLOEYwhrMxe6T # SXBCMo/7xuoc82VokaJNTIIRSFJo3hC9FFdd6BgTZcV/sk+FLEikVoQ11vkunKoA # FdE3/hoGlMJ8yOobMubKwvSnowMOdKWvObarYBLj6Na59zHh3K3kGKDYwSNHR7Oh # D26jq22YBoMbt2pnLdK9RBqSEIGPsDsJ18ebMlrC/2pgVItJwZPt4bRc4G/rJvmM # 1bL5OBDm6s6R9b7T+2+TYTRcvJNFKIM2KmYoX7BzzosmJQayg9Rc9hUZTO1i4F4z # 8ujo7AqnsAMrkbI2eb73rQgedaZlzLvjSFDzd5Ea/ttQokbIYViY9XwCFjyDKK05 # huzUtw1T0PhH5nUwjewwk3YUpltLXXRhTT8SkXbev1jLchApQfDVxW0mdmgRQRNY # mtwmKwH0iU1Z23jPgUo+QEdfyYFQc4UQIyFZYIpkVMHMIRroOBl8ZhzNeDhFMJlP # /2NPTLuqDQhTQXxYPUez+rbsjDIJAsxsPAxWEQIDAQABo4IBWTCCAVUwEgYDVR0T # AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHwYD # VR0jBBgwFoAU7NfjgtJxXWRM3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMG # A1UdJQQMMAoGCCsGAQUFBwMDMHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYY # aHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2Fj # ZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNV # HR8EPDA6MDigNqA0hjJodHRwOi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRU # cnVzdGVkUm9vdEc0LmNybDAcBgNVHSAEFTATMAcGBWeBDAEDMAgGBmeBDAEEATAN # BgkqhkiG9w0BAQwFAAOCAgEAOiNEPY0Idu6PvDqZ01bgAhql+Eg08yy25nRm95Ry # sQDKr2wwJxMSnpBEn0v9nqN8JtU3vDpdSG2V1T9J9Ce7FoFFUP2cvbaF4HZ+N3HL # IvdaqpDP9ZNq4+sg0dVQeYiaiorBtr2hSBh+3NiAGhEZGM1hmYFW9snjdufE5Btf # Q/g+lP92OT2e1JnPSt0o618moZVYSNUa/tcnP/2Q0XaG3RywYFzzDaju4ImhvTnh # OE7abrs2nfvlIVNaw8rpavGiPttDuDPITzgUkpn13c5UbdldAhQfQDN8A+KVssIh # dXNSy0bYxDQcoqVLjc1vdjcshT8azibpGL6QB7BDf5WIIIJw8MzK7/0pNVwfiThV # 9zeKiwmhywvpMRr/LhlcOXHhvpynCgbWJme3kuZOX956rEnPLqR0kq3bPKSchh/j # wVYbKyP/j7XqiHtwa+aguv06P0WmxOgWkVKLQcBIhEuWTatEQOON8BUozu3xGFYH # Ki8QxAwIZDwzj64ojDzLj4gLDb879M4ee47vtevLt/B3E+bnKD+sEq6lLyJsQfmC # XBVmzGwOysWGw/YmMwwHS6DTBwJqakAwSEs0qFEgu60bhQjiWQ1tygVQK+pKHJ6l # /aCnHwZ05/LWUpD9r4VIIflXO7ScA+2GRfS0YW6/aOImYIbqyK+p/pQd52MbOoZW # eE4wggdIMIIFMKADAgECAhAKgjCQR6s2I8rDH7I9rOuaMA0GCSqGSIb3DQEBCwUA # MGkxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjFBMD8GA1UE # AxM4RGlnaUNlcnQgVHJ1c3RlZCBHNCBDb2RlIFNpZ25pbmcgUlNBNDA5NiBTSEEz # ODQgMjAyMSBDQTEwHhcNMjIwNTE4MDAwMDAwWhcNMjUwNTE3MjM1OTU5WjBNMQsw # CQYDVQQGEwJERTEQMA4GA1UEBxMHSGFtYnVyZzEVMBMGA1UEChMMRmFiaWFuIEJh # ZGVyMRUwEwYDVQQDEwxGYWJpYW4gQmFkZXIwggIiMA0GCSqGSIb3DQEBAQUAA4IC # DwAwggIKAoICAQDBI8VJts4gUJjzaL//82nAioe/sYkIOqO74ImDtMCiMNXYINLP # vao3Y9iNXlqd+H+N4lUa0DsGsJ4paQvNUf0/ilbnaO4SHBF7t9u/uz4+SlOEsF3B # BeH8kcReki/2MuQ4YfdjGvGghLlt2fMp+7JSvyon8n5Tpr1KCQ6QU0zqkYcUZjZO # xEDzAyNN2mFgZMp/nzmEfiYPv8arV1vvYhAOmigpdg9mhtD4sC4u0X9GBNUfVi2D # /rWZ3bylXflDJm6MBxyhgmOANbN5zHs7tx1i7ACWw9+Hov5gVU7H0vK5pUVCDrDr # d7UM1gSC4iY+Xq1a0Aw4eaBfF3hrjD8fS29SSqM4fkrh1TgJaZwhKeR2Hax0c3DH # yCN9h7dPClbGUU5TUcRp7ocA0Xq1W0jJWFBHBLsnUM0k7Uog4ZkMGEqGI+SWvXtY # ydHl5gQI51xpyQcNP3JkndAeRPQYxrcqdlJHnpGE5vPs0fyWUlFJn/bLMM48CGIU # 6sqNk9hgvxHnbjxmTE7FtMlalOFbnd0o8zpv02i2qIlbmu7h45WrTKNIx208u21A # C7ocS00ojX3QCK/lc89BgzIjU8dUtjmxXumbfqEiljkRbbcecmzfTbgCIXjkU3Wb # EeVSSbtz4Jiw0BufJEmUhxTIXXbVqQU1W4ZBTBshCe2ZChr+TF3++ljakQIDAQAB # o4ICBjCCAgIwHwYDVR0jBBgwFoAUaDfg67Y7+F8Rhvv+YXsIiGX0TkIwHQYDVR0O # BBYEFPUKlMJ9lsMeVu5KQOaYqYXKAg45MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE # DDAKBggrBgEFBQcDAzCBtQYDVR0fBIGtMIGqMFOgUaBPhk1odHRwOi8vY3JsMy5k # aWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2lnbmluZ1JTQTQwOTZT # SEEzODQyMDIxQ0ExLmNybDBToFGgT4ZNaHR0cDovL2NybDQuZGlnaWNlcnQuY29t # L0RpZ2lDZXJ0VHJ1c3RlZEc0Q29kZVNpZ25pbmdSU0E0MDk2U0hBMzg0MjAyMUNB # MS5jcmwwPgYDVR0gBDcwNTAzBgZngQwBBAEwKTAnBggrBgEFBQcCARYbaHR0cDov # L3d3dy5kaWdpY2VydC5jb20vQ1BTMIGUBggrBgEFBQcBAQSBhzCBhDAkBggrBgEF # BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFwGCCsGAQUFBzAChlBodHRw # Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkRzRDb2RlU2ln # bmluZ1JTQTQwOTZTSEEzODQyMDIxQ0ExLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG # SIb3DQEBCwUAA4ICAQAJwchVKGCBGuhUPGL5IN8k6pUzZn3ZPbli/zHJYYxSbXhs # YQ4GCd8eIhQmYr0GmbST+GdgSlXkiWXz9F/bSX7K+XBOPWbiy3ZGvhzzhFIaatbz # eaRjEyGDlgu0uJl1p80JyS737bp2BnnfsrtgOEa4h5aDvTxVyECcMRvwKWKpYxgv # Doni9qBD3UTl6Y+mrsWEOzao0wSWeuNZQuNCRhEaUN/DbYBymy0KsQGRz7XxZmXo # EPY7DUPXCExXo/XjvZmBNyjo9ynwEqGuqihRerYIPBhclv+IU3BGe7sKzvy752Uu # 76xc3Gxsa49P0iD7k68LUWIcx45rhpLwdlKlNu7jDxxyUv0R1eqWBVcULY+UOKv/ # Zb1WP2zq2JKneF2Uft0g7kURCHwkut08XApdnx2uC8/box/XWMK/KQz5BCb2OEH9 # WECfCKySBSh0iR+jHRGMm0JCQ1PWheolUSvAGqX8hVBQ1AJHtDt8DxTaNTwUFORi # vJRABBogSrFq/dz4aoz3hOHcLkW+s67gJTbz8dm5ONlkIE/uzYRb//htFRBKdcHi # ZqzNRH7/xH5tf77J8f867UdAvloaj2rYvfqhpUWNozbzbDWnMUARR/SOClSQF4k4 # VR4W+KthbKp7H6grDLxXOCz4Ep3sU5KEtrvAJqLV+N9i+k7sbFul1gmpqc0yYDGC # Gm0wghppAgEBMH0waTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ # bmMuMUEwPwYDVQQDEzhEaWdpQ2VydCBUcnVzdGVkIEc0IENvZGUgU2lnbmluZyBS # U0E0MDk2IFNIQTM4NCAyMDIxIENBMQIQCoIwkEerNiPKwx+yPazrmjANBglghkgB # ZQMEAgEFAKCBhDAYBgorBgEEAYI3AgEMMQowCKACgAChAoAAMBkGCSqGSIb3DQEJ # AzEMBgorBgEEAYI3AgEEMBwGCisGAQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC8G # CSqGSIb3DQEJBDEiBCBiumLh4k4jZolVMTfZQVJ7hkHaVtDEriTrn7yr3G00LzAN # BgkqhkiG9w0BAQEFAASCAgAHxQmKzB6cIV5LOZ42N2s4rgRQEXkfKS4zqO+hViX0 # krNfNgZ1289x2bHCx1hOcz+S3gWV4RTwO9L2mOM/jTIp5hlNNzjYo8Y1lrRAROa0 # JI8/bDXtBitPDV0kMsMELa9H7zfqG1DBREhQNZNMNEpfkrG4X+bzk5WIS8kahryh # 2afyD2FuekcWF0388yAUZzosjm/oHcK/OWF+AjeaXJQ3jHZJ/ubngGiRE3gYupGE # e0o5Hauq7bxnk+FnzPatzBi57rSvQNdr/Lsp3q1To8VuixFodRNy/flcmlNBVDO2 # wANjzDXxNsxn6yeLPDv28KcFo/B4EBGOSwVKiQ2qrrI2NF4FP5we9bFwZPEeUF7s # hhU1EQWSyCBRffnBcYXx5Wq2jotbs7kdBXTkSiSRA5NlbmRh0GdUGAxbf0TKb3wZ # 4HhEU3iB4dhdpZF3RRsBVdTcAukTIUeHNdZSYv422zGPtX2r/XbTsGJRXz7eLiA2 # fPyQQmo71QoIgw9fUxnaS6WSL8neYc4tYdVoyfMpR6SSGH8FlwLAOCyr4KaEoHKw # wlazWELUFBjT47sGaP2EMOZs/hOpZiOwBPm3h3kH4kFm0UK3f/qS32kHWD908Ahs # MD618fMr1RUQ/KAPQ2OkqrXKzbQ/reaqrvhuNGHBoTzvDqF9cxhxb7vkROiq55Kp # faGCFzowghc2BgorBgEEAYI3AwMBMYIXJjCCFyIGCSqGSIb3DQEHAqCCFxMwghcP # AgEDMQ8wDQYJYIZIAWUDBAIBBQAweAYLKoZIhvcNAQkQAQSgaQRnMGUCAQEGCWCG # SAGG/WwHATAxMA0GCWCGSAFlAwQCAQUABCDbUBF/aymkpAK0klgivVfmu5C+DrM2 # j7Mg0aBLDh0jOQIRAKlN44x25O714Po0Iwnr5lMYDzIwMjQxMDIwMjAzNjI4WqCC # EwMwgga8MIIEpKADAgECAhALrma8Wrp/lYfG+ekE4zMEMA0GCSqGSIb3DQEBCwUA # MGMxCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UE # AxMyRGlnaUNlcnQgVHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBp # bmcgQ0EwHhcNMjQwOTI2MDAwMDAwWhcNMzUxMTI1MjM1OTU5WjBCMQswCQYDVQQG # EwJVUzERMA8GA1UEChMIRGlnaUNlcnQxIDAeBgNVBAMTF0RpZ2lDZXJ0IFRpbWVz # dGFtcCAyMDI0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvmpzn/aV # IauWMLpbbeZZo7Xo/ZEfGMSIO2qZ46XB/QowIEMSvgjEdEZ3v4vrrTHleW1JWGEr # rjOL0J4L0HqVR1czSzvUQ5xF7z4IQmn7dHY7yijvoQ7ujm0u6yXF2v1CrzZopykD # 07/9fpAT4BxpT9vJoJqAsP8YuhRvflJ9YeHjes4fduksTHulntq9WelRWY++TFPx # zZrbILRYynyEy7rS1lHQKFpXvo2GePfsMRhNf1F41nyEg5h7iOXv+vjX0K8RhUis # fqw3TTLHj1uhS66YX2LZPxS4oaf33rp9HlfqSBePejlYeEdU740GKQM7SaVSH3Tb # BL8R6HwX9QVpGnXPlKdE4fBIn5BBFnV+KwPxRNUNK6lYk2y1WSKour4hJN0SMkoa # NV8hyyADiX1xuTxKaXN12HgR+8WulU2d6zhzXomJ2PleI9V2yfmfXSPGYanGgxzq # I+ShoOGLomMd3mJt92nm7Mheng/TBeSA2z4I78JpwGpTRHiT7yHqBiV2ngUIyCtd # 0pZ8zg3S7bk4QC4RrcnKJ3FbjyPAGogmoiZ33c1HG93Vp6lJ415ERcC7bFQMRbxq # rMVANiav1k425zYyFMyLNyE1QulQSgDpW9rtvVcIH7WvG9sqYup9j8z9J1XqbBZP # J5XLln8mS8wWmdDLnBHXgYly/p1DhoQo5fkCAwEAAaOCAYswggGHMA4GA1UdDwEB # /wQEAwIHgDAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMCAG # A1UdIAQZMBcwCAYGZ4EMAQQCMAsGCWCGSAGG/WwHATAfBgNVHSMEGDAWgBS6Ftlt # TYUvcyl2mi91jGogj57IbzAdBgNVHQ4EFgQUn1csA3cOKBWQZqVjXu5Pkh92oFsw # WgYDVR0fBFMwUTBPoE2gS4ZJaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lD # ZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNybDCBkAYI # KwYBBQUHAQEEgYMwgYAwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0 # LmNvbTBYBggrBgEFBQcwAoZMaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0Rp # Z2lDZXJ0VHJ1c3RlZEc0UlNBNDA5NlNIQTI1NlRpbWVTdGFtcGluZ0NBLmNydDAN # BgkqhkiG9w0BAQsFAAOCAgEAPa0eH3aZW+M4hBJH2UOR9hHbm04IHdEoT8/T3HuB # SyZeq3jSi5GXeWP7xCKhVireKCnCs+8GZl2uVYFvQe+pPTScVJeCZSsMo1JCoZN2 # mMew/L4tpqVNbSpWO9QGFwfMEy60HofN6V51sMLMXNTLfhVqs+e8haupWiArSozy # AmGH/6oMQAh078qRh6wvJNU6gnh5OruCP1QUAvVSu4kqVOcJVozZR5RRb/zPd++P # GE3qF1P3xWvYViUJLsxtvge/mzA75oBfFZSbdakHJe2BVDGIGVNVjOp8sNt70+kE # oMF+T6tptMUNlehSR7vM+C13v9+9ZOUKzfRUAYSyyEmYtsnpltD/GWX8eM70ls1V # 6QG/ZOB6b6Yum1HvIiulqJ1Elesj5TMHq8CWT/xrW7twipXTJ5/i5pkU5E16RSBA # dOp12aw8IQhhA/vEbFkEiF2abhuFixUDobZaA0VhqAsMHOmaT3XThZDNi5U2zHKh # Us5uHHdG6BoQau75KiNbh0c+hatSF+02kULkftARjsyEpHKsF7u5zKRbt5oK5YGw # Fvgc4pEVUNytmB3BpIiowOIIuDgP5M9WArHYSAR16gc0dP2XdkMEP5eBsX7bf/MG # N4K3HP50v/01ZHo/Z5lGLvNwQ7XHBx1yomzLP8lx4Q1zZKDyHcp4VQJLu2kWTsKs # OqQwggauMIIElqADAgECAhAHNje3JFR82Ees/ShmKl5bMA0GCSqGSIb3DQEBCwUA # MGIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsT # EHd3dy5kaWdpY2VydC5jb20xITAfBgNVBAMTGERpZ2lDZXJ0IFRydXN0ZWQgUm9v # dCBHNDAeFw0yMjAzMjMwMDAwMDBaFw0zNzAzMjIyMzU5NTlaMGMxCzAJBgNVBAYT # AlVTMRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjE7MDkGA1UEAxMyRGlnaUNlcnQg # VHJ1c3RlZCBHNCBSU0E0MDk2IFNIQTI1NiBUaW1lU3RhbXBpbmcgQ0EwggIiMA0G # CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDGhjUGSbPBPXJJUVXHJQPE8pE3qZdR # odbSg9GeTKJtoLDMg/la9hGhRBVCX6SI82j6ffOciQt/nR+eDzMfUBMLJnOWbfhX # qAJ9/UO0hNoR8XOxs+4rgISKIhjf69o9xBd/qxkrPkLcZ47qUT3w1lbU5ygt69Ox # tXXnHwZljZQp09nsad/ZkIdGAHvbREGJ3HxqV3rwN3mfXazL6IRktFLydkf3YYMZ # 3V+0VAshaG43IbtArF+y3kp9zvU5EmfvDqVjbOSmxR3NNg1c1eYbqMFkdECnwHLF # uk4fsbVYTXn+149zk6wsOeKlSNbwsDETqVcplicu9Yemj052FVUmcJgmf6AaRyBD # 40NjgHt1biclkJg6OBGz9vae5jtb7IHeIhTZgirHkr+g3uM+onP65x9abJTyUpUR # K1h0QCirc0PO30qhHGs4xSnzyqqWc0Jon7ZGs506o9UD4L/wojzKQtwYSH8UNM/S # TKvvmz3+DrhkKvp1KCRB7UK/BZxmSVJQ9FHzNklNiyDSLFc1eSuo80VgvCONWPfc # Yd6T/jnA+bIwpUzX6ZhKWD7TA4j+s4/TXkt2ElGTyYwMO1uKIqjBJgj5FBASA31f # I7tk42PgpuE+9sJ0sj8eCXbsq11GdeJgo1gJASgADoRU7s7pXcheMBK9Rp6103a5 # 0g5rmQzSM7TNsQIDAQABo4IBXTCCAVkwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV # HQ4EFgQUuhbZbU2FL3MpdpovdYxqII+eyG8wHwYDVR0jBBgwFoAU7NfjgtJxXWRM # 3y5nP+e6mK4cD08wDgYDVR0PAQH/BAQDAgGGMBMGA1UdJQQMMAoGCCsGAQUFBwMI # MHcGCCsGAQUFBwEBBGswaTAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNl # cnQuY29tMEEGCCsGAQUFBzAChjVodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20v # RGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNydDBDBgNVHR8EPDA6MDigNqA0hjJodHRw # Oi8vY3JsMy5kaWdpY2VydC5jb20vRGlnaUNlcnRUcnVzdGVkUm9vdEc0LmNybDAg # BgNVHSAEGTAXMAgGBmeBDAEEAjALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQAD # ggIBAH1ZjsCTtm+YqUQiAX5m1tghQuGwGC4QTRPPMFPOvxj7x1Bd4ksp+3CKDaop # afxpwc8dB+k+YMjYC+VcW9dth/qEICU0MWfNthKWb8RQTGIdDAiCqBa9qVbPFXON # ASIlzpVpP0d3+3J0FNf/q0+KLHqrhc1DX+1gtqpPkWaeLJ7giqzl/Yy8ZCaHbJK9 # nXzQcAp876i8dU+6WvepELJd6f8oVInw1YpxdmXazPByoyP6wCeCRK6ZJxurJB4m # wbfeKuv2nrF5mYGjVoarCkXJ38SNoOeY+/umnXKvxMfBwWpx2cYTgAnEtp/Nh4ck # u0+jSbl3ZpHxcpzpSwJSpzd+k1OsOx0ISQ+UzTl63f8lY5knLD0/a6fxZsNBzU+2 # QJshIUDQtxMkzdwdeDrknq3lNHGS1yZr5Dhzq6YBT70/O3itTK37xJV77QpfMzmH # QXh6OOmc4d0j/R0o08f56PGYX/sr2H7yRp11LB4nLCbbbxV7HhmLNriT1ObyF5lZ # ynDwN7+YAN8gFk8n+2BnFqFmut1VwDophrCYoCvtlUG3OtUVmDG0YgkPCr2B2RP+ # v6TR81fZvAT6gt4y3wSJ8ADNXcL50CN/AAvkdgIm2fBldkKmKYcJRyvmfxqkhQ/8 # mJb2VVQrH4D6wPIOK+XW+6kvRBVK5xMOHds3OBqhK/bt1nz8MIIFjTCCBHWgAwIB # AgIQDpsYjvnQLefv21DiCEAYWjANBgkqhkiG9w0BAQwFADBlMQswCQYDVQQGEwJV # UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu # Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMjIw # ODAxMDAwMDAwWhcNMzExMTA5MjM1OTU5WjBiMQswCQYDVQQGEwJVUzEVMBMGA1UE # ChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSEwHwYD # VQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqGSIb3DQEBAQUA # A4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3yithZwuEppz1Y # q3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1Ifxp4VpX6+n6lX # FllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDVySAdYyktzuxe # TsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiODCu3T6cw2Vbu # yntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQjdjUN6QuBX2I # 9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/CNdaSaTC5qmg # Z92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCiEhtmmnTK3kse # 5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADMfRyVw4/3IbKy # Ebe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QYuKZ3AeEPlAwh # HbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXKchYiCd98THU/ # Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t9dmpsh3lGwID # AQABo4IBOjCCATYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU7NfjgtJxXWRM # 3y5nP+e6mK4cD08wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDgYD # VR0PAQH/BAQDAgGGMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcwAYYYaHR0cDov # L29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8vY2FjZXJ0cy5k # aWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0MEUGA1UdHwQ+ # MDwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3Vy # ZWRJRFJvb3RDQS5jcmwwEQYDVR0gBAowCDAGBgRVHSAAMA0GCSqGSIb3DQEBDAUA # A4IBAQBwoL9DXFXnOF+go3QbPbYW1/e/Vwe9mqyhhyzshV6pGrsi+IcaaVQi7aSI # d229GhT0E0p6Ly23OO/0/4C5+KH38nLeJLxSA8hO0Cre+i1Wz/n096wwepqLsl7U # z9FDRJtDIeuWcqFItJnLnU+nBgMTdydE1Od/6Fmo8L8vC6bp8jQ87PcDx4eo0kxA # GTVGamlUsLihVo7spNU96LHc/RzY9HdaXFSMb++hUD38dglohJ9vytsgjTVgHAID # yyCwrFigDkBjxZgiwbJZ9VVrzyerbHbObyMt9H5xaiNrIv8SuFQtJ37YOtnwtoeW # /VvRXKwYw02fc7cBqZ9Xql4o4rmUMYIDdjCCA3ICAQEwdzBjMQswCQYDVQQGEwJV # UzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xOzA5BgNVBAMTMkRpZ2lDZXJ0IFRy # dXN0ZWQgRzQgUlNBNDA5NiBTSEEyNTYgVGltZVN0YW1waW5nIENBAhALrma8Wrp/ # lYfG+ekE4zMEMA0GCWCGSAFlAwQCAQUAoIHRMBoGCSqGSIb3DQEJAzENBgsqhkiG # 9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjQxMDIwMjAzNjI4WjArBgsqhkiG9w0B # CRACDDEcMBowGDAWBBTb04XuYtvSPnvk9nFIUIck1YZbRTAvBgkqhkiG9w0BCQQx # IgQgLvJXoxKUD8HnQyp6e2fipjEMjhCnxbYSJKME+YuqfcEwNwYLKoZIhvcNAQkQ # Ai8xKDAmMCQwIgQgdnafqPJjLx9DCzojMK7WVnX+13PbBdZluQWTmEOPmtswDQYJ # KoZIhvcNAQEBBQAEggIAEQ/m4tnMWC+d9VC4/yVLomjZt+wprRBUcP4pv18Zyaj+ # s++sj/3ALZQB/evMEZARSawJJhzfVrx7M6SKDfj9Xix5KeKrE7blQOK7SP1/zi6g # eBgGriZtNuJ27DpaITAvE+3Hofw2X+AaBw8CSSjKo6G5bKOsRDeGtZd91SUGzAIN # NEUpColYIKjhff1AmJxPz7yTFyCvp1sy+9NjJJ+s7jETd5kdChwPDvbC93pLkbOy # byA1zIfPMPkXq2RRFGv1dp8GJDs1G0hCdMmwr8GTPpQc4/ohSyrwdn95WNulNccb # TcajXSzWnIMNncUogQ0tO4/MWggTyPulbjZ9UrsNWflOpkgiWAOOqIzawMylHZ9k # uz8heogZRuYtz3Qa8zpPWylqr6HFx9jIwBg9AVQAI1jvjuYPBSv+zAWqbJly6/aq # p9eSpZU2VAMbsohlfGGKJUoeDfJ/IAVgqzWti8r18b4jIkYq2w/vFCAYFUc3Y6nY # +aQYwj6wInqkn0J8MSMruVVRkbvxNBhRfe/PcDtTZ8GKX0n5evsvcuTl+eWxXOv4 # BXvCCedxhwQKU4IXsyiN5YPb1Xm2D+M6MW7L04cubhF4ReATCRf/va5mEfhqu9d1 # CyP6+CW9Tpq0jPmg75JQpLHnXh7kCDItY2p3A6Mgbz0jAIVX0ZwNtcBxU/vX2kQ= # SIG # End signature block |