Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SignatureCommands.cs624 linesDownload Raw Back to security
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.ObjectModel;6using System.Diagnostics.CodeAnalysis;7using System.IO;8using System.Management.Automation;9using System.Management.Automation.Internal;10using System.Security.Cryptography.X509Certificates;11 12using Dbg = System.Management.Automation.Diagnostics;13 14namespace Microsoft.PowerShell.Commands15{16    /// <summary>17    /// Defines the base class from which all signature commands18    /// are derived.19    /// </summary>20    public abstract class SignatureCommandsBase : PSCmdlet21    {22        /// <summary>23        /// Gets or sets the path to the file for which to get or set the24        /// digital signature.25        /// </summary>26        [Parameter(Position = 0, Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByPath")]27        public string[] FilePath28        {29            get30            {31                return _path;32            }33 34            set35            {36                _path = value;37            }38        }39 40        private string[] _path;41 42        /// <summary>43        /// Gets or sets the literal path to the file for which to get or set the44        /// digital signature.45        /// </summary>46        [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByLiteralPath")]47        [Alias("PSPath", "LP")]48        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]49        public string[] LiteralPath50        {51            get52            {53                return _path;54            }55 56            set57            {58                _path = value;59                _isLiteralPath = true;60            }61        }62 63        private bool _isLiteralPath = false;64 65        /// <summary>66        /// Gets or sets the digital signature to be written to67        /// the output pipeline.68        /// </summary>69        protected Signature Signature70        {71            get { return _signature; }72 73            set { _signature = value; }74        }75 76        private Signature _signature;77 78        /// <summary>79        /// Gets or sets the file type of the byte array containing the content with80        /// digital signature.81        /// </summary>82        [Parameter(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByContent")]83        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]84        public string[] SourcePathOrExtension85        {86            get87            {88                return _sourcePathOrExtension;89            }90 91            set92            {93                _sourcePathOrExtension = value;94            }95        }96 97        private string[] _sourcePathOrExtension;98 99        /// <summary>100        /// File contents as a byte array.101        /// </summary>102        [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, ParameterSetName = "ByContent")]103        [ValidateNotNullOrEmpty]104        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]105        public byte[] Content106        {107            get108            {109                return _content;110            }111 112            set113            {114                _content = value;115            }116        }117 118        private byte[] _content;119 120        //121        // name of this command122        //123        private readonly string _commandName;124 125        /// <summary>126        /// Initializes a new instance of the SignatureCommandsBase class,127        /// using the given command name.128        /// </summary>129        /// <param name="name">130        /// The name of the command.131        /// </param>132        protected SignatureCommandsBase(string name) : base()133        {134            _commandName = name;135        }136 137        //138        // hide default ctor139        //140        private SignatureCommandsBase() : base() { }141 142        /// <summary>143        /// Processes records from the input pipeline.144        /// For each input object, the command gets or145        /// sets the digital signature on the object, and146        /// and exports the object.147        /// </summary>148        protected override void ProcessRecord()149        {150            if (Content == null)151            {152                //153                // this cannot happen as we have specified the Path154                // property to be mandatory parameter155                //156                Dbg.Assert((FilePath != null) && (FilePath.Length > 0),157                    "GetSignatureCommand: Param binder did not bind path");158 159                foreach (string p in FilePath)160                {161                    Collection<string> paths = new();162 163                    // Expand wildcard characters164                    if (_isLiteralPath)165                    {166                        paths.Add(SessionState.Path.GetUnresolvedProviderPathFromPSPath(p));167                    }168                    else169                    {170                        try171                        {172                            foreach (PathInfo tempPath in SessionState.Path.GetResolvedPSPathFromPSPath(p))173                            {174                                paths.Add(tempPath.ProviderPath);175                            }176                        }177                        catch (ItemNotFoundException)178                        {179                            WriteError(180                                SecurityUtils.CreateFileNotFoundErrorRecord(181                                    SignatureCommands.FileNotFound,182                                    "SignatureCommandsBaseFileNotFound", p));183                        }184                    }185 186                    if (paths.Count == 0)187                        continue;188 189                    bool foundFile = false;190 191                    foreach (string path in paths)192                    {193                        if (!System.IO.Directory.Exists(path))194                        {195                            foundFile = true;196 197                            string resolvedFilePath = SecurityUtils.GetFilePathOfExistingFile(this, path);198 199                            if (resolvedFilePath == null)200                            {201                                WriteError(SecurityUtils.CreateFileNotFoundErrorRecord(202                                    SignatureCommands.FileNotFound,203                                    "SignatureCommandsBaseFileNotFound",204                                    path));205                            }206                            else207                            {208                                if ((Signature = PerformAction(resolvedFilePath)) != null)209                                {210                                    WriteObject(Signature);211                                }212                            }213                        }214                    }215 216                    if (!foundFile)217                    {218                        WriteError(SecurityUtils.CreateFileNotFoundErrorRecord(219                            SignatureCommands.CannotRetrieveFromContainer,220                            "SignatureCommandsBaseCannotRetrieveFromContainer"));221                    }222                }223            }224            else225            {226                foreach (string sourcePathOrExtension in SourcePathOrExtension)227                {228                    if ((Signature = PerformAction(sourcePathOrExtension, Content)) != null)229                    {230                        WriteObject(Signature);231                    }232                }233            }234        }235 236        /// <summary>237        /// Performs the action (ie: get signature, or set signature)238        /// on the specified file.239        /// </summary>240        /// <param name="filePath">241        /// The name of the file on which to perform the action.242        /// </param>243        protected abstract Signature PerformAction(string filePath);244 245        /// <summary>246        /// Performs the action (ie: get signature, or set signature)247        /// on the specified contents.248        /// </summary>249        /// <param name="fileName">250        /// The filename used for type if content is specified.251        /// </param>252        /// <param name="content">253        /// The file contents on which to perform the action.254        /// </param>255        protected abstract Signature PerformAction(string fileName, byte[] content);256    }257 258    /// <summary>259    /// Defines the implementation of the 'get-AuthenticodeSignature' cmdlet.260    /// This cmdlet extracts the digital signature from the given file.261    /// </summary>262    [Cmdlet(VerbsCommon.Get, "AuthenticodeSignature", DefaultParameterSetName = "ByPath", HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096823")]263    [OutputType(typeof(Signature))]264    public sealed class GetAuthenticodeSignatureCommand : SignatureCommandsBase265    {266        /// <summary>267        /// Initializes a new instance of the GetSignatureCommand class.268        /// </summary>269        public GetAuthenticodeSignatureCommand() : base("Get-AuthenticodeSignature") { }270 271        /// <summary>272        /// Gets the signature from the specified file.273        /// </summary>274        /// <param name="filePath">275        /// The name of the file on which to perform the action.276        /// </param>277        /// <returns>278        /// The signature on the specified file.279        /// </returns>280        protected override Signature PerformAction(string filePath)281        {282            return SignatureHelper.GetSignature(filePath, null);283        }284 285        /// <summary>286        /// Gets the signature from the specified file contents.287        /// </summary>288        /// <param name="sourcePathOrExtension">The file type associated with the contents.</param>289        /// <param name="content">290        /// The contents of the file on which to perform the action.291        /// </param>292        /// <returns>293        /// The signature on the specified file contents.294        /// </returns>295        protected override Signature PerformAction(string sourcePathOrExtension, byte[] content)296        {297            return SignatureHelper.GetSignature(sourcePathOrExtension, content);298        }299    }300 301    /// <summary>302    /// Defines the implementation of the 'set-AuthenticodeSignature' cmdlet.303    /// This cmdlet sets the digital signature on a given file.304    /// </summary>305    [Cmdlet(VerbsCommon.Set, "AuthenticodeSignature", SupportsShouldProcess = true, DefaultParameterSetName = "ByPath",306        HelpUri = "https://go.microsoft.com/fwlink/?LinkID=2096919")]307    [OutputType(typeof(Signature))]308    public sealed class SetAuthenticodeSignatureCommand : SignatureCommandsBase309    {310        /// <summary>311        /// Initializes a new instance of the SetAuthenticodeSignatureCommand class.312        /// </summary>313        public SetAuthenticodeSignatureCommand() : base("set-AuthenticodeSignature") { }314 315        /// <summary>316        /// Gets or sets the certificate with which to sign the317        /// file.318        /// </summary>319        [Parameter(Position = 1, Mandatory = true)]320        public X509Certificate2 Certificate321        {322            get323            {324                return _certificate;325            }326 327            set328            {329                _certificate = value;330            }331        }332 333        private X509Certificate2 _certificate;334 335        /// <summary>336        /// Gets or sets the additional certificates to337        /// include in the digital signature.338        /// Use 'signer' to include only the signer's certificate.339        /// Use 'notroot' to include all certificates in the certificate340        ///    chain, except for the root authority.341        /// Use 'all' to include all certificates in the certificate chain.342        ///343        /// Defaults to 'notroot'.344        /// </summary>345        [Parameter(Mandatory = false)]346        [ValidateSet("signer", "notroot", "all")]347        public string IncludeChain348        {349            get350            {351                return _includeChain;352            }353 354            set355            {356                _includeChain = value;357            }358        }359 360        private string _includeChain = "notroot";361 362        /// <summary>363        /// Gets or sets the Url of the time stamping server.364        /// The time stamping server certifies the exact time365        /// that the certificate was added to the file.366        /// </summary>367        [Parameter(Mandatory = false)]368        public string TimestampServer369        {370            get371            {372                return _timestampServer;373            }374 375            set376            {377                value ??= string.Empty;378 379                _timestampServer = value;380            }381        }382 383        private string _timestampServer = string.Empty;384 385        /// <summary>386        /// Gets or sets the hash algorithm used for signing.387        /// This string value must represent the name of a Cryptographic Algorithm388        /// Identifier supported by Windows.389        /// </summary>390        [Parameter(Mandatory = false)]391        public string HashAlgorithm392        {393            get394            {395                return _hashAlgorithm;396            }397 398            set399            {400                _hashAlgorithm = value;401            }402        }403 404        private string _hashAlgorithm = "SHA256";405 406        /// <summary>407        /// Property that sets force parameter.408        /// </summary>409        [Parameter]410        public SwitchParameter Force411        {412            get413            {414                return _force;415            }416 417            set418            {419                _force = value;420            }421        }422 423        private bool _force;424 425        /// <summary>426        /// Sets the digital signature on the specified file.427        /// </summary>428        /// <param name="filePath">429        /// The name of the file on which to perform the action.430        /// </param>431        /// <returns>432        /// The signature on the specified file.433        /// </returns>434        protected override Signature PerformAction(string filePath)435        {436            SigningOption option = GetSigningOption(IncludeChain);437 438            if (Certificate == null)439            {440                throw PSTraceSource.NewArgumentNullException("certificate");441            }442 443            //444            // if the cert is not good for signing, we cannot445            // process any more files. Exit the command.446            //447            if (!SecuritySupport.CertIsGoodForSigning(Certificate))448            {449                Exception e = PSTraceSource.NewArgumentException(450                        "certificate",451                        SignatureCommands.CertNotGoodForSigning);452 453                throw e;454            }455 456            if (!ShouldProcess(filePath))457                return null;458 459            FileInfo readOnlyFileInfo = null;460            try461            {462                if (this.Force)463                {464                    try465                    {466                        // remove readonly attributes on the file467                        FileInfo fInfo = new(filePath);468                        if (fInfo != null)469                        {470                            // Save some disk write time by checking whether file is readonly..471                            if ((fInfo.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)472                            {473                                // remember to reset the read-only attribute later474                                readOnlyFileInfo = fInfo;475                                // Make sure the file is not read only476                                fInfo.Attributes &= ~(FileAttributes.ReadOnly);477                            }478                        }479                    }480                    // These are the known exceptions for File.Load and StreamWriter.ctor481                    catch (ArgumentException e)482                    {483                        ErrorRecord er = new(484                            e,485                            "ForceArgumentException",486                            ErrorCategory.WriteError,487                            filePath);488                        WriteError(er);489                        return null;490                    }491                    catch (IOException e)492                    {493                        ErrorRecord er = new(494                            e,495                            "ForceIOException",496                            ErrorCategory.WriteError,497                            filePath);498                        WriteError(er);499                        return null;500                    }501                    catch (UnauthorizedAccessException e)502                    {503                        ErrorRecord er = new(504                            e,505                            "ForceUnauthorizedAccessException",506                            ErrorCategory.PermissionDenied,507                            filePath);508                        WriteError(er);509                        return null;510                    }511                    catch (NotSupportedException e)512                    {513                        ErrorRecord er = new(514                            e,515                            "ForceNotSupportedException",516                            ErrorCategory.WriteError,517                            filePath);518                        WriteError(er);519                        return null;520                    }521                    catch (System.Security.SecurityException e)522                    {523                        ErrorRecord er = new(524                            e,525                            "ForceSecurityException",526                            ErrorCategory.PermissionDenied,527                            filePath);528                        WriteError(er);529                        return null;530                    }531                }532 533                //534                // ProcessRecord() code in base class has already535                // ascertained that filePath really represents an existing536                // file. Thus we can safely call GetFileSize() below.537                //538 539                if (SecurityUtils.GetFileSize(filePath) < 4)540                {541                    // Note that the message param comes first542                    string message = string.Format(543                        System.Globalization.CultureInfo.CurrentCulture,544                        UtilsStrings.FileSmallerThan4Bytes, filePath);545 546                    PSArgumentException e = new(message, nameof(filePath));547                    ErrorRecord er = SecurityUtils.CreateInvalidArgumentErrorRecord(548                            e,549                            "SignatureCommandsBaseFileSmallerThan4Bytes"550                            );551 552                    WriteError(er);553 554                    return null;555                }556 557                return SignatureHelper.SignFile(option,558                                                filePath,559                                                Certificate,560                                                TimestampServer,561                                                _hashAlgorithm);562            }563            finally564            {565                // reset the read-only attribute566                if (readOnlyFileInfo != null)567                {568                    readOnlyFileInfo.Attributes |= FileAttributes.ReadOnly;569                }570            }571        }572 573        /// <summary>574        /// Not implemented.575        /// </summary>576        protected override Signature PerformAction(string sourcePathOrExtension, byte[] content)577        {578            throw new NotImplementedException();579        }580 581        private struct SigningOptionInfo582        {583            internal SigningOption option;584            internal string optionName;585 586            internal SigningOptionInfo(SigningOption o, string n)587            {588                option = o;589                optionName = n;590            }591        }592 593        /// <summary>594        /// Association between SigningOption.* values and the595        /// corresponding string names.596        /// </summary>597        private static readonly SigningOptionInfo[] s_sigOptionInfo =598        {599            new SigningOptionInfo(SigningOption.AddOnlyCertificate, "signer"),600            new SigningOptionInfo(SigningOption.AddFullCertificateChainExceptRoot, "notroot"),601            new SigningOptionInfo(SigningOption.AddFullCertificateChain, "all")602        };603 604        /// <summary>605        /// Get SigningOption value corresponding to a string name.606        /// </summary>607        /// <param name="optionName">Name of option.</param>608        /// <returns>SigningOption.</returns>609        private static SigningOption GetSigningOption(string optionName)610        {611            foreach (SigningOptionInfo si in s_sigOptionInfo)612            {613                if (string.Equals(optionName, si.optionName,614                                  StringComparison.OrdinalIgnoreCase))615                {616                    return si.option;617                }618            }619 620            return SigningOption.AddFullCertificateChainExceptRoot;621        }622    }623}624