diff --git a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs
index 1449afbedcb..b8bcee8bd4b 100644
--- a/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs
+++ b/src/Microsoft.PowerShell.Security/security/CertificateProvider.cs
@@ -15,6 +15,7 @@
using System.Collections;
using System.Runtime.InteropServices;
using System.Management.Automation.Provider;
+using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.RegularExpressions;
using System.Globalization;
@@ -154,134 +155,6 @@ public override string ToString()
}
}
- ///
- /// 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.
- ///
- /// For Win 8 and later, we also support:
- /// SSLServerAuthentication
- /// If provided, only return certificates valid for server authentication.
- ///
- /// DnsName
- /// If provided, only return certificates matching the supplied DNS Name.
- ///
- /// Eku
- /// If provided, only return certificates containing all of the OIDs
- /// supplied.
- ///
- /// ExpiringInDays
- /// If provided, only return certificates expiring within the specified
- /// number of days.
- ///
- ///
-
- internal sealed class CertificateProviderDynamicParameters
- {
- ///
- /// switch that controls whether we only return
- /// code signing certs.
- ///
- [Parameter()]
- public SwitchParameter CodeSigningCert
- {
- get { return _codeSigningCert; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _codeSigningCert = value; }
- }
- private SwitchParameter _codeSigningCert = new SwitchParameter();
-
- ///
- /// switch that controls whether we only return
- /// data encipherment certs.
- ///
- [Parameter()]
- public SwitchParameter DocumentEncryptionCert
- {
- get { return _documentEncryptionCert; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _documentEncryptionCert = value; }
- }
- private SwitchParameter _documentEncryptionCert = new SwitchParameter();
-
- ///
- /// switch that controls whether we only return
- /// code signing certs.
- ///
- [Parameter()]
- public SwitchParameter SSLServerAuthentication
- {
- get { return _sslServerAuthentication; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _sslServerAuthentication = value; }
- }
-
- private SwitchParameter _sslServerAuthentication = new SwitchParameter();
-
- ///
- /// string to filter certs by DNSName
- /// Expected content is a single DNS Name that may start and/or end
- /// with '*': "contoso.com" or "*toso.c*"
- ///
- [Parameter()]
- public DnsNameRepresentation DnsName
- {
- get { return _dnsName; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _dnsName = value; }
- }
-
- private DnsNameRepresentation _dnsName;
-
- ///
- /// string to filter certs by EKU
- /// Expected content is one or more OID strings:
- /// "1.3.6.1.5.5.7.3.1", etc.
- /// For a cert to match, it must be valid for all listed OIDs.
- ///
- [Parameter()]
- public string[] Eku
- {
- get { return _eku; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _eku = value; }
- }
-
- private string[] _eku = null;
-
- ///
- /// string to filter certs 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 midnight tonight (local time).
- ///
- [Parameter()]
- public int ExpiringInDays
- {
- get { return _expiringInDays; }
-
- [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "This method is used by command line processing")]
- set
- { _expiringInDays = value; }
- }
-
- private int _expiringInDays = -1;
- }
-
///
/// Defines the Certificate Provider remove-item dynamic parameters.
///
@@ -351,42 +224,6 @@ public IntPtr Handle
}
}
- ///
- /// Defines the safe handle class for native cert store handles,
- /// HCERTSTORE.
- ///
- internal sealed class CertificateFilterHandle : SafeHandle
- {
- public CertificateFilterHandle() : base(IntPtr.Zero, true)
- {
- return;
- }
-
- public override bool IsInvalid
- {
- get { return handle == IntPtr.Zero; }
- }
-
- protected override bool ReleaseHandle()
- {
- bool fResult = false;
-
- if (IntPtr.Zero != handle)
- {
- Security.NativeMethods.CCFindCertificateFreeFilter(handle);
- handle = IntPtr.Zero;
- fResult = true;
- }
- return fResult;
- }
-
- public IntPtr Handle
- {
- get { return handle; }
- set { handle = value; }
- }
- }
-
///
/// Defines the Certificate Provider store handle class
///
@@ -477,25 +314,8 @@ public void Open(bool includeArchivedCerts)
}
}
- public IntPtr GetFirstCert(
- CertificateFilterInfo filter)
+ public IntPtr GetFirstCert()
{
- _filterHandle = null;
- if (DownLevelHelper.NativeFilteringSupported() && filter != null)
- {
- IntPtr hFilter = IntPtr.Zero;
-
- _filterHandle = new CertificateFilterHandle();
- int hr = Security.NativeMethods.CCFindCertificateBuildFilter(
- filter.FilterString,
- ref hFilter);
- if (hr != Security.NativeConstants.S_OK)
- {
- _filterHandle = null;
- throw new System.ComponentModel.Win32Exception(hr);
- }
- _filterHandle.Handle = hFilter;
- }
return GetNextCert(IntPtr.Zero);
}
@@ -508,19 +328,9 @@ public IntPtr GetNextCert(IntPtr certContext)
}
if (Valid)
{
- if (_filterHandle != null)
- {
- certContext = Security.NativeMethods.CCFindCertificateFromFilter(
- _storeHandle.Handle,
- _filterHandle.Handle,
- certContext);
- }
- else
- {
- certContext = Security.NativeMethods.CertEnumCertificatesInStore(
- _storeHandle.Handle,
- certContext);
- }
+ certContext = Security.NativeMethods.CertEnumCertificatesInStore(
+ _storeHandle.Handle,
+ certContext);
}
else
{
@@ -635,7 +445,6 @@ public bool Valid
private X509StoreLocation _storeLocation = null;
private string _storeName = null;
private CertificateStoreHandle _storeHandle = null;
- private CertificateFilterHandle _filterHandle = null;
private bool _valid = false;
private bool _open = false;
}
@@ -1233,7 +1042,7 @@ protected override bool HasChildItems(string path)
if (store != null)
{
store.Open(IncludeArchivedCerts());
- IntPtr certContext = store.GetFirstCert(null);
+ IntPtr certContext = store.GetFirstCert();
if (IntPtr.Zero != certContext)
{
store.FreeCert(certContext);
@@ -1944,7 +1753,7 @@ private void RemoveCertStore(string storeName, bool fDeleteKey, string sourcePat
//
// enumerate over each cert and remove it
//
- IntPtr certContext = store.GetFirstCert(null);
+ IntPtr certContext = store.GetFirstCert();
while (IntPtr.Zero != certContext)
{
X509Certificate2 cert = new X509Certificate2(certContext);
@@ -2092,10 +1901,7 @@ private void DoRemove(X509Certificate2 cert, bool fDeleteKey, bool fMachine, str
CommitUserDS(context.hCertStore);
}
- if (DownLevelHelper.LogCertChangeSupported())
- {
- Security.NativeMethods.LogCertDelete(fMachine, cert.Handle);
- }
+ //TODO: Log Cert Delete
//delete private key
if (fDeleteKey && fHasPrivateKey)
@@ -2173,18 +1979,7 @@ private void DoMove(string destination, X509Certificate2 cert, X509NativeStore s
throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
}
- if (DownLevelHelper.LogCertChangeSupported())
- {
- bool fMachine = store.Location.Location == StoreLocation.LocalMachine;
-
- if (cert.HasPrivateKey &&
- String.Equals(store.StoreName, "MY", StringComparison.OrdinalIgnoreCase))
- {
- Security.NativeMethods.LogCertCopy(fMachine, cert.Handle);
- }
-
- Security.NativeMethods.LogCertDelete(fMachine, cert.Handle);
- }
+ //TODO: log cert move
}
//commit the change to physical store
@@ -2499,14 +2294,7 @@ protected override bool IsItemContainer(string path)
///
protected override object GetItemDynamicParameters(string path)
{
- if (DownLevelHelper.NativeFilteringSupported())
- {
- return new CertificateProviderDynamicParameters();
- }
- else
- {
- return new CertificateProviderCodeSigningDynamicParameters();
- }
+ return new CertificateProviderCodeSigningDynamicParameters();
}
///
@@ -2531,14 +2319,7 @@ protected override object GetItemDynamicParameters(string path)
///
protected override object GetChildItemsDynamicParameters(string path, bool recurse)
{
- if (DownLevelHelper.NativeFilteringSupported())
- {
- return new CertificateProviderDynamicParameters();
- }
- else
- {
- return new CertificateProviderCodeSigningDynamicParameters();
- }
+ return new CertificateProviderCodeSigningDynamicParameters();
}
#endregion DriveCmdletProvider overrides
@@ -2718,7 +2499,7 @@ private void GetCertificatesOrNames(string path,
//
// enumerate over each cert and return it (or its name)
//
- IntPtr certContext = store.GetFirstCert(filter);
+ IntPtr certContext = store.GetFirstCert();
while (IntPtr.Zero != certContext)
{
@@ -2952,62 +2733,14 @@ private CertificateFilterInfo GetFilter()
if (DynamicParameters != null)
{
- if (DownLevelHelper.NativeFilteringSupported())
+ CertificateProviderCodeSigningDynamicParameters dp =
+ DynamicParameters as CertificateProviderCodeSigningDynamicParameters;
+ if (dp != null)
{
- CertificateProviderDynamicParameters dp =
- DynamicParameters as CertificateProviderDynamicParameters;
- if (dp != null)
+ if (dp.CodeSigningCert)
{
- bool filterSpecified = false;
-
filter = new CertificateFilterInfo();
- if (dp.CodeSigningCert)
- {
- filter.Purpose = CertificatePurpose.CodeSigning;
- filterSpecified = true;
- }
- if (dp.DocumentEncryptionCert)
- {
- filter.Purpose = CertificatePurpose.DocumentEncryption;
- filterSpecified = true;
- }
- if (dp.SSLServerAuthentication)
- {
- filter.SSLServerAuthentication = true;
- filterSpecified = true;
- }
- if (dp.DnsName.Punycode != null)
- {
- filter.DnsName = dp.DnsName.Punycode;
- filterSpecified = true;
- }
- if (dp.Eku != null)
- {
- filter.Eku = dp.Eku;
- filterSpecified = true;
- }
- if (dp.ExpiringInDays >= 0)
- {
- filter.ExpiringInDays = dp.ExpiringInDays;
- filterSpecified = true;
- }
- if (!filterSpecified)
- {
- filter = null;
- }
- }
- }
- else
- {
- CertificateProviderCodeSigningDynamicParameters dp =
- DynamicParameters as CertificateProviderCodeSigningDynamicParameters;
- if (dp != null)
- {
- if (dp.CodeSigningCert)
- {
- filter = new CertificateFilterInfo();
- filter.Purpose = CertificatePurpose.CodeSigning;
- }
+ filter.Purpose = CertificatePurpose.CodeSigning;
}
}
}
@@ -3541,33 +3274,20 @@ public List EnhancedKeyUsageList
///
public EnhancedKeyUsageProperty(X509Certificate2 cert)
{
- if (DownLevelHelper.NativeFilteringSupported())
+ foreach (X509Extension extension in cert.Extensions)
{
- Collection ekuCollection = System.Management.Automation.Internal.SecuritySupport.GetCertEKU(cert);
-
- foreach (string oidString in ekuCollection)
+ // Filter to the OID for EKU
+ if (extension.Oid.Value == "2.5.29.37")
{
- if (!String.IsNullOrEmpty(oidString))
+ X509EnhancedKeyUsageExtension ext = extension as X509EnhancedKeyUsageExtension;
+ if(ext != null)
{
- IntPtr stringAnsi = (IntPtr)Marshal.StringToHGlobalAnsi(oidString);
-
- EnhancedKeyUsageRepresentation ekuString;
- IntPtr oidPtr = Security.NativeMethods.CryptFindOIDInfo(
- Security.NativeConstants.CRYPT_OID_INFO_OID_KEY,
- stringAnsi,
- 0);
- if (oidPtr != IntPtr.Zero)
+ OidCollection oids = ext.EnhancedKeyUsages;
+ foreach (Oid oid in oids)
{
- Security.NativeMethods.CRYPT_OID_INFO oidInfo =
- ClrFacade.PtrToStructure(oidPtr);
- ekuString = new EnhancedKeyUsageRepresentation(oidInfo.pwszName, oidString);
+ EnhancedKeyUsageRepresentation ekuString = new EnhancedKeyUsageRepresentation(oid.FriendlyName, oid.Value);
+ _ekuList.Add(ekuString);
}
- else //if oidInfo is not available
- {
- ekuString = new EnhancedKeyUsageRepresentation(null, oidString);
- }
-
- _ekuList.Add(ekuString);
}
}
}
@@ -3581,6 +3301,9 @@ public EnhancedKeyUsageProperty(X509Certificate2 cert)
public sealed class DnsNameProperty
{
private List _dnsList = new List();
+ private System.Globalization.IdnMapping idnMapping = new System.Globalization.IdnMapping();
+ private const string dnsNamePrefix = "DNS Name=";
+ private const string distinguishedNamePrefix = "CN=";
///
/// get property of DnsNameList
@@ -3598,81 +3321,65 @@ public List DnsNameList
///
public DnsNameProperty(X509Certificate2 cert)
{
- if (DownLevelHelper.NativeFilteringSupported())
+ string name;
+ string unicodeName;
+ DnsNameRepresentation dnsName;
+ _dnsList = new List();
+
+ // extract DNS name from subject distinguish name
+ // if it exists and does not contain a comma
+ // a comma, indicates it is not a DNS name
+ if(cert.Subject.StartsWith(distinguishedNamePrefix, System.StringComparison.InvariantCultureIgnoreCase) &&
+ cert.Subject.IndexOf(",",System.StringComparison.InvariantCulture)==-1)
{
- if (cert != null)
+ name = cert.Subject.Substring(distinguishedNamePrefix.Length);
+ try
{
- //need to get subject alternative name from the certificate context
- _dnsList = GetCertNames(
- cert.Handle,
- Security.NativeMethods.AltNameType.CERT_ALT_NAME_DNS_NAME);
+ unicodeName = idnMapping.GetUnicode(name);
}
- }
- }
-
- // Wrapper function for CCGetCertNameList and CCFreeStringArray
- private List GetCertNames(IntPtr certHandle, Security.NativeMethods.AltNameType nameType)
- {
- DWORD cPunycodeName;
- IntPtr papwszPunycodeNames = IntPtr.Zero;
- IntPtr papwszUnicodeNames = IntPtr.Zero;
- List names = new List();
- int hr;
-
- if (certHandle != IntPtr.Zero)
- {
- hr = Security.NativeMethods.CCGetCertNameList(
- certHandle,
- nameType,
- 0, // no conversion to Unicode
- out cPunycodeName,
- out papwszPunycodeNames);
- if (hr != Security.NativeConstants.S_OK)
+ catch(System.ArgumentException)
{
- if (hr != Security.NativeMethods.CRYPT_E_NOT_FOUND)
- {
- throw Marshal.GetExceptionForHR(hr);
- }
- cPunycodeName = 0;
+ // The name is not valid punyCode, assume it's valid ascii.
+ unicodeName = name;
}
- try
+ dnsName = new DnsNameRepresentation(name,unicodeName);
+ _dnsList.Add(dnsName);
+ }
+
+ foreach (X509Extension extension in cert.Extensions)
+ {
+ // Filter to the OID for Subject Alternative Name
+ if (extension.Oid.Value == "2.5.29.17")
{
- if (0 < cPunycodeName)
+ string[] names = extension.Format(true).Split(Environment.NewLine);
+ foreach(string nameLine in names)
{
- DWORD cUnicodeName;
-
- hr = Security.NativeMethods.CCGetCertNameList(
- certHandle,
- nameType,
- Security.NativeMethods.CryptDecodeFlags.CRYPT_DECODE_ENABLE_IA5CONVERSION_FLAG,
- out cUnicodeName,
- out papwszUnicodeNames);
- if (hr != Security.NativeConstants.S_OK)
- {
- throw Marshal.GetExceptionForHR(hr);
- }
- if (cPunycodeName != cUnicodeName)
+ // Get the part after 'DNS Name='
+ if(nameLine.StartsWith(dnsNamePrefix, System.StringComparison.InvariantCultureIgnoreCase))
{
- throw Marshal.GetExceptionForHR(
- Security.NativeMethods.E_INVALID_DATA);
- }
- for (int i = 0; i < cPunycodeName; i++)
- {
- names.Add(new DnsNameRepresentation(
- Marshal.PtrToStringUni(Marshal.ReadIntPtr(papwszPunycodeNames, i * Marshal.SizeOf(papwszPunycodeNames))),
- Marshal.PtrToStringUni(Marshal.ReadIntPtr(papwszUnicodeNames, i * Marshal.SizeOf(papwszUnicodeNames)))));
+ name = nameLine.Substring(dnsNamePrefix.Length);
+ try
+ {
+ unicodeName = idnMapping.GetUnicode(name);
+ }
+ catch(System.ArgumentException)
+ {
+ // The name is not valid punyCode, assume it's valid ascii.
+ unicodeName = name;
+ }
+
+ dnsName = new DnsNameRepresentation(name,unicodeName);
+
+ // Only add the name if it is not the same as an existing name.
+ if(!_dnsList.Contains(dnsName))
+ {
+ _dnsList.Add(dnsName);
+ }
}
}
}
- finally
- {
- Security.NativeMethods.CCFreeStringArray(papwszPunycodeNames);
- Security.NativeMethods.CCFreeStringArray(papwszUnicodeNames);
- }
}
-
- return names;
}
}
@@ -3689,9 +3396,6 @@ internal static bool IsWin8AndAbove()
{
if (!s_isWin8Set)
{
-#if CORECLR
- s_isWin8 = true;
-#else
System.OperatingSystem osInfo = System.Environment.OSVersion;
PlatformID platform = osInfo.Platform;
Version version = osInfo.Version;
@@ -3702,44 +3406,12 @@ internal static bool IsWin8AndAbove()
{
s_isWin8 = true;
}
-#endif
+
s_isWin8Set = true;
}
return s_isWin8;
}
- private static bool s_nativeFilteringSet = false;
- private static bool s_nativeFiltering = false;
-
- internal static bool NativeFilteringSupported()
- {
- if (!s_nativeFilteringSet)
- {
- if (IsWin8AndAbove() && Security.NativeMethods.IsSystem32DllPresent("certca.dll"))
- {
- s_nativeFiltering = true;
- }
- s_nativeFilteringSet = true;
- }
- return s_nativeFiltering;
- }
-
- private static bool s_logChangesSet = false;
- private static bool s_logChanges = false;
-
- internal static bool LogCertChangeSupported()
- {
- if (!s_logChangesSet)
- {
- if (IsWin8AndAbove() && Security.NativeMethods.IsSystem32DllPresent("certenroll.dll"))
- {
- s_logChanges = true;
- }
- s_logChangesSet = true;
- }
- return s_logChanges;
- }
-
internal static bool TrustedIssuerSupported()
{
return IsWin8AndAbove();
diff --git a/src/System.Management.Automation/security/nativeMethods.cs b/src/System.Management.Automation/security/nativeMethods.cs
index 0c26ee17145..6bcd9ee48b1 100644
--- a/src/System.Management.Automation/security/nativeMethods.cs
+++ b/src/System.Management.Automation/security/nativeMethods.cs
@@ -1453,59 +1453,6 @@ internal enum CryptDecodeFlags : uint
CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG = 0x04000000,
CRYPT_DECODE_ENABLE_IA5CONVERSION_FLAG = (CRYPT_DECODE_ENABLE_PUNYCODE_FLAG | CRYPT_DECODE_ENABLE_UTF8PERCENT_FLAG),
}
-
- // -------------------------------------------------------------------
- // certca.dll stuff
- //
-
- [DllImport("certca.dll")]
- internal static extern
- int CCFindCertificateBuildFilter(
- [MarshalAsAttribute(UnmanagedType.LPWStr)]
- string filter,
- ref IntPtr certFilter);
-
- [DllImport("certca.dll")]
- internal static extern
- void CCFindCertificateFreeFilter(
- IntPtr certFilter);
-
-
- [DllImport("certca.dll")]
- internal static extern
- IntPtr CCFindCertificateFromFilter(
- IntPtr storeHandle,
- IntPtr certFilter,
- IntPtr prevCertContext);
-
- [DllImport("certca.dll")]
- internal static extern
- int // HRESULT
- CCGetCertNameList(
- IntPtr certContext,
- AltNameType dwAltNameChoice,
- CryptDecodeFlags dwFlags,
- out DWORD cName,
- out IntPtr papwszName);
-
- [DllImport("certca.dll")]
- internal static extern
- void CCFreeStringArray(IntPtr papwsz);
- }
-
- internal static partial class NativeMethods
- {
- // HRESULT LogCertDelete(")
- // __in bool fMachine,")
- // __in PCCERT_CONTEXT pCertContext)
- [DllImport("certenroll.dll")]
- internal static extern int LogCertDelete(bool fMachine, IntPtr pCertContext);
-
- // HRESULT LogCertCopy(")
- // __in bool fMachine,")
- // __in PCCERT_CONTEXT pCertContext)
- [DllImport("certenroll.dll")]
- internal static extern int LogCertCopy(bool fMachine, IntPtr pCertContext);
}
#region Check_UI_Allowed
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CertificateProvider.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CertificateProvider.Tests.ps1
new file mode 100644
index 00000000000..c9e84f5c99a
--- /dev/null
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CertificateProvider.Tests.ps1
@@ -0,0 +1,167 @@
+# The import and table creation work on non-windows, but are currently not needed
+if($IsWindows)
+{
+ Import-Module (Join-Path -Path $PSScriptRoot 'certificateCommon.psm1') -Force
+
+ $currentUserMyLocations = @(
+ @{path = 'Cert:\CurrentUser\my'}
+ @{path = 'cert:\currentuser\my'}
+ @{path = 'Microsoft.PowerShell.Security\Certificate::CurrentUser\My'}
+ @{path = 'Microsoft.PowerShell.Security\certificate::currentuser\my'}
+ )
+
+ $testLocations = @(
+ @{path = 'cert:\'}
+ @{path = 'CERT:\'}
+ @{path = 'Microsoft.PowerShell.Security\Certificate::'}
+ )
+}
+
+# Add CurrentUserMyLocations to TestLocations
+foreach($location in $currentUserMyLocations)
+{
+ $testLocations += $location
+}
+
+Describe "Certificate Provider tests" -Tags "CI" {
+ BeforeAll{
+ if(!$IsWindows)
+ {
+ # Skip for non-Windows platforms
+ $defaultParamValues = $PSdefaultParameterValues.Clone()
+ $PSdefaultParameterValues = @{ "it:skip" = $true }
+ }
+ }
+
+ AfterAll {
+ if(!$IsWindows)
+ {
+ $PSdefaultParameterValues = $defaultParamValues
+ }
+ }
+
+ Context "Get-Item tests" {
+ it "Should be able to get a certificate store, path: " -TestCases $testLocations {
+ param([string] $path)
+ $expectedResolvedPath = Resolve-Path -LiteralPath $path
+ $result = Get-Item -LiteralPath $path
+ $result | should not be null
+ $result | ForEach-Object {
+ $resolvedPath = Resolve-Path $_.PSPath
+ $resolvedPath.Provider | should be $expectedResolvedPath.Provider
+ $resolvedPath.ProviderPath.TrimStart('\') | should be $expectedResolvedPath.ProviderPath.TrimStart('\')
+ }
+ }
+ it "Should return two items at the root of the provider" {
+ (Get-Item -Path cert:\*).Count | should be 2
+ }
+ it "Should be able to get multiple items explictly" {
+ (get-item cert:\LocalMachine , cert:\CurrentUser).Count | should be 2
+ }
+ it "Should return PathNotFound when getting a non-existant certificate store" {
+ {Get-Item cert:\IDONTEXIST -ErrorAction Stop} | ShouldBeErrorId "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
+ }
+ it "Should return PathNotFound when getting a non-existant certificate" {
+ {Get-Item cert:\currentuser\my\IDONTEXIST -ErrorAction Stop} | ShouldBeErrorId "PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand"
+ }
+ }
+ Context "Get-ChildItem tests"{
+ it "should be able to get a container using a wildcard" {
+ (Get-ChildItem Cert:\CurrentUser\M?).PSPath | should be 'Microsoft.PowerShell.Security\Certificate::CurrentUser\My'
+ }
+ it "Should return two items at the root of the provider" {
+ (Get-ChildItem -Path cert:\).Count | should be 2
+ }
+ }
+}
+
+Describe "Certificate Provider tests" -Tags "Feature" {
+ BeforeAll{
+ if($IsWindows)
+ {
+ Install-TestCertificates
+ Push-Location Cert:\
+ }
+ else
+ {
+ # Skip for non-Windows platforms
+ $defaultParamValues = $PSdefaultParameterValues.Clone()
+ $PSdefaultParameterValues = @{ "it:skip" = $true }
+ }
+ }
+
+ AfterAll {
+ if($IsWindows)
+ {
+ Remove-TestCertificates
+ Pop-Location
+ }
+ else
+ {
+ $PSdefaultParameterValues = $defaultParamValues
+ }
+ }
+
+ Context "Get-Item tests" {
+ it "Should be able to get certifate by path: " -TestCases $currentUserMyLocations {
+ param([string] $path)
+ $expectedThumbprint = (Get-GoodCertificateObject).Thumbprint
+ $leafPath = Join-Path -Path $path -ChildPath $expectedThumbprint
+ $cert = (Get-item -LiteralPath $leafPath)
+ $cert | should not be null
+ $cert.Thumbprint | should be $expectedThumbprint
+ }
+ it "Should be able to get DnsNameList of certifate by path: " -TestCases $currentUserMyLocations {
+ param([string] $path)
+ $expectedThumbprint = (Get-GoodCertificateObject).Thumbprint
+ $expectedName = (Get-GoodCertificateObject).DnsNameList[0].Unicode
+ $expectedEncodedName = (Get-GoodCertificateObject).DnsNameList[0].Punycode
+ $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
+ }
+ it "Should be able to get DNSNameList of certifate by 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.EnhancedKeyUsageList | should not be null
+ $cert.EnhancedKeyUsageList.Count | should be 1
+ $cert.EnhancedKeyUsageList[0].ObjectId.Length | should not be 0
+ $cert.EnhancedKeyUsageList[0].ObjectId | should be $expectedOid
+ }
+ it "Should filter to codesign certificates" {
+ $allCerts = get-item cert:\CurrentUser\My\*
+ $codeSignCerts = get-item 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 be able to exclude by thumbprint" {
+ $allCerts = get-item cert:\CurrentUser\My\*
+ $testThumbprint = (Get-GoodCertificateObject).Thumbprint
+ $allCertsExceptOne = (Get-Item "cert:\currentuser\my\*" -Exclude $testThumbprint)
+ $allCerts | should not be null
+ $allCertsExceptOne | should not be null
+ $countDifference = $allCerts.Count - $allCertsExceptOne.Count
+ $countDifference | should be 1
+ }
+ }
+ Context "Get-ChildItem tests"{
+ 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
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1
index 2e021e250c8..e2fb9ddb803 100644
--- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1
@@ -1,96 +1,9 @@
-
-Function Create-GoodCertificate
-{
- $dataEnciphermentCert = "
-MIIKYAIBAzCCCiAGCSqGSIb3DQEHAaCCChEEggoNMIIKCTCCBgoGCSqGSIb3DQEHAaCCBfsEggX3
-MIIF8zCCBe8GCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcNAQwBAzAOBAgPOFDMBkCffQIC
-B9AEggTYjY55RrmAhdj1grENxXjiPrVNdS++pb5UOn3M7O78BR0U1i2h5zvjkPjOwdLoOCbq5pgg
-F0PKaMjHVu8EoZxSqsib17ptR5Rx5N23hseuJUzS8fTAHiBet9payNOJlPfkpuqMfQEmCAo9gAPz
-w4RiyZNOA3NhxkfGl9yU4O9GSEr2koWKCUoCNelkIXVbkV728L7zSiWRSqRb7V4QJAtwtgPLTbl/
-zo2SFhdNAGPeXbcOsKCv9trhuxPZ0FH4fukbXkHs0I3b5mYgMUI5Mds7UwT3wCtz+Ev9pLbmYN8X
-NfH0tAK8ZGnQS1GcI4xCMEM8T9Tx3uwWY4arvRM3GTLwyt8JZEVZNTuYL9A9+RyeiO5d5xEKG8H4
-snOCoTriT45tdl8hzMBCdc3jWxWiydmNRw47irifv5BX7BK/6FLAxkMRwACAxNO63ezG/OxuDDEz
-ml+KzeZNvr4u4mTBcgZ49vMSyfRt/my+5+iLnSMGp4Rt0uix8489wctkxGlgyXGk23pA4Cj4hq/6
-txopcl2gHn+DAFrHIgLg4JR8lcuOzBw8nFOrhK7iR9aMK21apxwImIaDCKJ1grOfbuElq4pkMpov
-SltJe00WB94o69LibOg5LqpTrHW2/DY951sIgElF83FdUBhoZHasfCme/RxgliQf3QHedmENXSjr
-8R8PAWX4wC0ZZVC0qcq5XP0PkwtuDKmfqq69R32nmBzpRrfypm9S+PfsYZeCeuROh6YKQ0ZBMnLb
-8Y9povpXh0lYwVLuPanvAFiCT4vI7oRd1Mg1Zr9ZooMFAVomall1UnQQ29fvsoADjEDcPymVT80o
-kTkw3NXnTX6fGZ94Eh0KZcuMgjTqIO3OKpH0lcaSBxlES4V0sO/mwP4ULy8l3dcnn440Nei33VDo
-B7n2jhjJl/HvtltfEEEw1DW9AWDvkJDp878sD6VoyQZehvvxBNT0FwMr20TbVKeAGxf9n+xJ9Alo
-VUS3qE7XnpxAAAR5L2OG+tMd4dyDSge1qrkVNZ3/uUzKKCZei2P7ICR9cX1FRsmcINdNfydIA2cA
-Pmeq+UkRdqsJxt1NSK5bLvMM4EHRQZMMbXVKxxJ+kQDrzfQtERFPyd3Hdm2F4T/JXUQ+PrTQnRqY
-LruTAiZfxygZuFrxJnNTRydRdbEaTAtMjFCMRFZ2wctJsgCb3yN9tt0JDYxIvm0MSehXiF+sCrl4
-yZvvUzJqrgppHRTBR4Sao+MZ/rJ30vVU19Q3oBi9ikTqDY+4SrHsp5Y4llnsbrz0Web+h2jLvyJz
-LgKuqs87qHhToVMLuULy/HLqY3m661EMwNqh5D76gSFI+TP2/rzT5mVOGglahFoc848o4cshtPWE
-9MjAkDfsMbIfeKH3uh3D+eBIxYmZ5Cq2aHzqdQ0pU/nDNX7BDjC3E80VcQnXx4U6tRsQHsGtbcld
-MFTp0yHJ2KLkz+inH3WPy/lYuVZ0QJe+LqvGt+bt1DgQmLBMD9WLFML3d0TtkuY3RhD5Y0wr2zt9
-tT6WVTn8Hob1cJns4N7tDEr8Q3TdIar0I5Bzj3qoesJt+4lxwnVdUA1bNJ2zxXIkDfX/MTB464FI
-2g9uhUs3lIOEiCjeJCwBebgZa1HlfhyCRu0E7fnNnKLaGWRs8LVy7MZIfe1kJoDVgTGB3TATBgkq
-hkiG9w0BCRUxBgQEAQAAADBdBgkrBgEEAYI3EQExUB5OAE0AaQBjAHIAbwBzAG8AZgB0ACAAUwB0
-AHIAbwBuAGcAIABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByMGcG
-CSqGSIb3DQEJFDFaHlgAQwBlAHIAdABSAGUAcQAtAGEAYgA5AGUAZgA3AGYAOAAtAGUAYwA2AGEA
-LQA0ADUAMwA4AC0AOQA4AGQAOAAtADAAYQA4AGUAYwA4ADUAOQBkADkAMgAxMIID9wYJKoZIhvcN
-AQcGoIID6DCCA+QCAQAwggPdBgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAiYL6rZmAGN9QIC
-B9CAggOw8eaNgIqx26SlOBKKQZ5O7NDZQHbytHTWn4ifNhVFUkbuaj22/VnYOFB9//8BLY6t0Dvw
-X6wqXSMnbr1jOuUYaFdJzOBZBsYQfFTfoJ4iOb2jwwIpZSgTHeqgXbvnI7MIxauu6F4UseWVxt3u
-ZhHjEZQjKWeC5mNCb6wX0IOQk96n1RJnJ3v1D4Q5YrVekOVq70VhRNtLOZMkrJV7vDMNlUYXD69D
-PbcyPajVvETq0W98YNKB89oNwFWuKoMLNPWmSwIfn10oSEtybNEEr2IVgCBt2w2eb+nIDuA3c/Rc
-qKPXwVGMzoUyAiGwTcueCdMRmiuQAuKCUyi9P/JqeIbgHtg15nAoGtw+l4MsFXfdMJjTCDd0WYff
-l9ipaNnw8erCPquD0+wXeMnNivXaFzu2+CGwCSwbDl2M49HAQdtpKhNj5jKJBEP1GRQIk173gbEZ
-n69IXUCsf0GDZiZVNbAQHBOuRoEHpBhendFgTJFAU2LDHlmV6OA0LYHaSn7CP/vOXOhWXJ1yGL2p
-SeUepciwQV7sOHqDExWY82fd1kHSHcgCAkWLSSdIPlWhyeqjC1agSP6b74VK8uLRPkin5F9wGIPi
-ewe/LsW3PTtDkDnj3DiSioKlQRUUxVxzi5qPBs+7vJEhbuO7UhtsMCWeUygDbw6n8BKan4w9iLhx
-7/z6zVvQmLnK4HZChTPFuThRy1NctupoX7nE+CDgyhcmryaTDXohkviMWl4Od+8uGh8Quv2bHk6Y
-UnFqNB/hSqYMkTuMLH4F9sVzoQEsYu96CDwbQaggbLMnPtmHKsPtzdnWQnys+oGT4uD8vl9xFdEW
-AZdestrxbDK0La0AgGszUE+6B/GtOs2pv0fMXXYV2h+dAlwfz7oLxzm9E+SFgzviL+6PuI9fDHNd
-pWeq/Rr5OpFb3rSotGTl84aIjk3hPd3uHujPQh8GO2EQ5k6p6ukk+a7gOUB+pH8fHihFl5L7pI0z
-yRp0FvbZo//hmACYMvINoy2EQxjYLh7QLeE4qEr8bkzJVgEURUvcUpyHFJT6PGzUMqGx/Wjh2jJc
-HfEDPMUDoTE/QRzLW7XrmQgJIRuHgPI/cqmOyvpEvuwdRhYyHEKktRO3tGjeflohDCyDW9bxOaJV
-ZP64KBordM28ZHCQbnSdU0I5us6qiFX2PiLlBzRMH2ftUNMYReioqZyR+Xv5wjaoydV3//BDMH8M
-1lh9GazUO8+OtzQEH0jiBi6ctlzFT8nNI2C+cOB9S3yMAjCEQa8wNzAfMAcGBSsOAwIaBBR96vF2
-OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM=
-"
-
- $dataEnciphermentCert = $dataEnciphermentCert -replace '\s',''
- $certBytes = [Convert]::FromBase64String($dataEnciphermentCert)
- $certLocation = Join-Path $TestDrive "ProtectedEventLogging.pfx"
- [IO.File]::WriteAllBytes($certLocation, $certBytes)
-
- return $certLocation
-}
-
-Function Create-BadCertificate
-{
- $codeSigningCert = "
-MIIDAjCCAeqgAwIBAgIQW/oHcNaftoFGOYb4w5A0JTANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQD
-DA5DTVNUZXN0QmFkQ2VydDAeFw0xNzAzMDcwNjEyMDNaFw0xODAzMDcwNjMyMDNaMBkxFzAVBgNV
-BAMMDkNNU1Rlc3RCYWRDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAogOnCBPp
-xCQXvCJOe4KUXrTL5hwzKSV/mA4pF/kWCVLseWkeTzll+02S0SzMR1oqyxGZOU+KiakmH8sIxDpS
-pBpYi3R+JtaUYeK7IwvM7yMgxzYbVUFupNXDIdFcgd7FwX4R9wJGwd/hEw5fe+ua96G6bBlfQC8j
-I8iHfqHZ2GmssIuSt72WhT6tKZhPJIMjwmKaB8j/gm6EC7eH83wNmVW/ss2AsG5cMT0Zmk2vkXPd
-7rVYbAh9WcvxYzTYZLsPkXx/s6uanLo7pBPMqQ8fgImSXiD5EBO9d6SzqoagoAkH/l3oKCUztsqU
-PAfTu1aTAYRW5O26AcICTbIYOMkDMQIDAQABo0YwRDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww
-CgYIKwYBBQUHAwMwHQYDVR0OBBYEFLSLHDqLWoDBj0j/UavIf0hAHZ2YMA0GCSqGSIb3DQEBCwUA
-A4IBAQB7GJ3ykI07k2D1mfiQ10+Xse4b6KXylbzYfJ1k3K0NEBwT7H/lhMu4yz95A7pXU41yKKVE
-OzmpX8QGyczRM269+WpUvVOXwudQL7s/JFeZyEhxPYRP0JC8U9rur1iJeULvsPZJU2kGeLceTl7k
-psuZeHouYeNuFeeKR66GcHKzqm+5odAJBxjQ/iGP+CVfNVX56Abhu8mXX6sFiorrBSV/NzPThqja
-mtsMC3Fq53xANMjFT4kUqMtK+oehPf0+0jHHra4hpCVZ2KoPLLPxpJPko8hUO5LxATLU+UII7w3c
-nMbw+XY4C8xdDnHfS6mF+Hol98dURB/MC/x3sZ3gSjKo
-"
-
- $codeSigningCert = $codeSigningCert -replace '\s',''
- $certBytes = [Convert]::FromBase64String($codeSigningCert)
- $certLocation = Join-Path $TestDrive "CMSTestBadCert"
- [IO.File]::WriteAllBytes($certLocation, $certBytes)
-
- return $certLocation
-}
-
+Import-Module (Join-Path -Path $PSScriptRoot 'certificateCommon.psm1') -Force
Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" {
BeforeAll {
- $certLocation = Create-GoodCertificate
+ $certLocation = New-GoodCertificate
$certLocation | Should Not BeNullOrEmpty | Out-Null
}
@@ -148,62 +61,23 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" {
Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" {
- BeforeAll {
- if ($IsWindows)
+ BeforeAll{
+ if($IsWindows)
{
- $certLocation = Create-GoodCertificate
- $certLocation | Should Not BeNullOrEmpty | Out-Null
-
- $badCertLocation = Create-BadCertificate
- $badCertLocation | Should Not BeNullOrEmpty | Out-Null
-
- if ($IsCoreCLR)
- {
- # PKI module is not available for PowerShell Core, so we need to use Windows PowerShell to import the cert
- $fullPowerShell = Join-Path "$env:SystemRoot" "System32\WindowsPowerShell\v1.0\powershell.exe"
-
- try {
- $modulePathCopy = $env:PSModulePath
- $env:PSModulePath = $null
-
- $command = @"
-Import-PfxCertificate $certLocation -CertStoreLocation cert:\CurrentUser\My | % PSPath
-Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | % PSPath
-"@
- $certPaths = & $fullPowerShell -NoProfile -NonInteractive -Command $command
- $certPaths.Count | Should Be 2 | Out-Null
-
- $importedCert = Get-ChildItem $certPaths[0]
- $testBadCert = Get-ChildItem $certPaths[1]
- } finally {
- $env:PSModulePath = $modulePathCopy
- }
- }
- else
- {
- $importedCert = Import-PfxCertificate $certLocation -CertStoreLocation cert:\CurrentUser\My
- $testBadCert = Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My
- }
+ Install-TestCertificates
}
else
{
# Skip for non-Windows platforms
$defaultParamValues = $PSdefaultParameterValues.Clone()
$PSdefaultParameterValues = @{ "it:skip" = $true }
- }
+ }
}
-
+
AfterAll {
- if ($IsWindows)
+ if($IsWindows)
{
- if ($importedCert)
- {
- Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) -Force -ErrorAction SilentlyContinue
- }
- if ($testBadCert)
- {
- Remove-Item (Join-Path Cert:\CurrentUser\My $testBadCert.Thumbprint) -Force -ErrorAction SilentlyContinue
- }
+ Remove-TestCertificates
}
else
{
@@ -246,7 +120,7 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
It "Verify wildcarded recipient resolution by path [Decryption]" {
$errors = $null
- $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*")
+ $recipient = [System.Management.Automation.CmsMessageRecipient] ((Get-GoodCertificateLocation) + "*")
$recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors)
# Should have resolved single cert
@@ -255,7 +129,7 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
It "Verify wildcarded recipient resolution by path [Encryption]" {
$errors = $null
- $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*")
+ $recipient = [System.Management.Automation.CmsMessageRecipient] ((Get-GoodCertificateLocation) + "*")
$recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors)
$recipient.Certificates.Count | Should Be 1
@@ -264,9 +138,9 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
It "Verify resolution by directory" {
$protectedEventLoggingCertPath = Join-Path $TestDrive ProtectedEventLoggingDir
$null = New-Item -ItemType Directory $protectedEventLoggingCertPath -Force
- Copy-Item $certLocation $protectedEventLoggingCertPath
- Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "SecondCert.pfx")
- Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "ThirdCert.pfx")
+ Copy-Item (Get-GoodCertificateLocation) $protectedEventLoggingCertPath
+ Copy-Item (Get-GoodCertificateLocation) (Join-Path $protectedEventLoggingCertPath "SecondCert.pfx")
+ Copy-Item (Get-GoodCertificateLocation) (Join-Path $protectedEventLoggingCertPath "ThirdCert.pfx")
$errors = $null
$recipient = [System.Management.Automation.CmsMessageRecipient] $protectedEventLoggingCertPath
@@ -277,21 +151,21 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
It "Verify resolution by thumbprint" {
$errors = $null
- $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Thumbprint
+ $recipient = [System.Management.Automation.CmsMessageRecipient] (Get-GoodCertificateObject).Thumbprint
$recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors)
# "Should have certs from thumbprint in 'My' store"
$recipient.Certificates.Count | Should Be 1
- $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint
+ $recipient.Certificates[0].Thumbprint | Should Be (Get-GoodCertificateObject).Thumbprint
}
It "Verify resolution by subject name" {
$errors = $null
- $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Subject
+ $recipient = [System.Management.Automation.CmsMessageRecipient] (Get-GoodCertificateObject).Subject
$recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors)
$recipient.Certificates.Count | Should Be 1
- $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint
+ $recipient.Certificates[0].Thumbprint | Should Be (Get-GoodCertificateObject).Thumbprint
}
It "Verify error when no cert found in encryption for encryption" {
@@ -314,7 +188,7 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
It "Verify error when encrypting to wrong cert" {
$errors = $null
- $recipient = [System.Management.Automation.CmsMessageRecipient] $testBadCert.Thumbprint
+ $recipient = [System.Management.Automation.CmsMessageRecipient] (Get-BadCertificateObject).Thumbprint
$recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors)
$errors.Count | Should Be 1
@@ -346,17 +220,17 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
$encryptedPath = $tempPath + ".encrypted.txt"
"Hello World","How are you?" | Set-Content $tempPath
- Protect-CmsMessage -Path $tempPath -To $certLocation -OutFile $encryptedPath
+ Protect-CmsMessage -Path $tempPath -To (Get-GoodCertificateLocation) -OutFile $encryptedPath
$message = Get-CmsMessage -LiteralPath $encryptedPath
$message.Recipients.Count | Should Be 1
$message.Recipients[0].IssuerName | Should Be "CN=MyDataEnciphermentCert"
$expected = "Hello World" + [System.Environment]::NewLine + "How are you?" + [System.Environment]::NewLine
- $decrypted = $message | Unprotect-CmsMessage -To $certLocation
+ $decrypted = $message | Unprotect-CmsMessage -To (Get-GoodCertificateLocation)
$decrypted | Should Be $expected
- $decrypted = Unprotect-CmsMessage -Path $encryptedPath -To $certLocation
+ $decrypted = Unprotect-CmsMessage -Path $encryptedPath -To (Get-GoodCertificateLocation)
$decrypted | Should Be $expected
} finally {
Remove-Item $tempPath, $encryptedPath -Force -ErrorAction SilentlyContinue
@@ -367,7 +241,7 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
try {
$randomNum = Get-Random -Minimum 1000 -Maximum 9999
$tempPath = Join-Path $TestDrive "$randomNum-Path-Test-File"
- "Hello World" | Protect-CmsMessage -To $certLocation -OutFile $tempPath
+ "Hello World" | Protect-CmsMessage -To (Get-GoodCertificateLocation) -OutFile $tempPath
# Decrypt using $importedCert in the Cert store
$decrypted = Unprotect-CmsMessage -Path $tempPath
@@ -411,11 +285,11 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
}
It "Verify Unprotect-CmsMessage lets you include context" {
- $protected = "Hello World" | Protect-CmsMessage -To $certLocation
+ $protected = "Hello World" | Protect-CmsMessage -To (Get-GoodCertificateLocation)
$adjustedProtected = "Pre content" + [System.Environment]::NewLine + $protected + [System.Environment]::NewLine + "Post content"
- $decryptedNoContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation
- $decryptedWithContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation -IncludeContext
+ $decryptedNoContext = $adjustedProtected | Unprotect-CmsMessage -To (Get-GoodCertificateLocation)
+ $decryptedWithContext = $adjustedProtected | Unprotect-CmsMessage -To (Get-GoodCertificateLocation) -IncludeContext
$decryptedNoContext | Should Be "Hello World"
@@ -424,16 +298,16 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
}
It "Verify Unprotect-CmsMessage treats event logs as a first class citizen" {
- $protected = "Encrypted Message1","Encrypted Message2" | Protect-CmsMessage -To $certLocation
+ $protected = "Encrypted Message1","Encrypted Message2" | Protect-CmsMessage -To (Get-GoodCertificateLocation)
$virtualEventLog = Get-WinEvent Microsoft-Windows-PowerShell/Operational -MaxEvents 1
$savedId = $virtualEventLog.Id
$virtualEventLog.Message = $protected
$expected = "Encrypted Message1" + [System.Environment]::NewLine + "Encrypted Message2"
- $decrypted = $virtualEventLog | Unprotect-CmsMessage -To $certLocation
+ $decrypted = $virtualEventLog | Unprotect-CmsMessage -To (Get-GoodCertificateLocation)
$decrypted | Should Be $expected
- $processed = $virtualEventLog | Unprotect-CmsMessage -To $certLocation -IncludeContext
+ $processed = $virtualEventLog | Unprotect-CmsMessage -To (Get-GoodCertificateLocation) -IncludeContext
$processed.Id | Should Be $savedId
$processed.Message | Should Be $expected
}
@@ -451,8 +325,8 @@ Import-Certificate $badCertLocation -CertStoreLocation Cert:\CurrentUser\My | %
}
It "Verify protect message using OutString" {
- $protected = Get-Process -Id $pid | Protect-CmsMessage -To $certLocation
- $decrypted = $protected | Unprotect-CmsMessage -To $certLocation
+ $protected = Get-Process -Id $pid | Protect-CmsMessage -To (Get-GoodCertificateLocation)
+ $decrypted = $protected | Unprotect-CmsMessage -To (Get-GoodCertificateLocation)
# Should have had PID in output
$decrypted | Should Match $pid
}
diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1 b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1
new file mode 100644
index 00000000000..53dbb5d8ec0
--- /dev/null
+++ b/test/powershell/Modules/Microsoft.PowerShell.Security/certificateCommon.psm1
@@ -0,0 +1,159 @@
+Function New-GoodCertificate
+{
+ $dataEnciphermentCert = "
+MIIKYAIBAzCCCiAGCSqGSIb3DQEHAaCCChEEggoNMIIKCTCCBgoGCSqGSIb3DQEHAaCCBfsEggX3
+MIIF8zCCBe8GCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcNAQwBAzAOBAgPOFDMBkCffQIC
+B9AEggTYjY55RrmAhdj1grENxXjiPrVNdS++pb5UOn3M7O78BR0U1i2h5zvjkPjOwdLoOCbq5pgg
+F0PKaMjHVu8EoZxSqsib17ptR5Rx5N23hseuJUzS8fTAHiBet9payNOJlPfkpuqMfQEmCAo9gAPz
+w4RiyZNOA3NhxkfGl9yU4O9GSEr2koWKCUoCNelkIXVbkV728L7zSiWRSqRb7V4QJAtwtgPLTbl/
+zo2SFhdNAGPeXbcOsKCv9trhuxPZ0FH4fukbXkHs0I3b5mYgMUI5Mds7UwT3wCtz+Ev9pLbmYN8X
+NfH0tAK8ZGnQS1GcI4xCMEM8T9Tx3uwWY4arvRM3GTLwyt8JZEVZNTuYL9A9+RyeiO5d5xEKG8H4
+snOCoTriT45tdl8hzMBCdc3jWxWiydmNRw47irifv5BX7BK/6FLAxkMRwACAxNO63ezG/OxuDDEz
+ml+KzeZNvr4u4mTBcgZ49vMSyfRt/my+5+iLnSMGp4Rt0uix8489wctkxGlgyXGk23pA4Cj4hq/6
+txopcl2gHn+DAFrHIgLg4JR8lcuOzBw8nFOrhK7iR9aMK21apxwImIaDCKJ1grOfbuElq4pkMpov
+SltJe00WB94o69LibOg5LqpTrHW2/DY951sIgElF83FdUBhoZHasfCme/RxgliQf3QHedmENXSjr
+8R8PAWX4wC0ZZVC0qcq5XP0PkwtuDKmfqq69R32nmBzpRrfypm9S+PfsYZeCeuROh6YKQ0ZBMnLb
+8Y9povpXh0lYwVLuPanvAFiCT4vI7oRd1Mg1Zr9ZooMFAVomall1UnQQ29fvsoADjEDcPymVT80o
+kTkw3NXnTX6fGZ94Eh0KZcuMgjTqIO3OKpH0lcaSBxlES4V0sO/mwP4ULy8l3dcnn440Nei33VDo
+B7n2jhjJl/HvtltfEEEw1DW9AWDvkJDp878sD6VoyQZehvvxBNT0FwMr20TbVKeAGxf9n+xJ9Alo
+VUS3qE7XnpxAAAR5L2OG+tMd4dyDSge1qrkVNZ3/uUzKKCZei2P7ICR9cX1FRsmcINdNfydIA2cA
+Pmeq+UkRdqsJxt1NSK5bLvMM4EHRQZMMbXVKxxJ+kQDrzfQtERFPyd3Hdm2F4T/JXUQ+PrTQnRqY
+LruTAiZfxygZuFrxJnNTRydRdbEaTAtMjFCMRFZ2wctJsgCb3yN9tt0JDYxIvm0MSehXiF+sCrl4
+yZvvUzJqrgppHRTBR4Sao+MZ/rJ30vVU19Q3oBi9ikTqDY+4SrHsp5Y4llnsbrz0Web+h2jLvyJz
+LgKuqs87qHhToVMLuULy/HLqY3m661EMwNqh5D76gSFI+TP2/rzT5mVOGglahFoc848o4cshtPWE
+9MjAkDfsMbIfeKH3uh3D+eBIxYmZ5Cq2aHzqdQ0pU/nDNX7BDjC3E80VcQnXx4U6tRsQHsGtbcld
+MFTp0yHJ2KLkz+inH3WPy/lYuVZ0QJe+LqvGt+bt1DgQmLBMD9WLFML3d0TtkuY3RhD5Y0wr2zt9
+tT6WVTn8Hob1cJns4N7tDEr8Q3TdIar0I5Bzj3qoesJt+4lxwnVdUA1bNJ2zxXIkDfX/MTB464FI
+2g9uhUs3lIOEiCjeJCwBebgZa1HlfhyCRu0E7fnNnKLaGWRs8LVy7MZIfe1kJoDVgTGB3TATBgkq
+hkiG9w0BCRUxBgQEAQAAADBdBgkrBgEEAYI3EQExUB5OAE0AaQBjAHIAbwBzAG8AZgB0ACAAUwB0
+AHIAbwBuAGcAIABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByMGcG
+CSqGSIb3DQEJFDFaHlgAQwBlAHIAdABSAGUAcQAtAGEAYgA5AGUAZgA3AGYAOAAtAGUAYwA2AGEA
+LQA0ADUAMwA4AC0AOQA4AGQAOAAtADAAYQA4AGUAYwA4ADUAOQBkADkAMgAxMIID9wYJKoZIhvcN
+AQcGoIID6DCCA+QCAQAwggPdBgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAiYL6rZmAGN9QIC
+B9CAggOw8eaNgIqx26SlOBKKQZ5O7NDZQHbytHTWn4ifNhVFUkbuaj22/VnYOFB9//8BLY6t0Dvw
+X6wqXSMnbr1jOuUYaFdJzOBZBsYQfFTfoJ4iOb2jwwIpZSgTHeqgXbvnI7MIxauu6F4UseWVxt3u
+ZhHjEZQjKWeC5mNCb6wX0IOQk96n1RJnJ3v1D4Q5YrVekOVq70VhRNtLOZMkrJV7vDMNlUYXD69D
+PbcyPajVvETq0W98YNKB89oNwFWuKoMLNPWmSwIfn10oSEtybNEEr2IVgCBt2w2eb+nIDuA3c/Rc
+qKPXwVGMzoUyAiGwTcueCdMRmiuQAuKCUyi9P/JqeIbgHtg15nAoGtw+l4MsFXfdMJjTCDd0WYff
+l9ipaNnw8erCPquD0+wXeMnNivXaFzu2+CGwCSwbDl2M49HAQdtpKhNj5jKJBEP1GRQIk173gbEZ
+n69IXUCsf0GDZiZVNbAQHBOuRoEHpBhendFgTJFAU2LDHlmV6OA0LYHaSn7CP/vOXOhWXJ1yGL2p
+SeUepciwQV7sOHqDExWY82fd1kHSHcgCAkWLSSdIPlWhyeqjC1agSP6b74VK8uLRPkin5F9wGIPi
+ewe/LsW3PTtDkDnj3DiSioKlQRUUxVxzi5qPBs+7vJEhbuO7UhtsMCWeUygDbw6n8BKan4w9iLhx
+7/z6zVvQmLnK4HZChTPFuThRy1NctupoX7nE+CDgyhcmryaTDXohkviMWl4Od+8uGh8Quv2bHk6Y
+UnFqNB/hSqYMkTuMLH4F9sVzoQEsYu96CDwbQaggbLMnPtmHKsPtzdnWQnys+oGT4uD8vl9xFdEW
+AZdestrxbDK0La0AgGszUE+6B/GtOs2pv0fMXXYV2h+dAlwfz7oLxzm9E+SFgzviL+6PuI9fDHNd
+pWeq/Rr5OpFb3rSotGTl84aIjk3hPd3uHujPQh8GO2EQ5k6p6ukk+a7gOUB+pH8fHihFl5L7pI0z
+yRp0FvbZo//hmACYMvINoy2EQxjYLh7QLeE4qEr8bkzJVgEURUvcUpyHFJT6PGzUMqGx/Wjh2jJc
+HfEDPMUDoTE/QRzLW7XrmQgJIRuHgPI/cqmOyvpEvuwdRhYyHEKktRO3tGjeflohDCyDW9bxOaJV
+ZP64KBordM28ZHCQbnSdU0I5us6qiFX2PiLlBzRMH2ftUNMYReioqZyR+Xv5wjaoydV3//BDMH8M
+1lh9GazUO8+OtzQEH0jiBi6ctlzFT8nNI2C+cOB9S3yMAjCEQa8wNzAfMAcGBSsOAwIaBBR96vF2
+OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM=
+"
+
+ $dataEnciphermentCert = $dataEnciphermentCert -replace '\s',''
+ $certBytes = [Convert]::FromBase64String($dataEnciphermentCert)
+ $certLocation = Join-Path $TestDrive "ProtectedEventLogging.pfx"
+ [IO.File]::WriteAllBytes($certLocation, $certBytes)
+
+ return $certLocation
+}
+
+Function New-BadCertificate
+{
+ $codeSigningCert = "
+MIIDAjCCAeqgAwIBAgIQW/oHcNaftoFGOYb4w5A0JTANBgkqhkiG9w0BAQsFADAZMRcwFQYDVQQD
+DA5DTVNUZXN0QmFkQ2VydDAeFw0xNzAzMDcwNjEyMDNaFw0xODAzMDcwNjMyMDNaMBkxFzAVBgNV
+BAMMDkNNU1Rlc3RCYWRDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAogOnCBPp
+xCQXvCJOe4KUXrTL5hwzKSV/mA4pF/kWCVLseWkeTzll+02S0SzMR1oqyxGZOU+KiakmH8sIxDpS
+pBpYi3R+JtaUYeK7IwvM7yMgxzYbVUFupNXDIdFcgd7FwX4R9wJGwd/hEw5fe+ua96G6bBlfQC8j
+I8iHfqHZ2GmssIuSt72WhT6tKZhPJIMjwmKaB8j/gm6EC7eH83wNmVW/ss2AsG5cMT0Zmk2vkXPd
+7rVYbAh9WcvxYzTYZLsPkXx/s6uanLo7pBPMqQ8fgImSXiD5EBO9d6SzqoagoAkH/l3oKCUztsqU
+PAfTu1aTAYRW5O26AcICTbIYOMkDMQIDAQABo0YwRDAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww
+CgYIKwYBBQUHAwMwHQYDVR0OBBYEFLSLHDqLWoDBj0j/UavIf0hAHZ2YMA0GCSqGSIb3DQEBCwUA
+A4IBAQB7GJ3ykI07k2D1mfiQ10+Xse4b6KXylbzYfJ1k3K0NEBwT7H/lhMu4yz95A7pXU41yKKVE
+OzmpX8QGyczRM269+WpUvVOXwudQL7s/JFeZyEhxPYRP0JC8U9rur1iJeULvsPZJU2kGeLceTl7k
+psuZeHouYeNuFeeKR66GcHKzqm+5odAJBxjQ/iGP+CVfNVX56Abhu8mXX6sFiorrBSV/NzPThqja
+mtsMC3Fq53xANMjFT4kUqMtK+oehPf0+0jHHra4hpCVZ2KoPLLPxpJPko8hUO5LxATLU+UII7w3c
+nMbw+XY4C8xdDnHfS6mF+Hol98dURB/MC/x3sZ3gSjKo
+"
+
+ $codeSigningCert = $codeSigningCert -replace '\s',''
+ $certBytes = [Convert]::FromBase64String($codeSigningCert)
+ $certLocation = Join-Path $TestDrive "CMSTestBadCert"
+ [IO.File]::WriteAllBytes($certLocation, $certBytes)
+
+ return $certLocation
+}
+
+function Install-TestCertificates
+{
+ $script:certLocation = New-GoodCertificate
+ $script:certLocation | Should Not BeNullOrEmpty | Out-Null
+
+ $script:badCertLocation = New-BadCertificate
+ $script:badCertLocation | Should Not BeNullOrEmpty | Out-Null
+
+ if ($IsCoreCLR -and $IsWindows)
+ {
+ # PKI module is not available for PowerShell Core, so we need to use Windows PowerShell to import the cert
+ $fullPowerShell = Join-Path "$env:SystemRoot" "System32\WindowsPowerShell\v1.0\powershell.exe"
+
+ try {
+ $modulePathCopy = $env:PSModulePath
+ $env:PSModulePath = $null
+
+ $command = @"
+Import-PfxCertificate $script:certLocation -CertStoreLocation cert:\CurrentUser\My | % PSPath
+Import-Certificate $script:badCertLocation -CertStoreLocation Cert:\CurrentUser\My | % PSPath
+"@
+ $certPaths = & $fullPowerShell -NoProfile -NonInteractive -Command $command
+ $certPaths.Count | Should Be 2 | Out-Null
+
+ $script:importedCert = Get-ChildItem $certPaths[0]
+ $script:testBadCert = Get-ChildItem $certPaths[1]
+ } finally {
+ $env:PSModulePath = $modulePathCopy
+ }
+ }
+ elseif($IsWindows)
+ {
+ $script:importedCert = Import-PfxCertificate $script:certLocation -CertStoreLocation cert:\CurrentUser\My
+ $script:testBadCert = Import-Certificate $script:badCertLocation -CertStoreLocation Cert:\CurrentUser\My
+ }
+ else {
+ throw 'Not supported on non-windows platforms'
+ }
+}
+
+function Get-GoodCertificateLocation
+{
+ return $script:certLocation
+}
+
+function Get-GoodCertificateObject
+{
+ return $script:importedCert
+}
+
+function Get-BadCertificateObject
+{
+ return $script:testBadCert
+}
+
+function Remove-TestCertificates
+{
+ if($IsWindows)
+ {
+ if ($script:importedCert)
+ {
+ Remove-Item (Join-Path Cert:\CurrentUser\My $script:importedCert.Thumbprint) -Force -ErrorAction SilentlyContinue
+ }
+ if ($script:testBadCert)
+ {
+ Remove-Item (Join-Path Cert:\CurrentUser\My $script:testBadCert.Thumbprint) -Force -ErrorAction SilentlyContinue
+ }
+ }
+ else {
+ throw 'Not supported on non-windows platforms'
+ }
+}
\ No newline at end of file