SVT/SVT.ps1
Set-StrictMode -Version Latest function Get-AzSKADOSecurityStatus { <# .SYNOPSIS This command would help in validating the security controls for the Azure resources meeting the specified input criteria. .DESCRIPTION This command will execute the security controls and will validate their status as 'Success' or 'Failure' based on the security guidance. Refer https://aka.ms/azskossdocs for more information .PARAMETER OrganizationName Organization name for which the security evaluation has to be performed. .PARAMETER ProjectNames Project name for which the security evaluation has to be performed. .PARAMETER BuildNames Build name for which the security evaluation has to be performed. .PARAMETER ReleaseNames Release name for which the security evaluation has to be performed. .PARAMETER AgentPoolNames Agent name for which the security evaluation has to be performed. .PARAMETER DetailedScan Print detailed scan logs for controls. .NOTES This command helps the application team to verify whether their Azure resources are compliant with the security guidance or not .LINK https://aka.ms/azskossdocs #> [OutputType([String])] [Alias("Get-AzSKAzureDevOpsSecurityStatus")] Param ( [string] [Parameter(Position = 0, Mandatory = $true, HelpMessage="OrganizationName for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("oz")] $OrganizationName, [string] [Parameter( HelpMessage="Project names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("pns", "ProjectName", "pn")] $ProjectNames, [string] [Parameter(HelpMessage="Build names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("bns", "BuildName","bn")] $BuildNames, [string] [Parameter(HelpMessage="Release names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("rns", "ReleaseName","rn")] $ReleaseNames, [string] [Parameter(HelpMessage="Agent Pool names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("aps", "AgentPoolName","ap")] $AgentPoolNames, [string] [Parameter(HelpMessage="Service connection names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("sc", "ServiceConnectionName", "scs")] $ServiceConnectionNames, [string] [Parameter(HelpMessage="Variable group names for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("vg", "VariableGroupName", "vgs")] $VariableGroupNames, [string] [Parameter(HelpMessage="Repo name for which the security evaluation has to be perform.")] [ValidateNotNullOrEmpty()] [Alias("rpn", "RepoName","rp")] $RepoNames, [string] [Parameter(HelpMessage="Secure file name for which the security evaluation has to be perform.")] [ValidateNotNullOrEmpty()] [Alias("sfn", "SecureFileName","sf")] $SecureFileNames, [string] [Parameter(HelpMessage="Feed name for which the security evaluation has to be perform.")] [ValidateNotNullOrEmpty()] [Alias("fd", "FeedName","fdn")] $FeedNames, [string] [Parameter(HelpMessage="Environment name for which the security evaluation has to be perform.")] [ValidateNotNullOrEmpty()] [Alias("en", "EnvironmentName","env")] $EnvironmentNames, [switch] [Parameter(HelpMessage="Scan all supported resource types present under organization like build, release, projects etc.")] [Alias("sar", "saa" , "ScanAllArtifacts", "sat", "ScanAllResourceTypes")] $ScanAllResources, [string] [Parameter(Mandatory = $false, ParameterSetName = "Default", HelpMessage = "Comma separated control ids to filter the security controls. e.g.: ADO_Organization_AuthN_Use_AAD_Auth, ADO_Organization_SI_Review_InActive_Users etc.")] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestation", HelpMessage="Comma separated control ids to filter the security controls. e.g.: ADO_Organization_AuthN_Use_AAD_Auth, ADO_Organization_SI_Review_InActive_Users etc.")] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestationClear", HelpMessage="Comma separated control ids to filter the security controls. e.g.: ADO_Organization_AuthN_Use_AAD_Auth, ADO_Organization_SI_Review_InActive_Users etc.")] [Alias("BulkAttestControlId","cids","bacid")] [AllowEmptyString()] $ControlIds, [string] [Parameter(Mandatory = $false)] [Alias("ft")] $FilterTags, [string] [Parameter(Mandatory = $false)] [Alias("xt")] $ExcludeTags, [string] [Parameter(Mandatory = $false)] [Alias("xcids")] [AllowEmptyString()] $ExcludeControlIds, [switch] [Parameter(Mandatory = $false)] [Alias("ubc")] $UseBaselineControls, [switch] [Parameter(Mandatory = $false)] [Alias("upbc")] $UsePreviewBaselineControls, [string] [Parameter(Mandatory = $false, HelpMessage="Specify the severity of controls to be scanned. Example `"High, Medium`"")] [Alias("ControlSeverity")] $Severity, [int] [Parameter(Mandatory = $false, HelpMessage="Max # of objects to check. Default is 0 which means scan all.")] [Alias("mo")] $MaxObj = 0, [System.Security.SecureString] [Parameter(HelpMessage="Token to run scan in non-interactive mode")] [Alias("tk")] $PATToken, [switch] [Parameter(HelpMessage = "Switch to provide personal access token (PAT) using UI.")] [Alias("pfp")] $PromptForPAT, [string] [Parameter(Mandatory=$false, HelpMessage="KeyVault URL for PATToken")] [Alias("ptu")] $PATTokenURL, [ResourceTypeName] [Alias("rtn")] $ResourceTypeName = [ResourceTypeName]::All, [switch] [Parameter(Mandatory = $false)] [Alias("upc")] $UsePartialCommits, [switch] [Parameter(Mandatory = $false)] [Alias("dnrr")] $DoNotRefetchResources, [switch] [Parameter(Mandatory = $false)] [Alias("dnof")] $DoNotOpenOutputFolder, [ValidateSet("All","AlreadyAttested","NotAttested","None")] [Parameter(Mandatory = $false, ParameterSetName = "Default", HelpMessage="Using this switch, AzSK.ADO enters 'attest' mode immediately after a scan is completed. This ensures that attestation is done on the basis of the most current control statuses.")] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestation", HelpMessage="Using this switch, AzSK.ADO enters 'attest' mode immediately after a scan is completed. This ensures that attestation is done on the basis of the most current control statuses.")] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestationClear", HelpMessage="Using this switch, AzSK.ADO enters 'attest' mode immediately after a scan is completed. This ensures that attestation is done on the basis of the most current control statuses.")] [Alias("AttestControls","cta")] $ControlsToAttest = [AttestControls]::None, [switch] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestationClear", HelpMessage="Use this option if you want to clear the attestation for multiple resources in bulk, for a specified controlId.")] [Alias("bc")] $BulkClear, [string] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestation", HelpMessage="Use this option to provide an apt justification with proper business reason.")] [Alias("jt")] $JustificationText, [ValidateSet("NotAnIssue", "WillNotFix", "WillFixLater","NotApplicable","StateConfirmed","ApprovedException")] [Parameter(Mandatory = $true, ParameterSetName = "BulkAttestation", HelpMessage="Attester must select one of the attestation reasons (NotAnIssue, WillNotFix, WillFixLater, NotApplicable, StateConfirmed(if valid for the control))")] [Alias("as")] $AttestationStatus = [AttestationStatus]::None, [switch] [Parameter(Mandatory = $false, HelpMessage = "Switch to add approved exceptions.")] [Alias("aex")] $AddException, [Datetime] [Parameter(Mandatory = $false, HelpMessage = "Expiry date of approved exception.")] [Alias("aee")] $ApprovedExceptionExpiryDate, [string] [Parameter(Mandatory = $false, HelpMessage = "ID of approved exception.")] [Alias("aei")] $ApprovedExceptionID, [string] [Parameter(HelpMessage="Project name to store attestation details for organization-specific controls.")] [ValidateNotNullOrEmpty()] [Alias("atp","HostProjectName")] $AttestationHostProjectName, [ValidateSet("All","BaselineControls","PreviewBaselineControls", "Custom")] [Parameter(Mandatory = $false)] [Alias("abl")] [string] $AutoBugLog = [BugLogForControls]::All, [switch] [Parameter(HelpMessage = "Switch to auto-close bugs after the scan.")] [Alias("acb")] $AutoCloseBugs, [string] [Parameter(Mandatory=$false)] [Alias("apt")] $AreaPath, [string] [Parameter(Mandatory=$false)] [Alias("ipt")] $IterationPath, [string] [Parameter(Mandatory = $false, HelpMessage = "Specify the security severity of bugs to be logged.")] [Alias("ssv")] $SecuritySeverity, [string] [Parameter(HelpMessage="Specify the custom field reference name for bug description.")] [ValidateNotNullOrEmpty()] [Alias("bdf")] $BugDescriptionField, [switch] [Parameter(HelpMessage="Allow long running scan.")] [Alias("als", "alrs")] $AllowLongRunningScan, [string] [Parameter(Mandatory = $false, HelpMessage="Name of the project hosting organization policy with which the scan should run.")] [ValidateNotNullOrEmpty()] [Alias("pp")] $PolicyProject, [switch] [Parameter(HelpMessage="Print detailed scan logs for controls.")] [Alias("ds")] $DetailedScan, [string] [Parameter(HelpMessage="Service id for which the security evaluation has to be performed.")] [ValidateNotNullOrEmpty()] [Alias("svcid")] $ServiceIds, [switch] [Parameter(HelpMessage="Include admin controls (organization and project specific controls) in scan.")] [Alias("iac")] $IncludeAdminControls, [switch] [Parameter(HelpMessage="Skip organization and user controls.")] [Alias("souc")] $SkipOrgUserControls, [string] [Parameter(Mandatory = $false, HelpMessage="Name of the repository containing org policy endpoint.")] [ValidateNotNullOrEmpty()] [Alias("prn")] $PolicyRepoName, [ValidateSet("Graph", "RegEx", "GraphThenRegEx")] [Parameter(Mandatory = $false, HelpMessage="Evaluation method to evaluate SC-ALT admin controls.")] [Alias("acem")] [string] $ALTControlEvaluationMethod, [string] [Parameter(Mandatory = $false, HelpMessage="Folder path of builds to be scanned.")] [ValidateNotNullOrEmpty()] [Alias("bp")] $BuildsFolderPath, [string] [Parameter(Mandatory = $false, HelpMessage="Folder path of releases to be scanned.")] [ValidateNotNullOrEmpty()] [Alias("rfp")] $ReleasesFolderPath, [switch] [Parameter(HelpMessage="Print SARIF logs for the scan.")] [Alias("gsl")] $GenerateSarifLogs, [switch] [Parameter(HelpMessage="Switch to reset default logged in user.")] [Alias("rc")] $ResetCredentials, [switch] [Parameter(HelpMessage="Switch to copy current data object in local folder to facilitate control fix.")] [Alias("pcf")] $PrepareForControlFix, [switch] [Parameter(HelpMessage="Scan and generate backup of feeds on which current user has owner access for control fix.")] [Alias("coa")] $CheckOwnerAccess, [switch] [Parameter(Mandatory = $false, HelpMessage="Scan only those resource objects modified after immediately previous scan.")] [Alias("inc", "ScanIncrementally")] $IncrementalScan, [switch] [Parameter(Mandatory = $false, HelpMessage="Scan only those resource objects modified after immediately previous scan.")] [Alias("f")] $Force, [switch] [Parameter()] [Alias("bs")] $BatchScan, [switch] [switch] [Parameter()] [Alias("bsmp")] $BatchScanMultipleProjects, [string] [Parameter()] [Alias("fn")] $FolderName, [DateTime] [Parameter(Mandatory = $false, HelpMessage="Date to use as threshold for incremental scanning.")] [ValidateNotNullOrEmpty()] [Alias("dt", "IncrementDate")] $IncrementalDate, [switch] [Parameter(Mandatory = $false, HelpMessage="Scan attested resources during incremental scan")] [Alias("sars")] $ScanAttestedResources ) Begin { [CommandHelper]::BeginCommand($PSCmdlet.MyInvocation); [ListenerHelper]::RegisterListeners(); } Process { try { [ConfigurationHelper]::PolicyCacheContent = @() [ConfigurationHelper]::OnlinePolicyEnabled = $false [ConfigurationHelper]::OssPolicyUrl = "" [ConfigurationHelper]::OssPolicyEnabled = $false [ConfigurationHelper]::LocalPolicyEnabled = $false [ConfigurationHelper]::ConfigVersion = "" [AzSKSettings]::Instance = $null [AzSKConfig]::Instance = $null [ConfigurationHelper]::ServerConfigMetadata = $null [ControlHelper]::IsGroupDetailsFetchedFromPolicy = $false [ControlHelper]::CloudmineDataHelperObj=$null [CloudmineDataHelper]::CloudmineDataHelperInstance = $null [Build]::YamlBranchPolicies=@() [ADOSVTBase]::ResourceApprovalChecks = @() #Refresh singlton in different gads commands. (Powershell session keep cach object of the class, so need to make it null befor command run) [AutoBugLog]::AutoBugInstance = $null #Clear the cache of nested groups if the org name is not matching from previous scan in same session if ([ControlHelper]::GroupMembersResolutionObj.ContainsKey("OrgName") -and [ControlHelper]::GroupMembersResolutionObj["OrgName"] -ne $OrganizationName) { [ControlHelper]::GroupMembersResolutionObj = @{} [AdministratorHelper]::isCurrentUserPCA = $false [AdministratorHelper]::isCurrentUserPA= $false [AdministratorHelper]::AllPCAMembers = @() [AdministratorHelper]::AllPAMembers = @() } if ($PrepareForControlFix -eq $true) { if ($UsePartialCommits -ne $true) { Write-Host "PrepareForControlFix switch requires -UsePartialCommits switch." -ForegroundColor Red return; } elseif ([String]::IsNullOrEmpty($ControlIds) -or $ControlIds -match ','){ Write-Host "PrepareForControlFix switch requires one controlid. Use -ControlIds parameter to provide it." -ForegroundColor Red return; } } if($PromptForPAT -eq $true) { if($null -ne $PATToken) { Write-Host "Parameters '-PromptForPAT' and '-PATToken' can not be used simultaneously in the scan command." -ForegroundColor Red return; } else { $PATToken = Read-Host "Provide PAT for [$OrganizationName] org:" -AsSecureString } } if (-not [String]::IsNullOrEmpty($PATTokenURL)) { # For now, if PAT URL is specified we will trigger an Azure login. $Context = @(Get-AzContext -ErrorAction SilentlyContinue ) if ($Context.count -eq 0) { Write-Host "No active Azure login session found.`r`nPlease login to Azure tenant hosting the key vault..." -ForegroundColor Yellow Connect-AzAccount -ErrorAction Stop $Context = @(Get-AzContext -ErrorAction SilentlyContinue) } if ($null -eq $Context) { Write-Host "Login failed. Azure login context is required to use a key vault-based PAT token.`r`nStopping scan command." -ForegroundColor Red return; } #Parse the key-vault-URL to determine vaultname, secretname, version if ($PATTokenURL -match "^https://(?<kv>[\w]+)(?:[\.\w+]*)/secrets/(?<sn>[\w]+)/?(?<sv>[\w]*)") { $kvName = $Matches["kv"] $secretName = $Matches["sn"] $secretVersion = $Matches["sv"] if (-not [String]::IsNullOrEmpty($secretVersion)) { $kvSecret = Get-AzKeyVaultSecret -VaultName $kvName -SecretName $secretName -Version $secretVersion } else { $kvSecret = Get-AzKeyVaultSecret -VaultName $kvName -SecretName $secretName } if ($null -eq $kvSecret) { Write-Host "Could not extract PATToken from the given key vault URL.`r`nStopping scan command." -ForegroundColor Red return; } $PATToken = $kvSecret.SecretValue; } else { Write-Host "Could not extract PATToken from the given key vault URL.`r`nStopping scan command." -ForegroundColor Red return; } } if ($ResetCredentials) { [ContextHelper]::PromptForLogin = $true } else { [ContextHelper]::PromptForLogin =$false } if(![string]::IsNullOrEmpty($BuildsFolderPath)) { if($ResourceTypeName -notin([ResourceTypeName]::Build_Release,[ResourceTypeName]::Build)) { Write-Host "Parameter -ResourceTypeName(-rtn) should be Build/Build_Release when the parameter '-BuildsFolderPath' is used in the scan command." -ForegroundColor Red return; } } if(![string]::IsNullOrEmpty($ReleasesFolderPath)) { if($ResourceTypeName -notin([ResourceTypeName]::Build_Release,[ResourceTypeName]::Release)) { Write-Host "Parameter -ResourceTypeName(-rtn) should be Release/Build_Release when the parameter '-ReleasesFolderPath' is used in the scan command." -ForegroundColor Red return; } } $resolver = [SVTResourceResolver]::new($OrganizationName,$ProjectNames,$BuildNames,$ReleaseNames,$AgentPoolNames, $ServiceConnectionNames, $VariableGroupNames, $MaxObj, $ScanAllResources, $PATToken,$ResourceTypeName, $AllowLongRunningScan, $ServiceIds, $IncludeAdminControls, $SkipOrgUserControls, $RepoNames, $SecureFileNames, $FeedNames, $EnvironmentNames, $BuildsFolderPath,$ReleasesFolderPath,$UsePartialCommits,$DoNotRefetchResources,$BatchScan, $IncrementalScan, $IncrementalDate); $secStatus = [ServicesSecurityStatus]::new($OrganizationName, $PSCmdlet.MyInvocation, $resolver); if ($secStatus) { if ($null -ne $secStatus.Resolver.SVTResources) { $secStatus.ControlIdString = $ControlIds; $secStatus.Severity = $Severity; $secStatus.UseBaselineControls = $UseBaselineControls; $secStatus.UsePreviewBaselineControls = $UsePreviewBaselineControls; $secStatus.FilterTags = $FilterTags; $secStatus.ExcludeTags = $ExcludeTags; $secStatus.ExcludeControlIdString = $ExcludeControlIds #build the attestation options object [AttestationOptions] $attestationOptions = [AttestationOptions]::new(); $attestationOptions.AttestControls = $ControlsToAttest $attestationOptions.JustificationText = $JustificationText $attestationOptions.AttestationStatus = $AttestationStatus $attestationOptions.IsBulkClearModeOn = $BulkClear $attestationOptions.IsExemptModeOn = $AddException $attestationOptions.ApprovedExceptionExpiryDate = $ApprovedExceptionExpiryDate $attestationOptions.ApprovedExceptionID = $ApprovedExceptionID $secStatus.AttestationOptions = $attestationOptions; return $secStatus.EvaluateControlStatus(); } } } catch { [EventBase]::PublishGenericException($_); } } End { [ListenerHelper]::UnregisterListeners(); } } # SIG # Begin signature block # MIIjkgYJKoZIhvcNAQcCoIIjgzCCI38CAQExDzANBglghkgBZQMEAgEFADB5Bgor # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCIwKagsUT3UDVm # omlD5ZspYL2u8hd6Ld9ZLgT2z1zxJqCCDYEwggX/MIID56ADAgECAhMzAAACUosz # qviV8znbAAAAAAJSMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD # VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p # bmcgUENBIDIwMTEwHhcNMjEwOTAyMTgzMjU5WhcNMjIwOTAxMTgzMjU5WjB0MQsw # CQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9u # ZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMR4wHAYDVQQDExVNaWNy # b3NvZnQgQ29ycG9yYXRpb24wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB # AQDQ5M+Ps/X7BNuv5B/0I6uoDwj0NJOo1KrVQqO7ggRXccklyTrWL4xMShjIou2I # sbYnF67wXzVAq5Om4oe+LfzSDOzjcb6ms00gBo0OQaqwQ1BijyJ7NvDf80I1fW9O # L76Kt0Wpc2zrGhzcHdb7upPrvxvSNNUvxK3sgw7YTt31410vpEp8yfBEl/hd8ZzA # v47DCgJ5j1zm295s1RVZHNp6MoiQFVOECm4AwK2l28i+YER1JO4IplTH44uvzX9o # RnJHaMvWzZEpozPy4jNO2DDqbcNs4zh7AWMhE1PWFVA+CHI/En5nASvCvLmuR/t8 # q4bc8XR8QIZJQSp+2U6m2ldNAgMBAAGjggF+MIIBejAfBgNVHSUEGDAWBgorBgEE # AYI3TAgBBggrBgEFBQcDAzAdBgNVHQ4EFgQUNZJaEUGL2Guwt7ZOAu4efEYXedEw # UAYDVR0RBEkwR6RFMEMxKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVyYXRpb25zIFB1 # ZXJ0byBSaWNvMRYwFAYDVQQFEw0yMzAwMTIrNDY3NTk3MB8GA1UdIwQYMBaAFEhu # ZOVQBdOCqhc3NyK1bajKdQKVMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly93d3cu # bWljcm9zb2Z0LmNvbS9wa2lvcHMvY3JsL01pY0NvZFNpZ1BDQTIwMTFfMjAxMS0w # Ny0wOC5jcmwwYQYIKwYBBQUHAQEEVTBTMFEGCCsGAQUFBzAChkVodHRwOi8vd3d3 # Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL01pY0NvZFNpZ1BDQTIwMTFfMjAx # MS0wNy0wOC5jcnQwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAFkk3 # uSxkTEBh1NtAl7BivIEsAWdgX1qZ+EdZMYbQKasY6IhSLXRMxF1B3OKdR9K/kccp # kvNcGl8D7YyYS4mhCUMBR+VLrg3f8PUj38A9V5aiY2/Jok7WZFOAmjPRNNGnyeg7 # l0lTiThFqE+2aOs6+heegqAdelGgNJKRHLWRuhGKuLIw5lkgx9Ky+QvZrn/Ddi8u # TIgWKp+MGG8xY6PBvvjgt9jQShlnPrZ3UY8Bvwy6rynhXBaV0V0TTL0gEx7eh/K1 # o8Miaru6s/7FyqOLeUS4vTHh9TgBL5DtxCYurXbSBVtL1Fj44+Od/6cmC9mmvrti # yG709Y3Rd3YdJj2f3GJq7Y7KdWq0QYhatKhBeg4fxjhg0yut2g6aM1mxjNPrE48z # 6HWCNGu9gMK5ZudldRw4a45Z06Aoktof0CqOyTErvq0YjoE4Xpa0+87T/PVUXNqf # 7Y+qSU7+9LtLQuMYR4w3cSPjuNusvLf9gBnch5RqM7kaDtYWDgLyB42EfsxeMqwK # WwA+TVi0HrWRqfSx2olbE56hJcEkMjOSKz3sRuupFCX3UroyYf52L+2iVTrda8XW # esPG62Mnn3T8AuLfzeJFuAbfOSERx7IFZO92UPoXE1uEjL5skl1yTZB3MubgOA4F # 8KoRNhviFAEST+nG8c8uIsbZeb08SeYQMqjVEmkwggd6MIIFYqADAgECAgphDpDS # 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/BvW1taslScxMNelDNMYIVZzCCFWMCAQEwgZUwfjELMAkG # A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx # HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEoMCYGA1UEAxMfTWljcm9z # b2Z0IENvZGUgU2lnbmluZyBQQ0EgMjAxMQITMwAAAlKLM6r4lfM52wAAAAACUjAN # BglghkgBZQMEAgEFAKCBrjAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAcBgor # BgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgXAIsTQuM # oaMrNhSF180tansSA7MxniEX2g+khY9D9fQwQgYKKwYBBAGCNwIBDDE0MDKgFIAS # AE0AaQBjAHIAbwBzAG8AZgB0oRqAGGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbTAN # BgkqhkiG9w0BAQEFAASCAQAsvRw27qu+o+BR7hiLRLHGtKpR9na+Nf6Kgfc15H08 # XpZasRZtTB9A2okYCDyE3Yl+mU2ovWgpN9sRMtvB18A6b2HAYiLUqxyLTVz1tuV2 # Zk2jZ0FuuJ0Zzou7Jc3rkfWnkZ/1uWnwFXXQIycOq2RKAG01esXz+H6UaGzaRf1/ # JGZ9ScksisnVmQIfChx0oMDQe3kTtAzmq75Xw+89qV95qiB+hNq8p5o0WH7LpsA3 # 1rr/ShA13MCqZrjbGTbfJEtmrZg58vgQif5GX3xv3k7ppASCzH7lBAGvhvquMlmo # YYgunzmA1Ey42rrMKZboQQ/0P+nQkswYApkIm273O6XkoYIS8TCCEu0GCisGAQQB # gjcDAwExghLdMIIS2QYJKoZIhvcNAQcCoIISyjCCEsYCAQMxDzANBglghkgBZQME # AgEFADCCAVUGCyqGSIb3DQEJEAEEoIIBRASCAUAwggE8AgEBBgorBgEEAYRZCgMB # MDEwDQYJYIZIAWUDBAIBBQAEIIDLYA03ENvf4GAHuQrOVwz4YgIOTRy5jnb+QwRB # aSS1AgZiEAIuLwoYEzIwMjIwMzE0MTA0MzUzLjA2M1owBIACAfSggdSkgdEwgc4x # CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt # b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1p # Y3Jvc29mdCBPcGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMg # VFNTIEVTTjo2MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt # U3RhbXAgU2VydmljZaCCDkQwggT1MIID3aADAgECAhMzAAABWiy5bkQ0y28oAAAA # AAFaMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo # aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y # cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw # MB4XDTIxMDExNDE5MDIxNloXDTIyMDQxMTE5MDIxNlowgc4xCzAJBgNVBAYTAlVT # MRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQK # ExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBPcGVy # YXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2MEJD # LUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vydmlj # ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALC9XBxXDa0nCK70Hf+G # ih6NxRl1mAhzFJdok8bs3xpJ87TM28rEeHkZAaE+Kb9Gi9UvTpQ3zrEWyWSpIQky # xv/Wf0cIhA1mJOqyu20TN3l96ZvgzYrzO/rQlPvbKW79oAO4+YFsekQCtrzM9hQo # S5BYGwPh9Qz66BuSxH9QweywNBQsjkVoikpBxkS+EXSIzpba2afvnRMX7LLe2ery # c+PlPXmTSOfH1WNykc25u9zo6ZX0gAd4jUpBzdMLnHCtE62bL2PO00cmAJsitqga # ov+3lFrfd0sPACwTGO9iymlJlb2savwjqSnj5RzG4RxG6rU2i7etbnQTozR73OHM # GOUCAwEAAaOCARswggEXMB0GA1UdDgQWBBRkcyU/9RyPkn7QBoXZOTQ8wN4xZzAf # BgNVHSMEGDAWgBTVYzpcijGQ80N7fEYbxTNoWoVtVTBWBgNVHR8ETzBNMEugSaBH # hkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20vcGtpL2NybC9wcm9kdWN0cy9NaWNU # aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcmwwWgYIKwYBBQUHAQEETjBMMEoGCCsGAQUF # BzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtpL2NlcnRzL01pY1RpbVN0 # YVBDQV8yMDEwLTA3LTAxLmNydDAMBgNVHRMBAf8EAjAAMBMGA1UdJQQMMAoGCCsG # AQUFBwMIMA0GCSqGSIb3DQEBCwUAA4IBAQAAAG3sfFgbUiw4gWMV8VOxlbIG/CIM # SiciDtIZnPL84OMN4lJeV5LeJr+HYBcox5ruWZm49K29iBmJv6ViXMtP81pYZ1EF # M7306Y+zLIh/tS574PeWsHvPD0QOxQ4HOM2GNPvFAdUvo8z5pgV/5E+lPu61uUCI # BTDESiHO+N7ragqb3METPqRKPLNAJcKPDcalKznmGPlnzY6P1zop/7a90VcBHRKK # Q/hTvn/8C8Y6b+Mvk5kYJh67KNbVVcuuBWyFSMZTHGenHnuHVg9svH7+lm/V/wIb # ZUKKJJO0HQmyodySeD/JLC7NNsDYRpFN+29dLRtx0eWyZosJmT8qKbBIMIIGcTCC # BFmgAwIBAgIKYQmBKgAAAAAAAjANBgkqhkiG9w0BAQsFADCBiDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEyMDAGA1UEAxMpTWljcm9zb2Z0IFJv # b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTAwHhcNMTAwNzAxMjEzNjU1WhcN # MjUwNzAxMjE0NjU1WjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3Rv # bjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0 # aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDCCASIw # DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkdDbx3EYo6IOz8E5f1+n9plGt0 # VBDVpQoAgoX77XxoSyxfxcPlYcJ2tz5mK1vwFVMnBDEfQRsalR3OCROOfGEwWbEw # RA/xYIiEVEMM1024OAizQt2TrNZzMFcmgqNFDdDq9UeBzb8kYDJYYEbyWEeGMoQe # dGFnkV+BVLHPk0ySwcSmXdFhE24oxhr5hoC732H8RsEnHSRnEnIaIYqvS2SJUGKx # Xf13Hz3wV3WsvYpCTUBR0Q+cBj5nf/VmwAOWRH7v0Ev9buWayrGo8noqCjHw2k4G # kbaICDXoeByw6ZnNPOcvRLqn9NxkvaQBwSAJk3jN/LzAyURdXhacAQVPIk0CAwEA # AaOCAeYwggHiMBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTVYzpcijGQ80N7 # fEYbxTNoWoVtVTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMC # AYYwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTV9lbLj+iiXGJo0T2UkFvX # zpoYxDBWBgNVHR8ETzBNMEugSaBHhkVodHRwOi8vY3JsLm1pY3Jvc29mdC5jb20v # cGtpL2NybC9wcm9kdWN0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcmwwWgYI # KwYBBQUHAQEETjBMMEoGCCsGAQUFBzAChj5odHRwOi8vd3d3Lm1pY3Jvc29mdC5j # b20vcGtpL2NlcnRzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNydDCBoAYDVR0g # AQH/BIGVMIGSMIGPBgkrBgEEAYI3LgMwgYEwPQYIKwYBBQUHAgEWMWh0dHA6Ly93 # d3cubWljcm9zb2Z0LmNvbS9QS0kvZG9jcy9DUFMvZGVmYXVsdC5odG0wQAYIKwYB # BQUHAgIwNB4yIB0ATABlAGcAYQBsAF8AUABvAGwAaQBjAHkAXwBTAHQAYQB0AGUA # bQBlAG4AdAAuIB0wDQYJKoZIhvcNAQELBQADggIBAAfmiFEN4sbgmD+BcQM9naOh # IW+z66bM9TG+zwXiqf76V20ZMLPCxWbJat/15/B4vceoniXj+bzta1RXCCtRgkQS # +7lTjMz0YBKKdsxAQEGb3FwX/1z5Xhc1mCRWS3TvQhDIr79/xn/yN31aPxzymXlK # kVIArzgPF/UveYFl2am1a+THzvbKegBvSzBEJCI8z+0DpZaPWSm8tv0E4XCfMkon # /VWvL/625Y4zu2JfmttXQOnxzplmkIz/amJ/3cVKC5Em4jnsGUpxY517IW3DnKOi # PPp/fZZqkHimbdLhnPkd/DjYlPTGpQqWhqS9nhquBEKDuLWAmyI4ILUl5WTs9/S/ # fmNZJQ96LjlXdqJxqgaKD4kWumGnEcua2A5HmoDF0M2n0O99g/DhO3EJ3110mCII # YdqwUB5vvfHhAN/nMQekkzr3ZUd46PioSKv33nJ+YWtvd6mBy6cJrDm77MbL2IK0 # cs0d9LiFAR6A+xuJKlQ5slvayA1VmXqHczsI5pgt6o3gMy4SKfXAL1QnIffIrE7a # KLixqduWsqdCosnPGUFN4Ib5KpqjEWYw07t0MkvfY3v1mYovG8chr1m1rtxEPJdQ # cdeh0sVV42neV8HR3jDA/czmTfsNv11P6Z0eGTgvvM9YBS7vDaBQNdrvCScc1bN+ # NR4Iuto229Nfj950iEkSoYIC0jCCAjsCAQEwgfyhgdSkgdEwgc4xCzAJBgNVBAYT # AlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYD # VQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKTAnBgNVBAsTIE1pY3Jvc29mdCBP # cGVyYXRpb25zIFB1ZXJ0byBSaWNvMSYwJAYDVQQLEx1UaGFsZXMgVFNTIEVTTjo2 # MEJDLUUzODMtMjYzNTElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUtU3RhbXAgU2Vy # dmljZaIjCgEBMAcGBSsOAwIaAxUAzIAFmL3GHHWcAJYi3haGwlplGi6ggYMwgYCk # fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH # UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD # Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMDANBgkqhkiG9w0BAQUFAAIF # AOXZewEwIhgPMjAyMjAzMTQxMjI3NDVaGA8yMDIyMDMxNTEyMjc0NVowdzA9Bgor # BgEEAYRZCgQBMS8wLTAKAgUA5dl7AQIBADAKAgEAAgIi6gIB/zAHAgEAAgIRCTAK # AgUA5drMgQIBADA2BgorBgEEAYRZCgQCMSgwJjAMBgorBgEEAYRZCgMCoAowCAIB # AAIDB6EgoQowCAIBAAIDAYagMA0GCSqGSIb3DQEBBQUAA4GBAJAFFNg9NpYbe0wl # jwqbaO3hPh2N2ol/iY7Bu9TphE0WohZmtXh5GTU4Zh8Re2Q6Z5LqR9uG1j/tD9QG # kZo37mrW8SXsGYLkeNtxp3/TE5u6wRTo8hJsaYHUi1P4Kn4pKywxQjUuM/aEoXQn # Le5FTGGG1FphixPrIogxMN+cYL8HMYIDDTCCAwkCAQEwgZMwfDELMAkGA1UEBhMC # VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV # BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRp # bWUtU3RhbXAgUENBIDIwMTACEzMAAAFaLLluRDTLbygAAAAAAVowDQYJYIZIAWUD # BAIBBQCgggFKMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAvBgkqhkiG9w0B # CQQxIgQg9/US0iwZs2jAewOE0WOgMAUtKnLsjxwgWzQKqzkD88AwgfoGCyqGSIb3 # DQEJEAIvMYHqMIHnMIHkMIG9BCCT/KgmdMSy5F0ww4Iar9cmf5Is3pM0hUuIInL5 # bbF/sDCBmDCBgKR+MHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9u # MRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRp # b24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAAB # Wiy5bkQ0y28oAAAAAAFaMCIEIE+gMtasqy2jrzGZPRyHKWZnEPsQDadCfOuHVa38 # QgwZMA0GCSqGSIb3DQEBCwUABIIBAAxzHwAdkoCM8dP2hhT/+HgvJqXB1iUvxf8I # U0KuHvob3MooZWvoAfUjvdLtimdx+ZGHjxDD04CVu9t8v1C81GS0thYWycg1pI1W # Uapw0/hAFwE2sBJNdZ465VexxUTHZtnMc+x1RLJrB4os/zzVrgMSJf4exeaQ6klH # xuMjpTXHyu4KghwotN/r29W9U00sFBPxDWHJKabbD33OYoZsHSMDmMiq8N0OhXTu # ZvD62ZgywQZ3WRMs7LsqHjqjBmo6taazOOnbo9Yj6h15KHPLWUST5BLGydGSkPfq # 9ZtlFQ3hW9IKchX5oBagdLL9u8FxpBsGYn5o6pJhLVA0YqUF+qU= # SIG # End signature block |