From 8bd284e467ffd91c8f9c9de7f71ec57401744828 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 21 Jan 2020 12:05:06 -0500 Subject: [PATCH 01/24] updated CmsCommands to use Store vs cert provider --- .../security/SecuritySupport.cs | 107 ++++-------------- 1 file changed, 25 insertions(+), 82 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 41c92c01915..d3d33256201 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1163,19 +1163,13 @@ public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out Er return; } - // Then by thumbprint - ResolveFromThumbprint(sessionState, purpose, out error); + // Then by cert store + ResolveFromStoreById(sessionState, purpose, out error); if ((error != null) || (Certificates.Count != 0)) { return; } - // Then by Subject Name - ResolveFromSubjectName(sessionState, purpose, out error); - if ((error != null) || (Certificates.Count != 0)) - { - return; - } } // Generate an error if no cert was found (and this is an encryption attempt). @@ -1216,7 +1210,7 @@ private void ResolveFromBase64Encoding(ResolutionPurpose purpose, out ErrorRecor return; } - List certificatesToProcess = new List(); + X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); try { X509Certificate2 newCertificate = new X509Certificate2(messageBytes); @@ -1290,7 +1284,7 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos resolvedPaths.Remove(path); } - List certificatesToProcess = new List(); + X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); foreach (string path in resolvedPaths) { X509Certificate2 certificate = null; @@ -1312,99 +1306,48 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos } } - private void ResolveFromThumbprint(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error) + private void ResolveFromStoreById(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error) { - // Quickly check that this is a thumbprint-like pattern (just hex) - if (!System.Text.RegularExpressions.Regex.IsMatch(_identifier, "^[a-f0-9]+$", Text.RegularExpressions.RegexOptions.IgnoreCase)) - { - error = null; - return; - } - Collection certificates = new Collection(); try { - // Get first from 'My' store - string certificatePath = sessionState.Path.Combine("Microsoft.PowerShell.Security\\Certificate::CurrentUser\\My", _identifier); - if (sessionState.InvokeProvider.Item.Exists(certificatePath)) - { - foreach (PSObject certificateObject in sessionState.InvokeProvider.Item.Get(certificatePath)) - { - certificates.Add(certificateObject); - } - } + X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); - // Second from 'LocalMachine' store - certificatePath = sessionState.Path.Combine("Microsoft.PowerShell.Security\\Certificate::LocalMachine\\My", _identifier); - if (sessionState.InvokeProvider.Item.Exists(certificatePath)) + using (X509Store storeCU = new X509Store("my", StoreLocation.CurrentUser)) { - foreach (PSObject certificateObject in sessionState.InvokeProvider.Item.Get(certificatePath)) - { - certificates.Add(certificateObject); - } - } - } - catch (SessionStateException) - { - // If we got an ItemNotFound / etc., then this didn't represent a valid path. - } - - List certificatesToProcess = new List(); - foreach (PSObject certificateObject in certificates) - { - X509Certificate2 certificate = certificateObject.BaseObject as X509Certificate2; - if (certificate != null) - { - certificatesToProcess.Add(certificate); - } - } - - ProcessResolvedCertificates(purpose, certificatesToProcess, out error); - } - - private void ResolveFromSubjectName(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error) - { - Collection certificates = new Collection(); - WildcardPattern subjectNamePattern = WildcardPattern.Get(_identifier, WildcardOptions.IgnoreCase); - - try - { - // Get first from 'My' store, then 'LocalMachine' - string[] certificatePaths = new string[] { - "Microsoft.PowerShell.Security\\Certificate::CurrentUser\\My", - "Microsoft.PowerShell.Security\\Certificate::LocalMachine\\My" }; + storeCU.Open(OpenFlags.ReadOnly); + X509Certificate2Collection storeCerts = storeCU.Certificates; - foreach (string certificatePath in certificatePaths) - { - foreach (PSObject certificateObject in sessionState.InvokeProvider.ChildItem.Get(certificatePath, false)) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (subjectNamePattern.IsMatch(certificateObject.Properties["Subject"].Value.ToString())) + using (X509Store storeLM = new X509Store("my", StoreLocation.LocalMachine)) { - certificates.Add(certificateObject); + storeLM.Open(OpenFlags.ReadOnly); + storeCerts.AddRange(storeLM.Certificates); } } + + // Find is case insensitive + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier.Trim(), false)); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, _identifier.Trim(), false)); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier.Trim(), false)); + ProcessResolvedCertificates(purpose, certificatesToProcess, out error); + } + } catch (SessionStateException) { - // If we got an ItemNotFound / etc., then this didn't represent a valid path. - } - List certificatesToProcess = new List(); - foreach (PSObject certificateObject in certificates) - { - X509Certificate2 certificate = certificateObject.BaseObject as X509Certificate2; - if (certificate != null) - { - certificatesToProcess.Add(certificate); - } } - ProcessResolvedCertificates(purpose, certificatesToProcess, out error); + } - private void ProcessResolvedCertificates(ResolutionPurpose purpose, List certificatesToProcess, out ErrorRecord error) + + + private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certificate2Collection certificatesToProcess, out ErrorRecord error) { error = null; HashSet processedThumbprints = new HashSet(); From be3105066046d3c2db1990db156a69b4ddc56c63 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 21 Jan 2020 13:01:47 -0500 Subject: [PATCH 02/24] cmscommands fixed x509collection type --- src/System.Management.Automation/security/SecuritySupport.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index d3d33256201..d1572615c81 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1140,7 +1140,7 @@ public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out Er if (_pendingCertificate != null) { ProcessResolvedCertificates(purpose, - new List { _pendingCertificate }, out error); + new X509Certificate2Collection(_pendingCertificate), out error); if ((error != null) || (Certificates.Count != 0)) { return; From 52e1679eccd57b23f7ba0e44f974c880e22303ed Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 21 Jan 2020 14:33:37 -0500 Subject: [PATCH 03/24] codacity fix 1 --- .../security/SecuritySupport.cs | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index d1572615c81..1547c59bfed 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1164,13 +1164,12 @@ public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out Er } // Then by cert store - ResolveFromStoreById(sessionState, purpose, out error); + ResolveFromStoreById(purpose, out error); if ((error != null) || (Certificates.Count != 0)) { return; } - - } + } // Generate an error if no cert was found (and this is an encryption attempt). // If it is only decryption, then the system will always look in the 'My' store anyways, so @@ -1306,9 +1305,10 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos } } - private void ResolveFromStoreById(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error) + private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord error) { + error = null; try { @@ -1333,20 +1333,14 @@ private void ResolveFromStoreById(SessionState sessionState, ResolutionPurpose p certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, _identifier.Trim(), false)); certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier.Trim(), false)); ProcessResolvedCertificates(purpose, certificatesToProcess, out error); - } } catch (SessionStateException) { - } - - } - - private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certificate2Collection certificatesToProcess, out ErrorRecord error) { error = null; @@ -1362,9 +1356,14 @@ private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certific { error = new ErrorRecord( new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - SecuritySupportStrings.CertificateCannotBeUsedForEncryption, certificate.Thumbprint, CertificateFilterInfo.DocumentEncryptionOid)), - "CertificateCannotBeUsedForEncryption", ErrorCategory.InvalidData, certificate); + string.Format( + CultureInfo.InvariantCulture, + SecuritySupportStrings.CertificateCannotBeUsedForEncryption, + certificate.Thumbprint, + CertificateFilterInfo.DocumentEncryptionOid)), + "CertificateCannotBeUsedForEncryption", + ErrorCategory.InvalidData, + certificate); return; } else @@ -1399,9 +1398,14 @@ private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certific { error = new ErrorRecord( new ArgumentException( - string.Format(CultureInfo.InvariantCulture, - SecuritySupportStrings.IdentifierMustReferenceSingleCertificate, _identifier, "To")), - "IdentifierMustReferenceSingleCertificate", ErrorCategory.LimitsExceeded, certificatesToProcess); + string.Format( + CultureInfo.InvariantCulture, + SecuritySupportStrings.IdentifierMustReferenceSingleCertificate, + _identifier, + "To")), + "IdentifierMustReferenceSingleCertificate", + ErrorCategory.LimitsExceeded, + certificatesToProcess); Certificates.Clear(); return; } From 164a0dd71ba39ca64a18d08272ed83152a16bf1d Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Thu, 23 Jan 2020 10:18:07 -0500 Subject: [PATCH 04/24] removed GetCertEKU, getting EKUs from cert directly --- .../security/SecuritySupport.cs | 84 ++++--------------- 1 file changed, 16 insertions(+), 68 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 1547c59bfed..fd6be09cc7c 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -620,16 +620,24 @@ internal static bool CertIsGoodForEncryption(X509Certificate2 c) private static bool CertHasOid(X509Certificate2 c, string oid) { - Collection ekus = GetCertEKU(c); - - foreach (string testOid in ekus) + foreach(var extension in c.Extensions) { - if (testOid == oid) + if(extension is X509EnhancedKeyUsageExtension) { - return true; + var EnhancedKeyUsages = (extension as X509EnhancedKeyUsageExtension).EnhancedKeyUsages; + if(EnhancedKeyUsages != null) + { + foreach(var usageOid in EnhancedKeyUsages ) + { + if (usageOid.Value == oid) + { + return true; + } + break; + } + } } - } - + } return false; } @@ -637,18 +645,16 @@ private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsa { foreach (X509Extension extension in c.Extensions) { - X509KeyUsageExtension keyUsageExtension = extension as X509KeyUsageExtension; + var keyUsageExtension = extension as X509KeyUsageExtension; if (keyUsageExtension != null) { if ((keyUsageExtension.KeyUsages & keyUsage) == keyUsage) { return true; } - break; } } - return false; } @@ -662,64 +668,6 @@ internal static bool CertHasPrivatekey(X509Certificate2 cert) return cert.HasPrivateKey; } - /// - /// Get the EKUs of a cert. - /// - /// Certificate object. - /// A collection of cert eku strings. - [ArchitectureSensitive] - internal static Collection GetCertEKU(X509Certificate2 cert) - { - Collection ekus = new Collection(); - 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(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; - } - /// /// Convert an int to a DWORD. /// From d020ca9f08470b59e43c3cee76f47fff2874ea70 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Thu, 23 Jan 2020 11:38:20 -0500 Subject: [PATCH 05/24] added Cms commands to Unix modules --- .../Microsoft.PowerShell.Security.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index d5961d1008d..14fda5e6720 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -7,7 +7,7 @@ ModuleVersion="7.0.0.0" CompatiblePSEditions = @("Core") PowerShellVersion="3.0" FunctionsToExport = @() -CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" +CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate", "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" AliasesToExport = @() NestedModules="Microsoft.PowerShell.Security.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=2113533' From 7124b18d02b10d9ed69d5afaaa8057189d765877 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Thu, 23 Jan 2020 14:36:50 -0500 Subject: [PATCH 06/24] removed break from CertHasOid --- src/System.Management.Automation/security/SecuritySupport.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index fd6be09cc7c..5108cda4e8b 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -595,7 +595,7 @@ internal static void CheckIfFileExists(string filePath) /// True on success, false otherwise. internal static bool CertIsGoodForSigning(X509Certificate2 c) { - if (!CertHasPrivatekey(c)) + if (!CertHasPrivatekey(c)) // why not just c.HasPrivateKey? { return false; } @@ -632,8 +632,7 @@ private static bool CertHasOid(X509Certificate2 c, string oid) if (usageOid.Value == oid) { return true; - } - break; + } } } } From c9fe59d25b69402a0aac9e6e080fb4b05c6bc7c9 Mon Sep 17 00:00:00 2001 From: mikeTWC1984 <31977106+mikeTWC1984@users.noreply.github.com> Date: Thu, 23 Jan 2020 22:35:37 -0500 Subject: [PATCH 07/24] checking if this is failing pester on linux --- .../Microsoft.PowerShell.Security.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index 14fda5e6720..2abcae4195c 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -7,7 +7,7 @@ ModuleVersion="7.0.0.0" CompatiblePSEditions = @("Core") PowerShellVersion="3.0" FunctionsToExport = @() -CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate", "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" +CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" #, "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" AliasesToExport = @() NestedModules="Microsoft.PowerShell.Security.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=2113533' From 9da7f8ecb79c4a5e1df3bb0f14e1fd7e26c9a530 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Fri, 24 Jan 2020 17:08:27 -0500 Subject: [PATCH 08/24] updated CertHasOid and DefaultCommandsTests --- .../Microsoft.PowerShell.Security.psd1 | 2 +- .../security/SecuritySupport.cs | 24 +++++++++---------- .../engine/Basic/DefaultCommands.Tests.ps1 | 6 ++--- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 index 2abcae4195c..c287a6cef3c 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 @@ -7,7 +7,7 @@ ModuleVersion="7.0.0.0" CompatiblePSEditions = @("Core") PowerShellVersion="3.0" FunctionsToExport = @() -CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" #, "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" +CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" , "Protect-CmsMessage", "Unprotect-CmsMessage", "Get-CmsMessage" AliasesToExport = @() NestedModules="Microsoft.PowerShell.Security.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=2113533' diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 5108cda4e8b..3fe29bcc5fe 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -620,22 +620,20 @@ internal static bool CertIsGoodForEncryption(X509Certificate2 c) private static bool CertHasOid(X509Certificate2 c, string oid) { - foreach(var extension in c.Extensions) + foreach(X509Extension extension in c.Extensions) { - if(extension is X509EnhancedKeyUsageExtension) + X509EnhancedKeyUsageExtension ext = extension as X509EnhancedKeyUsageExtension; + if (ext != null) { - var EnhancedKeyUsages = (extension as X509EnhancedKeyUsageExtension).EnhancedKeyUsages; - if(EnhancedKeyUsages != null) + foreach (Oid ekuOid in ext.EnhancedKeyUsages) { - foreach(var usageOid in EnhancedKeyUsages ) - { - if (usageOid.Value == oid) - { - return true; - } + if(ekuOid.Value == oid) + { + return true; } - } - } + } + break; + } } return false; } @@ -644,7 +642,7 @@ private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsa { foreach (X509Extension extension in c.Extensions) { - var keyUsageExtension = extension as X509KeyUsageExtension; + X509KeyUsageExtension keyUsageExtension = extension as X509KeyUsageExtension; if (keyUsageExtension != null) { if ((keyUsageExtension.KeyUsages & keyUsage) == keyUsage) diff --git a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 index f11e6abd911..a0fb1a1540e 100644 --- a/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 +++ b/test/powershell/engine/Basic/DefaultCommands.Tests.ps1 @@ -260,7 +260,7 @@ Describe "Verify approved aliases list" -Tags "CI" { "Cmdlet", "Get-AuthenticodeSignature", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-ChildItem", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Clipboard", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" -"Cmdlet", "Get-CmsMessage", "", $($FullCLR -or $CoreWindows ), "", "", "None" +"Cmdlet", "Get-CmsMessage", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-Command", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Get-ComputerInfo", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Get-ComputerRestorePoint", "", $($FullCLR ), "", "", "" @@ -375,7 +375,7 @@ Describe "Verify approved aliases list" -Tags "CI" { "Cmdlet", "Out-Printer", "", $($FullCLR -or $CoreWindows ), "", "", "None" "Cmdlet", "Out-String", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Pop-Location", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" -"Cmdlet", "Protect-CmsMessage", "", $($FullCLR -or $CoreWindows ), "", "", "None" +"Cmdlet", "Protect-CmsMessage", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Push-Location", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Read-Host", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Receive-Job", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" @@ -470,7 +470,7 @@ Describe "Verify approved aliases list" -Tags "CI" { "Cmdlet", "Trace-Command", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Unblock-File", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium" "Cmdlet", "Undo-Transaction", "", $($FullCLR ), "", "", "" -"Cmdlet", "Unprotect-CmsMessage", "", $($FullCLR -or $CoreWindows ), "", "", "None" +"Cmdlet", "Unprotect-CmsMessage", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "None" "Cmdlet", "Unregister-Event", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Medium" "Cmdlet", "Unregister-PSSessionConfiguration","", $($FullCLR -or $CoreWindows ), "", "", "Low" "Cmdlet", "Update-FormatData", "", $($FullCLR -or $CoreWindows -or $CoreUnix), "", "", "Low" From 931538b9cd7a6281da66b3d51667e816f6275ecf Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 28 Jan 2020 16:20:03 -0500 Subject: [PATCH 09/24] added new test for CMS commands --- .../CmsMessage2.Tests.ps1 | 156 ++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 new file mode 100644 index 00000000000..d17ecfc472a --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -0,0 +1,156 @@ + +# CMS Test + +using namespace System.Security.Cryptography.X509Certificates +using namespace System.Security.Cryptography + +function New-CmsRecipient { param([String]$Name, [Switch]$Invalid) + $hash = [HashAlgorithmName]::SHA256 + $pad = [RSASignaturePadding]::Pkcs1 + + $oids = [OidCollection]::new() + $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null + + $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false) + $ext2 = [X509EnhancedKeyUsageExtension]::new($oids,$false) + + $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) + if(!$Invalid){($ext1, $ext2).ForEach({$req.CertificateExtensions.Add($_)})} + + return $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) +} + + +# ------------------------------------------------------------- + +Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { + + +BeforeAll { + Write-Host "Generating certs" -ForegroundColor Gray + $vc1 = New-CmsRecipient "ValidCms1" + $vc2 = New-CmsRecipient "ValidCms2" + $ic = New-CmsRecipient "InvalidCms" -Invalid # invalid cert + $tmpfile = New-TemporaryFile +} + +It " Encrypting with X509Cert" { + "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*' +} + +It " Encrypting with multiple X509Cert" { + $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' +} + +It " Decrypt with X509Cert" { + "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to $vc1 | Should -Be "test" +} + +It " Decrypt with multiple X509Cert" { + "test" | Protect-CmsMessage -to $vc1, $vc2 | Unprotect-CmsMessage -to $vc1, $vc2 | Should -Be "test" +} + +It " Encrypt with invalid cert" { + $e = try { "test" | Protect-CmsMessage -to $ic} catch {$_} + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' +} + +It "Encrypt with valid and invalid" { + $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic} catch {$_} + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' +} + +It "Encrypt/Decrypt from file" { + "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile + $msg = Unprotect-CmsMessage -to $vc1 -Path $tmpfile + $msg | Should -Be "test" + +} + +It "Get-CmsMessage from content" { + ("test" | Protect-CmsMessage -to $vc1 | Get-CmsMessage).Content | Should -BeLike '-----BEGIN CMS*' +} + +It "Get-CmsMessage from file" { + (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' +} + + +} + + +# ---------------------- FILES ---------------------------- + +Describe "CmsMessage cmdlets using files" -Tags "CI" { + +BeforeAll { + Write-Host "generating temp cert files" -ForegroundColor Gray + $vc1File = New-TemporaryFile + $vc2File = New-TemporaryFile + [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) + [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) +} + +It "Encrypt With Single File" { + "test" | Protect-CmsMessage -to "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -Be 'test' +} + +It "Encrypt With Multiple File" { + $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" + ($msg | Unprotect-CmsMessage -to $vc1) | Should -Be "test" + ($msg | Unprotect-CmsMessage -to $vc2) | Should -Be "test" +} + +It "Decrypt with multiple files" { + + "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -Be 'test' + +} + +} + + +# ------------------ STORE ---------------------------------# + + + +Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { + +BeforeAll -Scriptblock { + Write-Host "adding temp certs to CurrentUser\My Store" -ForegroundColor Gray + $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) + $store.Open("ReadWrite") + $cert1 = [X509Certificate2]::new("$vc1File") + $cert2 = [X509Certificate2]::new("$vc2File") + $store.Add($cert1) + $store.Add($cert2) + # $store.Certificates + } + + It "Encrypt/Decrypt using subject" { + "test" | Protect-CmsMessage -to $cert1.Subject | Unprotect-CmsMessage | Should -Be "test" + "test" | Protect-CmsMessage -to $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -Be "test" + } + + It "Encrypt/Decrypt using Thumbprint" { + "test" | Protect-CmsMessage -to $cert1.Thumbprint | Unprotect-CmsMessage | Should -Be "test" + "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -Be "test" + + } + + It "Encrypt/Decrypt mix" { + "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -Be "test" + } + +} + + +# ---------------------------------------------------------------- + +Write-Host "Removing temp files and certs" -ForegroundColor Gray +$store.Remove($cert1) +$store.Remove($cert2) +$store.Dispose() + +Remove-Item $vc1File, $vc2File, $tmpfile + From f076dcca432f7acf3fe915fb7f45b5dd6e97e119 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 28 Jan 2020 17:28:48 -0500 Subject: [PATCH 10/24] codacity fix --- .../CmsMessage2.Tests.ps1 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index d17ecfc472a..35e237c741c 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -4,7 +4,9 @@ using namespace System.Security.Cryptography.X509Certificates using namespace System.Security.Cryptography -function New-CmsRecipient { param([String]$Name, [Switch]$Invalid) +function New-CmsRecipient { + [CmdletBinding(SupportsShouldProcess=$true)] + param([String]$Name, [Switch]$Invalid) $hash = [HashAlgorithmName]::SHA256 $pad = [RSASignaturePadding]::Pkcs1 @@ -27,7 +29,7 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { BeforeAll { - Write-Host "Generating certs" -ForegroundColor Gray + Write-Verbose "Generating certs" $vc1 = New-CmsRecipient "ValidCms1" $vc2 = New-CmsRecipient "ValidCms2" $ic = New-CmsRecipient "InvalidCms" -Invalid # invalid cert @@ -84,7 +86,7 @@ It "Get-CmsMessage from file" { Describe "CmsMessage cmdlets using files" -Tags "CI" { BeforeAll { - Write-Host "generating temp cert files" -ForegroundColor Gray + Write-Verbose "generating temp cert files" $vc1File = New-TemporaryFile $vc2File = New-TemporaryFile [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) @@ -117,7 +119,7 @@ It "Decrypt with multiple files" { Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { BeforeAll -Scriptblock { - Write-Host "adding temp certs to CurrentUser\My Store" -ForegroundColor Gray + Write-Verbose "adding temp certs to CurrentUser\My Store" $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) $store.Open("ReadWrite") $cert1 = [X509Certificate2]::new("$vc1File") @@ -147,7 +149,7 @@ BeforeAll -Scriptblock { # ---------------------------------------------------------------- -Write-Host "Removing temp files and certs" -ForegroundColor Gray +Write-Verbose "Removing temp files and certs" $store.Remove($cert1) $store.Remove($cert2) $store.Dispose() From a3a4b259f80e50fd504b988780e06f8ff7f0f405 Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Tue, 28 Jan 2020 20:40:31 -0500 Subject: [PATCH 11/24] removing test --- .../CmsMessage2.Tests.ps1 | 158 ------------------ 1 file changed, 158 deletions(-) delete mode 100644 test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 deleted file mode 100644 index 35e237c741c..00000000000 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ /dev/null @@ -1,158 +0,0 @@ - -# CMS Test - -using namespace System.Security.Cryptography.X509Certificates -using namespace System.Security.Cryptography - -function New-CmsRecipient { - [CmdletBinding(SupportsShouldProcess=$true)] - param([String]$Name, [Switch]$Invalid) - $hash = [HashAlgorithmName]::SHA256 - $pad = [RSASignaturePadding]::Pkcs1 - - $oids = [OidCollection]::new() - $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null - - $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false) - $ext2 = [X509EnhancedKeyUsageExtension]::new($oids,$false) - - $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) - if(!$Invalid){($ext1, $ext2).ForEach({$req.CertificateExtensions.Add($_)})} - - return $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) -} - - -# ------------------------------------------------------------- - -Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { - - -BeforeAll { - Write-Verbose "Generating certs" - $vc1 = New-CmsRecipient "ValidCms1" - $vc2 = New-CmsRecipient "ValidCms2" - $ic = New-CmsRecipient "InvalidCms" -Invalid # invalid cert - $tmpfile = New-TemporaryFile -} - -It " Encrypting with X509Cert" { - "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*' -} - -It " Encrypting with multiple X509Cert" { - $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' -} - -It " Decrypt with X509Cert" { - "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to $vc1 | Should -Be "test" -} - -It " Decrypt with multiple X509Cert" { - "test" | Protect-CmsMessage -to $vc1, $vc2 | Unprotect-CmsMessage -to $vc1, $vc2 | Should -Be "test" -} - -It " Encrypt with invalid cert" { - $e = try { "test" | Protect-CmsMessage -to $ic} catch {$_} - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' -} - -It "Encrypt with valid and invalid" { - $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic} catch {$_} - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' -} - -It "Encrypt/Decrypt from file" { - "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile - $msg = Unprotect-CmsMessage -to $vc1 -Path $tmpfile - $msg | Should -Be "test" - -} - -It "Get-CmsMessage from content" { - ("test" | Protect-CmsMessage -to $vc1 | Get-CmsMessage).Content | Should -BeLike '-----BEGIN CMS*' -} - -It "Get-CmsMessage from file" { - (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' -} - - -} - - -# ---------------------- FILES ---------------------------- - -Describe "CmsMessage cmdlets using files" -Tags "CI" { - -BeforeAll { - Write-Verbose "generating temp cert files" - $vc1File = New-TemporaryFile - $vc2File = New-TemporaryFile - [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) - [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) -} - -It "Encrypt With Single File" { - "test" | Protect-CmsMessage -to "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -Be 'test' -} - -It "Encrypt With Multiple File" { - $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" - ($msg | Unprotect-CmsMessage -to $vc1) | Should -Be "test" - ($msg | Unprotect-CmsMessage -to $vc2) | Should -Be "test" -} - -It "Decrypt with multiple files" { - - "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -Be 'test' - -} - -} - - -# ------------------ STORE ---------------------------------# - - - -Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { - -BeforeAll -Scriptblock { - Write-Verbose "adding temp certs to CurrentUser\My Store" - $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) - $store.Open("ReadWrite") - $cert1 = [X509Certificate2]::new("$vc1File") - $cert2 = [X509Certificate2]::new("$vc2File") - $store.Add($cert1) - $store.Add($cert2) - # $store.Certificates - } - - It "Encrypt/Decrypt using subject" { - "test" | Protect-CmsMessage -to $cert1.Subject | Unprotect-CmsMessage | Should -Be "test" - "test" | Protect-CmsMessage -to $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -Be "test" - } - - It "Encrypt/Decrypt using Thumbprint" { - "test" | Protect-CmsMessage -to $cert1.Thumbprint | Unprotect-CmsMessage | Should -Be "test" - "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -Be "test" - - } - - It "Encrypt/Decrypt mix" { - "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -Be "test" - } - -} - - -# ---------------------------------------------------------------- - -Write-Verbose "Removing temp files and certs" -$store.Remove($cert1) -$store.Remove($cert2) -$store.Dispose() - -Remove-Item $vc1File, $vc2File, $tmpfile - From 08b57a8a7644c1187646ed0468fac55e200651b6 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Wed, 29 Jan 2020 13:24:30 -0500 Subject: [PATCH 12/24] refactor test file --- .../CmsMessage2.Tests.ps1 | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 new file mode 100644 index 00000000000..18fdf0b9348 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -0,0 +1,126 @@ +using namespace System.Security.Cryptography.X509Certificates +using namespace System.Security.Cryptography +function New-CmsRecipient { + [CmdletBinding(SupportsShouldProcess = $true)] + param([String]$Name, [Switch]$Invalid) + $hash = [HashAlgorithmName]::SHA256 + $pad = [RSASignaturePadding]::Pkcs1 + $oids = [OidCollection]::new() + $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null + $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false) + $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false) + $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) + if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) } + return $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) +} + +Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { + + BeforeAll { + Write-Verbose "Generating certs" + $vc1 = New-CmsRecipient "ValidCms1" + $vc2 = New-CmsRecipient "ValidCms2" + $ic = New-CmsRecipient "InvalidCms" -Invalid + $tmpfile = New-TemporaryFile + } + + It " Encrypting with X509Cert" { + "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*' + } + + It " Encrypting with multiple X509Cert" { + $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' + } + + It " Decrypt with X509Cert" { + "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to $vc1 | Should -BeExactly "test" + } + + It " Decrypt with multiple X509Cert" { + "test" | Protect-CmsMessage -to $vc1, $vc2 | Unprotect-CmsMessage -to $vc1, $vc2 | Should -BeExactly "test" + } + + It " Encrypt with invalid cert" { + $e = try { "test" | Protect-CmsMessage -to $ic } catch { $_ } + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + } + + It "Encrypt with valid and invalid" { + $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic } catch { $_ } + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + } + + It "Encrypt/Decrypt from file" { + "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile + $msg = Unprotect-CmsMessage -to $vc1 -Path $tmpfile + $msg | Should -BeExactly "test" + } + + It "Get-CmsMessage from content" { + ("test" | Protect-CmsMessage -to $vc1 | Get-CmsMessage).Content | Should -BeLike '-----BEGIN CMS*' + } + + It "Get-CmsMessage from file" { + (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' + } +} + +Describe "CmsMessage cmdlets using files" -Tags "CI" { + + BeforeAll { + Write-Verbose "generating temp cert files" + $vc1File = New-TemporaryFile + $vc2File = New-TemporaryFile + [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) + [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) + } + + It "Encrypt With Single File" { + "test" | Protect-CmsMessage -to "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" + } + + It "Encrypt With Multiple File" { + $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" + ($msg | Unprotect-CmsMessage -to $vc1) | Should -BeExactly "test" + ($msg | Unprotect-CmsMessage -to $vc2) | Should -BeExactly "test" + } + + It "Decrypt with multiple files" { + "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -BeExactly "test" + } +} + +Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { + + BeforeAll -Scriptblock { + Write-Verbose "adding temp certs to CurrentUser\My Store" + $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) + $store.Open("ReadWrite") + $cert1 = [X509Certificate2]::new("$vc1File") + $cert2 = [X509Certificate2]::new("$vc2File") + $store.Add($cert1) + $store.Add($cert2) + } + + It "Encrypt/Decrypt using subject" { + "test" | Protect-CmsMessage -to $cert1.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -to $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Encrypt/Decrypt using Thumbprint" { + "test" | Protect-CmsMessage -to $cert1.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Encrypt/Decrypt mix" { + "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + AfterAll { + Write-Verbose "Removing temp files and certs" + $store.Remove($cert1) + $store.Remove($cert2) + $store.Dispose() + Remove-Item $vc1File, $vc2File, $tmpfile + } +} From 205544e655c0aeca5d82ea69cb98a934823b4e5a Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Wed, 29 Jan 2020 15:36:03 -0500 Subject: [PATCH 13/24] added wildcard for subj name --- .../security/SecuritySupport.cs | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 3fe29bcc5fe..67293623778 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1254,6 +1254,7 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err { error = null; + WildcardPattern subjectNamePattern = WildcardPattern.Get(_identifier, WildcardOptions.IgnoreCase); try { @@ -1273,10 +1274,23 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err } } + foreach(X509Certificate2 c in storeCerts) + { + if(c.Thumbprint == _identifier) + { + certificatesToProcess.Add(c); + break; + } + if(subjectNamePattern.IsMatch(c.Subject)) + { + certificatesToProcess.Add(c); + } + } + // Find is case insensitive - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier.Trim(), false)); - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, _identifier.Trim(), false)); - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier.Trim(), false)); + //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier.Trim(), false)); + //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, _identifier.Trim(), false)); + //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier.Trim(), false)); ProcessResolvedCertificates(purpose, certificatesToProcess, out error); } From 8705eef85ad37cd82d5a0ee7c49fc7a7df3525c4 Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Fri, 31 Jan 2020 23:24:30 -0500 Subject: [PATCH 14/24] updated test --- .../security/SecuritySupport.cs | 35 ++++++------ .../CmsMessage2.Tests.ps1 | 57 +++++++++++++++---- 2 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 67293623778..da0e9fcdfeb 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -620,21 +620,21 @@ internal static bool CertIsGoodForEncryption(X509Certificate2 c) private static bool CertHasOid(X509Certificate2 c, string oid) { - foreach(X509Extension extension in c.Extensions) + foreach (X509Extension extension in c.Extensions) { X509EnhancedKeyUsageExtension ext = extension as X509EnhancedKeyUsageExtension; if (ext != null) { foreach (Oid ekuOid in ext.EnhancedKeyUsages) { - if(ekuOid.Value == oid) - { - return true; + if (ekuOid.Value == oid) + { + return true; } } break; - } - } + } + } return false; } @@ -1114,7 +1114,7 @@ public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out Er { return; } - } + } // Generate an error if no cert was found (and this is an encryption attempt). // If it is only decryption, then the system will always look in the 'My' store anyways, so @@ -1274,23 +1274,20 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err } } - foreach(X509Certificate2 c in storeCerts) + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, false)); + + if (certificatesToProcess.Count == 0) { - if(c.Thumbprint == _identifier) - { - certificatesToProcess.Add(c); - break; - } - if(subjectNamePattern.IsMatch(c.Subject)) + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier, false)); + foreach (X509Certificate2 c in storeCerts) { - certificatesToProcess.Add(c); + if (subjectNamePattern.IsMatch(c.Subject)) + { + certificatesToProcess.Add(c); + } } } - // Find is case insensitive - //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier.Trim(), false)); - //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, _identifier.Trim(), false)); - //certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier.Trim(), false)); ProcessResolvedCertificates(purpose, certificatesToProcess, out error); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 18fdf0b9348..ddb29803ea2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -22,12 +22,39 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { $vc2 = New-CmsRecipient "ValidCms2" $ic = New-CmsRecipient "InvalidCms" -Invalid $tmpfile = New-TemporaryFile + $certContent = " + -----BEGIN CERTIFICATE----- + MIIDXTCCAkWgAwIBAgIQRTsRwsx0LZBHrx9z5Dag2zANBgkqhkiG9w0BAQUFADAh + MR8wHQYDVQQDDBZNeURhdGFFbmNpcGhlcm1lbnRDZXJ0MCAXDTE0MDcyNTIyMjkz + OVoYDzMwMTQwNzI1MjIzOTM5WjAhMR8wHQYDVQQDDBZNeURhdGFFbmNpcGhlcm1l + bnRDZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx3SuShUvnRqn + tYOIouJdP3wPZ5rtDi2KYPurpngGNZjM0EGDTrnhmEAI8DL4Kp6n/zz1mYVoX73+ + 6uCpZX/13VDXg1neebJ261XpBX6FzxtclIQr8ywdUtrEgCnUAhgqgvO1Wwm4ogNR + tWGCGkmlnqyaoV1j/V4KSn4WvKqSUIOZm0umGCTtNAJ6VtdpYO+uxxnRAapPUCY+ + qQ7DFzTUECIo1lMlBcuMiXj6NSFr4/D7ltkZ27jCdsZmzI7ZvRnDlfSYTPQnAO/E + 0uYn9uyKY/xfngWkUX/pe+j+10Lm1ypbASrj2Ezgf0KeZRXBwqKUOLhKheEmBJ18 + rLV27qwHeQIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIEMDAUBgNVHSUEDTALBgkr + BgEEAYI3UAEwRAYJKoZIhvcNAQkPBDcwNTAOBggqhkiG9w0DAgICAIAwDgYIKoZI + hvcNAwQCAgCAMAcGBSsOAwIHMAoGCCqGSIb3DQMHMB0GA1UdDgQWBBRIyIzwInLJ + 3B+FajVUFMACf1hrxjANBgkqhkiG9w0BAQUFAAOCAQEAfFt4rmUmWfCbbwi2mCrZ + Osq0lfVNUiZ+iLlEKga4VAI3sJZRtErnVM70eXUt7XpRaOdIfxjuXFpsgc37KyLi + ByCORLuRC0itZVs3aba48opfMDXivxBy0ngqCPPLQsyaN9K7WnpvYV1QxiudYwwU + 8U5rFmzlwNLvc3XiyoGWaVZluk2DIJawQ5QYAU9/NMBBCbPHjTG7k0l4cpcEC+Ex + od3RlO6/MOYuK2WB4VTxKsV80EdA3ljlu7Td8P4movnrbB4rG4wpCpk05eREkg/5 + Y54Ilo9m5OSAWtdx4yfS779eebLgUs3P+dk6EKwovXMokVveZA8cenIp3QkqSpeT + cQ== + -----END CERTIFICATE----- + " } It " Encrypting with X509Cert" { "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*' } + It " Encrypting with base64 string" { + "test" | Protect-CmsMessage -to $certContent | Should -BeLike '-----BEGIN CMS*' + } + It " Encrypting with multiple X509Cert" { $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' } @@ -42,12 +69,12 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { It " Encrypt with invalid cert" { $e = try { "test" | Protect-CmsMessage -to $ic } catch { $_ } - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' } It "Encrypt with valid and invalid" { $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic } catch { $_ } - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' } It "Encrypt/Decrypt from file" { @@ -66,13 +93,16 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { } Describe "CmsMessage cmdlets using files" -Tags "CI" { - + BeforeAll { - Write-Verbose "generating temp cert files" + Write-Verbose "generating temp cert files" $vc1File = New-TemporaryFile $vc2File = New-TemporaryFile + $tempDir = New-Item -ItemType Directory -Path (Join-Path $vc1File.Directory.FullName "psCertTempDir") -Force + $vc3File = New-Item -Name "vc1.cert" -Path $tempDir [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) + [System.IO.File]::WriteAllBytes("$vc3File", $vc1.Export("pfx")) } It "Encrypt With Single File" { @@ -80,9 +110,13 @@ Describe "CmsMessage cmdlets using files" -Tags "CI" { } It "Encrypt With Multiple File" { - $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" - ($msg | Unprotect-CmsMessage -to $vc1) | Should -BeExactly "test" - ($msg | Unprotect-CmsMessage -to $vc2) | Should -BeExactly "test" + $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" + ($msg | Unprotect-CmsMessage -to $vc1) | Should -BeExactly "test" + ($msg | Unprotect-CmsMessage -to $vc2) | Should -BeExactly "test" + } + + It "Encrypt/Decrypt with Directory" { + "test" | Protect-CmsMessage -to "$tempDir" | Unprotect-CmsMessage -To $tempDir | Should -BeExactly "test" } It "Decrypt with multiple files" { @@ -91,9 +125,9 @@ Describe "CmsMessage cmdlets using files" -Tags "CI" { } Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { - - BeforeAll -Scriptblock { - Write-Verbose "adding temp certs to CurrentUser\My Store" + + BeforeAll -Scriptblock { + Write-Verbose "adding temp certs to CurrentUser\My Store" $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) $store.Open("ReadWrite") $cert1 = [X509Certificate2]::new("$vc1File") @@ -117,10 +151,11 @@ Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { } AfterAll { - Write-Verbose "Removing temp files and certs" + Write-Verbose "Removing temp files and certs" $store.Remove($cert1) $store.Remove($cert2) $store.Dispose() Remove-Item $vc1File, $vc2File, $tmpfile + Remove-Item -Recurse $tempDir -Force } } From ccd717f741dc387a00a7241979bbe344e0e237c5 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Sat, 1 Feb 2020 00:02:20 -0500 Subject: [PATCH 15/24] sometest fix --- .../Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index ddb29803ea2..ce4f559b08d 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -116,7 +116,7 @@ Describe "CmsMessage cmdlets using files" -Tags "CI" { } It "Encrypt/Decrypt with Directory" { - "test" | Protect-CmsMessage -to "$tempDir" | Unprotect-CmsMessage -To $tempDir | Should -BeExactly "test" + "test" | Protect-CmsMessage -to "$tempDir" | Unprotect-CmsMessage -To "$tempDir" | Should -BeExactly "test" } It "Decrypt with multiple files" { From 7d9b179a7c908e464cf5e46434c082884a267f83 Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Mon, 3 Feb 2020 21:57:02 -0500 Subject: [PATCH 16/24] mac test update --- .../CmsMessage2.Tests.ps1 | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index ce4f559b08d..5d1702ab5b2 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -1,8 +1,10 @@ -using namespace System.Security.Cryptography.X509Certificates +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. +using namespace System.Security.Cryptography.X509Certificates using namespace System.Security.Cryptography function New-CmsRecipient { [CmdletBinding(SupportsShouldProcess = $true)] - param([String]$Name, [Switch]$Invalid) + param([String]$Name, [Switch]$Invalid, [String]$OutPfxFile) $hash = [HashAlgorithmName]::SHA256 $pad = [RSASignaturePadding]::Pkcs1 $oids = [OidCollection]::new() @@ -11,7 +13,13 @@ function New-CmsRecipient { $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false) $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) } - return $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) + $certTmp = $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) + [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" + $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) + if ($OutPfxFile) { + [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) + } + return $cert } Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { @@ -120,20 +128,26 @@ Describe "CmsMessage cmdlets using files" -Tags "CI" { } It "Decrypt with multiple files" { - "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -BeExactly "test" + "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -BeExactly "test" } } Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { BeforeAll -Scriptblock { - Write-Verbose "adding temp certs to CurrentUser\My Store" + Write-Verbose "adding temp certs to CurrentUser\My Store (on Mac those were added while generating vc1/vc2)" $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) $store.Open("ReadWrite") - $cert1 = [X509Certificate2]::new("$vc1File") - $cert2 = [X509Certificate2]::new("$vc2File") - $store.Add($cert1) - $store.Add($cert2) + if (!$IsMacOS) { + $cert1 = [X509Certificate2]::new("$vc1File") + $cert2 = [X509Certificate2]::new("$vc2File") + $store.Add($cert1) + $store.Add($cert2) + } + else { + $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false) + $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false) + } } It "Encrypt/Decrypt using subject" { @@ -154,6 +168,9 @@ Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { Write-Verbose "Removing temp files and certs" $store.Remove($cert1) $store.Remove($cert2) + if($IsMacOS){ + $store.Remove($ic) + } $store.Dispose() Remove-Item $vc1File, $vc2File, $tmpfile Remove-Item -Recurse $tempDir -Force From 9a36db198ad89a34f4972d0baf639ddf91f36409 Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Mon, 3 Feb 2020 22:48:34 -0500 Subject: [PATCH 17/24] test - certgen fix --- .../Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 5d1702ab5b2..a37fc28cd54 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -14,6 +14,7 @@ function New-CmsRecipient { $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) } $certTmp = $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) + $certBytes = $certTmp.Export([X509ContentType]::Pfx, "tmp") [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) if ($OutPfxFile) { From 2c0ac81642144f952cda39cc2e354351fccc862c Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Mon, 3 Feb 2020 22:55:21 -0500 Subject: [PATCH 18/24] test - certgen fix2 --- .../Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index a37fc28cd54..7104865075f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -146,8 +146,8 @@ Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { $store.Add($cert2) } else { - $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false) - $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false) + $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false)[0] + $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false)[0] } } From 514a9e81f6b908a6af3e5df892bae8c00d4a085c Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Mon, 3 Feb 2020 23:52:27 -0500 Subject: [PATCH 19/24] add findBySubjectName search + codacity fix --- .../security/SecuritySupport.cs | 12 +++--------- .../CmsMessage2.Tests.ps1 | 1 + 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index da0e9fcdfeb..45702fdddd2 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1277,15 +1277,9 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, false)); if (certificatesToProcess.Count == 0) - { - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectDistinguishedName, _identifier, false)); - foreach (X509Certificate2 c in storeCerts) - { - if (subjectNamePattern.IsMatch(c.Subject)) - { - certificatesToProcess.Add(c); - } - } + { // FindBySubjectName is case insensitive and acts like "contains" + String subjectName = _identifier.Trim().ToUpper().TrimStart('C','N','='); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, subjectName, false)); } ProcessResolvedCertificates(purpose, certificatesToProcess, out error); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 7104865075f..a145309911b 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -4,6 +4,7 @@ using namespace System.Security.Cryptography.X509Certificates using namespace System.Security.Cryptography function New-CmsRecipient { [CmdletBinding(SupportsShouldProcess = $true)] + [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] param([String]$Name, [Switch]$Invalid, [String]$OutPfxFile) $hash = [HashAlgorithmName]::SHA256 $pad = [RSASignaturePadding]::Pkcs1 From f00595fec17525061255cae46fb0d684e6ef827c Mon Sep 17 00:00:00 2001 From: mikeTWC1984 Date: Tue, 4 Feb 2020 00:15:30 -0500 Subject: [PATCH 20/24] codacity fix2 --- .../security/SecuritySupport.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 45702fdddd2..203edd0b2eb 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1252,10 +1252,8 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord error) { - error = null; - WildcardPattern subjectNamePattern = WildcardPattern.Get(_identifier, WildcardOptions.IgnoreCase); - + try { X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); @@ -1275,10 +1273,10 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err } certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, false)); - + if (certificatesToProcess.Count == 0) { // FindBySubjectName is case insensitive and acts like "contains" - String subjectName = _identifier.Trim().ToUpper().TrimStart('C','N','='); + String subjectName = _identifier.Trim().ToUpperInvariant().TrimStart('C', 'N', '='); certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, subjectName, false)); } From 9f3baa05f9d289c48309e68f3ac15e7a4717706a Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 4 Feb 2020 11:59:49 -0500 Subject: [PATCH 21/24] code review refactor1 --- .../security/SecuritySupport.cs | 43 ++++++++--------- .../CmsMessage2.Tests.ps1 | 46 +++++++++---------- 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 203edd0b2eb..49fd3e17cc9 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -595,7 +595,7 @@ internal static void CheckIfFileExists(string filePath) /// True on success, false otherwise. internal static bool CertIsGoodForSigning(X509Certificate2 c) { - if (!CertHasPrivatekey(c)) // why not just c.HasPrivateKey? + if (!c.HasPrivateKey) { return false; } @@ -655,16 +655,6 @@ private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsa return false; } - /// - /// Check if the specified cert has a private key in it. - /// - /// Certificate object. - /// True on success, false otherwise. - internal static bool CertHasPrivatekey(X509Certificate2 cert) - { - return cert.HasPrivateKey; - } - /// /// Convert an int to a DWORD. /// @@ -1084,8 +1074,10 @@ public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out Er // Process the certificate if that was supplied exactly if (_pendingCertificate != null) { - ProcessResolvedCertificates(purpose, - new X509Certificate2Collection(_pendingCertificate), out error); + ProcessResolvedCertificates( + purpose, + new X509Certificate2Collection(_pendingCertificate), + out error); if ((error != null) || (Certificates.Count != 0)) { return; @@ -1154,7 +1146,7 @@ private void ResolveFromBase64Encoding(ResolutionPurpose purpose, out ErrorRecor return; } - X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); + var certificatesToProcess = new X509Certificate2Collection(); try { X509Certificate2 newCertificate = new X509Certificate2(messageBytes); @@ -1228,7 +1220,7 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos resolvedPaths.Remove(path); } - X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); + var certificatesToProcess = new X509Certificate2Collection(); foreach (string path in resolvedPaths) { X509Certificate2 certificate = null; @@ -1253,31 +1245,33 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord error) { error = null; - + try { - X509Certificate2Collection certificatesToProcess = new X509Certificate2Collection(); + var certificatesToProcess = new X509Certificate2Collection(); + bool validOnly = false; - using (X509Store storeCU = new X509Store("my", StoreLocation.CurrentUser)) + using (var storeCU = new X509Store("my", StoreLocation.CurrentUser)) { storeCU.Open(OpenFlags.ReadOnly); X509Certificate2Collection storeCerts = storeCU.Certificates; if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - using (X509Store storeLM = new X509Store("my", StoreLocation.LocalMachine)) + using (var storeLM = new X509Store("my", StoreLocation.LocalMachine)) { storeLM.Open(OpenFlags.ReadOnly); storeCerts.AddRange(storeLM.Certificates); } } - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, false)); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, validOnly)); if (certificatesToProcess.Count == 0) - { // FindBySubjectName is case insensitive and acts like "contains" - String subjectName = _identifier.Trim().ToUpperInvariant().TrimStart('C', 'N', '='); - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, subjectName, false)); + { + // FindBySubjectName is case insensitive and acts like "contains" + string subjectName = _identifier.Trim().ToUpperInvariant().TrimStart('C', 'N', '='); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, subjectName, validOnly)); } ProcessResolvedCertificates(purpose, certificatesToProcess, out error); @@ -1344,13 +1338,14 @@ private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certific // may be encrypted to the wrong person on accident. if (Certificates.Count > 0) { + string parameter = "To"; error = new ErrorRecord( new ArgumentException( string.Format( CultureInfo.InvariantCulture, SecuritySupportStrings.IdentifierMustReferenceSingleCertificate, _identifier, - "To")), + parameter)), "IdentifierMustReferenceSingleCertificate", ErrorCategory.LimitsExceeded, certificatesToProcess); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index a145309911b..47db9570314 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -1,27 +1,29 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the MIT License. + using namespace System.Security.Cryptography.X509Certificates using namespace System.Security.Cryptography + function New-CmsRecipient { - [CmdletBinding(SupportsShouldProcess = $true)] - [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] - param([String]$Name, [Switch]$Invalid, [String]$OutPfxFile) - $hash = [HashAlgorithmName]::SHA256 - $pad = [RSASignaturePadding]::Pkcs1 - $oids = [OidCollection]::new() - $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null - $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false) - $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false) - $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) - if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) } - $certTmp = $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) - $certBytes = $certTmp.Export([X509ContentType]::Pfx, "tmp") - [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" - $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) - if ($OutPfxFile) { - [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) - } - return $cert + [CmdletBinding(SupportsShouldProcess = $true)] + [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate2])] + param([String]$Name, [Switch]$Invalid, [String]$OutPfxFile) + $hash = [HashAlgorithmName]::SHA256 + $pad = [RSASignaturePadding]::Pkcs1 + $oids = [OidCollection]::new() + $oids.Add("1.3.6.1.4.1.311.80.1") | Out-Null + $ext1 = [X509KeyUsageExtension]::new([X509KeyUsageFlags]::DataEncipherment, $false) + $ext2 = [X509EnhancedKeyUsageExtension]::new($oids, $false) + $req = ([CertificateRequest]::new("CN=$Name", ([RSA]::Create(2048)), $hash, $pad)) + if (!$Invalid) { ($ext1, $ext2).ForEach( { $req.CertificateExtensions.Add($_) }) } + $certTmp = $req.CreateSelfSigned([datetime]::Now.AddDays(-1), [datetime]::Now.AddDays(365)) + $certBytes = $certTmp.Export([X509ContentType]::Pfx, "tmp") + [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" + $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) + if ($OutPfxFile) { + [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) + } + return $cert } Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { @@ -78,13 +80,11 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { } It " Encrypt with invalid cert" { - $e = try { "test" | Protect-CmsMessage -to $ic } catch { $_ } - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + {"test" | Protect-CmsMessage -to $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' } It "Encrypt with valid and invalid" { - $e = try { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic } catch { $_ } - $e.FullyQualifiedErrorId | Should -BeLike '*CertificateCannotBeUsedForEncryption*' + { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' } It "Encrypt/Decrypt from file" { From 3b6ad33d6b3bed0183dabe94a31a0f0312620fdb Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Tue, 4 Feb 2020 15:54:41 -0500 Subject: [PATCH 22/24] review refact2 + go back to foreach --- .../security/SecuritySupport.cs | 26 ++- .../CmsMessage2.Tests.ps1 | 219 +++++++++--------- 2 files changed, 123 insertions(+), 122 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 49fd3e17cc9..6a7442e6dae 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -620,10 +620,9 @@ internal static bool CertIsGoodForEncryption(X509Certificate2 c) private static bool CertHasOid(X509Certificate2 c, string oid) { - foreach (X509Extension extension in c.Extensions) + foreach (var extension in c.Extensions) { - X509EnhancedKeyUsageExtension ext = extension as X509EnhancedKeyUsageExtension; - if (ext != null) + if (extension is X509EnhancedKeyUsageExtension ext) { foreach (Oid ekuOid in ext.EnhancedKeyUsages) { @@ -1245,11 +1244,11 @@ private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpos private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord error) { error = null; - + WildcardPattern subjectNamePattern = WildcardPattern.Get(_identifier, WildcardOptions.IgnoreCase); + try { var certificatesToProcess = new X509Certificate2Collection(); - bool validOnly = false; using (var storeCU = new X509Store("my", StoreLocation.CurrentUser)) { @@ -1265,13 +1264,17 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err } } - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, validOnly)); + certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindByThumbprint, _identifier, validOnly: false)); if (certificatesToProcess.Count == 0) - { - // FindBySubjectName is case insensitive and acts like "contains" - string subjectName = _identifier.Trim().ToUpperInvariant().TrimStart('C', 'N', '='); - certificatesToProcess.AddRange(storeCerts.Find(X509FindType.FindBySubjectName, subjectName, validOnly)); + { + foreach (var cert in storeCerts) + { + if (subjectNamePattern.IsMatch(cert.Subject)) + { + certificatesToProcess.Add(cert); + } + } } ProcessResolvedCertificates(purpose, certificatesToProcess, out error); @@ -1338,14 +1341,13 @@ private void ProcessResolvedCertificates(ResolutionPurpose purpose, X509Certific // may be encrypted to the wrong person on accident. if (Certificates.Count > 0) { - string parameter = "To"; error = new ErrorRecord( new ArgumentException( string.Format( CultureInfo.InvariantCulture, SecuritySupportStrings.IdentifierMustReferenceSingleCertificate, _identifier, - parameter)), + arg1: "To")), "IdentifierMustReferenceSingleCertificate", ErrorCategory.LimitsExceeded, certificatesToProcess); diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 47db9570314..7b99b1a1842 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -21,20 +21,20 @@ function New-CmsRecipient { [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) if ($OutPfxFile) { - [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) + [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) } return $cert } Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { - BeforeAll { - Write-Verbose "Generating certs" - $vc1 = New-CmsRecipient "ValidCms1" - $vc2 = New-CmsRecipient "ValidCms2" - $ic = New-CmsRecipient "InvalidCms" -Invalid - $tmpfile = New-TemporaryFile - $certContent = " + BeforeAll { + Write-Verbose "Generating certs" + $vc1 = New-CmsRecipient "ValidCms1" + $vc2 = New-CmsRecipient "ValidCms2" + $ic = New-CmsRecipient "InvalidCms" -Invalid + $tmpfile = New-TemporaryFile + $certContent = " -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIQRTsRwsx0LZBHrx9z5Dag2zANBgkqhkiG9w0BAQUFADAh MR8wHQYDVQQDDBZNeURhdGFFbmNpcGhlcm1lbnRDZXJ0MCAXDTE0MDcyNTIyMjkz @@ -57,124 +57,123 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { cQ== -----END CERTIFICATE----- " - } + } - It " Encrypting with X509Cert" { - "test" | Protect-CmsMessage -to $vc1 | Should -BeLike '-----BEGIN CMS*' - } + It " Encrypting with X509Cert" { + "test" | Protect-CmsMessage -To $vc1 | Should -BeLike '-----BEGIN CMS*' + } - It " Encrypting with base64 string" { - "test" | Protect-CmsMessage -to $certContent | Should -BeLike '-----BEGIN CMS*' - } + It " Encrypting with base64 string" { + "test" | Protect-CmsMessage -To $certContent | Should -BeLike '-----BEGIN CMS*' + } - It " Encrypting with multiple X509Cert" { - $msg = "test" | Protect-CmsMessage -to $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' - } + It " Encrypting with multiple X509Cert" { + $msg = "test" | Protect-CmsMessage -To $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' + } - It " Decrypt with X509Cert" { - "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to $vc1 | Should -BeExactly "test" - } + It " Decrypt with X509Cert" { + "test" | Protect-CmsMessage -To $vc1 | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" + } - It " Decrypt with multiple X509Cert" { - "test" | Protect-CmsMessage -to $vc1, $vc2 | Unprotect-CmsMessage -to $vc1, $vc2 | Should -BeExactly "test" - } + It " Decrypt with multiple X509Cert" { + "test" | Protect-CmsMessage -To $vc1, $vc2 | Unprotect-CmsMessage -To $vc1, $vc2 | Should -BeExactly "test" + } - It " Encrypt with invalid cert" { - {"test" | Protect-CmsMessage -to $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' - } + It " Encrypt with invalid cert" { + { "test" | Protect-CmsMessage -To $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' + } - It "Encrypt with valid and invalid" { - { "test" | Protect-CmsMessage -to $vc1, $vc2, $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' - } + It "Encrypt with valid and invalid" { + { "test" | Protect-CmsMessage -To $vc1, $vc2, $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' + } - It "Encrypt/Decrypt from file" { - "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile - $msg = Unprotect-CmsMessage -to $vc1 -Path $tmpfile - $msg | Should -BeExactly "test" - } + It "Encrypt/Decrypt from file" { + "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile + $msg = Unprotect-CmsMessage -To $vc1 -Path $tmpfile + $msg | Should -BeExactly "test" + } - It "Get-CmsMessage from content" { - ("test" | Protect-CmsMessage -to $vc1 | Get-CmsMessage).Content | Should -BeLike '-----BEGIN CMS*' - } + It "Get-CmsMessage from content" { + ("test" | Protect-CmsMessage -To $vc1 | Get-CmsMessage).Content | Should -BeLike '-----BEGIN CMS*' + } - It "Get-CmsMessage from file" { - (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' - } + It "Get-CmsMessage from file" { + (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' + } } Describe "CmsMessage cmdlets using files" -Tags "CI" { - BeforeAll { - Write-Verbose "generating temp cert files" - $vc1File = New-TemporaryFile - $vc2File = New-TemporaryFile - $tempDir = New-Item -ItemType Directory -Path (Join-Path $vc1File.Directory.FullName "psCertTempDir") -Force - $vc3File = New-Item -Name "vc1.cert" -Path $tempDir - [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) - [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) - [System.IO.File]::WriteAllBytes("$vc3File", $vc1.Export("pfx")) - } - - It "Encrypt With Single File" { - "test" | Protect-CmsMessage -to "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" - } - - It "Encrypt With Multiple File" { - $msg = "test" | Protect-CmsMessage -to "$vc1File", "$vc2File" - ($msg | Unprotect-CmsMessage -to $vc1) | Should -BeExactly "test" - ($msg | Unprotect-CmsMessage -to $vc2) | Should -BeExactly "test" - } - - It "Encrypt/Decrypt with Directory" { - "test" | Protect-CmsMessage -to "$tempDir" | Unprotect-CmsMessage -To "$tempDir" | Should -BeExactly "test" - } - - It "Decrypt with multiple files" { - "test" | Protect-CmsMessage -to $vc1 | Unprotect-CmsMessage -to "$vc1File", "$vc2File" | Should -BeExactly "test" - } + BeforeAll { + Write-Verbose "generating temp cert files" + $vc1File = New-TemporaryFile + $vc2File = New-TemporaryFile + $tempDir = New-Item -ItemType Directory -Path (Join-Path $vc1File.Directory.FullName "psCertTempDir") -Force + $vc3File = New-Item -Name "vc1.cert" -Path $tempDir + [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) + [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) + [System.IO.File]::WriteAllBytes("$vc3File", $vc1.Export("pfx")) + } + + It "Encrypt With Single File" { + "test" | Protect-CmsMessage -To "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" + } + + It "Encrypt With Multiple File" { + $msg = "test" | Protect-CmsMessage -To "$vc1File", "$vc2File" + ($msg | Unprotect-CmsMessage -To $vc1) | Should -BeExactly "test" + ($msg | Unprotect-CmsMessage -To $vc2) | Should -BeExactly "test" + } + + It "Encrypt/Decrypt with Directory" { + "test" | Protect-CmsMessage -To "$tempDir" | Unprotect-CmsMessage -To "$tempDir" | Should -BeExactly "test" + } + + It "Decrypt with multiple files" { + "test" | Protect-CmsMessage -To $vc1 | Unprotect-CmsMessage -To "$vc1File", "$vc2File" | Should -BeExactly "test" + } } Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { - BeforeAll -Scriptblock { - Write-Verbose "adding temp certs to CurrentUser\My Store (on Mac those were added while generating vc1/vc2)" - $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) - $store.Open("ReadWrite") - if (!$IsMacOS) { - $cert1 = [X509Certificate2]::new("$vc1File") - $cert2 = [X509Certificate2]::new("$vc2File") - $store.Add($cert1) - $store.Add($cert2) - } - else { - $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false)[0] - $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false)[0] - } - } - - It "Encrypt/Decrypt using subject" { - "test" | Protect-CmsMessage -to $cert1.Subject | Unprotect-CmsMessage | Should -BeExactly "test" - "test" | Protect-CmsMessage -to $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" - } - - It "Encrypt/Decrypt using Thumbprint" { - "test" | Protect-CmsMessage -to $cert1.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" - "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" - } - - It "Encrypt/Decrypt mix" { - "test" | Protect-CmsMessage -to $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" - } - - AfterAll { - Write-Verbose "Removing temp files and certs" - $store.Remove($cert1) - $store.Remove($cert2) - if($IsMacOS){ - $store.Remove($ic) - } - $store.Dispose() - Remove-Item $vc1File, $vc2File, $tmpfile - Remove-Item -Recurse $tempDir -Force - } + BeforeAll -Scriptblock { + Write-Verbose "adding temp certs to CurrentUser\My Store (on Mac those were added while generating vc1/vc2)" + $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) + $store.Open("ReadWrite") + if (!$IsMacOS) { + $cert1 = [X509Certificate2]::new("$vc1File") + $cert2 = [X509Certificate2]::new("$vc2File") + $store.Add($cert1) + $store.Add($cert2) + } else { + $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false)[0] + $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false)[0] + } + } + + It "Encrypt/Decrypt using subject" { + "test" | Protect-CmsMessage -To $cert1.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Encrypt/Decrypt using Thumbprint" { + "test" | Protect-CmsMessage -To $cert1.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Encrypt/Decrypt mix" { + "test" | Protect-CmsMessage -To $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + AfterAll { + Write-Verbose "Removing temp files and certs" + $store.Remove($cert1) + $store.Remove($cert2) + if ($IsMacOS) { + $store.Remove($ic) + } + $store.Dispose() + Remove-Item $vc1File, $vc2File, $tmpfile + Remove-Item -Recurse $tempDir -Force + } } From 0c69438bcac9565f80663dd0335cc7faf599b465 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Wed, 5 Feb 2020 15:13:40 -0500 Subject: [PATCH 23/24] test refactor + added simple name lookup --- .../security/SecuritySupport.cs | 35 ++-- .../CmsMessage2.Tests.ps1 | 154 +++++++++--------- 2 files changed, 100 insertions(+), 89 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index 87b434b4735..eb4eecb6d2f 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -142,15 +142,20 @@ internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPol switch (policy) { case ExecutionPolicy.Restricted: - executionPolicy = "Restricted"; break; + executionPolicy = "Restricted"; + break; case ExecutionPolicy.AllSigned: - executionPolicy = "AllSigned"; break; + executionPolicy = "AllSigned"; + break; case ExecutionPolicy.RemoteSigned: - executionPolicy = "RemoteSigned"; break; + executionPolicy = "RemoteSigned"; + break; case ExecutionPolicy.Unrestricted: - executionPolicy = "Unrestricted"; break; + executionPolicy = "Unrestricted"; + break; case ExecutionPolicy.Bypass: - executionPolicy = "Bypass"; break; + executionPolicy = "Bypass"; + break; } // Set the execution policy @@ -359,12 +364,18 @@ internal static string GetExecutionPolicy(ExecutionPolicy policy) { switch (policy) { - case ExecutionPolicy.Bypass: return "Bypass"; - case ExecutionPolicy.Unrestricted: return "Unrestricted"; - case ExecutionPolicy.RemoteSigned: return "RemoteSigned"; - case ExecutionPolicy.AllSigned: return "AllSigned"; - case ExecutionPolicy.Restricted: return "Restricted"; - default: return "Restricted"; + case ExecutionPolicy.Bypass: + return "Bypass"; + case ExecutionPolicy.Unrestricted: + return "Unrestricted"; + case ExecutionPolicy.RemoteSigned: + return "RemoteSigned"; + case ExecutionPolicy.AllSigned: + return "AllSigned"; + case ExecutionPolicy.Restricted: + return "Restricted"; + default: + return "Restricted"; } } @@ -1269,7 +1280,7 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err { foreach (var cert in storeCerts) { - if (subjectNamePattern.IsMatch(cert.Subject)) + if (subjectNamePattern.IsMatch(cert.Subject) || subjectNamePattern.IsMatch(cert.GetNameInfo(X509NameType.SimpleName, forIssuer: false))) { certificatesToProcess.Add(cert); } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 7b99b1a1842..44e91289115 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -21,7 +21,8 @@ function New-CmsRecipient { [X509KeyStorageFlags[]]$flags = "PersistKeySet", "Exportable" $cert = [X509Certificate2]::new($certBytes, "tmp", $flags) if ($OutPfxFile) { - [System.IO.File]::WriteAllBytes($OutPfxFile, $cert.Export([X509ContentType]::Pfx)) + $outfile = New-Item $OutPfxFile -Force + [System.IO.File]::WriteAllBytes($outfile.FullName, $cert.Export([X509ContentType]::Pfx)) } return $cert } @@ -29,11 +30,26 @@ function New-CmsRecipient { Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { BeforeAll { - Write-Verbose "Generating certs" - $vc1 = New-CmsRecipient "ValidCms1" - $vc2 = New-CmsRecipient "ValidCms2" - $ic = New-CmsRecipient "InvalidCms" -Invalid - $tmpfile = New-TemporaryFile + Setup -Dir "certDir" + Setup -File "vc1.pfx" + Setup -File "vc2.pfx" + Setup -File "certDir/vc3.pfx" + Setup -File "message.txt" -Content "test" + $file1 = "TestDrive:\vc1.pfx" + $file2 = "TestDrive:\vc2.pfx" + $messageFile = "TestDrive:\message.txt" + $cipherFile = "TestDrive:\cipher.txt" + $vc1 = New-CmsRecipient "ValidCms1" -OutPfxFile $file1 + $vc2 = New-CmsRecipient "ValidCms2" -OutPfxFile $file2 + $vc3 = New-CmsRecipient "ValidCms22" -OutPfxFile "TestDrive:\certDir\vc3.pfx" + $ic = New-CmsRecipient "InvalidCms" -Invalid -OutPfxFile "TestDrive:\ic.pfx" + $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) + $store.Open("ReadWrite") + if (!$IsMacOS) { + $store.Add($vc1) + $store.Add($vc2) + $store.Add($vc3) + } $certContent = " -----BEGIN CERTIFICATE----- MIIDXTCCAkWgAwIBAgIQRTsRwsx0LZBHrx9z5Dag2zANBgkqhkiG9w0BAQUFADAh @@ -59,27 +75,63 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { " } - It " Encrypting with X509Cert" { + It "Cert Store: Encrypt/Decrypt using Subject" { + "test" | Protect-CmsMessage -To $vc1.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $vc1.Subject, $vc2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Cert Store: Subject with wildcard (returns single cert)" { + "test" | Protect-CmsMessage -To "*dCms1" | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Cert Store: Subject with wrong wildcard (returns multiple certs)" { + { "test" | Protect-CmsMessage -To "*ValidCms*" -ErrorAction Stop } | Should -Throw -ErrorId 'IdentifierMustReferenceSingleCertificate' + } + + It "Cert Store: Encrypt/Decrypt using Thumbprint" { + "test" | Protect-CmsMessage -To $vc1.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $vc1.Thumbprint, $vc2.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Cert Store: Encrypt/Decrypt subject and thumbprint" { + "test" | Protect-CmsMessage -To $vc1.Thumbprint, $vc2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + } + + It "Cert Store: removing test certificates" { + $store.Remove($vc1) + $store.Remove($vc2) + $store.Remove($vc3) + if ($IsMacOS) { + $store.Remove($ic) + } + + $store.Certificates.Find("FindByThumbprint", $vc1.Thumbprint, $false).Count | Should -BeExactly 0 + $store.Certificates.Find("FindByThumbprint", $vc2.Thumbprint, $false).Count | Should -BeExactly 0 + $store.Certificates.Find("FindByThumbprint", $vc3.Thumbprint, $false).Count | Should -BeExactly 0 + $store.Certificates.Find("FindByThumbprint", $ic.Thumbprint, $false).Count | Should -BeExactly 0 + } + + It "Encrypting with X509Cert" { "test" | Protect-CmsMessage -To $vc1 | Should -BeLike '-----BEGIN CMS*' } - It " Encrypting with base64 string" { + It "Encrypting with base64 string" { "test" | Protect-CmsMessage -To $certContent | Should -BeLike '-----BEGIN CMS*' } - It " Encrypting with multiple X509Cert" { - $msg = "test" | Protect-CmsMessage -To $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' + It "Encrypting with multiple X509Cert" { + "test" | Protect-CmsMessage -To $vc1, $vc2 | Should -BeLike '-----BEGIN CMS*' } - It " Decrypt with X509Cert" { + It "Decrypt with X509Cert" { "test" | Protect-CmsMessage -To $vc1 | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" } - It " Decrypt with multiple X509Cert" { + It "Decrypt with multiple X509Cert" { "test" | Protect-CmsMessage -To $vc1, $vc2 | Unprotect-CmsMessage -To $vc1, $vc2 | Should -BeExactly "test" } - It " Encrypt with invalid cert" { + It "Encrypt with invalid cert" { { "test" | Protect-CmsMessage -To $ic -ErrorAction Stop } | Should -Throw -ErrorId 'CertificateCannotBeUsedForEncryption' } @@ -88,8 +140,8 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { } It "Encrypt/Decrypt from file" { - "test" | Protect-CmsMessage -To $vc1 -OutFile $tmpfile - $msg = Unprotect-CmsMessage -To $vc1 -Path $tmpfile + Protect-CmsMessage -Path $messageFile -To $vc1 -OutFile $cipherFile + $msg = Unprotect-CmsMessage -To $vc1 -Path $cipherFile $msg | Should -BeExactly "test" } @@ -98,82 +150,30 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { } It "Get-CmsMessage from file" { - (Get-CmsMessage -Path $tmpfile).Content | Should -BeLike '-----BEGIN CMS*' - } -} - -Describe "CmsMessage cmdlets using files" -Tags "CI" { - - BeforeAll { - Write-Verbose "generating temp cert files" - $vc1File = New-TemporaryFile - $vc2File = New-TemporaryFile - $tempDir = New-Item -ItemType Directory -Path (Join-Path $vc1File.Directory.FullName "psCertTempDir") -Force - $vc3File = New-Item -Name "vc1.cert" -Path $tempDir - [System.IO.File]::WriteAllBytes("$vc1File", $vc1.Export("pfx")) - [System.IO.File]::WriteAllBytes("$vc2File", $vc2.Export("pfx")) - [System.IO.File]::WriteAllBytes("$vc3File", $vc1.Export("pfx")) + (Get-CmsMessage -Path $cipherFile).Content | Should -BeLike '-----BEGIN CMS*' } It "Encrypt With Single File" { - "test" | Protect-CmsMessage -To "$vc1File" | Unprotect-CmsMessage -To $vc1 | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $file1 | Unprotect-CmsMessage -To $file1 | Should -BeExactly "test" } - It "Encrypt With Multiple File" { - $msg = "test" | Protect-CmsMessage -To "$vc1File", "$vc2File" - ($msg | Unprotect-CmsMessage -To $vc1) | Should -BeExactly "test" - ($msg | Unprotect-CmsMessage -To $vc2) | Should -BeExactly "test" + It "Encrypt With Multiple Files" { + $msg = "test" | Protect-CmsMessage -To $file1, $file2 + ($msg | Unprotect-CmsMessage -To $file1) | Should -BeExactly "test" + ($msg | Unprotect-CmsMessage -To $file2) | Should -BeExactly "test" } It "Encrypt/Decrypt with Directory" { - "test" | Protect-CmsMessage -To "$tempDir" | Unprotect-CmsMessage -To "$tempDir" | Should -BeExactly "test" + "test" | Protect-CmsMessage -To "TestDrive:\certDir" | Unprotect-CmsMessage -To "TestDrive:\certDir" | Should -BeExactly "test" } It "Decrypt with multiple files" { - "test" | Protect-CmsMessage -To $vc1 | Unprotect-CmsMessage -To "$vc1File", "$vc2File" | Should -BeExactly "test" - } -} - -Describe "CmsMessage cmdlets using cert Store" -Tags "CI" { - - BeforeAll -Scriptblock { - Write-Verbose "adding temp certs to CurrentUser\My Store (on Mac those were added while generating vc1/vc2)" - $store = [X509Store]::new("My", [StoreLocation]::CurrentUser) - $store.Open("ReadWrite") - if (!$IsMacOS) { - $cert1 = [X509Certificate2]::new("$vc1File") - $cert2 = [X509Certificate2]::new("$vc2File") - $store.Add($cert1) - $store.Add($cert2) - } else { - $cert1 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc1.Thumbprint, $false)[0] - $cert2 = $store.Certificates.Find([X509FindType]::FindByThumbprint, $vc2.Thumbprint, $false)[0] - } - } - - It "Encrypt/Decrypt using subject" { - "test" | Protect-CmsMessage -To $cert1.Subject | Unprotect-CmsMessage | Should -BeExactly "test" - "test" | Protect-CmsMessage -To $cert1.Subject, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" - } - - It "Encrypt/Decrypt using Thumbprint" { - "test" | Protect-CmsMessage -To $cert1.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" - "test" | Protect-CmsMessage -To $cert1.Thumbprint, $cert2.Thumbprint | Unprotect-CmsMessage | Should -BeExactly "test" - } - - It "Encrypt/Decrypt mix" { - "test" | Protect-CmsMessage -To $cert1.Thumbprint, $cert2.Subject | Unprotect-CmsMessage | Should -BeExactly "test" + "test" | Protect-CmsMessage -To $vc1 | Unprotect-CmsMessage -To $file1, $file2 | Should -BeExactly "test" } AfterAll { - Write-Verbose "Removing temp files and certs" - $store.Remove($cert1) - $store.Remove($cert2) - if ($IsMacOS) { - $store.Remove($ic) - } $store.Dispose() - Remove-Item $vc1File, $vc2File, $tmpfile - Remove-Item -Recurse $tempDir -Force } } + + From 341339466bc503bfb2f037b3c73944142250bb65 Mon Sep 17 00:00:00 2001 From: Aleksandrovs Date: Thu, 6 Feb 2020 09:39:59 -0500 Subject: [PATCH 24/24] fixed minor format issues --- src/System.Management.Automation/security/SecuritySupport.cs | 1 - .../Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index eb4eecb6d2f..b7b08491e5f 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1289,7 +1289,6 @@ private void ResolveFromStoreById(ResolutionPurpose purpose, out ErrorRecord err ProcessResolvedCertificates(purpose, certificatesToProcess, out error); } - } catch (SessionStateException) { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 index 44e91289115..f58e8759351 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage2.Tests.ps1 @@ -175,5 +175,3 @@ Describe "CmsMessage cmdlets using X509 cert" -Tags "CI" { $store.Dispose() } } - -