Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes308downloads
SecuritySupport.cs1777 linesDownload Raw Back to security
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#pragma warning disable 1634, 16915#pragma warning disable 565236 7using System.Collections.Generic;8using System.Collections.ObjectModel;9using System.Diagnostics;10using System.Diagnostics.CodeAnalysis;11using System.IO;12using System.Globalization;13using System.Management.Automation.Configuration;14using System.Management.Automation.Internal;15using System.Management.Automation.Security;16using System.Runtime.InteropServices;17using System.Security.Cryptography;18using System.Security.Cryptography.X509Certificates;19using System.Text;20 21using Microsoft.PowerShell;22using Microsoft.PowerShell.Commands;23 24using DWORD = System.UInt32;25 26namespace Microsoft.PowerShell27{28    /// <summary>29    /// Defines the different Execution Policies supported by the30    /// PSAuthorizationManager class.31    /// </summary>32    public enum ExecutionPolicy33    {34        /// Unrestricted - No files must be signed.  If a file originates from the35        ///    internet, PowerShell provides a warning prompt to alert the user.  To36        ///    suppress this warning message, right-click on the file in File Explorer,37        ///    select "Properties," and then "Unblock."38        Unrestricted = 0,39 40        /// RemoteSigned - Only .ps1 and .ps1xml files originating from the internet41        ///    must be digitally signed.  If remote, signed, and executed, PowerShell42        ///    prompts to determine if files from the signing publisher should be43        ///    run or not.  This is the default setting.44        RemoteSigned = 1,45 46        /// AllSigned - All .ps1 and .ps1xml files must be digitally signed.  If47        ///    signed and executed, PowerShell prompts to determine if files from the48        ///    signing publisher should be run or not.49        AllSigned = 2,50 51        /// Restricted - All .ps1 files are blocked.  Ps1xml files must be digitally52        ///    signed, and by a trusted publisher.  If you haven't made a trust decision53        ///    on the publisher yet, prompting is done as in AllSigned mode.54        Restricted = 3,55 56        /// Bypass - No files must be signed, and internet origin is not verified57        Bypass = 4,58 59        /// Undefined - Not specified at this scope60        Undefined = 5,61 62        /// <summary>63        /// Default - The most restrictive policy available.64        /// </summary>65        Default = Restricted66    }67 68    /// <summary>69    /// Defines the available configuration scopes for an execution70    /// policy. They are in the following priority, with successive71    /// elements overriding the items that precede them:72    /// LocalMachine -> CurrentUser -> Runspace.73    /// </summary>74    public enum ExecutionPolicyScope75    {76        /// Execution policy is retrieved from the77        /// PSExecutionPolicyPreference environment variable.78        Process = 0,79 80        /// Execution policy is retrieved from the HKEY_CURRENT_USER81        /// registry hive for the current ShellId.82        CurrentUser = 1,83 84        /// Execution policy is retrieved from the HKEY_LOCAL_MACHINE85        /// registry hive for the current ShellId.86        LocalMachine = 2,87 88        /// Execution policy is retrieved from the current user's89        /// group policy setting.90        UserPolicy = 3,91 92        /// Execution policy is retrieved from the machine-wide93        /// group policy setting.94        MachinePolicy = 495    }96}97 98namespace System.Management.Automation.Internal99{100    /// <summary>101    /// The SAFER policy associated with this file.102    /// </summary>103    internal enum SaferPolicy104    {105        /// Explicitly allowed through an Allow rule106        ExplicitlyAllowed = 0,107 108        /// Allowed because it has not been explicitly disallowed109        Allowed = 1,110 111        /// Disallowed by a rule or policy.112        Disallowed = 2113    }114 115    /// <summary>116    /// Security Support APIs.117    /// </summary>118    public static class SecuritySupport119    {120        #region execution policy121 122        internal static ExecutionPolicyScope[] ExecutionPolicyScopePreferences123        {124            get125            {126                return new ExecutionPolicyScope[] {127                        ExecutionPolicyScope.MachinePolicy,128                        ExecutionPolicyScope.UserPolicy,129                        ExecutionPolicyScope.Process,130                        ExecutionPolicyScope.CurrentUser,131                        ExecutionPolicyScope.LocalMachine132                    };133            }134        }135 136        internal static void SetExecutionPolicy(ExecutionPolicyScope scope, ExecutionPolicy policy, string shellId)137        {138#if UNIX139            throw new PlatformNotSupportedException();140#else141            string executionPolicy = "Restricted";142 143            switch (policy)144            {145                case ExecutionPolicy.Restricted:146                    executionPolicy = "Restricted";147                    break;148                case ExecutionPolicy.AllSigned:149                    executionPolicy = "AllSigned";150                    break;151                case ExecutionPolicy.RemoteSigned:152                    executionPolicy = "RemoteSigned";153                    break;154                case ExecutionPolicy.Unrestricted:155                    executionPolicy = "Unrestricted";156                    break;157                case ExecutionPolicy.Bypass:158                    executionPolicy = "Bypass";159                    break;160            }161 162            // Set the execution policy163            switch (scope)164            {165                case ExecutionPolicyScope.Process:166 167                    if (policy == ExecutionPolicy.Undefined)168                        executionPolicy = null;169 170                    Environment.SetEnvironmentVariable("PSExecutionPolicyPreference", executionPolicy);171                    break;172 173                case ExecutionPolicyScope.CurrentUser:174 175                    // They want to remove it176                    if (policy == ExecutionPolicy.Undefined)177                    {178                        PowerShellConfig.Instance.RemoveExecutionPolicy(ConfigScope.CurrentUser, shellId);179                    }180                    else181                    {182                        PowerShellConfig.Instance.SetExecutionPolicy(ConfigScope.CurrentUser, shellId, executionPolicy);183                    }184 185                    break;186 187                case ExecutionPolicyScope.LocalMachine:188 189                    // They want to remove it190                    if (policy == ExecutionPolicy.Undefined)191                    {192                        PowerShellConfig.Instance.RemoveExecutionPolicy(ConfigScope.AllUsers, shellId);193                    }194                    else195                    {196                        PowerShellConfig.Instance.SetExecutionPolicy(ConfigScope.AllUsers, shellId, executionPolicy);197                    }198 199                    break;200            }201#endif202        }203 204        internal static ExecutionPolicy GetExecutionPolicy(string shellId)205        {206            foreach (ExecutionPolicyScope scope in ExecutionPolicyScopePreferences)207            {208                ExecutionPolicy policy = GetExecutionPolicy(shellId, scope);209                if (policy != ExecutionPolicy.Undefined)210                    return policy;211            }212 213            return ExecutionPolicy.Restricted;214        }215 216        private static bool? _hasGpScriptParent;217 218        /// <summary>219        /// A value indicating that the current process was launched by GPScript.exe220        /// Used to determine execution policy when group policies are in effect.221        /// </summary>222        /// <remarks>223        /// This is somewhat expensive to determine and does not change within the lifetime of the current process224        /// </remarks>225        private static bool HasGpScriptParent226        {227            get228            {229                if (!_hasGpScriptParent.HasValue)230                {231                    _hasGpScriptParent = IsCurrentProcessLaunchedByGpScript();232                }233 234                return _hasGpScriptParent.Value;235            }236        }237 238        private static bool IsCurrentProcessLaunchedByGpScript()239        {240            Process currentProcess = Process.GetCurrentProcess();241            string gpScriptPath = IO.Path.Combine(242                Environment.GetFolderPath(Environment.SpecialFolder.System),243                "gpscript.exe");244 245            bool foundGpScriptParent = false;246            try247            {248                while (currentProcess != null)249                {250                    if (string.Equals(gpScriptPath,251                            currentProcess.MainModule.FileName, StringComparison.OrdinalIgnoreCase))252                    {253                        foundGpScriptParent = true;254                        break;255                    }256                    else257                    {258                        currentProcess = PsUtils.GetParentProcess(currentProcess);259                    }260                }261            }262            catch (System.ComponentModel.Win32Exception)263            {264                // If you attempt to retrieve the MainModule of a 64-bit process265                // from a WOW64 (32-bit) process, the Win32 API has a fatal266                // flaw that causes this to return the error:267                //   "Only part of a ReadProcessMemory or WriteProcessMemory268                //   request was completed."269                // In this case, we just catch the exception and eat it.270                // The implication is that logon / logoff scripts that somehow271                // launch the Wow64 version of PowerShell will be subject272                // to the execution policy deployed by Group Policy (where273                // our goal here is to not have the Group Policy execution policy274                // affect logon / logoff scripts.275            }276 277            return foundGpScriptParent;278        }279 280        internal static ExecutionPolicy GetExecutionPolicy(string shellId, ExecutionPolicyScope scope)281        {282#if UNIX283            return ExecutionPolicy.Unrestricted;284#else285            switch (scope)286            {287                case ExecutionPolicyScope.Process:288                    {289                        string policy = Environment.GetEnvironmentVariable("PSExecutionPolicyPreference");290 291                        if (!string.IsNullOrEmpty(policy))292                            return ParseExecutionPolicy(policy);293                        else294                            return ExecutionPolicy.Undefined;295                    }296 297                case ExecutionPolicyScope.CurrentUser:298                case ExecutionPolicyScope.LocalMachine:299                    {300                        string policy = GetLocalPreferenceValue(shellId, scope);301 302                        if (!string.IsNullOrEmpty(policy))303                            return ParseExecutionPolicy(policy);304                        else305                            return ExecutionPolicy.Undefined;306                    }307 308                // TODO: Group Policy is only supported on Full systems, but !LINUX && CORECLR309                // will run there as well, so I don't think we should remove it.310                case ExecutionPolicyScope.UserPolicy:311                case ExecutionPolicyScope.MachinePolicy:312                    {313                        string groupPolicyPreference = GetGroupPolicyValue(shellId, scope);314 315                        // Be sure we aren't being called by Group Policy316                        // itself. A group policy should never block a logon /317                        // logoff script.318                        if (string.IsNullOrEmpty(groupPolicyPreference) || HasGpScriptParent)319                        {320                            return ExecutionPolicy.Undefined;321                        }322 323                        return ParseExecutionPolicy(groupPolicyPreference);324                    }325            }326 327            return ExecutionPolicy.Restricted;328#endif329        }330 331        internal static ExecutionPolicy ParseExecutionPolicy(string policy)332        {333            if (string.Equals(policy, "Bypass",334                                   StringComparison.OrdinalIgnoreCase))335            {336                return ExecutionPolicy.Bypass;337            }338            else if (string.Equals(policy, "Unrestricted",339                                   StringComparison.OrdinalIgnoreCase))340            {341                return ExecutionPolicy.Unrestricted;342            }343            else if (string.Equals(policy, "RemoteSigned",344                                   StringComparison.OrdinalIgnoreCase))345            {346                return ExecutionPolicy.RemoteSigned;347            }348            else if (string.Equals(policy, "AllSigned",349                              StringComparison.OrdinalIgnoreCase))350            {351                return ExecutionPolicy.AllSigned;352            }353            else if (string.Equals(policy, "Restricted",354                         StringComparison.OrdinalIgnoreCase))355            {356                return ExecutionPolicy.Restricted;357            }358            else359            {360                return ExecutionPolicy.Default;361            }362        }363 364        internal static string GetExecutionPolicy(ExecutionPolicy policy)365        {366            switch (policy)367            {368                case ExecutionPolicy.Bypass:369                    return "Bypass";370                case ExecutionPolicy.Unrestricted:371                    return "Unrestricted";372                case ExecutionPolicy.RemoteSigned:373                    return "RemoteSigned";374                case ExecutionPolicy.AllSigned:375                    return "AllSigned";376                case ExecutionPolicy.Restricted:377                    return "Restricted";378                default:379                    return "Restricted";380            }381        }382 383        /// <summary>384        /// Returns true if file has product binary signature.385        /// </summary>386        /// <param name="file">Name of file to check.</param>387        /// <returns>True when file has product binary signature.</returns>388        public static bool IsProductBinary(string file)389        {390            if (string.IsNullOrEmpty(file) || (!IO.File.Exists(file)))391            {392                return false;393            }394 395            // Check if it is in the product folder, if not, skip checking the catalog396            // and any other checks.397            var isUnderProductFolder = Utils.IsUnderProductFolder(file);398            if (!isUnderProductFolder)399            {400                return false;401            }402 403#if UNIX404            // There is no signature support on non-Windows platforms (yet), when405            // execution reaches here, we are sure the file is under product folder406            return true;407#else408            // Check the file signature409            Signature fileSignature = SignatureHelper.GetSignature(file, null);410            if ((fileSignature != null) && (fileSignature.IsOSBinary))411            {412                return true;413            }414 415            // WTGetSignatureInfo, via Microsoft.Security.Extensions, is used to verify catalog signature.416            // On Win7, catalog API is not available.417            // On OneCore SKUs like NanoServer/IoT, the API has a bug that makes it not able to find the418            // corresponding catalog file for a given product file, so it doesn't work properly.419            // In these cases, we just trust the 'isUnderProductFolder' check.420            if (Signature.CatalogApiAvailable.HasValue && !Signature.CatalogApiAvailable.Value)421            {422                // When execution reaches here, we are sure the file is under product folder423                return true;424            }425 426            return false;427#endif428        }429 430        /// <summary>431        /// Returns the value of the Execution Policy as retrieved432        /// from group policy.433        /// </summary>434        /// <returns>NULL if it is not defined at this level.</returns>435        private static string GetGroupPolicyValue(string shellId, ExecutionPolicyScope scope)436        {437            ConfigScope[] scopeKey = null;438 439            switch (scope)440            {441                case ExecutionPolicyScope.MachinePolicy:442                    scopeKey = Utils.SystemWideOnlyConfig;443                    break;444 445                case ExecutionPolicyScope.UserPolicy:446                    scopeKey = Utils.CurrentUserOnlyConfig;447                    break;448            }449 450            var scriptExecutionSetting = Utils.GetPolicySetting<ScriptExecution>(scopeKey);451            if (scriptExecutionSetting != null)452            {453                if (scriptExecutionSetting.EnableScripts == false)454                {455                    // Script execution is explicitly disabled456                    return "Restricted";457                }458                else if (scriptExecutionSetting.EnableScripts == true)459                {460                    // Script execution is explicitly enabled461                    return scriptExecutionSetting.ExecutionPolicy;462                }463            }464 465            return null;466        }467 468        /// <summary>469        /// Returns the value of the Execution Policy as retrieved470        /// from the local preference.471        /// </summary>472        /// <returns>NULL if it is not defined at this level.</returns>473        private static string GetLocalPreferenceValue(string shellId, ExecutionPolicyScope scope)474        {475            switch (scope)476            {477                // 1: Look up the current-user preference478                case ExecutionPolicyScope.CurrentUser:479                    return PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.CurrentUser, shellId);480 481                // 2: Look up the system-wide preference482                case ExecutionPolicyScope.LocalMachine:483                    return PowerShellConfig.Instance.GetExecutionPolicy(ConfigScope.AllUsers, shellId);484            }485 486            return null;487        }488 489        #endregion execution policy490 491        private static bool _saferIdentifyLevelApiSupported = true;492 493        /// <summary>494        /// Get the pass / fail result of calling the SAFER API.495        /// </summary>496        /// <param name="path">The path to the file in question.</param>497        /// <param name="handle">A file handle to the file in question, if available.</param>498        [SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]499        internal static SaferPolicy GetSaferPolicy(string path, SafeHandle handle)500        {501            SaferPolicy status = SaferPolicy.Allowed;502 503            if (!_saferIdentifyLevelApiSupported)504            {505                return status;506            }507 508            SAFER_CODE_PROPERTIES codeProperties = new SAFER_CODE_PROPERTIES();509            IntPtr hAuthzLevel;510 511            // Prepare the code properties struct.512            codeProperties.cbSize = (uint)Marshal.SizeOf(typeof(SAFER_CODE_PROPERTIES));513            codeProperties.dwCheckFlags = (514                NativeConstants.SAFER_CRITERIA_IMAGEPATH |515                NativeConstants.SAFER_CRITERIA_IMAGEHASH |516                NativeConstants.SAFER_CRITERIA_AUTHENTICODE);517            codeProperties.ImagePath = path;518 519            if (handle != null)520            {521                codeProperties.hImageFileHandle = handle.DangerousGetHandle();522            }523 524            // turn off WinVerifyTrust UI525            codeProperties.dwWVTUIChoice = NativeConstants.WTD_UI_NONE;526 527            // Identify the level associated with the code528            if (NativeMethods.SaferIdentifyLevel(1, ref codeProperties, out hAuthzLevel, NativeConstants.SRP_POLICY_SCRIPT))529            {530                // We found an Authorization Level applicable to this application.531                IntPtr hRestrictedToken = IntPtr.Zero;532                try533                {534                    if (!NativeMethods.SaferComputeTokenFromLevel(535                                               hAuthzLevel,                    // Safer Level536                                               IntPtr.Zero,                    // Test current process' token537                                               ref hRestrictedToken,           // target token538                                               NativeConstants.SAFER_TOKEN_NULL_IF_EQUAL,539                                               IntPtr.Zero))540                    {541                        int lastError = Marshal.GetLastWin32Error();542                        if ((lastError == NativeConstants.ERROR_ACCESS_DISABLED_BY_POLICY) ||543                            (lastError == NativeConstants.ERROR_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY))544                        {545                            status = SaferPolicy.Disallowed;546                        }547                        else548                        {549                            throw new System.ComponentModel.Win32Exception();550                        }551                    }552                    else553                    {554                        if (hRestrictedToken == IntPtr.Zero)555                        {556                            // This is not necessarily the "fully trusted" level,557                            // it means that the thread token is complies with the requested level558                            status = SaferPolicy.Allowed;559                        }560                        else561                        {562                            status = SaferPolicy.Disallowed;563                            NativeMethods.CloseHandle(hRestrictedToken);564                        }565                    }566                }567                finally568                {569                    NativeMethods.SaferCloseLevel(hAuthzLevel);570                }571            }572            else573            {574                int lastError = Marshal.GetLastWin32Error();575                if (lastError == NativeConstants.FUNCTION_NOT_SUPPORTED)576                {577                    _saferIdentifyLevelApiSupported = false;578                }579                else580                {581                    throw new System.ComponentModel.Win32Exception(lastError);582                }583            }584 585            return status;586        }587 588        /// <summary>589        /// Throw if file does not exist.590        /// </summary>591        /// <param name="filePath">Path to file.</param>592        /// <returns>Does not return a value.</returns>593        internal static void CheckIfFileExists(string filePath)594        {595            if (!File.Exists(filePath))596            {597                throw new FileNotFoundException(filePath);598            }599        }600 601        /// <summary>602        /// Check to see if the specified cert is suitable to be603        /// used as a code signing cert.604        /// </summary>605        /// <param name="c">Certificate object.</param>606        /// <returns>True on success, false otherwise.</returns>607        internal static bool CertIsGoodForSigning(X509Certificate2 c)608        {609            if (!c.HasPrivateKey)610            {611                return false;612            }613 614            return CertHasOid(c, CertificateFilterInfo.CodeSigningOid);615        }616 617        /// <summary>618        /// Check to see if the specified cert is suitable to be619        /// used as an encryption cert for PKI encryption. Note620        /// that this cert doesn't require the private key.621        /// </summary>622        /// <param name="c">Certificate object.</param>623        /// <returns>True on success, false otherwise.</returns>624        internal static bool CertIsGoodForEncryption(X509Certificate2 c)625        {626            return (627                CertHasOid(c, CertificateFilterInfo.DocumentEncryptionOid) &&628                (CertHasKeyUsage(c, X509KeyUsageFlags.DataEncipherment) ||629                 CertHasKeyUsage(c, X509KeyUsageFlags.KeyEncipherment)));630        }631 632        /// <summary>633        /// Check to see if the specified cert is expiring by the time.634        /// </summary>635        /// <param name="c">Certificate object.</param>636        /// <param name="expiring">Certificate expire time.</param>637        /// <returns>True on success, false otherwise.</returns>638        internal static bool CertExpiresByTime(X509Certificate2 c, DateTime expiring)639        {640            return c.NotAfter < expiring;641        }642 643        private static bool CertHasOid(X509Certificate2 c, string oid)644        {645            foreach (var extension in c.Extensions)646            {647                if (extension is X509EnhancedKeyUsageExtension ext)648                {649                    foreach (Oid ekuOid in ext.EnhancedKeyUsages)650                    {651                        if (ekuOid.Value == oid)652                        {653                            return true;654                        }655                    }656                    break;657                }658            }659            return false;660        }661 662        private static bool CertHasKeyUsage(X509Certificate2 c, X509KeyUsageFlags keyUsage)663        {664            foreach (X509Extension extension in c.Extensions)665            {666                if (extension is X509KeyUsageExtension keyUsageExtension)667                {668                    if ((keyUsageExtension.KeyUsages & keyUsage) == keyUsage)669                    {670                        return true;671                    }672                    break;673                }674            }675            return false;676        }677 678        /// <summary>679        /// Get the EKUs of a cert.680        /// </summary>681        /// <param name="cert">Certificate object.</param>682        /// <returns>A collection of cert eku strings.</returns>683        internal static Collection<string> GetCertEKU(X509Certificate2 cert)684        {685            Collection<string> ekus = new Collection<string>();686            IntPtr pCert = cert.Handle;687            int structSize = 0;688            IntPtr dummy = IntPtr.Zero;689 690            if (Security.NativeMethods.CertGetEnhancedKeyUsage(pCert, 0, dummy,691                                                      out structSize))692            {693                if (structSize > 0)694                {695                    IntPtr ekuBuffer = Marshal.AllocHGlobal(structSize);696 697                    try698                    {699                        if (Security.NativeMethods.CertGetEnhancedKeyUsage(pCert, 0,700                                                                  ekuBuffer,701                                                                  out structSize))702                        {703                            Security.NativeMethods.CERT_ENHKEY_USAGE ekuStruct =704                                Marshal.PtrToStructure<Security.NativeMethods.CERT_ENHKEY_USAGE>(ekuBuffer);705                            IntPtr ep = ekuStruct.rgpszUsageIdentifier;706                            IntPtr ekuptr;707 708                            for (int i = 0; i < ekuStruct.cUsageIdentifier; i++)709                            {710                                ekuptr = Marshal.ReadIntPtr(ep, i * Marshal.SizeOf(ep));711                                string eku = Marshal.PtrToStringAnsi(ekuptr);712                                ekus.Add(eku);713                            }714                        }715                        else716                        {717                            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());718                        }719                    }720                    finally721                    {722                        Marshal.FreeHGlobal(ekuBuffer);723                    }724                }725            }726            else727            {728                throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());729            }730 731            return ekus;732        }733 734        /// <summary>735        /// Convert an int to a DWORD.736        /// </summary>737        /// <param name="n">Signed int number.</param>738        /// <returns>DWORD.</returns>739        internal static DWORD GetDWORDFromInt(int n)740        {741            UInt32 result = BitConverter.ToUInt32(BitConverter.GetBytes(n), 0);742            return (DWORD)result;743        }744 745        /// <summary>746        /// Convert a DWORD to int.747        /// </summary>748        /// <param name="n">Number.</param>749        /// <returns>Int.</returns>750        internal static int GetIntFromDWORD(DWORD n)751        {752            Int64 n64 = n - 0x100000000L;753            return (int)n64;754        }755    }756 757    /// <summary>758    /// Information used for filtering a set of certs.759    /// </summary>760    internal sealed class CertificateFilterInfo761    {762        internal CertificateFilterInfo()763        {764        }765 766        /// <summary>767        /// Gets or sets purpose of a certificate.768        /// </summary>769        internal CertificatePurpose Purpose770        {771            get;772            set;773        } = CertificatePurpose.NotSpecified;774 775        /// <summary>776        /// Gets or sets SSL Server Authentication.777        /// </summary>778        internal bool SSLServerAuthentication779        {780            get;781 782            set;783        }784 785        /// <summary>786        /// Gets or sets DNS name of a certificate.787        /// </summary>788        internal WildcardPattern DnsName789        {790            get;791            set;792        }793 794        /// <summary>795        /// Gets or sets EKU OID list of a certificate.796        /// </summary>797        internal List<WildcardPattern> Eku798        {799            get;800            set;801        }802 803        /// <summary>804        /// Gets or sets validity time for a certificate.805        /// </summary>806        internal DateTime Expiring807        {808            get;809            set;810        } = DateTime.MinValue;811 812        internal const string CodeSigningOid = "1.3.6.1.5.5.7.3.3";813        internal const string OID_PKIX_KP_SERVER_AUTH = "1.3.6.1.5.5.7.3.1";814 815        // The OID arc 1.3.6.1.4.1.311.80 is assigned to PowerShell. If we need816        // new OIDs, we can assign them under this branch.817        internal const string DocumentEncryptionOid = "1.3.6.1.4.1.311.80.1";818        internal const string SubjectAlternativeNameOid = "2.5.29.17";819    }820}821 822namespace Microsoft.PowerShell.Commands823{824    /// <summary>825    /// Defines the valid purposes by which826    /// we can filter certificates.827    /// </summary>828    internal enum CertificatePurpose829    {830        /// <summary>831        /// Certificates where a purpose has not been specified.832        /// </summary>833        NotSpecified = 0,834 835        /// <summary>836        /// Certificates that can be used to sign837        /// code and scripts.838        /// </summary>839        CodeSigning = 0x1,840 841        /// <summary>842        /// Certificates that can be used to encrypt843        /// data.844        /// </summary>845        DocumentEncryption = 0x2,846 847        /// <summary>848        /// Certificates that can be used for any849        /// purpose.850        /// </summary>851        All = 0xffff852    }853}854 855namespace System.Management.Automation856{857    using System.Management.Automation.Tracing;858    using System.Security.Cryptography.Pkcs;859 860    /// <summary>861    /// Utility class for CMS (Cryptographic Message Syntax) related operations.862    /// </summary>863    internal static class CmsUtils864    {865        internal static string Encrypt(byte[] contentBytes, CmsMessageRecipient[] recipients, SessionState sessionState, out ErrorRecord error)866        {867            error = null;868 869            if ((contentBytes == null) || (contentBytes.Length == 0))870            {871                return string.Empty;872            }873 874            // After review with the crypto board, NIST_AES256_CBC is more appropriate875            // than .NET's default 3DES. Also, when specified, uses szOID_RSAES_OAEP for key876            // encryption to prevent padding attacks.877            const string szOID_NIST_AES256_CBC = "2.16.840.1.101.3.4.1.42";878 879            ContentInfo content = new ContentInfo(contentBytes);880            EnvelopedCms cms = new EnvelopedCms(content,881                new AlgorithmIdentifier(882                    Oid.FromOidValue(szOID_NIST_AES256_CBC, OidGroup.EncryptionAlgorithm)));883 884            CmsRecipientCollection recipientCollection = new CmsRecipientCollection();885            foreach (CmsMessageRecipient recipient in recipients)886            {887                // Resolve the recipient, if it hasn't been done yet.888                if ((recipient.Certificates != null) && (recipient.Certificates.Count == 0))889                {890                    recipient.Resolve(sessionState, ResolutionPurpose.Encryption, out error);891                }892 893                if (error != null)894                {895                    return null;896                }897 898                foreach (X509Certificate2 certificate in recipient.Certificates)899                {900                    recipientCollection.Add(new CmsRecipient(certificate));901                }902            }903 904            cms.Encrypt(recipientCollection);905 906            byte[] encodedBytes = cms.Encode();907            string encodedContent = CmsUtils.GetAsciiArmor(encodedBytes);908            return encodedContent;909        }910 911        internal static readonly string BEGIN_CMS_SIGIL = "-----BEGIN CMS-----";912        internal static readonly string END_CMS_SIGIL = "-----END CMS-----";913 914        internal static readonly string BEGIN_CERTIFICATE_SIGIL = "-----BEGIN CERTIFICATE-----";915        internal static readonly string END_CERTIFICATE_SIGIL = "-----END CERTIFICATE-----";916 917        /// <summary>918        /// Adds Ascii armour to a byte stream in Base64 format.919        /// </summary>920        /// <param name="bytes">The bytes to encode.</param>921        internal static string GetAsciiArmor(byte[] bytes)922        {923            StringBuilder output = new StringBuilder();924            output.AppendLine(BEGIN_CMS_SIGIL);925 926            string encodedString = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);927            output.AppendLine(encodedString);928            output.Append(END_CMS_SIGIL);929 930            return output.ToString();931        }932 933        /// <summary>934        /// Removes Ascii armour from a byte stream.935        /// </summary>936        /// <param name="actualContent">The Ascii armored content.</param>937        /// <param name="beginMarker">The marker of the start of the Base64 content.</param>938        /// <param name="endMarker">The marker of the end of the Base64 content.</param>939        /// <param name="startIndex">The beginning of where the Ascii armor was detected.</param>940        /// <param name="endIndex">The end of where the Ascii armor was detected.</param>941        internal static byte[] RemoveAsciiArmor(string actualContent, string beginMarker, string endMarker, out int startIndex, out int endIndex)942        {943            byte[] messageBytes = null;944            startIndex = -1;945            endIndex = -1;946 947            startIndex = actualContent.IndexOf(beginMarker, StringComparison.OrdinalIgnoreCase);948            if (startIndex < 0)949            {950                return null;951            }952 953            endIndex = actualContent.IndexOf(endMarker, startIndex, StringComparison.OrdinalIgnoreCase) +954                 endMarker.Length;955            if (endIndex < endMarker.Length)956            {957                return null;958            }959 960            int startContent = startIndex + beginMarker.Length;961            int endContent = endIndex - endMarker.Length;962            string encodedContent = actualContent.Substring(startContent, endContent - startContent);963            encodedContent = System.Text.RegularExpressions.Regex.Replace(encodedContent, "\\s", string.Empty);964            messageBytes = Convert.FromBase64String(encodedContent);965 966            return messageBytes;967        }968    }969 970    /// <summary>971    /// Represents a message recipient for the Cms cmdlets.972    /// </summary>973    public class CmsMessageRecipient974    {975        /// <summary>976        /// Creates an instance of the CmsMessageRecipient class.977        /// </summary>978        internal CmsMessageRecipient() { }979 980        /// <summary>981        /// Creates an instance of the CmsMessageRecipient class.982        /// </summary>983        /// <param name="identifier">984        ///     The identifier of the CmsMessageRecipient.985        ///     Can be either:986        ///         - The path to a file containing the certificate987        ///         - The path to a directory containing the certificate988        ///         - The thumbprint of the certificate, used to find the certificate in the certificate store989        ///         - The Subject name of the recipient, used to find the certificate in the certificate store990        /// </param>991        public CmsMessageRecipient(string identifier)992        {993            _identifier = identifier;994            this.Certificates = new X509Certificate2Collection();995        }996 997        private readonly string _identifier;998 999        /// <summary>1000        /// Creates an instance of the CmsMessageRecipient class.1001        /// </summary>1002        /// <param name="certificate">The certificate to use.</param>1003        public CmsMessageRecipient(X509Certificate2 certificate)1004        {1005            _pendingCertificate = certificate;1006            this.Certificates = new X509Certificate2Collection();1007        }1008 1009        private readonly X509Certificate2 _pendingCertificate;1010 1011        /// <summary>1012        /// Gets the certificate associated with this recipient.1013        /// </summary>1014        public X509Certificate2Collection Certificates1015        {1016            get;1017            internal set;1018        }1019 1020        /// <summary>1021        /// Resolves the provided identifier into a collection of certificates.1022        /// </summary>1023        /// <param name="sessionState">A reference to an instance of Powershell's SessionState class.</param>1024        /// <param name="purpose">The purpose for which this identifier is being resolved (Encryption / Decryption.</param>1025        /// <param name="error">The error generated (if any) for this resolution.</param>1026        public void Resolve(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error)1027        {1028            error = null;1029 1030            // Process the certificate if that was supplied exactly1031            if (_pendingCertificate != null)1032            {1033                ProcessResolvedCertificates(1034                    purpose,1035                    new X509Certificate2Collection(_pendingCertificate),1036                    out error);1037                if ((error != null) || (Certificates.Count != 0))1038                {1039                    return;1040                }1041            }1042 1043            if (_identifier != null)1044            {1045                // First try to resolve assuming that the cert was Base64 encoded.1046                ResolveFromBase64Encoding(purpose, out error);1047                if ((error != null) || (Certificates.Count != 0))1048                {1049                    return;1050                }1051 1052                // Then try to resolve by path.1053                ResolveFromPath(sessionState, purpose, out error);1054                if ((error != null) || (Certificates.Count != 0))1055                {1056                    return;1057                }1058 1059                // Then by cert store1060                ResolveFromStoreById(purpose, out error);1061                if ((error != null) || (Certificates.Count != 0))1062                {1063                    return;1064                }1065            }1066 1067            // Generate an error if no cert was found (and this is an encryption attempt).1068            // If it is only decryption, then the system will always look in the 'My' store anyways, so1069            // don't generate an error if they used wildcards. If they did not use wildcards,1070            // then generate an error because they were expecting something specific.1071            if ((purpose == ResolutionPurpose.Encryption) ||1072                (!WildcardPattern.ContainsWildcardCharacters(_identifier)))1073            {1074                error = new ErrorRecord(1075                    new ArgumentException(1076                        string.Format(CultureInfo.InvariantCulture,1077                            SecuritySupportStrings.NoCertificateFound, _identifier)),1078                    "NoCertificateFound", ErrorCategory.ObjectNotFound, _identifier);1079            }1080 1081            return;1082        }1083 1084        private void ResolveFromBase64Encoding(ResolutionPurpose purpose, out ErrorRecord error)1085        {1086            error = null;1087            int startIndex, endIndex;1088            byte[] messageBytes = null;1089            try1090            {1091                messageBytes = CmsUtils.RemoveAsciiArmor(_identifier, CmsUtils.BEGIN_CERTIFICATE_SIGIL, CmsUtils.END_CERTIFICATE_SIGIL, out startIndex, out endIndex);1092            }1093            catch (FormatException)1094            {1095                // Not Base-64 encoded1096                return;1097            }1098 1099            // Didn't have the sigil1100            if (messageBytes == null)1101            {1102                return;1103            }1104 1105            var certificatesToProcess = new X509Certificate2Collection();1106            try1107            {1108                #pragma warning disable SYSLIB00571109                X509Certificate2 newCertificate = new X509Certificate2(messageBytes);1110                #pragma warning restore SYSLIB00571111 1112                certificatesToProcess.Add(newCertificate);1113            }1114            catch (Exception)1115            {1116                // User call-out, catch-all OK1117 1118                // Wasn't certificate data1119                return;1120            }1121 1122            // Now validate the certificate1123            ProcessResolvedCertificates(purpose, certificatesToProcess, out error);1124        }1125 1126        private void ResolveFromPath(SessionState sessionState, ResolutionPurpose purpose, out ErrorRecord error)1127        {1128            error = null;1129            ProviderInfo pathProvider = null;1130            Collection<string> resolvedPaths = null;1131 1132            try1133            {1134                resolvedPaths = sessionState.Path.GetResolvedProviderPathFromPSPath(_identifier, out pathProvider);1135            }1136            catch (SessionStateException)1137            {1138                // If we got an ItemNotFound / etc., then this didn't represent a valid path.1139            }1140 1141            // If we got a resolved path, try to load certs from that path.1142            if ((resolvedPaths != null) && (resolvedPaths.Count != 0))1143            {1144                // Ensure the path is from the file system provider1145                if (!string.Equals(pathProvider.Name, "FileSystem", StringComparison.OrdinalIgnoreCase))1146                {1147                    error = new ErrorRecord(1148                        new ArgumentException(1149                            string.Format(CultureInfo.InvariantCulture,1150                                SecuritySupportStrings.CertificatePathMustBeFileSystemPath, _identifier)),1151                        "CertificatePathMustBeFileSystemPath", ErrorCategory.ObjectNotFound, pathProvider);1152                    return;1153                }1154 1155                // If this is a directory, add all certificates in it. This will be the primary1156                // scenario for decryption via Group Protected PFX files1157                // (http://social.technet.microsoft.com/wiki/contents/articles/13922.certificate-pfx-export-and-import-using-ad-ds-account-protection.aspx)1158                List<string> pathsToAdd = new List<string>();1159                List<string> pathsToRemove = new List<string>();1160                foreach (string resolvedPath in resolvedPaths)1161                {1162                    if (System.IO.Directory.Exists(resolvedPath))1163                    {1164                        // It would be nice to limit this to *.pfx, *.cer, etc., but1165                        // the crypto APIs support extracting certificates from arbitrary file types.1166                        pathsToAdd.AddRange(System.IO.Directory.GetFiles(resolvedPath));1167                        pathsToRemove.Add(resolvedPath);1168                    }1169                }1170 1171                // Update resolved paths1172                foreach (string path in pathsToAdd)1173                {1174                    resolvedPaths.Add(path);1175                }1176 1177                foreach (string path in pathsToRemove)1178                {1179                    resolvedPaths.Remove(path);1180                }1181 1182                var certificatesToProcess = new X509Certificate2Collection();1183                foreach (string path in resolvedPaths)1184                {1185                    X509Certificate2 certificate = null;1186 1187                    try1188                    {1189                        #pragma warning disable SYSLIB00571190                        certificate = new X509Certificate2(path);1191                        #pragma warning restore SYSLIB00571192                    }1193                    catch (Exception)1194                    {1195                        // User call-out, catch-all OK1196                        continue;1197                    }1198 1199                    certificatesToProcess.Add(certificate);1200                }

Showing the first 1,200 of 1777 lines. Download the file for the rest.