From 56dddcd42944024bafa04f57d108c6760c5d09ae Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Thu, 23 Feb 2017 17:54:06 -0800 Subject: [PATCH 1/9] Port *-CmsMessage cmdlets and Get-PfxCertificate --- .../project.json | 9 +- .../security/CertificateCommands.cs | 14 +-- .../security/CmsCommands.cs | 9 +- .../security/Utils.cs | 118 ------------------ .../Microsoft.PowerShell.Security.psd1 | 0 .../Microsoft.PowerShell.Security.psd1 | 13 -- .../CoreCLR/CorePsStub.cs | 25 ---- .../security/SecuritySupport.cs | 13 +- .../utils/ClrFacade.cs | 30 +++++ 9 files changed, 41 insertions(+), 190 deletions(-) rename src/Modules/{Windows-Full => Windows-Core+Full}/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 (100%) delete mode 100644 src/Modules/Windows-Core/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 diff --git a/src/Microsoft.PowerShell.Security/project.json b/src/Microsoft.PowerShell.Security/project.json index 0f4a3ef2c86..025259f2f43 100644 --- a/src/Microsoft.PowerShell.Security/project.json +++ b/src/Microsoft.PowerShell.Security/project.json @@ -47,22 +47,19 @@ "define": [ "CORECLR" ], "compile": { "exclude": [ - "security/CertificateCommands.cs", - "security/CmsCommands.cs", "singleshell/installer/MshSecurityMshSnapin.cs", - "gen/CertificateCommands.cs", - "gen/CmsCommands.cs", "gen/SecurityMshSnapinResources.cs" ] }, "embed": { "exclude": [ - "resources/CertificateCommands.resx", - "resources/CmsCommands.resx", "resources/SecurityMshSnapinResources.resx" ] } + }, + "dependencies": { + "System.Security.Cryptography.Pkcs": "4.3.0" } }, "net451": { diff --git a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs index 345c38f272d..11c5c0ee88a 100644 --- a/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CertificateCommands.cs @@ -212,26 +212,20 @@ protected override void ProcessRecord() private static X509Certificate2 GetCertFromPfxFile(string path) { - X509Certificate2 cert = new X509Certificate2(); - - cert.Import(path); - + X509Certificate2 cert = new X509Certificate2(path); return cert; } private static X509Certificate2 GetCertFromPfxFile(string path, SecureString password) { - X509Certificate2 cert = new X509Certificate2(); - // // NTRAID#DevDiv Bugs-33007-2004/7/08-kumarp // the following will not be required once X509Certificate2.Import() // accepts a SecureString // - string clearTextPassword = SecurityUtils.GetStringFromSecureString(password); - - cert.Import(path, clearTextPassword, X509KeyStorageFlags.DefaultKeySet); - + string clearTextPassword = Utils.GetStringFromSecureString(password); + + var cert = new X509Certificate2(path, clearTextPassword, X509KeyStorageFlags.DefaultKeySet); return cert; } } diff --git a/src/Microsoft.PowerShell.Security/security/CmsCommands.cs b/src/Microsoft.PowerShell.Security/security/CmsCommands.cs index a4bf918ad5b..40ca423458e 100644 --- a/src/Microsoft.PowerShell.Security/security/CmsCommands.cs +++ b/src/Microsoft.PowerShell.Security/security/CmsCommands.cs @@ -3,19 +3,14 @@ --********************************************************************/ using System; -using System.IO; using System.Management.Automation; using System.Text; -using System.Security; -using System.Security.Cryptography; using System.Globalization; using System.Security.Cryptography.Pkcs; using System.Security.Cryptography.X509Certificates; using System.Diagnostics.CodeAnalysis; using System.Collections.ObjectModel; using System.Collections.Generic; -using System.Management.Automation.Security; -using System.Diagnostics.Eventing.Reader; namespace Microsoft.PowerShell.Commands { @@ -279,7 +274,7 @@ protected override void ProcessRecord() { if (_contentBuffer.Length > 0) { - _contentBuffer.Append(Environment.NewLine); + _contentBuffer.Append(System.Environment.NewLine); } _contentBuffer.Append(Content); @@ -456,7 +451,7 @@ protected override void ProcessRecord() { if (_contentBuffer.Length > 0) { - _contentBuffer.Append(Environment.NewLine); + _contentBuffer.Append(System.Environment.NewLine); } _contentBuffer.Append(Content); diff --git a/src/Microsoft.PowerShell.Security/security/Utils.cs b/src/Microsoft.PowerShell.Security/security/Utils.cs index 1bc0d25d5b3..f9e9c1842ff 100644 --- a/src/Microsoft.PowerShell.Security/security/Utils.cs +++ b/src/Microsoft.PowerShell.Security/security/Utils.cs @@ -5,21 +5,9 @@ using System; using System.IO; using System.Management.Automation; -using Microsoft.PowerShell.Commands; using System.Management.Automation.Host; using System.Management.Automation.Internal; using System.Security; -using System.Security.Principal; -using System.Security.AccessControl; -using System.Security.Cryptography; -using System.Security.Cryptography.X509Certificates; - -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Runtime.InteropServices; -using DWORD = System.UInt32; -using BOOL = System.UInt32; -using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; namespace Microsoft.PowerShell { @@ -47,44 +35,6 @@ internal static long GetFileSize(string filePath) return size; } -#if false - /// - /// throw if file is smaller than 4 bytes in length - /// - /// - /// path to file - /// - /// Does not return a value - /// - /// - /// - internal static void CheckIfFileSmallerThan4Bytes(string filePath) - { - if (GetFileSize(filePath) < 4) - { - string message = - StringUtil.Format( - UtilsStrings.FileSmallerThan4Bytes, - new object[] { filePath } - ); - - throw PSTraceSource.NewArgumentException(message, "path"); - /* - // 2004/10/22-JonN The above form of the constructor - // no longer exists. This should probably be as below, - // however I have not tested this. This method is not - // used so I have removed it. - throw PSTraceSource.NewArgumentException( - "path", - "Utils", - "FileSmallerThan4Bytes", - filePath - ); - */ - } - } -#endif - /// /// present a prompt for a SecureString data /// @@ -109,74 +59,6 @@ internal static SecureString PromptForSecureString(PSHostUserInterface hostUI, return ss; } -#if !CORECLR - /// - /// get plain text string from a SecureString - /// - /// This function will not be required once all of the methods - /// that we call accept a SecureString. The list below has - /// classes/methods that will be changed to accept a SecureString - /// after Whidbey beta1 - /// - /// -- X509Certificate2.Import (String, String, X509KeyStorageFlags) - /// (DCR #33007 in the DevDiv Schedule db) - /// - /// -- NetworkCredential(string, string); - /// - /// - /// - /// input data - /// - /// a string representing clear-text equivalent of ss - /// - /// - /// - [ArchitectureSensitive] - internal static string GetStringFromSecureString(SecureString ss) - { - IntPtr p = Marshal.SecureStringToGlobalAllocUnicode(ss); - string s = Marshal.PtrToStringUni(p); - - Marshal.ZeroFreeGlobalAllocUnicode(p); - - return s; - } -#endif - - /* - /// - /// display sec-desc of a file - /// - /// - /// file security descriptor - /// - /// Does not return a value - /// - /// - /// - internal static void ShowFileSd(FileSecurity sd) - { - string userName = null; - FileSystemRights rights = 0; - AccessControlType aceType = 0; - - rules = sd.GetAccessRules(true, false, typeof(NTAccount)); - - foreach (FileSystemAccessRule r in rules) - { - userName = r.IdentityReference.ToString(); - aceType = r.AccessControlType; - rights = r.FileSystemRights; - - Console.WriteLine("{0} : {1} : {2}", - userName, - aceType.ToString(), - rights.ToString()); - } - } - } - */ - /// /// /// diff --git a/src/Modules/Windows-Full/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Windows-Core+Full/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 similarity index 100% rename from src/Modules/Windows-Full/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 rename to src/Modules/Windows-Core+Full/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 diff --git a/src/Modules/Windows-Core/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 b/src/Modules/Windows-Core/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 deleted file mode 100644 index f47251e8321..00000000000 --- a/src/Modules/Windows-Core/Microsoft.PowerShell.Security/Microsoft.PowerShell.Security.psd1 +++ /dev/null @@ -1,13 +0,0 @@ -@{ -GUID="A94C8C7E-9810-47C0-B8AF-65089C13A35A" -Author="Microsoft Corporation" -CompanyName="Microsoft Corporation" -Copyright="© Microsoft Corporation. All rights reserved." -ModuleVersion="3.0.0.0" -PowerShellVersion="3.0" -AliasesToExport = @() -FunctionsToExport = @() -CmdletsToExport="Get-Acl", "Set-Acl", "Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "Get-AuthenticodeSignature", "Set-AuthenticodeSignature", "ConvertFrom-SecureString", "ConvertTo-SecureString", "New-FileCatalog" , "Test-FileCatalog" -NestedModules="Microsoft.PowerShell.Security.dll" -HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=390786' -} diff --git a/src/System.Management.Automation/CoreCLR/CorePsStub.cs b/src/System.Management.Automation/CoreCLR/CorePsStub.cs index 662356ccf40..b4bc1c57a23 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsStub.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsStub.cs @@ -793,31 +793,6 @@ public enum RollbackSeverity #endregion PSTransaction - #region CMS - - internal static class CmsUtils - { - internal static string BEGIN_CERTIFICATE_SIGIL = "-----BEGIN CERTIFICATE-----"; - internal static string END_CERTIFICATE_SIGIL = "-----END CERTIFICATE-----"; - - internal static string Encrypt(byte[] contentBytes, CmsMessageRecipient[] recipients, SessionState sessionState, out ErrorRecord error) - { - throw new NotImplementedException("CmsUtils.Encrypt(...) is not implemented in CoreCLR powershell."); - } - - internal static string GetAsciiArmor(byte[] bytes) - { - throw new NotImplementedException("CmsUtils.GetAsciiArmor(...) is not implemented in CoreCLR powershell."); - } - - internal static byte[] RemoveAsciiArmor(string actualContent, string beginMarker, string endMarker, out int startIndex, out int endIndex) - { - throw new NotImplementedException("CmsUtils.RemoveAsciiArmor(...) is not implemented in CoreCLR powershell."); - } - } - - #endregion CMS - #region ApartmentState internal enum ApartmentState diff --git a/src/System.Management.Automation/security/SecuritySupport.cs b/src/System.Management.Automation/security/SecuritySupport.cs index b1c72471921..fe6f53daab2 100644 --- a/src/System.Management.Automation/security/SecuritySupport.cs +++ b/src/System.Management.Automation/security/SecuritySupport.cs @@ -1012,17 +1012,11 @@ internal enum CertificatePurpose namespace System.Management.Automation { -#if !CORECLR - using System.Security.Cryptography.Pkcs; /// /// Utility class for CMS (Cryptographic Message Syntax) related operations /// - /// - /// The namespace 'System.Security.Cryptography.Pkcs' is not available in CoreCLR, - /// so the Cryptographic Message Syntax (CMS) will not be supported on OneCore PS. - /// internal static class CmsUtils { internal static string Encrypt(byte[] contentBytes, CmsMessageRecipient[] recipients, SessionState sessionState, out ErrorRecord error) @@ -1086,8 +1080,7 @@ internal static string GetAsciiArmor(byte[] bytes) StringBuilder output = new StringBuilder(); output.AppendLine(BEGIN_CMS_SIGIL); - string encodedString = Convert.ToBase64String( - bytes, Base64FormattingOptions.InsertLineBreaks); + string encodedString = ClrFacade.ToBase64StringWithLineBreaks(bytes); output.AppendLine(encodedString); output.Append(END_CMS_SIGIL); @@ -1131,8 +1124,6 @@ internal static byte[] RemoveAsciiArmor(string actualContent, string beginMarker } } -#endif - /// /// Represents a message recipient for the Cms cmdlets. /// @@ -1271,7 +1262,7 @@ private void ResolveFromBase64Encoding(ResolutionPurpose purpose, out ErrorRecor return; } - List certificatesToProcess = new List(); ; + List certificatesToProcess = new List(); try { X509Certificate2 newCertificate = new X509Certificate2(messageBytes); diff --git a/src/System.Management.Automation/utils/ClrFacade.cs b/src/System.Management.Automation/utils/ClrFacade.cs index 4583f925f14..2c7a8f713aa 100644 --- a/src/System.Management.Automation/utils/ClrFacade.cs +++ b/src/System.Management.Automation/utils/ClrFacade.cs @@ -661,6 +661,36 @@ internal static void SetCurrentThreadUiCulture(CultureInfo uiCultureInfo) #region Misc + /// + /// Facade for Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks) + /// Inserts line breaks after every 76 characters in the string representation. + /// + internal static string ToBase64StringWithLineBreaks(byte[] bytes) + { +#if CORECLR + // Inserts line breaks after every 76 characters in the string representation. + string encodedRawString = Convert.ToBase64String(bytes); + if (encodedRawString.Length <= 76) + return encodedRawString; + + StringBuilder builder = new StringBuilder(encodedRawString.Length); + int index = 0, remainingLen = encodedRawString.Length; + while (remainingLen > 76) + { + builder.Append(encodedRawString, index, 76); + builder.Append(System.Environment.NewLine); + + index += 76; + remainingLen -= 76; + } + + builder.Append(encodedRawString, index, remainingLen); + return builder.ToString(); +#else + return Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks); +#endif + } + /// /// Facade for RemotingServices.IsTransparentProxy(object) /// From 3bbfa7bf9e6093a2fc85ab9d3d10102085e5172b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Fri, 24 Feb 2017 17:25:59 -0800 Subject: [PATCH 2/9] Fix build --- src/Microsoft.PowerShell.Security/project.json | 3 --- src/System.Management.Automation/project.json | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Microsoft.PowerShell.Security/project.json b/src/Microsoft.PowerShell.Security/project.json index 025259f2f43..d0de3cb8ed8 100644 --- a/src/Microsoft.PowerShell.Security/project.json +++ b/src/Microsoft.PowerShell.Security/project.json @@ -57,9 +57,6 @@ "resources/SecurityMshSnapinResources.resx" ] } - }, - "dependencies": { - "System.Security.Cryptography.Pkcs": "4.3.0" } }, "net451": { diff --git a/src/System.Management.Automation/project.json b/src/System.Management.Automation/project.json index 904f2496f79..9af39fe58d5 100644 --- a/src/System.Management.Automation/project.json +++ b/src/System.Management.Automation/project.json @@ -183,6 +183,7 @@ "System.Reflection.Emit.Lightweight": "4.3.0", "System.Security.AccessControl": "4.3.0", "System.Security.Cryptography.Algorithms": "4.3.0", + "System.Security.Cryptography.Pkcs": "4.3.0", "System.Security.Cryptography.X509Certificates": "4.3.0", "System.Threading.Thread": "4.3.0", "System.Threading.Tasks.Parallel": "4.3.0", From c49df232097bb715bdb240f5684b47b8171bb1bf Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 27 Feb 2017 15:07:56 -0800 Subject: [PATCH 3/9] Port tests for CMS cmdlets --- .../CmsMessage.Tests.ps1 | 409 ++++++++++++++++++ 1 file changed, 409 insertions(+) create mode 100644 test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 new file mode 100644 index 00000000000..9dcfc9bfcb4 --- /dev/null +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -0,0 +1,409 @@ + +Function Create-TestCertificate +{ + $dataEnciphermentCert = " +MIIKYAIBAzCCCiAGCSqGSIb3DQEHAaCCChEEggoNMIIKCTCCBgoGCSqGSIb3DQEHAaCCBfsEggX3 +MIIF8zCCBe8GCyqGSIb3DQEMCgECoIIE/jCCBPowHAYKKoZIhvcNAQwBAzAOBAgPOFDMBkCffQIC +B9AEggTYjY55RrmAhdj1grENxXjiPrVNdS++pb5UOn3M7O78BR0U1i2h5zvjkPjOwdLoOCbq5pgg +F0PKaMjHVu8EoZxSqsib17ptR5Rx5N23hseuJUzS8fTAHiBet9payNOJlPfkpuqMfQEmCAo9gAPz +w4RiyZNOA3NhxkfGl9yU4O9GSEr2koWKCUoCNelkIXVbkV728L7zSiWRSqRb7V4QJAtwtgPLTbl/ +zo2SFhdNAGPeXbcOsKCv9trhuxPZ0FH4fukbXkHs0I3b5mYgMUI5Mds7UwT3wCtz+Ev9pLbmYN8X +NfH0tAK8ZGnQS1GcI4xCMEM8T9Tx3uwWY4arvRM3GTLwyt8JZEVZNTuYL9A9+RyeiO5d5xEKG8H4 +snOCoTriT45tdl8hzMBCdc3jWxWiydmNRw47irifv5BX7BK/6FLAxkMRwACAxNO63ezG/OxuDDEz +ml+KzeZNvr4u4mTBcgZ49vMSyfRt/my+5+iLnSMGp4Rt0uix8489wctkxGlgyXGk23pA4Cj4hq/6 +txopcl2gHn+DAFrHIgLg4JR8lcuOzBw8nFOrhK7iR9aMK21apxwImIaDCKJ1grOfbuElq4pkMpov +SltJe00WB94o69LibOg5LqpTrHW2/DY951sIgElF83FdUBhoZHasfCme/RxgliQf3QHedmENXSjr +8R8PAWX4wC0ZZVC0qcq5XP0PkwtuDKmfqq69R32nmBzpRrfypm9S+PfsYZeCeuROh6YKQ0ZBMnLb +8Y9povpXh0lYwVLuPanvAFiCT4vI7oRd1Mg1Zr9ZooMFAVomall1UnQQ29fvsoADjEDcPymVT80o +kTkw3NXnTX6fGZ94Eh0KZcuMgjTqIO3OKpH0lcaSBxlES4V0sO/mwP4ULy8l3dcnn440Nei33VDo +B7n2jhjJl/HvtltfEEEw1DW9AWDvkJDp878sD6VoyQZehvvxBNT0FwMr20TbVKeAGxf9n+xJ9Alo +VUS3qE7XnpxAAAR5L2OG+tMd4dyDSge1qrkVNZ3/uUzKKCZei2P7ICR9cX1FRsmcINdNfydIA2cA +Pmeq+UkRdqsJxt1NSK5bLvMM4EHRQZMMbXVKxxJ+kQDrzfQtERFPyd3Hdm2F4T/JXUQ+PrTQnRqY +LruTAiZfxygZuFrxJnNTRydRdbEaTAtMjFCMRFZ2wctJsgCb3yN9tt0JDYxIvm0MSehXiF+sCrl4 +yZvvUzJqrgppHRTBR4Sao+MZ/rJ30vVU19Q3oBi9ikTqDY+4SrHsp5Y4llnsbrz0Web+h2jLvyJz +LgKuqs87qHhToVMLuULy/HLqY3m661EMwNqh5D76gSFI+TP2/rzT5mVOGglahFoc848o4cshtPWE +9MjAkDfsMbIfeKH3uh3D+eBIxYmZ5Cq2aHzqdQ0pU/nDNX7BDjC3E80VcQnXx4U6tRsQHsGtbcld +MFTp0yHJ2KLkz+inH3WPy/lYuVZ0QJe+LqvGt+bt1DgQmLBMD9WLFML3d0TtkuY3RhD5Y0wr2zt9 +tT6WVTn8Hob1cJns4N7tDEr8Q3TdIar0I5Bzj3qoesJt+4lxwnVdUA1bNJ2zxXIkDfX/MTB464FI +2g9uhUs3lIOEiCjeJCwBebgZa1HlfhyCRu0E7fnNnKLaGWRs8LVy7MZIfe1kJoDVgTGB3TATBgkq +hkiG9w0BCRUxBgQEAQAAADBdBgkrBgEEAYI3EQExUB5OAE0AaQBjAHIAbwBzAG8AZgB0ACAAUwB0 +AHIAbwBuAGcAIABDAHIAeQBwAHQAbwBnAHIAYQBwAGgAaQBjACAAUAByAG8AdgBpAGQAZQByMGcG +CSqGSIb3DQEJFDFaHlgAQwBlAHIAdABSAGUAcQAtAGEAYgA5AGUAZgA3AGYAOAAtAGUAYwA2AGEA +LQA0ADUAMwA4AC0AOQA4AGQAOAAtADAAYQA4AGUAYwA4ADUAOQBkADkAMgAxMIID9wYJKoZIhvcN +AQcGoIID6DCCA+QCAQAwggPdBgkqhkiG9w0BBwEwHAYKKoZIhvcNAQwBBjAOBAiYL6rZmAGN9QIC +B9CAggOw8eaNgIqx26SlOBKKQZ5O7NDZQHbytHTWn4ifNhVFUkbuaj22/VnYOFB9//8BLY6t0Dvw +X6wqXSMnbr1jOuUYaFdJzOBZBsYQfFTfoJ4iOb2jwwIpZSgTHeqgXbvnI7MIxauu6F4UseWVxt3u +ZhHjEZQjKWeC5mNCb6wX0IOQk96n1RJnJ3v1D4Q5YrVekOVq70VhRNtLOZMkrJV7vDMNlUYXD69D +PbcyPajVvETq0W98YNKB89oNwFWuKoMLNPWmSwIfn10oSEtybNEEr2IVgCBt2w2eb+nIDuA3c/Rc +qKPXwVGMzoUyAiGwTcueCdMRmiuQAuKCUyi9P/JqeIbgHtg15nAoGtw+l4MsFXfdMJjTCDd0WYff +l9ipaNnw8erCPquD0+wXeMnNivXaFzu2+CGwCSwbDl2M49HAQdtpKhNj5jKJBEP1GRQIk173gbEZ +n69IXUCsf0GDZiZVNbAQHBOuRoEHpBhendFgTJFAU2LDHlmV6OA0LYHaSn7CP/vOXOhWXJ1yGL2p +SeUepciwQV7sOHqDExWY82fd1kHSHcgCAkWLSSdIPlWhyeqjC1agSP6b74VK8uLRPkin5F9wGIPi +ewe/LsW3PTtDkDnj3DiSioKlQRUUxVxzi5qPBs+7vJEhbuO7UhtsMCWeUygDbw6n8BKan4w9iLhx +7/z6zVvQmLnK4HZChTPFuThRy1NctupoX7nE+CDgyhcmryaTDXohkviMWl4Od+8uGh8Quv2bHk6Y +UnFqNB/hSqYMkTuMLH4F9sVzoQEsYu96CDwbQaggbLMnPtmHKsPtzdnWQnys+oGT4uD8vl9xFdEW +AZdestrxbDK0La0AgGszUE+6B/GtOs2pv0fMXXYV2h+dAlwfz7oLxzm9E+SFgzviL+6PuI9fDHNd +pWeq/Rr5OpFb3rSotGTl84aIjk3hPd3uHujPQh8GO2EQ5k6p6ukk+a7gOUB+pH8fHihFl5L7pI0z +yRp0FvbZo//hmACYMvINoy2EQxjYLh7QLeE4qEr8bkzJVgEURUvcUpyHFJT6PGzUMqGx/Wjh2jJc +HfEDPMUDoTE/QRzLW7XrmQgJIRuHgPI/cqmOyvpEvuwdRhYyHEKktRO3tGjeflohDCyDW9bxOaJV +ZP64KBordM28ZHCQbnSdU0I5us6qiFX2PiLlBzRMH2ftUNMYReioqZyR+Xv5wjaoydV3//BDMH8M +1lh9GazUO8+OtzQEH0jiBi6ctlzFT8nNI2C+cOB9S3yMAjCEQa8wNzAfMAcGBSsOAwIaBBR96vF2 +OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM= +" + + $dataEnciphermentCert = $dataEnciphermentCert -replace '\s','' + $certBytes = [Convert]::FromBase64String($dataEnciphermentCert) + $certLocation = Join-Path $TestDrive "ProtectedEventLogging.pfx" + [IO.File]::WriteAllBytes($certLocation, $certBytes) + + return $certLocation +} + + +Describe "CmsMessage cmdlets basic tests" -Tags "CI" { + + BeforeAll { + if ($IsWindows) + { + $certLocation = Create-TestCertificate + } + else + { + # Skip for non-Windows platforms + $defaultParamValues = $PSdefaultParameterValues.Clone() + $PSdefaultParameterValues = @{ "it:skip" = $true } + } + } + + AfterAll { + if ($defaultParamValues) + { + $PSdefaultParameterValues = $defaultParamValues + } + + if ($certLocation) + { + Remove-Item $certLocation -Force + } + } + + It "Verify message recipient resolution by path" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] $certLocation + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' + } + + It "Verify message recipient resolution by cert" { + $ers = $null + $cert = Get-PfxCertificate $certLocation + $recipient = [System.Management.Automation.CmsMessageRecipient] $cert + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' + } + + It "Verify a message can be protected / unprotected" { + $protected = "Hello World","How are you?" | Protect-CmsMessage -To $certLocation + $protected.IndexOf("-----BEGIN CMS-----") | Should Be 0 + + $message = $protected | Get-CmsMessage + $message.Recipients[0].IssuerName | Should Be "CN=MyDataEnciphermentCert" + + $decrypted = $message | Unprotect-CmsMessage -To $certLocation + $decrypted | Should Be "Hello World`r`nHow are you?" + + $decrypted = $protected | Unprotect-CmsMessage -To $certLocation + $decrypted | Should Be "Hello World`r`nHow are you?" + } +} + + +Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { + + BeforeAll { + if ($IsWindows) + { + $certLocation = Create-TestCertificate + + if ($IsCoreCLR) + { + # PKI module is not available for PowerShell Core, so we need to use Windows PowerShell to import the cert + $fullPowerShell = Join-Path "$env:SystemRoot" "System32\WindowsPowerShell\v1.0\powershell.exe" + + try { + $modulePathCopy = $env:PSMODULEPATH + $env:PSMODULEPATH = $null + + $importedCertPath = & $fullPowerShell -NoProfile -NonInteractive ` + -Command "Import-PfxCertificate $certLocation -CertStoreLocation cert:\CurrentUser\My | % PSPath" + $importedCert = Get-ChildItem $importedCertPath + } finally { + $env:PSMODULEPATH = $modulePathCopy + } + } + else + { + $importedCert = Import-PfxCertificate $certLocation -CertStoreLocation cert:\CurrentUser\My + } + } + else + { + # Skip for non-Windows platforms + $defaultParamValues = $PSdefaultParameterValues.Clone() + $PSdefaultParameterValues = @{ "it:skip" = $true } + } + } + + AfterAll { + if ($defaultParamValues) + { + $PSdefaultParameterValues = $defaultParamValues + } + + if ($importedCert) + { + Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) + } + + if ($certLocation) + { + Remove-Item $certLocation -Force + } + } + + It "Verify message recipient resolution by Base64Cert" { + $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----- + " + + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] $certContent + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' + } + + It "Verify wildcarded recipient resolution by path [Decryption]" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*") + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + + # Should have resolved single cert + $recipient.Certificates.Count | Should Be 1 + } + + It "Verify wildcarded recipient resolution by path [Encryption]" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*") + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $recipient.Certificates.Count | Should Be 1 + } + + It "Verify resolution by directory" { + $protectedEventLoggingCertPath = Join-Path $TestDrive ProtectedEventLoggingDir + $null = New-Item -ItemType Directory $protectedEventLoggingCertPath -Force + Copy-Item $certLocation $protectedEventLoggingCertPath + Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "SecondCert.pfx") + Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "ThirdCert.pfx") + + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] $protectedEventLoggingCertPath + $recipient.Resolve($executionContext.SessionState, "Decryption", [ref] $ers) + + $recipient.Certificates.Count | Should Be 1 + } + + It "Verify resolution by thumbprint" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Thumbprint + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + + # "Should have certs from thumbprint in 'My' store" + $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint + } + + It "Verify resolution by subject name" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Subject + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + + $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint + } + + It "Verify error when no cert found in encryption for encryption" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist*" + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $ers[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" + } + + It "Verify error when encrypting to non-wildcarded identifier for decryption" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist" + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + + $ers[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" + } + + It "Verify error when encrypting to wrong cert" { + $ers = $null + $goodCerts = @(Get-ChildItem Cert:\currentuser\My -DocumentEncryptionCert | ForEach-Object Thumbprint) + $badCert = Get-ChildItem Cert:\currentuser\My | ? { $_.Thumbprint -notin $goodCerts } | Select -First 1 + + $recipient = [System.Management.Automation.CmsMessageRecipient] $badCert.Thumbprint + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + + $ers[0].FullyQualifiedErrorId | Should Be "CertificateCannotBeUsedForEncryption" + } + + It "Verify no error when encrypting to wildcarded identifier for decryption" { + $ers = $null + $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist*" + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + + $ers | Should Be $null + $recipient.Certificates.Count | Should Be 0 + } + + It "Verify Protect-CmsMessage emits recipient errors" { + try { + "Hello World" | Protect-CmsMessage -To "SomeThumbprintThatDoesNotExist" -ErrorAction Stop + throw "No Exception!" + } catch { + $_.FullyQualifiedErrorId | Should Be "NoCertificateFound,Microsoft.PowerShell.Commands.ProtectCmsMessageCommand" + } + } + + It "Verify CmsMessage cmdlets works with paths" { + try { + $randomNum = Get-Random -Minimum 1000 -Maximum 9999 + $tempPath = Join-Path $TestDrive "$randomNum-Path-Test-File" + $encryptedPath = $tempPath + ".encrypted.txt" + "Hello World","How are you?" | Set-Content $tempPath + + Protect-CmsMessage -Path $tempPath -To $certLocation -OutFile $encryptedPath + + $message = Get-CmsMessage -LiteralPath $encryptedPath + $message.Recipients[0].IssuerName | Should Be "CN=MyDataEnciphermentCert" + + $decrypted = $message | Unprotect-CmsMessage -To $certLocation + $decrypted | Should Be "Hello World`r`nHow are you?`r`n" + + $decrypted = Unprotect-CmsMessage -Path $encryptedPath -To $certLocation + $decrypted | Should Be "Hello World`r`nHow are you?`r`n" + } finally { + Remove-Item $tempPath, $encryptedPath -Force -ErrorAction SilentlyContinue + } + } + + It "Verify Unprotect-CmsMessage works with local store" { + try { + $randomNum = Get-Random -Minimum 1000 -Maximum 9999 + $tempPath = Join-Path $TestDrive "$randomNum-Path-Test-File" + "Hello World" | Protect-CmsMessage -To $certLocation -OutFile $tempPath + + # Decrypt using $importedCert in the Cert store + $decrypted = Unprotect-CmsMessage -Path $tempPath + $decrypted | Should Be "Hello World" + } finally { + Remove-Item $tempPath -Force -ErrorAction SilentlyContinue + } + } + + It "Verify Unprotect-CmsMessage emits recipient errors" { + try { + "" | Unprotect-CmsMessage -To "SomeThumbprintThatDoesNotExist" -IncludeContext -ErrorAction Stop + throw "No Exception!" + } catch { + $_.FullyQualifiedErrorId | Should Be "NoCertificateFound,Microsoft.PowerShell.Commands.UnprotectCmsMessageCommand" + } + } + + It "Verify failure to extract Ascii armor generates an error" { + try { + "Hello World" | Unprotect-CmsMessage -ErrorAction Stop + throw "No Exception!" + } catch { + $_.FullyQualifiedErrorId | Should Be "InputContainedNoEncryptedContentIncludeContext,Microsoft.PowerShell.Commands.UnprotectCmsMessageCommand" + } + + # Should have round-tripped content + $result = "Hello World" | Unprotect-CmsMessage -IncludeContext + $result | Should Be "Hello World" + + try { + "Hello World" | Get-CmsMessage -ErrorAction Stop + throw "No Exception!" + } catch { + $_.FullyQualifiedErrorId | Should Be "InputContainedNoEncryptedContent,Microsoft.PowerShell.Commands.GetCmsMessageCommand" + } + } + + It "Verify Unprotect-CmsMessage lets you include context" { + $protected = "Hello World" | Protect-CmsMessage -To $certLocation + $adjustedProtected = "Pre content`r`n" + $protected + "`r`nPost content" + + $decryptedNoContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation + $decryptedWithContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation -IncludeContext + + $decryptedNoContext | Should Be "Hello World" + + $decryptedWithContext | Should Match "Pre content" + $decryptedWithContext | Should Match "World" + $decryptedWithContext | Should Match "Post content" + } + + It "Verify Unprotect-CmsMessage treats event logs as a first class citizen" { + $protected = "Encrypted Message1","Encrypted Message2" | Protect-CmsMessage -To $certLocation + $virtualEventLog = Get-WinEvent Microsoft-Windows-PowerShell/Operational -MaxEvents 1 + $savedId = $virtualEventLog.Id + $virtualEventLog.Message = $protected + + $decrypted = $virtualEventLog | Unprotect-CmsMessage -To $certLocation + $decrypted | Should Be "Encrypted Message1`r`nEncrypted Message2" + + $processed = $virtualEventLog | Unprotect-CmsMessage -To $certLocation -IncludeContext + $processed.Id | Should Be $savedId + $processed.Message | Should Be "Encrypted Message1`r`nEncrypted Message2" + } + + It "Verify -DocumentEncryptionCert parameter works" { + $foundCerts = Get-ChildItem Cert:\CurrentUser -Recurse -DocumentEncryptionCert + + # Validate they all match the EKU + $correctMatching = $foundCerts | ? { $_.EnhancedKeyUsageList[0].ObjectId -eq '1.3.6.1.4.1.311.80.1' } + # "All Document Encryption Cert should have had correct EKU" + @($foundCerts).Count | Should Be @($correctMatching).Count + } + + It "Verify protect message using OutString" { + $protected = Get-Process -Id $pid | Protect-CmsMessage -To $certLocation + $decrypted = $protected | Unprotect-CmsMessage -To $certLocation + # Should have had PID in output + $decrypted | Should Match $pid + } +} From b7715bceec1ebbba8f408add73b823d2462be47b Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 27 Feb 2017 16:24:35 -0800 Subject: [PATCH 4/9] enable 'Get-PfxCertificate' on non-Windows and add tests --- .../Microsoft.PowerShell.Security.psd1 | 2 +- .../CmsMessage.Tests.ps1 | 44 +++++++++---------- 2 files changed, 23 insertions(+), 23 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 f86fa695fbf..45859c96afa 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="3.0.0.0" PowerShellVersion="3.0" AliasesToExport = @() FunctionsToExport = @() -CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString" +CmdletsToExport="Get-Credential", "Get-ExecutionPolicy", "Set-ExecutionPolicy", "ConvertFrom-SecureString", "ConvertTo-SecureString", "Get-PfxCertificate" NestedModules="Microsoft.PowerShell.Security.dll" HelpInfoURI = 'https://go.microsoft.com/fwlink/?linkid=390786' } diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index 9dcfc9bfcb4..fa4534c30c6 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -60,34 +60,33 @@ OksttXT1kXf+aez9EzDlsgQU4ck78h0WTy01zHLwSKNWK4wFFQM= } -Describe "CmsMessage cmdlets basic tests" -Tags "CI" { +Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { BeforeAll { - if ($IsWindows) - { - $certLocation = Create-TestCertificate - } - else - { - # Skip for non-Windows platforms - $defaultParamValues = $PSdefaultParameterValues.Clone() - $PSdefaultParameterValues = @{ "it:skip" = $true } - } + $certLocation = Create-TestCertificate + $certLocation | Should Not BeNullOrEmpty | Out-Null } AfterAll { - if ($defaultParamValues) - { - $PSdefaultParameterValues = $defaultParamValues - } + Remove-Item $certLocation -Force + } - if ($certLocation) - { - Remove-Item $certLocation -Force - } + It "Verify Get-PfxCertificate -FilePath" { + $cert = Get-PfxCertificate -FilePath $certLocation + $cert.Subject | Should Be "CN=MyDataEnciphermentCert" + } + + It "Verify Get-PfxCertificate -LiteralPath" { + $cert = Get-PfxCertificate -LiteralPath $certLocation + $cert.Subject | Should Be "CN=MyDataEnciphermentCert" + } + + It "Verify Get-PfxCertificate positional argument" { + $cert = Get-PfxCertificate $certLocation + $cert.Subject | Should Be "CN=MyDataEnciphermentCert" } - It "Verify message recipient resolution by path" { + It "Verify CMS message recipient resolution by path" -Skip:(!$IsWindows) { $ers = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $certLocation $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) @@ -95,7 +94,7 @@ Describe "CmsMessage cmdlets basic tests" -Tags "CI" { $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' } - It "Verify message recipient resolution by cert" { + It "Verify CMS message recipient resolution by cert" -Skip:(!$IsWindows) { $ers = $null $cert = Get-PfxCertificate $certLocation $recipient = [System.Management.Automation.CmsMessageRecipient] $cert @@ -104,7 +103,7 @@ Describe "CmsMessage cmdlets basic tests" -Tags "CI" { $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' } - It "Verify a message can be protected / unprotected" { + It "Verify a CMS message can be protected / unprotected" -Skip:(!$IsWindows) { $protected = "Hello World","How are you?" | Protect-CmsMessage -To $certLocation $protected.IndexOf("-----BEGIN CMS-----") | Should Be 0 @@ -126,6 +125,7 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { if ($IsWindows) { $certLocation = Create-TestCertificate + $certLocation | Should Not BeNullOrEmpty | Out-Null if ($IsCoreCLR) { From 638fc7f2a106badff1dc65185477014e73c93119 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Mon, 27 Feb 2017 16:54:12 -0800 Subject: [PATCH 5/9] Fix an issue with the test --- .../Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index fa4534c30c6..fc8b2c6e19f 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -67,10 +67,6 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { $certLocation | Should Not BeNullOrEmpty | Out-Null } - AfterAll { - Remove-Item $certLocation -Force - } - It "Verify Get-PfxCertificate -FilePath" { $cert = Get-PfxCertificate -FilePath $certLocation $cert.Subject | Should Be "CN=MyDataEnciphermentCert" @@ -166,11 +162,6 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { { Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) } - - if ($certLocation) - { - Remove-Item $certLocation -Force - } } It "Verify message recipient resolution by Base64Cert" { From 85fdd7b5127270e1a6e9657930ab6a83edfebefe Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 28 Feb 2017 11:44:32 -0800 Subject: [PATCH 6/9] Address review comments in tests --- .../CmsMessage.Tests.ps1 | 105 ++++++++++-------- 1 file changed, 61 insertions(+), 44 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index fc8b2c6e19f..bf6221a8861 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -83,19 +83,21 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { } It "Verify CMS message recipient resolution by path" -Skip:(!$IsWindows) { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $certLocation - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) + $recipient.Certificates.Count | Should Be 1 $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' } It "Verify CMS message recipient resolution by cert" -Skip:(!$IsWindows) { - $ers = $null + $errors = $null $cert = Get-PfxCertificate $certLocation $recipient = [System.Management.Automation.CmsMessageRecipient] $cert - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) + $recipient.Certificates.Count | Should Be 1 $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' } @@ -104,13 +106,15 @@ Describe "CmsMessage cmdlets and Get-PfxCertificate basic tests" -Tags "CI" { $protected.IndexOf("-----BEGIN CMS-----") | Should Be 0 $message = $protected | Get-CmsMessage + $message.Recipients.Count | Should Be 1 $message.Recipients[0].IssuerName | Should Be "CN=MyDataEnciphermentCert" + $expected = "Hello World" + [System.Environment]::NewLine + "How are you?" $decrypted = $message | Unprotect-CmsMessage -To $certLocation - $decrypted | Should Be "Hello World`r`nHow are you?" + $decrypted | Should Be $expected $decrypted = $protected | Unprotect-CmsMessage -To $certLocation - $decrypted | Should Be "Hello World`r`nHow are you?" + $decrypted | Should Be $expected } } @@ -153,14 +157,16 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { } AfterAll { - if ($defaultParamValues) + if ($IsWindows) { - $PSdefaultParameterValues = $defaultParamValues + if ($importedCert) + { + Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) + } } - - if ($importedCert) + else { - Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) + $PSdefaultParameterValues = $defaultParamValues } } @@ -189,26 +195,27 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { -----END CERTIFICATE----- " - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $certContent - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) + $recipient.Certificates.Count | Should Be 1 $recipient.Certificates[0].Subject | Should Match 'CN=MyDataEnciphermentCert' } It "Verify wildcarded recipient resolution by path [Decryption]" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*") - $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors) # Should have resolved single cert $recipient.Certificates.Count | Should Be 1 } It "Verify wildcarded recipient resolution by path [Encryption]" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] ($certLocation + "*") - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) $recipient.Certificates.Count | Should Be 1 } @@ -220,63 +227,68 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "SecondCert.pfx") Copy-Item $certLocation (Join-Path $protectedEventLoggingCertPath "ThirdCert.pfx") - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $protectedEventLoggingCertPath - $recipient.Resolve($executionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($executionContext.SessionState, "Decryption", [ref] $errors) $recipient.Certificates.Count | Should Be 1 } It "Verify resolution by thumbprint" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Thumbprint - $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors) # "Should have certs from thumbprint in 'My' store" + $recipient.Certificates.Count | Should Be 1 $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint } It "Verify resolution by subject name" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] $importedCert.Subject - $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors) + $recipient.Certificates.Count | Should Be 1 $recipient.Certificates[0].Thumbprint | Should Be $importedCert.Thumbprint } It "Verify error when no cert found in encryption for encryption" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist*" - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) - $ers[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" + $errors.Count | Should Be 1 + $errors[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" } It "Verify error when encrypting to non-wildcarded identifier for decryption" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist" - $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors) - $ers[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" + $errors.Count | Should Be 1 + $errors[0].FullyQualifiedErrorId | Should Be "NoCertificateFound" } It "Verify error when encrypting to wrong cert" { - $ers = $null + $errors = $null $goodCerts = @(Get-ChildItem Cert:\currentuser\My -DocumentEncryptionCert | ForEach-Object Thumbprint) $badCert = Get-ChildItem Cert:\currentuser\My | ? { $_.Thumbprint -notin $goodCerts } | Select -First 1 $recipient = [System.Management.Automation.CmsMessageRecipient] $badCert.Thumbprint - $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Encryption", [ref] $errors) - $ers[0].FullyQualifiedErrorId | Should Be "CertificateCannotBeUsedForEncryption" + $errors.Count | Should Be 1 + $errors[0].FullyQualifiedErrorId | Should Be "CertificateCannotBeUsedForEncryption" } It "Verify no error when encrypting to wildcarded identifier for decryption" { - $ers = $null + $errors = $null $recipient = [System.Management.Automation.CmsMessageRecipient] "SomeCertificateThatDoesNotExist*" - $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $ers) + $recipient.Resolve($ExecutionContext.SessionState, "Decryption", [ref] $errors) - $ers | Should Be $null + $errors | Should Be $null $recipient.Certificates.Count | Should Be 0 } @@ -299,13 +311,15 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { Protect-CmsMessage -Path $tempPath -To $certLocation -OutFile $encryptedPath $message = Get-CmsMessage -LiteralPath $encryptedPath + $message.Recipients.Count | Should Be 1 $message.Recipients[0].IssuerName | Should Be "CN=MyDataEnciphermentCert" + $expected = "Hello World" + [System.Environment]::NewLine + "How are you?" + [System.Environment]::NewLine $decrypted = $message | Unprotect-CmsMessage -To $certLocation - $decrypted | Should Be "Hello World`r`nHow are you?`r`n" + $decrypted | Should Be $expected $decrypted = Unprotect-CmsMessage -Path $encryptedPath -To $certLocation - $decrypted | Should Be "Hello World`r`nHow are you?`r`n" + $decrypted | Should Be $expected } finally { Remove-Item $tempPath, $encryptedPath -Force -ErrorAction SilentlyContinue } @@ -356,16 +370,15 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { It "Verify Unprotect-CmsMessage lets you include context" { $protected = "Hello World" | Protect-CmsMessage -To $certLocation - $adjustedProtected = "Pre content`r`n" + $protected + "`r`nPost content" + $adjustedProtected = "Pre content" + [System.Environment]::NewLine + $protected + [System.Environment]::NewLine + "Post content" $decryptedNoContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation $decryptedWithContext = $adjustedProtected | Unprotect-CmsMessage -To $certLocation -IncludeContext $decryptedNoContext | Should Be "Hello World" - $decryptedWithContext | Should Match "Pre content" - $decryptedWithContext | Should Match "World" - $decryptedWithContext | Should Match "Post content" + $expected = "Pre content" + [System.Environment]::NewLine + "Hello World" + [System.Environment]::NewLine + "Post content" + $decryptedWithContext | Should Be $expected } It "Verify Unprotect-CmsMessage treats event logs as a first class citizen" { @@ -374,19 +387,23 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { $savedId = $virtualEventLog.Id $virtualEventLog.Message = $protected + $expected = "Encrypted Message1" + [System.Environment]::NewLine + "Encrypted Message2" $decrypted = $virtualEventLog | Unprotect-CmsMessage -To $certLocation - $decrypted | Should Be "Encrypted Message1`r`nEncrypted Message2" + $decrypted | Should Be $expected $processed = $virtualEventLog | Unprotect-CmsMessage -To $certLocation -IncludeContext $processed.Id | Should Be $savedId - $processed.Message | Should Be "Encrypted Message1`r`nEncrypted Message2" + $processed.Message | Should Be $expected } It "Verify -DocumentEncryptionCert parameter works" { $foundCerts = Get-ChildItem Cert:\CurrentUser -Recurse -DocumentEncryptionCert # Validate they all match the EKU - $correctMatching = $foundCerts | ? { $_.EnhancedKeyUsageList[0].ObjectId -eq '1.3.6.1.4.1.311.80.1' } + $correctMatching = $foundCerts | ? { + ($_.EnhancedKeyUsageList.Count -gt 0) -and + ($_.EnhancedKeyUsageList[0].ObjectId -eq '1.3.6.1.4.1.311.80.1') + } # "All Document Encryption Cert should have had correct EKU" @($foundCerts).Count | Should Be @($correctMatching).Count } From 563983ebabd99dc673ba5f268f604a7b250fdb90 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 28 Feb 2017 12:19:04 -0800 Subject: [PATCH 7/9] Address some more comments in tests --- .../Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index bf6221a8861..001e9f6afd3 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -161,7 +161,7 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { { if ($importedCert) { - Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) + Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) -Force } } else From 844b5e7ab4f69673bc8ebff6012dff5bce8631e1 Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 28 Feb 2017 12:25:59 -0800 Subject: [PATCH 8/9] Fix another comment in tests --- .../Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index 001e9f6afd3..cf0c0cba6b5 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -161,7 +161,7 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { { if ($importedCert) { - Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) -Force + Remove-Item (Join-Path Cert:\CurrentUser\My $importedCert.Thumbprint) -Force -ErrorAction SilentlyContinue } } else From a12e3942b8ded8b4e9e65953a53e1fc8d333efeb Mon Sep 17 00:00:00 2001 From: Dongbo Wang Date: Tue, 28 Feb 2017 22:08:40 -0800 Subject: [PATCH 9/9] Split a test case to 3 It blocks --- .../CmsMessage.Tests.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 index cf0c0cba6b5..1f500b2bb30 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Security/CmsMessage.Tests.ps1 @@ -348,18 +348,16 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { } } - It "Verify failure to extract Ascii armor generates an error" { + It "Verify failure to extract Ascii armor generates an error [Unprotect-CmsMessage]" { try { "Hello World" | Unprotect-CmsMessage -ErrorAction Stop throw "No Exception!" } catch { $_.FullyQualifiedErrorId | Should Be "InputContainedNoEncryptedContentIncludeContext,Microsoft.PowerShell.Commands.UnprotectCmsMessageCommand" } + } - # Should have round-tripped content - $result = "Hello World" | Unprotect-CmsMessage -IncludeContext - $result | Should Be "Hello World" - + It "Verify failure to extract Ascii armor generates an error [Get-CmsMessage]" { try { "Hello World" | Get-CmsMessage -ErrorAction Stop throw "No Exception!" @@ -368,6 +366,12 @@ Describe "CmsMessage cmdlets thorough tests" -Tags "Feature" { } } + It "Verify 'Unprotect-CmsMessage -IncludeContext' with no encrypted input" { + # Should have round-tripped content + $result = "Hello World" | Unprotect-CmsMessage -IncludeContext + $result | Should Be "Hello World" + } + It "Verify Unprotect-CmsMessage lets you include context" { $protected = "Hello World" | Protect-CmsMessage -To $certLocation $adjustedProtected = "Pre content" + [System.Environment]::NewLine + $protected + [System.Environment]::NewLine + "Post content"