Bring back Certificate provider parameters (#10622)

This commit is contained in:
Ilya 2020-06-02 23:44:16 +05:00 committed by GitHub
parent 8f79ce1d29
commit 73e8427586
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 510 additions and 206 deletions

View File

@ -31,20 +31,18 @@ namespace Microsoft.PowerShell.Commands
{
/// <summary>
/// Defines the Certificate Provider dynamic parameters.
///
/// We only support one dynamic parameter for Win 7 and earlier:
/// CodeSigningCert
/// If provided, we only return certificates valid for signing code or
/// scripts.
/// </summary>
internal sealed class CertificateProviderCodeSigningDynamicParameters
internal sealed class CertificateProviderDynamicParameters
{
/// <summary>
/// Switch that controls whether we only return
/// Gets or sets a switch that controls whether we only return
/// code signing certs.
/// </summary>
[Parameter()]
[Parameter]
public SwitchParameter CodeSigningCert
{
get { return _codeSigningCert; }
@ -53,6 +51,70 @@ namespace Microsoft.PowerShell.Commands
}
private SwitchParameter _codeSigningCert = new SwitchParameter();
/// <summary>
/// Gets or sets a filter that controls whether we only return
/// data encipherment certs.
/// </summary>
[Parameter]
public SwitchParameter DocumentEncryptionCert
{
get;
set;
}
/// <summary>
/// Gets or sets a filter that controls whether we only return
/// server authentication certs.
/// </summary>
[Parameter]
public SwitchParameter SSLServerAuthentication
{
get;
set;
}
/// <summary>
/// Gets or sets a filter by DNSName.
/// Expected content is a single DNS Name that may start and/or end
/// with '*': "contoso.com" or "*toso.c*".
/// All WildcardPattern class features supported.
/// </summary>
[Parameter]
public string DnsName
{
get;
set;
}
/// <summary>
/// Gets or sets a filter by EKU.
/// Expected content is one or more OID strings:
/// "1.3.6.1.5.5.7.3.1", "*Server*", etc.
/// For a cert to match, it must be valid for all listed OIDs.
/// All WildcardPattern class features supported.
/// </summary>
[Parameter]
public string[] Eku
{
get;
set;
}
/// <summary>
/// Gets or sets a filter by the number of valid days.
/// Expected content is a non-negative integer.
/// "0" matches all certs that have already expired.
/// "1" matches all certs that are currently valid and will expire
/// by next day (local time).
/// </summary>
[Parameter]
[ValidateRange(ValidateRangeKind.NonNegative)]
public int ExpiringInDays
{
get;
set;
} = -1;
}
/// <summary>
@ -169,7 +231,7 @@ namespace Microsoft.PowerShell.Commands
/// Switch that controls whether we should delete private key
/// when remove a certificate.
/// </summary>
[Parameter()]
[Parameter]
public SwitchParameter DeleteKey
{
get
@ -1185,15 +1247,11 @@ namespace Microsoft.PowerShell.Commands
}
else
{
// The filter is non null. If the certificate
// satisfies the filter, output it. Otherwise, don't.
// The filter is non null. If the certificate
// satisfies the filter, output it. Otherwise, don't.
X509Certificate2 cert = item as X509Certificate2;
Dbg.Diagnostics.Assert(cert != null, "item should be a certificate");
// If it's Win8 or above, filter matching for certain properties is done by
// the certificate enumeration filter at the API level. In that case,
// filter.Purpose will be 'None' and MatchesFilter will return 'True'.
if (MatchesFilter(cert, filter))
{
WriteItemObject(item, path, isContainer);
@ -2212,7 +2270,7 @@ namespace Microsoft.PowerShell.Commands
/// </returns>
protected override object GetItemDynamicParameters(string path)
{
return new CertificateProviderCodeSigningDynamicParameters();
return new CertificateProviderDynamicParameters();
}
/// <summary>
@ -2234,7 +2292,7 @@ namespace Microsoft.PowerShell.Commands
/// </returns>
protected override object GetChildItemsDynamicParameters(string path, bool recurse)
{
return new CertificateProviderCodeSigningDynamicParameters();
return new CertificateProviderDynamicParameters();
}
#endregion DriveCmdletProvider overrides
@ -2607,8 +2665,8 @@ namespace Microsoft.PowerShell.Commands
if (DynamicParameters != null)
{
CertificateProviderCodeSigningDynamicParameters dp =
DynamicParameters as CertificateProviderCodeSigningDynamicParameters;
CertificateProviderDynamicParameters dp =
DynamicParameters as CertificateProviderDynamicParameters;
if (dp != null)
{
if (dp.CodeSigningCert)
@ -2616,6 +2674,40 @@ namespace Microsoft.PowerShell.Commands
filter = new CertificateFilterInfo();
filter.Purpose = CertificatePurpose.CodeSigning;
}
if (dp.DocumentEncryptionCert)
{
filter = filter ?? new CertificateFilterInfo();
filter.Purpose = CertificatePurpose.DocumentEncryption;
}
if (dp.DnsName != null)
{
filter = filter ?? new CertificateFilterInfo();
filter.DnsName = new WildcardPattern(dp.DnsName, WildcardOptions.IgnoreCase);
}
if (dp.Eku != null)
{
filter = filter ?? new CertificateFilterInfo();
filter.Eku = new List<WildcardPattern>();
foreach (var pattern in dp.Eku)
{
filter.Eku.Add(new WildcardPattern(pattern, WildcardOptions.IgnoreCase));
}
}
if (dp.ExpiringInDays >= 0)
{
filter = filter ?? new CertificateFilterInfo();
filter.Expiring = DateTime.Now.AddDays(dp.ExpiringInDays);
}
if (dp.SSLServerAuthentication)
{
filter = filter ?? new CertificateFilterInfo();
filter.SSLServerAuthentication = true;
}
}
}
@ -2634,39 +2726,45 @@ namespace Microsoft.PowerShell.Commands
return includeArchivedCerts;
}
// If it's Win8 or above, filter matching for certain properties is done by
// the certificate enumeration filter at the API level. In that case,
// filter.Purpose will be 'None' and MatchesFilter will return 'True'.
private static bool MatchesFilter(X509Certificate2 cert,
CertificateFilterInfo filter)
private static bool MatchesFilter(X509Certificate2 cert, CertificateFilterInfo filter)
{
//
// no filter means, match everything
//
if ((filter == null) ||
(filter.Purpose == CertificatePurpose.NotSpecified) ||
(filter.Purpose == CertificatePurpose.All))
// No filter means, match everything
if (filter == null)
{
return true;
}
if (filter.Expiring > DateTime.MinValue && !SecuritySupport.CertExpiresByTime(cert, filter.Expiring))
{
return false;
}
if (filter.DnsName != null && !CertContainsName(cert, filter.DnsName))
{
return false;
}
if (filter.Eku != null && !CertContainsEku(cert, filter.Eku))
{
return false;
}
if (filter.SSLServerAuthentication && !CertIsSSLServerAuthentication(cert))
{
return false;
}
switch (filter.Purpose)
{
case CertificatePurpose.CodeSigning:
if (SecuritySupport.CertIsGoodForSigning(cert))
{
return true;
}
break;
return SecuritySupport.CertIsGoodForSigning(cert);
case CertificatePurpose.DocumentEncryption:
if (SecuritySupport.CertIsGoodForEncryption(cert))
{
return true;
}
return SecuritySupport.CertIsGoodForEncryption(cert);
break;
case CertificatePurpose.NotSpecified:
case CertificatePurpose.All:
return true;
default:
break;
@ -2675,6 +2773,89 @@ namespace Microsoft.PowerShell.Commands
return false;
}
/// <summary>
/// Check if the specified certificate has the name in DNS name list.
/// </summary>
/// <param name="cert">Certificate object.</param>
/// <param name="pattern">Wildcard pattern for DNS name to search.</param>
/// <returns>True on success, false otherwise.</returns>
internal static bool CertContainsName(X509Certificate2 cert, WildcardPattern pattern)
{
List<DnsNameRepresentation> list = (new DnsNameProperty(cert)).DnsNameList;
foreach (DnsNameRepresentation dnsName in list)
{
if (pattern.IsMatch(dnsName.Unicode))
{
return true;
}
}
return false;
}
/// <summary>
/// Check if the specified certificate is a server authentication certificate.
/// </summary>
/// <param name="cert">Certificate object.</param>
/// <returns>True on success, false otherwise.</returns>
internal static bool CertIsSSLServerAuthentication(X509Certificate2 cert)
{
X509ExtensionCollection extentionList = cert.Extensions;
foreach (var extension in extentionList)
{
if (extension is X509EnhancedKeyUsageExtension eku)
{
foreach (Oid usage in eku.EnhancedKeyUsages)
{
if (usage.Value.Equals(CertificateFilterInfo.OID_PKIX_KP_SERVER_AUTH, StringComparison.Ordinal))
{
return true;
}
}
}
}
return false;
}
/// <summary>
/// Check if the specified certificate contains EKU matching all of these patterns.
/// </summary>
/// <param name="cert">Certificate object.</param>
/// <param name="ekuPatterns">EKU patterns.</param>
/// <returns>True on success, false otherwise.</returns>
internal static bool CertContainsEku(X509Certificate2 cert, List<WildcardPattern> ekuPatterns)
{
X509ExtensionCollection extensionList = cert.Extensions;
foreach (var extension in extensionList)
{
if (extension is X509EnhancedKeyUsageExtension eku)
{
OidCollection enhancedKeyUsages = eku.EnhancedKeyUsages;
foreach (WildcardPattern ekuPattern in ekuPatterns)
{
bool patternPassed = false;
foreach (var usage in enhancedKeyUsages)
{
if (ekuPattern.IsMatch(usage.Value) || ekuPattern.IsMatch(usage.FriendlyName))
{
return true;
}
}
if (!patternPassed)
{
return false;
}
}
return true;
}
}
return false;
}
private static object GetCachedItem(string path)
{
object item = null;
@ -3195,7 +3376,7 @@ namespace Microsoft.PowerShell.Commands
}
/// <summary>
/// Constructor for EkuList.
/// Constructor for DnsNameProperty.
/// </summary>
public DnsNameProperty(X509Certificate2 cert)
{

View File

@ -4,22 +4,23 @@
#pragma warning disable 1634, 1691
#pragma warning disable 56523
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Commands;
using System.Management.Automation.Security;
using System.Globalization;
using System.Management.Automation.Configuration;
using System.Management.Automation.Internal;
using System.Management.Automation.Security;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Globalization;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using Microsoft.PowerShell;
using Microsoft.PowerShell.Commands;
using DWORD = System.UInt32;
namespace Microsoft.PowerShell
@ -629,6 +630,17 @@ namespace System.Management.Automation.Internal
CertHasKeyUsage(c, X509KeyUsageFlags.KeyEncipherment)));
}
/// <summary>
/// Check to see if the specified cert is expiring by the time.
/// </summary>
/// <param name="c">Certificate object.</param>
/// <param name="expiring">Certificate expire time.</param>
/// <returns>True on success, false otherwise.</returns>
internal static bool CertExpiresByTime(X509Certificate2 c, DateTime expiring)
{
return c.NotAfter < expiring;
}
private static bool CertHasOid(X509Certificate2 c, string oid)
{
foreach (var extension in c.Extensions)
@ -665,6 +677,64 @@ namespace System.Management.Automation.Internal
return false;
}
/// <summary>
/// Get the EKUs of a cert.
/// </summary>
/// <param name="cert">Certificate object.</param>
/// <returns>A collection of cert eku strings.</returns>
[ArchitectureSensitive]
internal static Collection<string> GetCertEKU(X509Certificate2 cert)
{
Collection<string> ekus = new Collection<string>();
IntPtr pCert = cert.Handle;
int structSize = 0;
IntPtr dummy = IntPtr.Zero;
if (Security.NativeMethods.CertGetEnhancedKeyUsage(pCert, 0, dummy,
out structSize))
{
if (structSize > 0)
{
IntPtr ekuBuffer = Marshal.AllocHGlobal(structSize);
try
{
if (Security.NativeMethods.CertGetEnhancedKeyUsage(pCert, 0,
ekuBuffer,
out structSize))
{
Security.NativeMethods.CERT_ENHKEY_USAGE ekuStruct =
(Security.NativeMethods.CERT_ENHKEY_USAGE)
Marshal.PtrToStructure<Security.NativeMethods.CERT_ENHKEY_USAGE>(ekuBuffer);
IntPtr ep = ekuStruct.rgpszUsageIdentifier;
IntPtr ekuptr;
for (int i = 0; i < ekuStruct.cUsageIdentifier; i++)
{
ekuptr = Marshal.ReadIntPtr(ep, i * Marshal.SizeOf(ep));
string eku = Marshal.PtrToStringAnsi(ekuptr);
ekus.Add(eku);
}
}
else
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
}
finally
{
Marshal.FreeHGlobal(ekuBuffer);
}
}
}
else
{
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
return ekus;
}
/// <summary>
/// Convert an int to a DWORD.
/// </summary>
@ -698,174 +768,53 @@ namespace System.Management.Automation.Internal
}
/// <summary>
/// Purpose of a certificate.
/// Gets or sets purpose of a certificate.
/// </summary>
internal CertificatePurpose Purpose
{
get { return _purpose; }
set { _purpose = value; }
}
get;
set;
} = CertificatePurpose.NotSpecified;
/// <summary>
/// SSL Server Authentication.
/// Gets or sets SSL Server Authentication.
/// </summary>
internal bool SSLServerAuthentication
{
get { return _sslServerAuthentication; }
get;
set { _sslServerAuthentication = value; }
set;
}
/// <summary>
/// DNS name of a certificate.
/// Gets or sets DNS name of a certificate.
/// </summary>
internal string DnsName
internal WildcardPattern DnsName
{
set { _dnsName = value; }
get;
set;
}
/// <summary>
/// EKU OID list of a certificate.
/// Gets or sets EKU OID list of a certificate.
/// </summary>
internal string[] Eku
internal List<WildcardPattern> Eku
{
set { _eku = value; }
get;
set;
}
/// <summary>
/// Remaining validity period in days for a certificate.
/// Gets or sets validity time for a certificate.
/// </summary>
internal int ExpiringInDays
internal DateTime Expiring
{
set { _expiringInDays = value; }
}
/// <summary>
/// Combine properties into a filter string.
/// </summary>
internal string FilterString
{
get
{
string filterString = string.Empty;
if (_dnsName != null)
{
filterString = AppendFilter(filterString, "dns", _dnsName);
}
string ekuT = string.Empty;
if (_eku != null)
{
for (int i = 0; i < _eku.Length; i++)
{
if (ekuT.Length != 0)
{
ekuT = ekuT + ",";
}
ekuT = ekuT + _eku[i];
}
}
if (_purpose == CertificatePurpose.CodeSigning)
{
if (ekuT.Length != 0)
{
ekuT = ekuT + ",";
}
ekuT = ekuT + CodeSigningOid;
}
if (_purpose == CertificatePurpose.DocumentEncryption)
{
if (ekuT.Length != 0)
{
ekuT = ekuT + ",";
}
ekuT = ekuT + DocumentEncryptionOid;
}
if (_sslServerAuthentication)
{
if (ekuT.Length != 0)
{
ekuT = ekuT + ",";
}
ekuT = ekuT + szOID_PKIX_KP_SERVER_AUTH;
}
if (ekuT.Length != 0)
{
filterString = AppendFilter(filterString, "eku", ekuT);
if (_purpose == CertificatePurpose.CodeSigning ||
_sslServerAuthentication)
{
filterString = AppendFilter(filterString, "key", "*");
}
}
if (_expiringInDays >= 0)
{
filterString = AppendFilter(
filterString,
"ExpiringInDays",
_expiringInDays.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
if (filterString.Length == 0)
{
filterString = null;
}
return filterString;
}
}
private string AppendFilter(
string filterString,
string name,
string value)
{
string newfilter = value;
// append a "name=value" filter to the existing filter string.
// insert a separating "&" if existing filter string is not empty.
// if the value is empty, do nothing.
if (newfilter.Length != 0)
{
// if the value contains an equal sign or an ampersand, throw
// an exception to avoid compromising the native code parser.
if (newfilter.Contains("=") || newfilter.Contains("&"))
{
Marshal.ThrowExceptionForHR(Security.NativeMethods.E_INVALID_DATA);
}
newfilter = name + "=" + newfilter;
if (filterString.Length != 0)
{
newfilter = "&" + newfilter;
}
}
return filterString + newfilter;
}
private CertificatePurpose _purpose = 0;
private bool _sslServerAuthentication = false;
private string _dnsName = null;
private string[] _eku = null;
private int _expiringInDays = -1;
get;
set;
} = DateTime.MinValue;
internal const string CodeSigningOid = "1.3.6.1.5.5.7.3.3";
internal const string szOID_PKIX_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";
internal const string OID_PKIX_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";
// The OID arc 1.3.6.1.4.1.311.80 is assigned to PowerShell. If we need
// new OIDs, we can assign them under this branch.

View File

@ -117,25 +117,29 @@ Describe "Certificate Provider tests" -Tags "Feature" {
It "Should be able to get DnsNameList of certifate by path: <path>" -TestCases $currentUserMyLocations {
param([string] $path)
$expectedThumbprint = (Get-GoodCertificateObject).Thumbprint
$expectedName = (Get-GoodCertificateObject).DnsNameList[0].Unicode
$expectedEncodedName = (Get-GoodCertificateObject).DnsNameList[0].Punycode
$expectedName = (Get-GoodCertificateObject).DnsNameList
$expectedEncodedName = (Get-GoodCertificateObject).DnsNameList
$leafPath = Join-Path -Path $path -ChildPath $expectedThumbprint
$cert = (Get-Item -LiteralPath $leafPath)
$cert | Should -Not -Be null
$cert.DnsNameList | Should -Not -Be null
$cert.DnsNameList.Count | Should -Be 1
$cert.DnsNameList[0].Unicode | Should -Be $expectedName
$cert.DnsNameList[0].Punycode | Should -Be $expectedEncodedName
$cert = (Get-item -LiteralPath $leafPath)
$cert | Should -Not -Be $null
$cert.DnsNameList | Should -Not -Be $null
$cert.DnsNameList.Count | Should -Be 3
$cert.DnsNameList[0].Unicode | Should -Be $expectedName[0].Unicode
$cert.DnsNameList[0].Punycode | Should -Be $expectedEncodedName[0].Punycode
$cert.DnsNameList[1].Unicode | Should -Be $expectedName[1].Unicode
$cert.DnsNameList[1].Punycode | Should -Be $expectedEncodedName[1].Punycode
$cert.DnsNameList[2].Unicode | Should -Be $expectedName[2].Unicode
$cert.DnsNameList[2].Punycode | Should -Be $expectedEncodedName[2].Punycode
}
It "Should be able to get DNSNameList of certifate by path: <path>" -TestCases $currentUserMyLocations {
it "Should be able to get EnhancedKeyUsageList of certifate by path: <path>" -TestCases $currentUserMyLocations {
param([string] $path)
$expectedThumbprint = (Get-GoodCertificateObject).Thumbprint
$expectedOid = (Get-GoodCertificateObject).EnhancedKeyUsageList[0].ObjectId
$leafPath = Join-Path -Path $path -ChildPath $expectedThumbprint
$cert = (Get-Item -LiteralPath $leafPath)
$cert | Should -Not -Be null
$cert = (Get-item -LiteralPath $leafPath)
$cert | Should -Not -Be $null
$cert.EnhancedKeyUsageList | Should -Not -Be null
$cert.EnhancedKeyUsageList.Count | Should -Be 1
$cert.EnhancedKeyUsageList.Count | Should -Be 3
$cert.EnhancedKeyUsageList[0].ObjectId.Length | Should -Not -Be 0
$cert.EnhancedKeyUsageList[0].ObjectId | Should -Be $expectedOid
}
@ -158,13 +162,69 @@ Describe "Certificate Provider tests" -Tags "Feature" {
}
}
Context "Get-ChildItem tests"{
It "Should filter to codesign certificates" {
$allCerts = Get-ChildItem cert:\CurrentUser\My
$codeSignCerts = Get-ChildItem cert:\CurrentUser\My -CodeSigningCert
BeforeAll {
$cert = Get-GoodServerCertificateObject
}
it "Should filter to codesign certificates" {
$allCerts = get-ChildItem cert:\CurrentUser\My
$codeSignCerts = get-ChildItem cert:\CurrentUser\My -CodeSigningCert
$codeSignCerts | Should -Not -Be null
$allCerts | Should -Not -Be null
$nonCodeSignCertCount = $allCerts.Count - $codeSignCerts.Count
$nonCodeSignCertCount | Should -Not -Be 0
}
it "Should filter to ExpiringInDays certificates" {
$thumbprint = $cert.Thumbprint
$NotAfter = $cert.NotAfter
$before = ($NotAfter.AddDays(-1) - (Get-Date)).Days
$after = ($NotAfter.AddDays(+1) - (Get-Date)).Days
$beforeCerts = Get-ChildItem cert:\CurrentUser\My\$thumbprint -ExpiringInDays $before
$afterCerts = Get-ChildItem cert:\CurrentUser\My\$thumbprint -ExpiringInDays $after
$beforeCerts.Count | Should -Be 0
$afterCerts.Count | Should -Be 1
$afterCerts.Thumbprint | Should -BeExactly $thumbprint
}
it "Should filter to DocumentEncryptionCert certificates" {
$thumbprint = $cert.Thumbprint
$certs = Get-ChildItem cert:\CurrentUser\My\$thumbprint -DocumentEncryptionCert
$certs.Count | Should -Be 1
$certs.Thumbprint | Should -BeExactly $thumbprint
}
it "Should filter to DNSName certificates: <name>" -TestCases @(
@{ Name = "in Subject"; SearchName = '*ncipher*'; Count = 1; Thumbprint = $cert.Thumbprint }
@{ Name = "in Subject Alternative Name"; SearchName = '*conto*'; Count = 1; Thumbprint = $cert.Thumbprint }
@{ Name = "not existing name"; SearchName = '*QWERTY*'; Count = 0; Thumbprint = $null }
) {
param($name, $searchName, $count, $thumbprint)
$certs = Get-ChildItem cert:\CurrentUser\My\$thumbprint -DNSName $searchName
$certs.Count | Should -Be $count
$certs.Thumbprint | Should -BeExactly $thumbprint
}
it "Should filter to SSLServerAuthentication certificates" {
$thumbprint = $cert.Thumbprint
$certs = Get-ChildItem cert:\CurrentUser\My\$thumbprint -SSLServerAuthentication
$certs.Count | Should -Be 1
$certs.Thumbprint | Should -BeExactly $thumbprint
}
it "Should filter to EKU certificates: <name>" -TestCases @(
@{ Name = "can filter by name"; EKU = '*encryp*'; Count = 1; Thumbprint = $cert.Thumbprint }
@{ Name = "can filter by OID"; EKU = '*1.4.1.311.80.1*'; Count = 1; Thumbprint = $cert.Thumbprint }
@{ Name = "all patterns should be passed - positive test"; EKU = "1.3.6.1.5.5.7.3.2","*1.4.1.311.80.1*"; Count = 1; Thumbprint = $cert.Thumbprint }
@{ Name = "all patterns should be passed - negative test"; EKU = "*QWERTY*","*encryp*"; Count = 0; Thumbprint = $null }
) {
param($name, $ekuSearch, $count, $thumbprint)
$certs = Get-ChildItem cert:\CurrentUser\My\$thumbprint -EKU $ekuSearch
$certs.Count | Should -Be $count
$certs.Thumbprint | Should -BeExactly $thumbprint
}
}
}

View File

@ -1,5 +1,6 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
Function New-GoodCertificate
{
<#
@ -68,6 +69,109 @@ OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM=
return $certLocation
}
Function New-GoodServerCertificate
{
<#
.NOTES
This certificate properties:
Subject:
CN = MyDataEnciphermentCert
Subject Alternative Name:
DNS Name=www.fabrikam.com
DNS Name=www.contoso.com
EnhancedKey Usage:
Client Authentication (1.3.6.1.5.5.7.3.2)
Server Authentication (1.3.6.1.5.5.7.3.1)
Document Encryption (1.3.6.1.4.1.311.80.1)
Key Usage:
Key Encipherment, Data Encipherment (30)
Thumbprint:
b79428ca5aa0f0620e5eba19223fdf7885fcf3c6
Serial Number:
40c14ec2f84344be4965954d091c266b
Howto update:
1. Import the module and test certificates
Import-Module certificateCommon.psm1 -Force
Install-TestCertificates
2. Read the certificate
$cert = Get-Item Cert:\CurrentUser\My\<Thumbprint>
3. Clone the certificate with new properties:
$b=New-SelfSignedCertificate -CloneCert $cert -TextExtension @("2.5.29.37={text}1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.1,1.3.6.1.4.1.311.80.1") -CertStoreLocation "Cert:\CurrentUser\My" -DnsName "www.fabrikam.com", "www.contoso.com"
$b.SerialNumber
4. Export new certificate to file and encode to Base64 (press Enter key at password prompt):
certutil -exportpfx -user my <Serial> C:\temp\newcert.pfx
certutil -encode C:\temp\newcert.pfx C:\temp\newcert.txt
5. Replace $dataEnciphermentCert with new value from C:\temp\newcert.txt
#>
$dataEnciphermentCert = "
MIIKmgIBAzCCClYGCSqGSIb3DQEHAaCCCkcEggpDMIIKPzCCBgAGCSqGSIb3DQEH
AaCCBfEEggXtMIIF6TCCBeUGCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcN
AQwBAzAOBAi0Gq/DrqxgYgICB9AEggTYy168efMBdfynAWPkh7S6VyhoaMOWR6Nt
l6MnGcWuGGFxLS2TxfZSN+mNYsAGG0yGnTyYZ/2uCW46irfMNPnq1OrYjWJB4Zmb
pRF2WI+ipVkKUSVtuCKR8GQR9Yw7C3PASqgm0JV1YpK9fw0EJ4tzeF4w81xzb5Ix
jm8jOwSBefYXjOPXwIvqVntOQHkMj75EVEjyTi/Sb3SoYk0b7uzqFsqtiQ3S9rtp
FuM3gRNY6zjHYa/iDrwt4aty8IU74yipyLj/9c4+BnaBiMCwX51FrHYGx1OYkcbN
K0iTWzxG3oYFxY9V9P6uzUqDUTsZNawkjne2WIFJrfPq25nU8vMHej0T/YqMczPF
6NtiHv0yMFNqxEh6vZgc00gitEV+Cbr9/lsctJ2YiYFW2Sc5q7wovc231xrLaDXZ
BLdnJZqqalobqdwfu84o7GiXw7y9pdvwNl4vKH4yiDv4kqCcuzqLxJ7QTk63EuGw
uiEhoC1ibvvi7+fCm60IxHxtGlUAZCaEidh70/VffRkea+oor9WLSIZ7q07ycB1+
2k0ecpeutaOPAckfIPLDb1m9BwlM47dVaSJNN5/5oQsRM7327TDjYphfVoUDX19p
eAiRcO68GbcmXQQuM8CxbCSdPC3F6Jr5YzMBnM6Yqacv8ywdYaZHmKBADF2FtuFb
zyFHFCzTYJyj3YPczK1Xmw7d4btJuIAvl5JOrbDqSEbwRvXZL2f5iIRydekcPnma
nu/mlRqupQWiasv7qoga8Gq5sKMIUAruTwAzhkNA01hj5Iv7NcFY9Ruc+MHmnGmE
BiDSh/wOuyRIGIfveR9e4msg6rP9KO7q6mnghBVy6Is6Xz5Ak/xS2v7RjxzgBxrE
LaPoeHpD2+LKN+w8eN9Pd2ewAwwHzrw65jN7P1avuioMi0KejYZZAt3scmIGTT+n
jzcmxKvAPYllRifZRoDe+hAeYHlGAA8hm/zmw5522L8hOR1j69JcbCbl8MtWww+W
2MiGYbEbbGg/HV+9PnMMU3i+eHtuxTukBYb1ksH5z7742WBYH+gE3CvPX5AZRY/N
rVo8qZPH2ZK1smmc7v2cv0ZhIGWiMe+LakjjB1QcFpCTh/uwhQhNGXOgU1oNKbuE
FE7iH3XHkDVLFxEhdtgvwXJIQp+7ROVry6sZW2cgi2yUOTWNjqDd6LlV8vy+lti6
/7L+rhfezHUpk89eWu8glEFqB96xmc9nbSF0On8aewdb43gW8h5TbBuSE1JA5SfE
cQNSxs4z+Bbx7cyX+f3CDriJkzXs5PvT861pNcYB1zjxJBStehMeazWf+D2Td10p
43nmEYaXHq/KwY1jn8yzQyj2V+c5Csw75879KHZ+6LwfzeWDCUlma+n1ZDNeDm2+
s40qBC4s7x9sEdUBQwl/JOtJt4ZlFje4xle5/RlS2il/e/X05n4XUuX7azWZjSoG
fflcIvMcnXydt/Nl05newUGobDLEw9sa9lDy8bG6+IGywg2x1A4hqsA2qUbVLyy/
VLdhIY38+FmcliL3o3uk9vsSHefODKrG1ZD+qu3+/9s3B7KmlT652cj6+fi54+N/
jM/VAT/6e8OntolNHVoauudBmgO0WRYbznvZd/C6ehTAZQo9HKiGkADk1i8Gw6NF
dgH4LZdHyWOgrvAL1FqOqzGB0zATBgkqhkiG9w0BCRUxBgQEAQAAADBdBgkqhkiG
9w0BCRQxUB5OAHQAZQAtAGYAZgBiADIAYQBiADMAYgAtAGMAZQA5ADEALQA0ADEA
MABhAC0AOAA1AGMAMQAtADkAYwBmADgAYwA3AGEAMAA5ADkAYwA4MF0GCSsGAQQB
gjcRATFQHk4ATQBpAGMAcgBvAHMAbwBmAHQAIABTAHQAcgBvAG4AZwAgAEMAcgB5
AHAAdABvAGcAcgBhAHAAaABpAGMAIABQAHIAbwB2AGkAZABlAHIwggQ3BgkqhkiG
9w0BBwagggQoMIIEJAIBADCCBB0GCSqGSIb3DQEHATAcBgoqhkiG9w0BDAEDMA4E
CNnzLxDoo0cMAgIH0ICCA/ChXpj5kGwmqH++L8JmdidMyhQAk//fnIxsE695lW4B
yUQ0wM7k2eWSdebuCMSvD1bL2A8B6qM/sfkuoAUHrSGZS56Qeh4C3j5FqLyMOg1H
7w4hkHDYTQp4s9fxk5NedqsctmmKnZmrET65g8KRMSiolFYqd69D1SWGnftUVMvU
MdrFQRP0GJPSvDzx17NJWRRiUXzYxakfpGW8QfV0I9/ZlP8uUEZlVqc1v7ikQf1e
A3i6+njdj9lkpa2CEdtAdpwVTpQ49UwGq4tD5aMlzjWNuzQpP0mEh9XzWr6J3aFz
poEpCuC7gT4tIZcC3BKS9Uvv53AShpxJCiWwG7k+CYzzKabq3guJh1uPKMqpHJGG
T/5a4lQJOQr2IyfoDfsNw2JtAVjM62haUap4ZZbuoJq9B6gECknUAbSsk1XdEktq
OhMP5HtlCEAdLeEo0ae3YGRHsKJgFSx/8R+MMdjMWMYT8+6mVSVC63KQMiBmVEBs
mDcOWY45eCHo4aXuEKcHZSxRtWvviACdEd/CSDGwFGuA8f+D0f6iLabQCLLeVRVN
iUiKER3Adw+dg6pegifM4r3trqR2/H1Z33TrarGMKGNJSy6ur8bW1L6aYjxx1hj+
dW9Tcj1QTLC1PJFaLdOD1ELho/EXdoa9VPuC2MWS9I6TqpY4Rkrcbr4KMqDLUTeN
SzgSZARVPv7VL8EDqeME24aQammby6nr25tA+Q45KBH8nc/hURVcoayl/cmH9Up3
D87oCdVuCvmiJnFhZnd7q6S3ChfIQhyGNlZQjRjDve9MhR0TwaDEm0nsBpSwSVwP
PyJ00Md/cq4nImXvMYXf1fZ3Tlp90kZ2ffQ9+EMzFXNBNLof+CjVR8EZI1tOjUQg
0GYJvDFCt+hz7AAQU+2Ggrp1L7FaSJmgEJIVYwQP4bM25ee4BiQt3hHJL8Nfr97W
NEg8W4AbpYHJkcXa6jrxZLvsKxZNnLF0eczpG6X2jq7JdbumlZ1viom2j1aPB5GF
owQOcBfI3nhA5nludg2CUT2cqtO4mKJyPXwGA0OcFZ4aVJeO7wnS/21g7AB/Opmt
BCxZBwysPns0JJbH39p2PNRw/q2Kp+pxm0MEyJJe27T/f4cEUaezaAu+7qU7diSb
bUKQZzH+zfvmGr+UyQf6t3UHMyOBMfURmYEVesY47Vu2swdN4QW+tnJ2JIdIjEIb
W+OiON35K4wJDY893wZRI9uPPOQ/6yCAuI0uEu7WV2xqmpvMOj0E4yqkX0IChFxj
Mb1wqu/wHSwktbpqZLykVfJYq5ol/gexrY04AJJSZEDXGvHLR47Qfzx2M0XcjZpi
vsa+CHXqcU5T1e+1tPp8TdcwOzAfMAcGBSsOAwIaBBQiJeRFYB+55Wp+h8bnYt0D
YSQdMwQUYoaBDgXqLdO2G97FQNL1XPhVEEkCAgfQ
"
$dataEnciphermentCert = $dataEnciphermentCert -replace '\s',''
$certBytes = [Convert]::FromBase64String($dataEnciphermentCert)
$certLocation = Join-Path $TestDrive "ProtectedEventLogging.pfx"
[IO.File]::WriteAllBytes($certLocation, $certBytes)
return $certLocation
}
Function New-CertificatePassword
{
$script:protectedCertPassword = ConvertTo-SecureString -Force -AsPlainText (New-RandomHexString)
@ -138,6 +242,9 @@ function Install-TestCertificates
$script:certLocation = New-GoodCertificate
$script:certLocation | Should -Not -BeNullOrEmpty | Out-Null
$script:certServerLocation = New-GoodServerCertificate
$script:certServerLocation | Should -Not -BeNullOrEmpty | Out-Null
$script:badCertLocation = New-BadCertificate
$script:badCertLocation | Should -Not -BeNullOrEmpty | Out-Null
@ -148,15 +255,17 @@ function Install-TestCertificates
$command = @"
Import-PfxCertificate $script:certLocation -CertStoreLocation cert:\CurrentUser\My | ForEach-Object PSPath
Import-PfxCertificate $script:certServerLocation -CertStoreLocation cert:\CurrentUser\My | ForEach-Object PSPath
Import-Certificate $script:badCertLocation -CertStoreLocation Cert:\CurrentUser\My | ForEach-Object PSPath
"@
$certPaths = & $fullPowerShell -NoProfile -NonInteractive -Command $command
$certPaths.Count | Should -Be 2 | Out-Null
$certPaths.Count | Should -Be 3 | Out-Null
$script:importedCert = Get-ChildItem $certPaths[0]
$script:testBadCert = Get-ChildItem $certPaths[1]
$script:importedServerCert = Get-ChildItem $certPaths[1]
$script:testBadCert = Get-ChildItem $certPaths[2]
}
elseif($IsWindows)
elseif ($IsWindows)
{
$script:importedCert = Import-PfxCertificate $script:certLocation -CertStoreLocation cert:\CurrentUser\My
$script:testBadCert = Import-Certificate $script:badCertLocation -CertStoreLocation Cert:\CurrentUser\My
@ -176,6 +285,11 @@ function Get-GoodCertificateObject
return $script:importedCert
}
function Get-GoodServerCertificateObject
{
return $script:importedServerCert
}
function Get-BadCertificateObject
{
return $script:testBadCert