internal static string Encrypt(byte[] contentBytes, CmsMessageRecipient[] recipients, SessionState sessionState, out ErrorRecord error) { throw new NotImplementedException("CmsUtils.Encrypt(...) is not implemented in CoreCLR powershell."); }
private static bool GetAndValidateEncryptionRecipients(ScriptBlock scriptBlock) { Dictionary<string, object> protectedEventLoggingSettings = Utils.GetGroupPolicySetting( "Software\\Policies\\Microsoft\\Windows\\EventLog", "ProtectedEventLogging", Utils.RegLocalMachine); // See if protected event logging is enabled object enableProtectedEventLogging = null; if (protectedEventLoggingSettings.TryGetValue("EnableProtectedEventLogging", out enableProtectedEventLogging)) { if (String.Equals("1", enableProtectedEventLogging.ToString(), StringComparison.OrdinalIgnoreCase)) { // Get the encryption certificate object encryptionCertificate = null; if (protectedEventLoggingSettings.TryGetValue("EncryptionCertificate", out encryptionCertificate)) { ErrorRecord error = null; ExecutionContext executionContext = LocalPipeline.GetExecutionContextFromTLS(); SessionState sessionState = null; // Use the session state from the current pipeline, if it exists. if (executionContext != null) { sessionState = executionContext.SessionState; } // If the engine hasn't started up yet, then we're just compiling script // blocks. We'll have to log them when they are used and we have an engine // to work with. if (sessionState == null) { return false; } string[] encryptionCertificateContent = encryptionCertificate as string[]; string fullCertificateContent = null; if (encryptionCertificateContent != null) { fullCertificateContent = String.Join(Environment.NewLine, encryptionCertificateContent); } else { fullCertificateContent = encryptionCertificate as string; } // If the certificate has changed, drop all of our cached information ResetCertificateCacheIfNeeded(fullCertificateContent); // If we have valid recipients, no need for further analysis. if (s_encryptionRecipients != null) { return true; } // If we've already verified all of the properties of the cert we care about (even if it // didn't result in a valid cert), return now. if (s_hasProcessedCertificate) { return true; } // Resolve the certificate to a recipient CmsMessageRecipient recipient = new CmsMessageRecipient(fullCertificateContent); recipient.Resolve(sessionState, ResolutionPurpose.Encryption, out error); s_hasProcessedCertificate = true; // If there's an error that we haven't already reported, report it in the event log. // We only do this once, as the error will always be the same for a given certificate. if (error != null) { // If we got an error resolving the encryption certificate, log a warning and continue // logging the (unencrypted) message anyways. Logging trumps protected logging - // being able to detect that an attacker has compromised a box outweighs the danger of the // attacker seeing potentially sensitive data. Because if they aren't detected, then // they can just wait on the compromised box and see the sensitive data eventually anyways. string errorMessage = StringUtil.Format(SecuritySupportStrings.CouldNotUseCertificate, error.ToString()); PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); return true; } // Now, save the certificate. We'll be comfortable using this one from now on. s_encryptionRecipients = new CmsMessageRecipient[] { recipient }; // Check if the certificate has a private key, and report a warning if so. // We only do this once, as the error will always be the same for a given certificate. foreach (X509Certificate2 validationCertificate in recipient.Certificates) { if (validationCertificate.HasPrivateKey) { // Only log the first line of what we pulled from the registry. If this is a path, this will have enough information. // If this is the actual certificate, only include the first line of the certificate content so that we're not permanently keeping the private // key in the log. string certificateForLog = fullCertificateContent; if ((encryptionCertificateContent != null) && (encryptionCertificateContent.Length > 1)) { certificateForLog = encryptionCertificateContent[1]; } string errorMessage = StringUtil.Format(SecuritySupportStrings.CertificateContainsPrivateKey, certificateForLog); PSEtwLog.LogOperationalError(PSEventId.ScriptBlock_Compile_Detail, PSOpcode.Create, PSTask.ExecuteCommand, PSKeyword.UseAlwaysAnalytic, 0, 0, errorMessage, scriptBlock.Id.ToString(), scriptBlock.File ?? String.Empty); } } } } } return true; }
internal static string Encrypt(byte[] contentBytes, CmsMessageRecipient[] recipients, SessionState sessionState, out ErrorRecord error) { error = null; if ((contentBytes == null) || (contentBytes.Length == 0)) { return String.Empty; } // After review with the crypto board, NIST_AES256_CBC is more appropriate // than .NET's default 3DES. Also, when specified, uses szOID_RSAES_OAEP for key // encryption to prevent padding attacks. const string szOID_NIST_AES256_CBC = "2.16.840.1.101.3.4.1.42"; ContentInfo content = new ContentInfo(contentBytes); EnvelopedCms cms = new EnvelopedCms(content, new AlgorithmIdentifier( Oid.FromOidValue(szOID_NIST_AES256_CBC, OidGroup.EncryptionAlgorithm))); CmsRecipientCollection recipientCollection = new CmsRecipientCollection(); foreach (CmsMessageRecipient recipient in recipients) { // Resolve the recipient, if it hasn't been done yet. if ((recipient.Certificates != null) && (recipient.Certificates.Count == 0)) { recipient.Resolve(sessionState, ResolutionPurpose.Encryption, out error); } if (error != null) { return null; } foreach (X509Certificate2 certificate in recipient.Certificates) { recipientCollection.Add(new CmsRecipient(certificate)); } } cms.Encrypt(recipientCollection); byte[] encodedBytes = cms.Encode(); string encodedContent = CmsUtils.GetAsciiArmor(encodedBytes); return encodedContent; }