Repository: PowerShell/PowerShell
File: test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 (PowerShell)

Code before:
using namespace System.Security.Cryptography
function New-CmsRecipient {
  [CmdletBinding(SupportsShouldProcess = $true)]
  param([String]$Name, [Switch]$Invalid)
  $hash = [HashAlgorithmName]::SHA256
  $pad = [RSASignaturePadding]::Pkcs1
  $oids = [OidCollection]::new()
  $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null
  $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false)
  $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false)
  $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad))
  if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) }
  return $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365))
}

Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" {

  BeforeAll {
    Write-Verbose  "Generating certs"
    $vc1 = New-CmsRecipient "ValidCms1"
    $vc2 = New-CmsRecipient "ValidCms2"
    $ic = New-CmsRecipient "InvalidCms" -Invalid
    $tmpfile = New-TemporaryFile
  }

  It " Encrypting with X509Cert" {
    "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*'
  }

  It " Encrypting with multiple X509Cert" {
    $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*'
  }

  It " Decrypt with X509Cert" {
    "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to $vc1 | Should -BeExactly "test"
  }

  It " Decrypt with multiple X509Cert" {
    "test" | Protect-CmsMessage -to $vc1, $vc2 | Unprotect-CmsMessage -to $vc1, $vc2 | Should -BeExactly "test"
  }

  It " Encrypt with invalid cert" {
    $e = try { "test" | Protect-CmsMessage -to $ic } catch { $_ }
    $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*'   
  }

  It "Encrypt with valid and invalid" {
    $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic } catch { $_ }
    $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' 
  }


Review comment (suggestion):
Can we make sure we have tests for all the following variants of `-to`:

- An actual certificate (as retrieved from the certificate provider).
- Path to the file containing the certificate.
- Path to a directory containing the certificate.
- Thumbprint of the certificate (used to look in the certificate store).
- Subject name of the certificate (used to look in the certificate store).

Code after:
# Licensed under the MIT License.

using namespace System.Security.Cryptography.X509Certificates
using namespace System.Security.Cryptography

function New-CmsRecipient {
    [CmdletBinding(SupportsShouldProcess = $true)]
    [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])]
    param([String]$Name, [Switch]$Invalid, [String]$OutPfxFile)
    $hash = [HashAlgorithmName]::SHA256
    $pad = [RSASignaturePadding]::Pkcs1
    $oids = [OidCollection]::new()
    $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null
    $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false)
    $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false)
    $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad))
    if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) }
    $certTmp = $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365))
    $certBytes = $certTmp.Export([X509ContentType]::Pfx, "tmp")
    [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable"
    $cert = [X509Certificate2]::new($certBytes, "tmp", $flags)
    if ($OutPfxFile) {
        $outfile = New-Item $OutPfxFile -Force
        [System.IO.File]::WriteAllBytes($outfile.FullName, $cert.Export([X509ContentType]::Pfx))
    }
    return $cert
}

Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" {

    BeforeAll {
        Setup -Dir "certDir"
        Setup -File "vc1.pfx"
        Setup -File "vc2.pfx"
        Setup -File "certDir/vc3.pfx"
        Setup -File "message.txt" -Content "test"
        $file1 = "TestDrive:\vc1.pfx"
        $file2 = "TestDrive:\vc2.pfx"
        $messageFile = "TestDrive:\message.txt"
        $cipherFile = "TestDrive:\cipher.txt"
        $vc1 = New-CmsRecipient "ValidCms1" -OutPfxFile $file1
        $vc2 = New-CmsRecipient "ValidCms2" -OutPfxFile $file2
        $vc3 = New-CmsRecipient "ValidCms22" -OutPfxFile "TestDrive:\certDir\vc3.pfx"
        $ic = New-CmsRecipient "InvalidCms" -Invalid -OutPfxFile "TestDrive:\ic.pfx"
        $store = [X509Store]::new("My", [StoreLocation]::CurrentUser)
        $store.Open("ReadWrite")
        if (!$IsMacOS) {
            $store.Add($vc1)
            $store.Add($vc2)
            $store.Add($vc3)
        }