mirror of
https://github.com/PowerShell/PowerShell.git
synced 2024-11-24 02:04:07 +08:00
Bring back Certificate provider parameters (#10622)
This commit is contained in:
parent
8f79ce1d29
commit
73e8427586
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user