MegaBites-AI/Windows-powershell
0372
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System.ComponentModel;5using System.Management.Automation.Internal;6using System.Security.Cryptography.X509Certificates;7 8using DWORD = System.UInt32;9 10namespace System.Management.Automation11{12 internal static class Win32Errors13 {14 internal const DWORD NO_ERROR = 0;15 internal const DWORD E_FAIL = 0x80004005;16 internal const DWORD TRUST_E_NOSIGNATURE = 0x800b0100;17 internal const DWORD TRUST_E_BAD_DIGEST = 0x80096010;18 internal const DWORD TRUST_E_PROVIDER_UNKNOWN = 0x800b0001;19 internal const DWORD TRUST_E_SUBJECT_FORM_UNKNOWN = 0x800B0003;20 internal const DWORD CERT_E_UNTRUSTEDROOT = 0x800b0109;21 internal const DWORD TRUST_E_EXPLICIT_DISTRUST = 0x800B0111;22 internal const DWORD CRYPT_E_BAD_MSG = 0x8009200d;23 internal const DWORD NTE_BAD_ALGID = 0x80090008;24 }25 26 /// <summary>27 /// Defines the valid status flags that a signature28 /// on a file may have.29 /// </summary>30 public enum SignatureStatus31 {32 /// <summary>33 /// The file has a valid signature. This means only that34 /// the signature is syntactically valid. It does not35 /// imply trust in any way.36 /// </summary>37 Valid,38 39 /// <summary>40 /// The file has an invalid signature.41 /// </summary>42 UnknownError,43 44 /// <summary>45 /// The file has no signature.46 /// </summary>47 NotSigned,48 49 /// <summary>50 /// The hash of the file does not match the hash stored51 /// along with the signature.52 /// </summary>53 HashMismatch,54 55 /// <summary>56 /// The certificate was signed by a publisher not trusted57 /// on the system.58 /// </summary>59 NotTrusted,60 61 /// <summary>62 /// The specified file format is not supported by the system63 /// for signing operations. This usually means that the64 /// system does not know how to sign or verify the file65 /// type requested.66 /// </summary>67 NotSupportedFileFormat,68 69 /// <summary>70 /// The signature cannot be verified because it is incompatible71 /// with the current system.72 /// </summary>73 Incompatible74 }75 76 /// <summary>77 /// Defines the valid types of signatures.78 /// </summary>79 public enum SignatureType80 {81 /// <summary>82 /// The file is not signed.83 /// </summary>84 None = 0,85 86 /// <summary>87 /// The signature is an Authenticode signature embedded into the file itself.88 /// </summary>89 Authenticode = 1,90 91 /// <summary>92 /// The signature is a catalog signature.93 /// </summary>94 Catalog = 295 }96 97 /// <summary>98 /// Represents a digital signature on a signed99 /// file.100 /// </summary>101 public sealed class Signature102 {103 private string _path;104 private SignatureStatus _status = SignatureStatus.UnknownError;105 private DWORD _win32Error;106 private X509Certificate2 _signerCert;107 private string _statusMessage = string.Empty;108 private X509Certificate2 _timeStamperCert;109 // private DateTime signedOn = new DateTime(0);110 111 // Three states:112 // - True: we can rely on the catalog API to check catalog signature.113 // - False: we cannot rely on the catalog API, either because it doesn't exist in the OS (win7, nano),114 // or it's not working properly (OneCore SKUs or dev environment where powershell might115 // be updated/refreshed).116 // - Null: it's not determined yet whether catalog API can be relied on or not.117 internal static bool? CatalogApiAvailable = null;118 119 /// <summary>120 /// Gets the X509 certificate of the publisher that121 /// signed the file.122 /// </summary>123 public X509Certificate2 SignerCertificate124 {125 get126 {127 return _signerCert;128 }129 }130 131 /// <summary>132 /// Gets the X509 certificate of the authority that133 /// time-stamped the file.134 /// </summary>135 public X509Certificate2 TimeStamperCertificate136 {137 get138 {139 return _timeStamperCert;140 }141 }142 143 /// <summary>144 /// Gets the status of the signature on the file.145 /// </summary>146 public SignatureStatus Status147 {148 get149 {150 return _status;151 }152 }153 154 /// <summary>155 /// Gets the message corresponding to the status of the156 /// signature on the file.157 /// </summary>158 public string StatusMessage159 {160 get161 {162 return _statusMessage;163 }164 }165 166 /// <summary>167 /// Gets the path of the file to which this signature168 /// applies.169 /// </summary>170 public string Path171 {172 get173 {174 return _path;175 }176 }177 178 /// <summary>179 /// Returns the signature type of the signature.180 /// </summary>181 public SignatureType SignatureType { get; internal set; }182 183 /// <summary>184 /// True if the item is signed as part of an operating system release.185 /// </summary>186 public bool IsOSBinary { get; internal set; }187 188 /// <summary>189 /// Gets the Subject Alternative Name from the signer certificate.190 /// </summary>191 public string[] SubjectAlternativeName { get; private set; }192 193 /// <summary>194 /// Constructor for class Signature195 ///196 /// Call this to create a validated time-stamped signature object.197 /// </summary>198 /// <param name="filePath">This signature is found in this file.</param>199 /// <param name="error">Win32 error code.</param>200 /// <param name="signer">Cert of the signer.</param>201 /// <param name="timestamper">Cert of the time stamper.</param>202 /// <returns>Constructed object.</returns>203 internal Signature(string filePath,204 DWORD error,205 X509Certificate2 signer,206 X509Certificate2 timestamper)207 {208 Utils.CheckArgForNullOrEmpty(filePath, "filePath");209 Utils.CheckArgForNull(signer, "signer");210 Utils.CheckArgForNull(timestamper, "timestamper");211 212 Init(filePath, signer, error, timestamper);213 }214 215 /// <summary>216 /// Constructor for class Signature217 ///218 /// Call this to create a validated signature object.219 /// </summary>220 /// <param name="filePath">This signature is found in this file.</param>221 /// <param name="signer">Cert of the signer.</param>222 /// <returns>Constructed object.</returns>223 internal Signature(string filePath,224 X509Certificate2 signer)225 {226 Utils.CheckArgForNullOrEmpty(filePath, "filePath");227 Utils.CheckArgForNull(signer, "signer");228 229 Init(filePath, signer, 0, null);230 }231 232 /// <summary>233 /// Constructor for class Signature234 ///235 /// Call this ctor when creating an invalid signature object.236 /// </summary>237 /// <param name="filePath">This signature is found in this file.</param>238 /// <param name="error">Win32 error code.</param>239 /// <param name="signer">Cert of the signer.</param>240 /// <returns>Constructed object.</returns>241 internal Signature(string filePath,242 DWORD error,243 X509Certificate2 signer)244 {245 Utils.CheckArgForNullOrEmpty(filePath, "filePath");246 Utils.CheckArgForNull(signer, "signer");247 248 Init(filePath, signer, error, null);249 }250 251 /// <summary>252 /// Constructor for class Signature253 ///254 /// Call this ctor when creating an invalid signature object.255 /// </summary>256 /// <param name="filePath">This signature is found in this file.</param>257 /// <param name="error">Win32 error code.</param>258 /// <returns>Constructed object.</returns>259 internal Signature(string filePath, DWORD error)260 {261 Utils.CheckArgForNullOrEmpty(filePath, "filePath");262 263 Init(filePath, null, error, null);264 }265 266 private void Init(string filePath,267 X509Certificate2 signer,268 DWORD error,269 X509Certificate2 timestamper)270 {271 _path = filePath;272 _win32Error = error;273 _signerCert = signer;274 _timeStamperCert = timestamper;275 SignatureType = SignatureType.None;276 277 SignatureStatus isc =278 GetSignatureStatusFromWin32Error(error);279 280 _status = isc;281 282 _statusMessage = GetSignatureStatusMessage(isc,283 error,284 filePath);285 286 // Extract Subject Alternative Name from the signer certificate287 SubjectAlternativeName = GetSubjectAlternativeName(signer);288 }289 290 private static SignatureStatus GetSignatureStatusFromWin32Error(DWORD error)291 {292 SignatureStatus isc = SignatureStatus.UnknownError;293 294 switch (error)295 {296 case Win32Errors.NO_ERROR:297 isc = SignatureStatus.Valid;298 break;299 300 case Win32Errors.NTE_BAD_ALGID:301 isc = SignatureStatus.Incompatible;302 break;303 304 case Win32Errors.TRUST_E_NOSIGNATURE:305 isc = SignatureStatus.NotSigned;306 break;307 308 case Win32Errors.TRUST_E_BAD_DIGEST:309 case Win32Errors.CRYPT_E_BAD_MSG:310 isc = SignatureStatus.HashMismatch;311 break;312 313 case Win32Errors.TRUST_E_PROVIDER_UNKNOWN:314 isc = SignatureStatus.NotSupportedFileFormat;315 break;316 317 case Win32Errors.TRUST_E_EXPLICIT_DISTRUST:318 isc = SignatureStatus.NotTrusted;319 break;320 }321 322 return isc;323 }324 325 private static string GetSignatureStatusMessage(SignatureStatus status,326 DWORD error,327 string filePath)328 {329 string message = null;330 string resourceString = null;331 string arg = null;332 333 switch (status)334 {335 case SignatureStatus.Valid:336 resourceString = MshSignature.MshSignature_Valid;337 break;338 339 case SignatureStatus.UnknownError:340 int intError = SecuritySupport.GetIntFromDWORD(error);341 Win32Exception e = new Win32Exception(intError);342 message = e.Message;343 break;344 345 case SignatureStatus.Incompatible:346 if (error == Win32Errors.NTE_BAD_ALGID)347 {348 resourceString = MshSignature.MshSignature_Incompatible_HashAlgorithm;349 }350 else351 {352 resourceString = MshSignature.MshSignature_Incompatible;353 }354 355 arg = filePath;356 break;357 358 case SignatureStatus.NotSigned:359 resourceString = MshSignature.MshSignature_NotSigned;360 arg = filePath;361 break;362 363 case SignatureStatus.HashMismatch:364 resourceString = MshSignature.MshSignature_HashMismatch;365 arg = filePath;366 break;367 368 case SignatureStatus.NotTrusted:369 resourceString = MshSignature.MshSignature_NotTrusted;370 arg = filePath;371 break;372 373 case SignatureStatus.NotSupportedFileFormat:374 resourceString = MshSignature.MshSignature_NotSupportedFileFormat;375 arg = System.IO.Path.GetExtension(filePath);376 377 if (string.IsNullOrEmpty(arg))378 {379 resourceString = MshSignature.MshSignature_NotSupportedFileFormat_NoExtension;380 arg = null;381 }382 383 break;384 }385 386 if (message == null)387 {388 if (arg == null)389 {390 message = resourceString;391 }392 else393 {394 message = StringUtil.Format(resourceString, arg);395 }396 }397 398 return message;399 }400 401 /// <summary>402 /// Extracts the Subject Alternative Name from the certificate.403 /// </summary>404 /// <param name="certificate">The certificate to extract SAN from.</param>405 /// <returns>Array of SAN entries or null if not found.</returns>406 private static string[] GetSubjectAlternativeName(X509Certificate2 certificate)407 {408 if (certificate == null)409 {410 return null;411 }412 413 foreach (X509Extension extension in certificate.Extensions)414 {415 if (extension.Oid != null && extension.Oid.Value == CertificateFilterInfo.SubjectAlternativeNameOid)416 {417 string formatted = extension.Format(multiLine: true);418 if (string.IsNullOrEmpty(formatted))419 {420 return null;421 }422 423 return formatted.Split(new[] { "\r\n", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries);424 }425 }426 427 return null;428 }429 }430}431 