HP.Firmware.SureRecover.psm1

# Copyright (C)2018 HP Inc
# All Rights Reserved.
#
# NOTICE: All information contained herein is, and remains the property of HP Inc.
#
# The intellectual and technical concepts contained herein are proprietary to HP Inc
# and may be covered by U.S. and Foreign Patents, patents in process, and are protected by
# trade secret or copyright law. Dissemination of this information or reproduction of this material
# is strictly forbidden unless prior written permission is obtained from HP Inc.

Set-StrictMode -Version 3.0
$ErrorActionPreference = 'Stop'
#requires -Modules "HP.Private"


[Flags()] enum DeprovisioningTarget{
  AgentProvisioning = 1
  OSImageProvisioning = 2
  ConfigurationData = 4
  TriggerRecoveryData = 8
  ScheduleRecoveryData = 16
}


# Convert a BIOS value to a boolean
function ConvertValue {
  param($value)
  if ($value -eq "Enable" -or $value -eq "Yes") { return $true }
  $false
}


<#
.SYNOPSIS
    Get the current state of the HP Sure Recover feature
 
.DESCRIPTION
  This function returns the current state of the HP Sure Recover feature
   
.NOTES
    - Supported on Windows 10.
  - Requires HP BIOS with HP Sure Recover support.
    - This command requires elevated privileges.
   
#>

function Get-HPSureRecoverState
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPSureRecoverState")]
  param([switch]$All)
  $mi_result = 0
  $data = New-Object -TypeName surerecover_state_t
  $c = '[DfmNativeSureRecover]::get_surerecover_state' + (Test-OSBitness) + '([ref]$data,[ref]$mi_result);'
  $result = Invoke-Expression -Command $c
  Test-HPPrivateCustomResult -result 0x80000711 -mi_result $result -Category 0x04

  $fixed_version = "$($data.subsystem_version[0]).$($data.subsystem_version[1])"
  if ($fixed_version -eq "0.0") {
    Write-Verbose "Patched SURERECOVER version 0.0 to 1.0"
    $fixed_version = "1.0"
  }
  $SchedulerIsDisabled = ($data.schedule.window_size -eq 0)

  $RecoveryTimeBetweenRetries = ([uint32]$data.os_flags -shr 8) -band 0x0f
  $RecoveryNumberOfRetries = ([uint32]$data.os_flags -shr 12) -band 0x07
  if ($RecoveryNumberOfRetries -eq 0)
  {
    $RecoveryNumberOfRetries = "Infinite"
  }

  $obj = [ordered]@{
    Version = $fixed_version
    Nonce = $data.Nonce
    #OsImageIsProvisioned = $data.os_provisioned

    OsImageFlags = ($data.os_flags -band 0xff)
    ImageIsProvisioned = (($data.flags -band 2) -ne 0)
    AgentFlags = ($data.re_flags -band 0xff)
    AgentIsProvisioned = (($data.flags -band 1) -ne 0)
    RecoveryTimeBetweenRetries = $RecoveryTimeBetweenRetries
    RecoveryNumberOfRetries = $RecoveryNumberOfRetries
    Schedule = New-Object -TypeName PSObject -Property @{
      DayOfWeek = $data.schedule.day_of_week
      Hour = [uint32]$data.schedule.Hour
      Minute = [uint32]$data.schedule.Minute
      WindowSize = [uint32]$data.schedule.window_size
    }
    ConfigurationDataIsProvisioned = (($data.flags -band 4) -ne 0)
    TriggerRecoveryDataIsProvisioned = (($data.flags -band 8) -ne 0)
    ScheduleRecoveryDataIsProvisioned = (($data.flags -band 16) -ne 0)
    SchedulerIsDisabled = $SchedulerIsDisabled
  }

  if ($all.IsPresent)
  {
    $ia = [ordered]@{
      Url = (Get-HPBiosSettingValue -Name "OS Recovery Image URL")
      Username = (Get-HPBiosSettingValue -Name "OS Recovery Image Username")
      #PublicKey = (Get-HPBiosSettingValue -name "OS Recovery Image Public Key")
      ProvisioningVersion = (Get-HPBiosSettingValue -Name "OS Recovery Image Provisioning Version")
    }

    $aa = [ordered]@{
      Url = (Get-HPBiosSettingValue -Name "OS Recovery Agent URL")
      Username = (Get-HPBiosSettingValue -Name "OS Recovery Agent Username")
      #PublicKey = (Get-HPBiosSettingValue -name "OS Recovery Agent Public Key")
      ProvisioningVersion = (Get-HPBiosSettingValue -Name "OS Recovery Agent Provisioning Version")
    }

    $Image = New-Object -TypeName PSObject -Property $ia
    $Agent = New-Object -TypeName PSObject -Property $aa
    
    $obj.Add("Image",$Image)
    $obj.Add("Agent",$Agent)
  }
  return New-Object -TypeName PSCustomObject -Property $obj
}

<#
.SYNOPSIS
    Get information about the HP Sure Recover embedded reimaging device.
 
.DESCRIPTION
    This function returns information about the embedded reimaging device for HP Sure Recover.
 
.NOTES
  The embedded reimaging device is an optional hardware feature, and if not present, the field Embedded Reimaging Device will be false.
 
.NOTES
    - Supported on Windows 10.
  - Requires HP BIOS with HP Sure Recover support
  - Requires Embedded Reimaging device hardware option
    - This command requires elevated privileges.
   
#>

function Get-HPSureRecoverReimagingDeviceDetails
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/Get%E2%80%90HPSureRecoverReimagingDeviceDetails")]
  param()
  $result = @{}

  try {
    [int]$ImageVersion = Get-HPBiosSettingValue -Name "OS Recovery Image Version"
    $result.Add("ImageVersion",$ImageVersion)

  }
  catch {}

  try {
    [int]$DriverVersion = Get-HPBiosSettingValue -Name "OS Recovery Driver Version"
    $result.Add("DriverVersion",$DriverVersion)
  }
  catch {}

  $result.Add("Embedded Reimaging Device",(Test-Path variable:ImageVersion) -and (Test-Path variable:DriverVersion))
  $result
}

<#
.SYNOPSIS
    Configure the HP Sure Recover OS or Recovery image
 
.DESCRIPTION
    This function defines a custom HP Sure Recover OS or Recovery image.
 
    On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter.
    This payload can then be passed to the [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
<div style="background-color: #ee8; padding:10px;">
 
<h4>Security note</h4>
Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the <b>Set-HPSecurePlatformPayload</b> . Creating the payload and passing it to the <b>Set-HPSecurePlatformPayload</b> function via the pipeline is not a recommended production pattern.
 
</div>
     
.PARAMETER Image
     This controls whether this command will create a configuration payload for
     a Recovery Agent image or a Recovery OS image.
 
.PARAMETER SigningKeyFile
     The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the SigningKeyPassword parameter should also be provided.
 
.PARAMETER SigningKeyPassword
     The secure platform signing key file password, if required.
 
.PARAMETER SigningKeyCertificate
     The secure platform signing key certificate, as an X509Certificate object.
 
.PARAMETER ImageKeyFile
     The path to the image signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the ImageKeyPassword parameter should also be provided. Depending on the Image switch, this will be either
     the signing key file for the Agent or the OS image.
 
     ImageKeyFile and PublicKeyFile are mutually exclusive.
 
.PARAMETER ImageKeyPassword
     The image signing key file password, if required.
 
.PARAMETER ImageCertificate
     The image signing key certificate, as an X509Certificate object. Depending on the Image switch, this will be either
     the signing key certificate for the Agent or the OS image.
 
.PARAMETER PublicKeyFile
      The image signing key, as the path to a base64-encoded RSA key (a PEM file).
 
      ImageKeyFile and PublicKeyFile are mutually exclusive.
 
.PARAMETER PublicKey
     The image signing key, as an array of bytes, including modulus and exponent.
 
      This option is currently reserved for internal use.
 
.PARAMETER Nonce
     The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a
     nonce greater or equal to the last nonce sent.
 
     If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds,
     so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller
     should use its own nonce derivation and provide it through this parameter.
 
.PARAMETER Version
     The operation version. Each new configuration payload must increment the last operation payload version, as available in the public WMI
     setting 'OS Recovery Image Provisioning Version'. If this switch is not provided, the function will read this public wmi setting and increment it, automatically.
 
.PARAMETER Username
     The username for accessing the url specified in the Url parameter, if any.
 
.PARAMETER Password
     The password for accessing the url specified in the Url parameter, if any.
 
.PARAMETER Url
     The url from where to download the image. If not specified, the default HP.COM location will be used.
    
.PARAMETER OutputFile
     Write the resulting output to the specified file, instead of writing it to the pipeline.
      
.NOTES
    - Supported on Windows 10.
  - Requires HP BIOS with HP Sure Recover support
 
.EXAMPLE
   $payload = New-HPSureRecoverImageConfigurationPayload -SigningKeyFile "$path\signing_key.pfx" -Image OS -ImageKeyFile `
                 "$path\os.pfx" -username my_http_user -password `s3cr3t` -url "http://my.company.com"
   ...
   $payload | Set-HPSecurePlatformPayload
#>

function New-HPSureRecoverImageConfigurationPayload
{
  [CmdletBinding(DefaultParameterSetName = "SKFileCert_OSFilePem",HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverImageConfigurationPayload")]
  param(
    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $true,Position = 0)]
    [ValidateSet("os","agent")]
    [string]$Image,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $true,Position = 1)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $true,Position = 1)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $true,Position = 1)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $true,Position = 1)]
    [System.IO.FileInfo]$SigningKeyFile,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 2)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 2)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 2)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 2)]
    [string]$SigningKeyPassword,

    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $true,Position = 3)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $true,Position = 3)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $true,Position = 3)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $true,Position = 3)]
    [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate,


    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $true,Position = 4)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $true,Position = 4)]
    [System.IO.FileInfo]$ImageKeyFile,

    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 5)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 5)]
    [string]$ImageKeyPassword,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $true,Position = 6)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $true,Position = 6)]
    [System.Security.Cryptography.X509Certificates.X509Certificate2]$ImageCertificate,


    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $true,Position = 7)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $true,Position = 7)]
    [System.IO.FileInfo]$PublicKeyFile,


    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $true,Position = 8)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $true,Position = 8)]
    [byte[]]$PublicKey,


    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 9)]
    [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")),


    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 10)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 10)]
    [uint16]$Version,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 11)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 11)]
    [string]$Username,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 12)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 12)]
    [string]$Password,

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 13)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 13)]
    [uri]$Url = "",

    [Parameter(ParameterSetName = "SKFileCert_OSBytesCert",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesCert",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKFileCert_OSFileCert",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFileCert",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKFileCert_OSBytesPem",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKBytesCert_OSBytesPem",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKFileCert_OSFilePem",Mandatory = $false,Position = 14)]
    [Parameter(ParameterSetName = "SKBytesCert_OSFilePem",Mandatory = $false,Position = 14)]
    [System.IO.FileInfo]$OutputFile
  )

  Write-Verbose "Creating SureRecover Image provisioning payload"

  $sk = Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -password $SIgningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference

  if ($PublicKeyFile -or $PublicKey) {
    $osk = Get-HPPrivatePublicKeyCoalesce -file $PublicKeyFile -key $PublicKey -Verbose:$VerbosePreference
      }
  else {
    $osk = Get-HPPrivateX509CertCoalesce -File $ImageKeyFile -password $ImageKeyPassword -cert $ImageCertificate -Verbose:$VerbosePreference
    }


  $OKBytes = $osk.Modulus

  $opaque = New-Object opaque4096_t
  $opaqueLength = 4096
  $mi_result = 0

  if (-not $Version) {
    if ($image -eq "os")
    {
      $Version = [uint16](Get-HPBiosSettingValue "OS Recovery Image Provisioning Version") + 1
    }
    else {
      $Version = [uint16](Get-HPBiosSettingValue "OS Recovery Agent Provisioning Version") + 1
    }
    Write-Verbose "New version number is $version"
  }

  $cmd = '[DfmNativeSureRecover]::get_surerecover_provisioning_opaque' + (Test-OSBitness) + '($Nonce, $Version, $OKBytes,$($OKBytes.Count),$Username, $Password, $($Url.ToString()), [ref]$opaque, [ref]$opaqueLength, [ref]$mi_result);'
  $result = Invoke-Expression -Command $cmd
  Test-HPPrivateCustomResult -result $result -mi_result $mi_result -Category 0x04

  $payload = $opaque.raw[0..($opaqueLength - 1)]

  $sig = Invoke-HPPrivateSignData -data $payload -Certificate $sk.Full -password $SigningKeyPassword -Verbose:$VerbosePreference

  [byte[]]$out = $sig + $payload

  Write-Verbose "Building output document"
  $output = New-Object -TypeName PortableFileFormat
  $output.data = $out

  if ($Image -eq "os") {
    $output.purpose = "hp:surerecover:provision:os_image"
  }
  else {
    $output.purpose = "hp:surerecover:provision:recovery_image"
  }

  Write-Verbose "Provisioning version will be $version"
  $output.timestamp = Get-Date

  if ($OutputFile) {
    Write-Verbose 'Will output to file $OutputFile'
    $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)
    $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8
  }
  else {
    $output | ConvertTo-Json -Compress
  }
}



<#
.SYNOPSIS
    Deprovision HP Sure Recover
 
.DESCRIPTION
    This function create a payload to deprovision the HP Sure Recover feature, or parts thereof.
 
    On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter.
    This payload can then be passed to the [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
<div style="background-color: #ee8; padding:10px;">
 
<h4>Security note</h4>
Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the <b>Set-HPSecurePlatformPayload</b> . Creating the payload and passing it to the <b>Set-HPSecurePlatformPayload</b> function via the pipeline is not a recommended production pattern.
 
</div>
     
.PARAMETER SigningKeyFile
     The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the SigningKeyPassword parameter should also be provided.
 
.PARAMETER SigningKeyPassword
     The secure platform signing key file password, if required.
 
.PARAMETER SigningKeyCertificate
     The secure platform signing key certificate, as an X509Certificate object.
 
 
.PARAMETER Nonce
     The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a
     nonce greater or equal to the last nonce sent.
 
     If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds,
     so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller
     should use its own nonce derivation and provide it through this parameter.
 
.PARAMETER RemoveOnly
     This parameter allows deprovisioning only specific parts of the Sure Recover subsystem. If not specified, the entire SureRecover is deprovisoned. Possible values
     are one or more of the following:
 
     - AgentProvisioning - remove the Agent provisioning
     - OSImageProvisioning - remove the OS Image provisioning
     - ConfigurationData - remove HP SureRecover configuration data
     - TriggerRecoveryData - remove the HP Sure Recover trigger definition
     - ScheduleRecoveryData - remove the HP Sure Recover schedule definition
 
.PARAMETER OutputFile
     Write the resulting output to the specified file, instead of writing it to the pipeline.
 
.NOTES
    - Supported on Windows 10.
    - Requires HP BIOS with HP Sure Recover support
     
#>

function New-HPSureRecoverDeprovisionPayload
{
  [CmdletBinding(DefaultParameterSetName = "SF",HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverDeprovisionPayload")]
  param(
    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 0)]
    [string]$SigningKeyFile,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 1)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 1)]
    [string]$SigningKeyPassword,

    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 0)]
    [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 3)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 3)]
    [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")),

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 4)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 4)]
    [DeprovisioningTarget[]]$RemoveOnly,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 5)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 5)]
    [System.IO.FileInfo]$OutputFile
  )

  Write-Verbose "Creating SureRecover deprovisioning payload"
  if ($RemoveOnly) {
    [byte]$target = 0
    $RemoveOnly | ForEach-Object { $target = $target -bor $_ }
    Write-Verbose "Will deprovision only $([string]$RemoveOnly)"
  }
  else
  {
    [byte]$target = 31 # all five bits
    Write-Verbose "No deprovisioning filter specified, will deprovision all SureRecover"
  }

  $payload = [BitConverter]::GetBytes($nonce) + $target
  $sk = Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -password $SIgningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference
  $sig = Invoke-HPPrivateSignData -data $payload -Certificate $sk.Full -password $SigningKeyPassword -Verbose:$VerbosePreference

  Write-Verbose "Building output document"
  $output = New-Object -TypeName PortableFileFormat
  $output.data = $sig + $payload
  $output.purpose = "hp:surerecover:deprovision"
  $output.timestamp = Get-Date

  if ($OutputFile) {
    Write-Verbose 'Will output to file $OutputFile'
    $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)
    $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8
  }
  else {
    $output | ConvertTo-Json -Compress
  }
}



<#
.SYNOPSIS
    Set HP Sure Recover schedule
 
.DESCRIPTION
    This function create a payload to set a HP Sure Recover schedule.
 
    On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter.
    This payload can then be passed to the [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
<div style="background-color: #ee8; padding:10px;">
 
<h4>Security note</h4>
Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the <b>Set-HPSecurePlatformPayload</b> . Creating the payload and passing it to the <b>Set-HPSecurePlatformPayload</b> function via the pipeline is not a recommended production pattern.
 
</div>
     
.PARAMETER SigningKeyFile
     The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the SigningKeyPassword parameter should also be provided.
 
.PARAMETER SigningKeyPassword
     The secure platform signing key file password, if required.
 
.PARAMETER SigningKeyCertificate
     The secure platform signing key certificate, as an X509Certificate object.
 
.PARAMETER Nonce
     The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a
     nonce greater or equal to the last nonce sent.
 
     If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds,
     so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller
     should use its own nonce derivation and provide it through this parameter.
 
.PARAMETER DayOfWeek
     Defines the day of the week for the schedule
 
.PARAMETER Hour
     Defines the hour value for the schedule
 
.PARAMETER Minute
     Defines the minute of the schedule
 
.PARAMETER WindowSize
     Defines a windows size for the schedule activation (in minutes), in case the exact configured schedule is
     missed. By default, the window is zero. The value may not be larger than 4 hours (240 minutes).
    
.PARAMETER OutputFile
     Write the resulting output to the specified file, instead of writing it to the pipeline.
 
.NOTES
    - Supported on Windows 10.
    - Requires HP BIOS with HP Sure Recover support
#>

function New-HPSureRecoverSchedulePayload
{
  [CmdletBinding(DefaultParameterSetName = "SF",HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverSchedulePayload")]
  param(

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 0)]
    [string]$SigningKeyFile,

    [Parameter(ValueFromPipeline,ParameterSetName = "SB",Mandatory = $true,Position = 0)]
    [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 1)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 1)]
    [string]$SigningKeyPassword,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 2)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 2)]
    [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")),

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 3)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 3)]
    [surerecover_day_of_week]$DayOfWeek,

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 4)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 4)]
    [ValidateRange(0,23)]
    [uint32]$Hour,

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 5)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 5)]
    [ValidateRange(0,59)]
    [uint32]$Minute,

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 6)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 6)]
    [ValidateRange(1,240)]
    [uint32]$WindowSize,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 7)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 7)]
    [System.IO.FileInfo]$OutputFile
  )

  Write-Verbose "Creating SureRecover scheduling payload"
  $schedule_data = New-Object -TypeName surerecover_schedule_data_t

  Write-Verbose "Will set the SureRecover scheduler"
  $schedule_data.day_of_week = $DayOfWeek
  $schedule_data.Hour = $Hour
  $schedule_data.Minute = $Minute
  $schedule_data.window_size = $WindowSize

  $schedule = New-Object -TypeName surerecover_schedule_data_payload_t
  $schedule.schedule = $schedule_data
  $schedule.Nonce = $Nonce

  $cmd = New-Object -TypeName surerecover_schedule_payload_t
  $cmd.data = $schedule
  [byte[]]$payload = (Convert-HPPrivateObjectToBytes -obj $schedule -Verbose:$VerbosePreference)[0]


  $sk = Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -password $SIgningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference
  $cmd.sig = Invoke-HPPrivateSignData -data $payload -Certificate $sk.Full -password $SigningKeyPassword -Verbose:$VerbosePreference

  Write-Verbose "Building output document"
  $output = New-Object -TypeName PortableFileFormat

  $output.data = (Convert-HPPrivateObjectToBytes -obj $cmd -Verbose:$VerbosePreference)[0]
  $output.purpose = "hp:surerecover:scheduler"
  $output.timestamp = Get-Date


  if ($OutputFile) {
    Write-Verbose 'Will output to file $OutputFile'
    $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)
    $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8
  }
  else {
    $output | ConvertTo-Json -Compress
  }
}


<#
.SYNOPSIS
    Configure HP Sure Recover
 
.DESCRIPTION
    This function create a payload to configure HP Sure Recover
 
    On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter.
    This payload can then be passed to the [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
<div style="background-color: #ee8; padding:10px;">
 
<h4>Security note</h4>
Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the <b>Set-HPSecurePlatformPayload</b> . Creating the payload and passing it to the <b>Set-HPSecurePlatformPayload</b> function via the pipeline is not a recommended production pattern.
 
</div>
     
.PARAMETER SigningKeyFile
     The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the SigningKeyPassword parameter should also be provided.
 
.PARAMETER SigningKeyPassword
     The secure platform signing key file password, if required.
 
.PARAMETER SigningKeyCertificate
     The secure platform signing key certificate, as an X509Certificate object.
 
 
.PARAMETER Nonce
     The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a
     nonce greater or equal to the last nonce sent.
 
     If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds,
     so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller
     should use its own nonce derivation and provide it through this parameter.
 
.PARAMETER OSImageFlags
      Defines the imaging flags to set
 
.PARAMETER AgentFlags
    Defines the agent flags to set
    
.PARAMETER OutputFile
     Write the resulting output to the specified file, instead of writing it to the pipeline.
 
.NOTES
    - Supported on Windows 10.
    - Requires HP BIOS with HP Sure Recover support
#>

function New-HPSureRecoverConfigurationPayload
{
  [CmdletBinding(DefaultParameterSetName = "SF",HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverConfigurationPayload")]
  param(

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 0)]
    [string]$SigningKeyFile,

    [Parameter(ValueFromPipeline,ParameterSetName = "SB",Mandatory = $true,Position = 0)]
    [System.Security.Cryptography.X509Certificates.X509Certificate2]$SigningKeyCertificate,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 1)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 1)]
    [string]$SigningKeyPassword,

    [Parameter(ValueFromPipeline,ParameterSetName = "SB",Mandatory = $true,Position = 2)]
    [byte[]]$SigningKeyModulus,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 3)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 3)]
    [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")),

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 4)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 4)]
    [surerecover_os_flags]$OSImageFlags,

    [Parameter(ParameterSetName = "SF",Mandatory = $true,Position = 5)]
    [Parameter(ParameterSetName = "SB",Mandatory = $true,Position = 5)]
    [ValidateRange(0,23)]
    [surerecover_re_flags]$AgentFlags,

    [Parameter(ParameterSetName = "SF",Mandatory = $false,Position = 6)]
    [Parameter(ParameterSetName = "SB",Mandatory = $false,Position = 6)]
    [System.IO.FileInfo]$OutputFile
  )
  $sk = Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -password $SIgningKeyPassword -cert $SigningKeycertificate

  $data = New-Object -TypeName surerecover_configuration_payload_t
  $data.os_flags = [uint32]$OSImageFlags
  $data.re_flags = [uint32]$AgentFlags
  $data.arp_counter = $Nonce

  $cmd = New-Object -TypeName surerecover_configuration_t
  $cmd.data = $data

  [byte[]]$payload = (Convert-HPPrivateObjectToBytes -obj $data -Verbose:$VerbosePreference)[0]

  $cmd.sig = Invoke-HPPrivateSignData -data $payload -Certificate $sk.Full -password $SigningKeyPassword -Verbose:$VerbosePreference

  Write-Verbose "Building output document"
  $output = New-Object -TypeName PortableFileFormat
  $output.data = (Convert-HPPrivateObjectToBytes -obj $cmd -Verbose:$VerbosePreference)[0]
  $output.purpose = "hp:surerecover:configure"
  $output.timestamp = Get-Date


  if ($OutputFile) {
    Write-Verbose 'Will output to file $OutputFile'
    $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)
    $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8
  }
  else {
    $output | ConvertTo-Json -Compress
  }

}


<#
.SYNOPSIS
    Trigger HP Sure Recover events
 
.DESCRIPTION
    This function create a payload to trigger HP Sure Recover
 
    On return, the function writes the created payload to the pipeline, or to the file specified in the OutputFile parameter.
    This payload can then be passed to the [Set-HPSecurePlatformPayload](Set-HPSecurePlatformPayload) function.
 
<div style="background-color: #ee8; padding:10px;">
 
<h4>Security note</h4>
Payloads should only be created on secure servers. Once created, the payload may be transferred to a client and applied via the <b>Set-HPSecurePlatformPayload</b> . Creating the payload and passing it to the <b>Set-HPSecurePlatformPayload</b> function via the pipeline is not a recommended production pattern.
 
</div>
     
.PARAMETER SigningKeyFile
     The path to the secure platform signing key, as a PFX file. If the PFX file is protected by a password (recommended),
     the SigningKeyPassword parameter should also be provided.
 
.PARAMETER SigningKeyPassword
     The secure platform signing key file password, if required.
 
.PARAMETER SigningKeyCertificate
     The secure platform signing key certificate, as an X509Certificate object.
 
 
.PARAMETER Nonce
     The operation nonce. In order to prevent replay attacks, the secure platform subsystem will only accept commands with a
     nonce greater or equal to the last nonce sent.
 
     If not specified, the nonce is inferred from the current local time. This works okay in most cases, however this approach has a resolution of seconds,
     so when doing high volume or parallel operations, it is possible to infer the same counter for two or more commands. In those cases, the caller
     should use its own nonce derivation and provide it through this parameter.
 
.PARAMETER Set
    Indicates this is an operation to set the trigger information. This switch is default, and optional.
 
.PARAMETER Cancel
    Indicates this is an operation to cancel any existing trigger definition.
 
 
.PARAMETER ForceAfterReboot
    Defines how many reboots to count before applying the trigger. If not specified, defaults to 1 (next reboot).
 
.PARAMETER PromptPolicy
    Defines the prompting policy. If not defined, it will default to prompt before recovery, and on error.
 
.PARAMETER ErasePolicy
    Defines the erase policy for the imaging process.
 
.PARAMETER OutputFile
     Write the resulting output to the specified file, instead of writing it to the pipeline.
 
.NOTES
    - Supported on Windows 10.
    - Requires HP BIOS with HP Sure Recover support
     
#>

function New-HPSureRecoverTriggerRecoveryPayload
{
  [CmdletBinding(DefaultParameterSetName = "SF_Schedule",HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverTriggerRecoveryPayload")]
  param(

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $true,Position = 0)]
    [Parameter(ParameterSetName = "SF_Cancel",Mandatory = $true,Position = 0)]
    [string]$SigningKeyFile,

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 1)]
    [Parameter(ParameterSetName = "SF_Cancel",Mandatory = $false,Position = 1)]
    [string]$SigningKeyPassword,

    [Parameter(ValueFromPipeline,ParameterSetName = "SB_Schedule",Mandatory = $true,Position = 0)]
    [Parameter(ValueFromPipeline,ParameterSetName = "SB_Cancel",Mandatory = $true,Position = 0)]
    [byte[]]$SigningKeyCertificate,

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 3)]
    [Parameter(ParameterSetName = "SF_Cancel",Mandatory = $false,Position = 3)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 3)]
    [Parameter(ParameterSetName = "SB_Cancel",Mandatory = $false,Position = 3)]
    [uint32]$Nonce = [math]::Floor([decimal](Get-Date (Get-Date).ToUniversalTime() -UFormat "%s")),

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 4)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 4)]
    [switch]$Set,

    [Parameter(ParameterSetName = "SF_Cancel",Mandatory = $true,Position = 4)]
    [Parameter(ParameterSetName = "SB_Cancel",Mandatory = $true,Position = 4)]
    [switch]$Cancel,

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 6)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 6)]
    [ValidateRange(1,7)]
    [byte]$ForceAfterReboot = 1,

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 7)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 7)]
    [surerecover_prompt_policy]$PromptPolicy = "PromptBeforeRecovery,PromptOnError",

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 8)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 8)]
    [surerecover_erase_policy]$ErasePolicy = "None",

    [Parameter(ParameterSetName = "SF_Schedule",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SB_Schedule",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SF_Cancel",Mandatory = $false,Position = 9)]
    [Parameter(ParameterSetName = "SB_Cancel",Mandatory = $false,Position = 9)]
    [System.IO.FileInfo]$OutputFile
  )

  $sk = Get-HPPrivateX509CertCoalesce -File $SigningKeyFile -password $SIgningKeyPassword -cert $SigningKeycertificate -Verbose:$VerbosePreference
  $data = New-Object -TypeName surerecover_trigger_payload_t
  $data.arp_counter = $Nonce
  $data.bios_trigger_flags = 0

  $output = New-Object -TypeName PortableFileFormat

  if ($Cancel.IsPresent)
  {
    Write-Verbose "Creating payload to cancel trigger"
    $output.purpose = "hp:surerecover:trigger"
    $data.bios_trigger_flags = 0
    $data.re_trigger_flags = 0
  }
  else {
    Write-Verbose ("Creating payload to set trigger")
    $output.purpose = "hp:surerecover:trigger"
    $data.bios_trigger_flags = [uint32]$ForceAfterReboot
    $data.re_trigger_flags = [uint32]$PromptPolicy
    $data.re_trigger_flags = ([uint32]$ErasePolicy -shl 4) -bor $data.re_trigger_flags
  }

  $cmd = New-Object -TypeName surerecover_trigger_t
  $cmd.data = $data

  [byte[]]$payload = (Convert-HPPrivateObjectToBytes -obj $data -Verbose:$VerbosePreference)[0]
  $cmd.sig = Invoke-HPPrivateSignData -data $payload -Certificate $sk.Full -password $SigningKeyPassword -Verbose:$VerbosePreference
  Write-Verbose "Building output document with nonce $([BitConverter]::GetBytes($nonce))"

  $output.data = (Convert-HPPrivateObjectToBytes -obj $cmd -Verbose:$VerbosePreference)[0]
  Write-Verbose "Sending document of size $($output.data.length)"
  $output.timestamp = Get-Date

  if ($OutputFile) {
    Write-Verbose 'Will output to file $OutputFile'
    $f = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputFile)
    $output | ConvertTo-Json -Compress | Out-File -FilePath $f -Encoding utf8
  }
  else {
    $output | ConvertTo-Json -Compress
  }
}


<#
.SYNOPSIS
    Flag an embedded device for update, where available.
 
.DESCRIPTION
    This triggers the embedded reimaging device for update. If the hardware option is not present, the
    function will throw a NotSupportedException.
 
.NOTES
    - Supported on Windows 10.
  - Requires HP BIOS with HP Sure Recover support
  - Requires Embedded Reimaging device hardware option
     
#>

function Invoke-HPSureRecoverTriggerUpdate
{
  [CmdletBinding(HelpUri = "https://developers.hp.com/hp-client-management/doc/New%E2%80%90HPSureRecoverTriggerUpdate")]
  param()

  $mi_result = 0
  $cmd = '[DfmNativeSureRecover]::raise_surerecover_service_event_opaque' + (Test-OSBitness) + '($null, $null, [ref]$mi_result);'
  $result = Invoke-Expression -Command $cmd
  Test-HPPrivateCustomResult -result $result -mi_result $mi_result -Category 0x04
}


# SIG # Begin signature block
# MIIcNwYJKoZIhvcNAQcCoIIcKDCCHCQCAQExDzANBglghkgBZQMEAgEFADB5Bgor
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCCN32BqI5miqZl3
# gKcPzsZdrLPkwAAtU7c60nVlGkvvgKCCCo0wggU2MIIEHqADAgECAhAM1s71mz4i
# 3j/UnuaI4vzeMA0GCSqGSIb3DQEBCwUAMHYxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xNTAzBgNV
# BAMTLERpZ2lDZXJ0IFNIQTIgSGlnaCBBc3N1cmFuY2UgQ29kZSBTaWduaW5nIENB
# MB4XDTE5MDQyMjAwMDAwMFoXDTIwMDQyOTEyMDAwMFowdTELMAkGA1UEBhMCVVMx
# EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVBhbG8gQWx0bzEQMA4GA1UE
# ChMHSFAgSW5jLjEZMBcGA1UECxMQSFAgQ3liZXJzZWN1cml0eTEQMA4GA1UEAxMH
# SFAgSW5jLjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANEwuTFpw7fQ
# 3Ds5fvexal46Gg9TNMvdiJu7qMqDZnDJNl7ECdEPyLxsioGS7/yomOS9RXdXMJOm
# tyV4/wIPbBaGC8E2tbLTbQQ4IJbgvC+Vc46vbo+sI8YTG6qBICOovFw9VhUNXXEy
# SwHMoBNk8JS8R1slPpJKmNGB10HSatMGaHja0Lbqos0QuEx/tx2OXe+mzepIo66T
# dtSv2MfPy2tcVcXIdiJGn7f4otxoj6T9X7hVIl78r5Y2XWHYtDK8KaV1E/qkiNXK
# 1Xw5S53zv2VsZl6i1LZwt3d1Q9pUmm1AZe2YdhSGvwMP2LYBJGXIBbyLYnxS4HKB
# R7MYZyz7H2kCAwEAAaOCAb8wggG7MB8GA1UdIwQYMBaAFGedDyAJDMyKOuWCRnJi
# /PHMkOVAMB0GA1UdDgQWBBSnSAWgK15kcBLxsg4XNsT7ncH29zAOBgNVHQ8BAf8E
# BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwbQYDVR0fBGYwZDAwoC6gLIYqaHR0
# cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItaGEtY3MtZzEuY3JsMDCgLqAshipo
# dHRwOi8vY3JsNC5kaWdpY2VydC5jb20vc2hhMi1oYS1jcy1nMS5jcmwwTAYDVR0g
# BEUwQzA3BglghkgBhv1sAwswKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGln
# aWNlcnQuY29tL0NQUzAIBgZngQwBBAEwgYgGCCsGAQUFBwEBBHwwejAkBggrBgEF
# BQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMFIGCCsGAQUFBzAChkZodHRw
# Oi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRTSEEySGlnaEFzc3VyYW5j
# ZUNvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
# ggEBAJQblkFw+UYKYSY2M/CIEpJxZDnf+cDhodKAy+goI3XfExRHhyLu3Gc2ibFB
# Y4wyz/sJSfHehtNPYckXxR9k/FB/GfYtEACug9xXxJ+iLxWUNQ4KPt3bXY/kmDxW
# D1QXJFLbW5Dop3w/K0DL3fxnjOfYCcxsYodbeEiCJprCdNi3zd6x/J8Y35GDbLA5
# p7RfIAzKrmBLPHFGDWr/jWTfwPfUNz6jYJ51m0Ba9j81kzpxNUD0yBIZXBkVvSkx
# A09KxzMSSvxvV9DSqSezQBVgWnl9TbElouYUQwk64i0GzL4lTsphK4rQJJ2uuKtH
# wN4E0ibpm0uIqbLhgk+3ic8fHTIwggVPMIIEN6ADAgECAhALfhCQPDhJD/ovZ5qH
# oae5MA0GCSqGSIb3DQEBCwUAMGwxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdp
# Q2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xKzApBgNVBAMTIkRp
# Z2lDZXJ0IEhpZ2ggQXNzdXJhbmNlIEVWIFJvb3QgQ0EwHhcNMTMxMDIyMTIwMDAw
# WhcNMjgxMDIyMTIwMDAwWjB2MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
# cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTUwMwYDVQQDEyxEaWdp
# Q2VydCBTSEEyIEhpZ2ggQXNzdXJhbmNlIENvZGUgU2lnbmluZyBDQTCCASIwDQYJ
# KoZIhvcNAQEBBQADggEPADCCAQoCggEBALRKXn0HD0HexPV2Fja9cf/PP09zS5zR
# Df5Ky1dYXoUW3QIVVJnwjzwvTQJ4EGjI2DVLP8H3Z86YHK4zuS0dpApUk8SFot81
# sfXxPKezNPtdSMlGyWJEvEiZ6yhJU8M9j8AO3jWY6WJR3z1rQGHuBEHaz6dcVpbR
# +Uy3RISHmGnlgrkT5lW/yJJwkgoxb3+LMqvPa1qfYsQ+7r7tWaRTfwvxUoiKewpn
# JMuQzezSTTRMsOG1n5zG9m8szebKU3QBn2c13jhJLc7tOUSCGXlOGrK1+7t48Elm
# p8/6XJZ1kosactn/UJJTzD7CQzIJGoYTaTz7gTIzMmR1cygmHQgwOwcCAwEAAaOC
# AeEwggHdMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMBMGA1Ud
# JQQMMAoGCCsGAQUFBwMDMH8GCCsGAQUFBwEBBHMwcTAkBggrBgEFBQcwAYYYaHR0
# cDovL29jc3AuZGlnaWNlcnQuY29tMEkGCCsGAQUFBzAChj1odHRwOi8vY2FjZXJ0
# cy5kaWdpY2VydC5jb20vRGlnaUNlcnRIaWdoQXNzdXJhbmNlRVZSb290Q0EuY3J0
# MIGPBgNVHR8EgYcwgYQwQKA+oDyGOmh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9E
# aWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5jcmwwQKA+oDyGOmh0dHA6Ly9j
# cmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEhpZ2hBc3N1cmFuY2VFVlJvb3RDQS5j
# cmwwTwYDVR0gBEgwRjA4BgpghkgBhv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBz
# Oi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCgYIYIZIAYb9bAMwHQYDVR0OBBYEFGed
# DyAJDMyKOuWCRnJi/PHMkOVAMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSYJhoIAu9j
# ZCvDMA0GCSqGSIb3DQEBCwUAA4IBAQBqDv9+E3wGpUvALoz5U2QJ4rpYkTBQ7Myf
# 4dOoL0hGNhgp0HgoX5hWQA8eur2xO4dc3FvYIA3tGhZN1REkIUvxJ2mQE+sRoQHa
# /bVOeVl1vTgqasP2jkEriqKL1yxRUdmcoMjjTrpsqEfSTtFoH4wCVzuzKWqOaiAq
# ufIAYmS6yOkA+cyk1LqaNdivLGVsFnxYId5KMND66yRdBsmdFretSkXTJeIM8ECq
# XE2sfs0Ggrl2RmkI2DK2gv7jqVg0QxuOZ2eXP2gxFjY4lT6H98fDr516dxnZ3pO1
# /W4r/JT5PbdMEjUsML7ojZ4FcJpIE/SM1ucerDjnqPOtDLd67GftMYIRADCCEPwC
# AQEwgYowdjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcG
# A1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTE1MDMGA1UEAxMsRGlnaUNlcnQgU0hBMiBI
# aWdoIEFzc3VyYW5jZSBDb2RlIFNpZ25pbmcgQ0ECEAzWzvWbPiLeP9Se5oji/N4w
# DQYJYIZIAWUDBAIBBQCgfDAQBgorBgEEAYI3AgEMMQIwADAZBgkqhkiG9w0BCQMx
# DAYKKwYBBAGCNwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkq
# hkiG9w0BCQQxIgQgqcSHg+eP0UU7GL4FeY4TI5aKNpm1uybHwOmizUVNc74wDQYJ
# KoZIhvcNAQEBBQAEggEAYjpycwgnL/0bdit1VaMM+eMQNQU4hfyOoskTfLrQHTpZ
# W+U7Yf4Hnq3FI++CU19k0EGRLyT59J+Vq6tFjiqcf3f7o0/8v4UP/JNM+yMnhQBT
# M2bxLn5C9BTzpge5fXwdvklXkBxlrGtCz9oS6xq+qPVSB1/ZM8hQAwKUClbXfLSR
# ciTQutNXS562mO/rSnv290GDqIgKUCKqiyBzIPJqldrIAJpVhUIDyKS5WXP9YUfa
# qKlQ/e3E0sUXkH1Efvt/MTIV5oNildGdXsg0zfVkqg5B3q/iguJHI3CafgRMD1af
# tXH4yERFj7xaULS9maWy7GIpR42y02OqRFdaPNvEq6GCDsgwgg7EBgorBgEEAYI3
# AwMBMYIOtDCCDrAGCSqGSIb3DQEHAqCCDqEwgg6dAgEDMQ8wDQYJYIZIAWUDBAIB
# BQAwdwYLKoZIhvcNAQkQAQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFl
# AwQCAQUABCCOjwhP2butZUsYAK20tgnmRRkzXhbxQ9BMILoMz6dlIAIQF5lPI/0Z
# sM0WuI5D8mpeABgPMjAyMDAyMTQyMjU3NDFaoIILuzCCBoIwggVqoAMCAQICEATN
# P4VornbGG7D+cWDMp20wDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMCVVMxFTAT
# BgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEx
# MC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBD
# QTAeFw0xOTEwMDEwMDAwMDBaFw0zMDEwMTcwMDAwMDBaMEwxCzAJBgNVBAYTAlVT
# MRcwFQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEkMCIGA1UEAxMbVElNRVNUQU1QLVNI
# QTI1Ni0yMDE5LTEwLTE1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
# 6WQ1nPqpmGVkG+QX3LgpNsxnCViFTTDgyf/lOzwRKFCvBzHiXQkYwvaJjGkIBCPg
# dy2dFeW46KFqjv/UrtJ6Fu/4QbUdOXXBzy+nrEV+lG2sAwGZPGI+fnr9RZcxtPq3
# 2UI+p1Wb31pPWAKoMmkiE76Lgi3GmKtrm7TJ8mURDHQNsvAIlnTE6LJIoqEUpfj6
# 4YlwRDuN7/uk9MO5vRQs6wwoJyWAqxBLFhJgC2kijE7NxtWyZVkh4HwsEo1wDo+K
# yuDT17M5d1DQQiwues6cZ3o4d1RA/0+VBCDU68jOhxQI/h2A3dDnK3jqvx9wxu5C
# FlM2RZtTGUlinXoCm5UUowIDAQABo4IDODCCAzQwDgYDVR0PAQH/BAQDAgeAMAwG
# A1UdEwEB/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwggG/BgNVHSAEggG2
# MIIBsjCCAaEGCWCGSAGG/WwHATCCAZIwKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3
# LmRpZ2ljZXJ0LmNvbS9DUFMwggFkBggrBgEFBQcCAjCCAVYeggFSAEEAbgB5ACAA
# dQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABpAGYAaQBjAGEAdABlACAA
# YwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBwAHQAYQBuAGMAZQAgAG8A
# ZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQAC8AQwBQAFMAIABhAG4A
# ZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQByAHQAeQAgAEEAZwByAGUA
# ZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0ACAAbABpAGEAYgBpAGwA
# aQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwByAHAAbwByAGEAdABlAGQA
# IABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBlAG4AYwBlAC4wCwYJYIZI
# AYb9bAMVMB8GA1UdIwQYMBaAFPS24SAd/imu0uRhpbKiJbLIFzVuMB0GA1UdDgQW
# BBRWUw/BxgenTdfYbldygFBM5OyewTBxBgNVHR8EajBoMDKgMKAuhixodHRwOi8v
# Y3JsMy5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDAyoDCgLoYsaHR0
# cDovL2NybDQuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwgYUGCCsG
# AQUFBwEBBHkwdzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29t
# ME8GCCsGAQUFBzAChkNodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNl
# cnRTSEEyQXNzdXJlZElEVGltZXN0YW1waW5nQ0EuY3J0MA0GCSqGSIb3DQEBCwUA
# A4IBAQAug6FEBUoE47kyUvrZgfAau/gJjSO5PdiSoeZGHEovbno8Y243F6Mav1gj
# skOclINOOQmwLOjH4eLM7ct5a87eIwFH7ZVUgeCAexKxrwKGqTpzav74n8GN0SGM
# 5CmCw4oLYAACnR9HxJ+0CmhTf1oQpvgi5vhTkjFf2IKDLW0TQq6DwRBOpCT0R5ze
# DyJyd1x/T+k5mCtXkkTX726T2UPHBDNjUTdWnkcEEcOjWFQh2OKOVtdJP1f8Cp8j
# Xnv0lI3dnRq733oqptJFplUMj/ZMivKWz4lG3DGykZCjXzMwYFX1/GswrKHt5EdO
# M55naii1TcLtW5eC+MupCGxTCbT3MIIFMTCCBBmgAwIBAgIQCqEl1tYyG35B5AXa
# NpfCFTANBgkqhkiG9w0BAQsFADBlMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
# aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtE
# aWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwHhcNMTYwMTA3MTIwMDAwWhcNMzEw
# MTA3MTIwMDAwWjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
# MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
# SEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBMIIBIjANBgkqhkiG9w0BAQEF
# AAOCAQ8AMIIBCgKCAQEAvdAy7kvNj3/dqbqCmcU5VChXtiNKxA4HRTNREH3Q+X1N
# aH7ntqD0jbOI5Je/YyGQmL8TvFfTw+F+CNZqFAA49y4eO+7MpvYyWf5fZT/gm+vj
# RkcGGlV+Cyd+wKL1oODeIj8O/36V+/OjuiI+GKwR5PCZA207hXwJ0+5dyJoLVOOo
# CXFr4M8iEA91z3FyTgqt30A6XLdR4aF5FMZNJCMwXbzsPGBqrC8HzP3w6kfZiFBe
# /WZuVmEnKYmEUeaC50ZQ/ZQqLKfkdT66mA+Ef58xFNat1fJky3seBdCEGXIX8RcG
# 7z3N1k3vBkL9olMqT4UdxB08r8/arBD13ays6Vb/kwIDAQABo4IBzjCCAcowHQYD
# VR0OBBYEFPS24SAd/imu0uRhpbKiJbLIFzVuMB8GA1UdIwQYMBaAFEXroq/0ksuC
# MS1Ri6enIZ3zbcgPMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGG
# MBMGA1UdJQQMMAoGCCsGAQUFBwMIMHkGCCsGAQUFBwEBBG0wazAkBggrBgEFBQcw
# AYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEMGCCsGAQUFBzAChjdodHRwOi8v
# Y2FjZXJ0cy5kaWdpY2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3J0
# MIGBBgNVHR8EejB4MDqgOKA2hjRodHRwOi8vY3JsNC5kaWdpY2VydC5jb20vRGln
# aUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMDqgOKA2hjRodHRwOi8vY3JsMy5kaWdp
# Y2VydC5jb20vRGlnaUNlcnRBc3N1cmVkSURSb290Q0EuY3JsMFAGA1UdIARJMEcw
# OAYKYIZIAYb9bAACBDAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy
# dC5jb20vQ1BTMAsGCWCGSAGG/WwHATANBgkqhkiG9w0BAQsFAAOCAQEAcZUS6VGH
# VmnN793afKpjerN4zwY3QITvS4S/ys8DAv3Fp8MOIEIsr3fzKx8MIVoqtwU0HWqu
# mfgnoma/Capg33akOpMP+LLR2HwZYuhegiUexLoceywh4tZbLBQ1QwRostt1AuBy
# x5jWPGTlH0gQGF+JOGFNYkYkh2OMkVIsrymJ5Xgf1gsUpYDXEkdws3XVk4WTfraS
# Z/tTYYmo9WuWwPRYaQ18yAGxuSh1t5ljhSKMYcp5lH5Z/IwP42+1ASa2bKXuh1Eh
# 5Fhgm7oMLSttosR+u8QlK0cCCHxJrhO24XxCQijGGFbPQTS2Zl22dHv1VjMiLyI2
# skuiSpXY9aaOUjGCAk0wggJJAgEBMIGGMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNV
# BAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0ECEATN
# P4VornbGG7D+cWDMp20wDQYJYIZIAWUDBAIBBQCggZgwGgYJKoZIhvcNAQkDMQ0G
# CyqGSIb3DQEJEAEEMBwGCSqGSIb3DQEJBTEPFw0yMDAyMTQyMjU3NDFaMCsGCyqG
# SIb3DQEJEAIMMRwwGjAYMBYEFAMlvVBe2pYwLcIvT6AeTCi+KDTFMC8GCSqGSIb3
# DQEJBDEiBCCv7sodtsV5XTTlL1kHNzjb1fWy/NQe7R1NQFEMJ8bOHTANBgkqhkiG
# 9w0BAQEFAASCAQCRRCO5FGtqA30EM+k5wUZ/x47CYB91XOJij1rh+RXojylhDLAM
# QX/Qj8VtLJOdGH7dh+Z/kp2rfOQuji39ofIPHIIUeL6FZRbFcOq0HEI8xZIYxrUe
# /XQmIL3jliF53gmaF9L64kN1fWdV74FDe2Jh+bP1xV0ddzwOcgB4Y5nWVaVZmrd4
# cL4SCPIV72Fqk3+eiziECXcq7xptYyMLOYS4VtfNe+0633JUJ6WlBiTaXm1MUycz
# c5o4oOqQr0ely8F+w8bPRUnsPF9haKQ3q039V3lAfXNnW1UFd1/gICpI3Xzgm5NN
# Ec+axCTCl04l8Ds/J8vps7U7c37uvDbpSvqB
# SIG # End signature block