internal AuthenticodeSignatureInformation(X509Native.AXL_AUTHENTICODE_SIGNER_INFO signer, X509Chain signatureChain, TimestampInformation timestamp) { m_verificationResult = (SignatureVerificationResult)signer.dwError; m_hashAlgorithmId = signer.algHash; if (signer.pwszDescription != IntPtr.Zero) { m_description = Marshal.PtrToStringUni(signer.pwszDescription); } if (signer.pwszDescriptionUrl != IntPtr.Zero) { string descriptionUrl = Marshal.PtrToStringUni(signer.pwszDescriptionUrl); Uri.TryCreate(descriptionUrl, UriKind.RelativeOrAbsolute, out m_descriptionUrl); } m_signatureChain = signatureChain; // If there was a timestamp, and it was not valid we need to invalidate the entire Authenticode // signature as well, since we cannot assume that the signature would have verified without // the timestamp. if (timestamp != null && timestamp.VerificationResult != SignatureVerificationResult.MissingSignature) { if (timestamp.IsValid) { m_timestamp = timestamp; } else { m_verificationResult = SignatureVerificationResult.InvalidTimestamp; } } else { m_timestamp = null; } }
public static X509Certificate2 CreateSelfSignedCertificate(this CngKey key, X509Certificates.X509CertificateCreationParameters creationParameters) { if (creationParameters == null) { throw new ArgumentNullException("creationParameters"); } // If we are not being asked to hand ownership of the key over to the certificate, then we need // ensure that we are running in a trusted context as we have no way to ensure that the caller // will not force the key to be cleaned up and then continue to use the dangling handle left in // the certificate. if (!creationParameters.TakeOwnershipOfKey) { new PermissionSet(PermissionState.Unrestricted).Demand(); } using (SafeCertContextHandle selfSignedCertHandle = X509Native.CreateSelfSignedCertificate(key, creationParameters.TakeOwnershipOfKey, creationParameters.SubjectName.RawData, creationParameters.CertificateCreationOptions, X509Native.MapCertificateSignatureAlgorithm(creationParameters.SignatureAlgorithm), creationParameters.StartTime, creationParameters.EndTime, creationParameters.ExtensionsNoDemand)) { // We need to get the raw handle out of the safe handle because X509Certificate2 only // exposes an IntPtr constructor. To do that we'll temporarially bump the ref count on // the handle. // // X509Certificate2 will duplicate the handle value in the .ctor, so once we've created // the certificate object, we can safely drop the ref count and dispose of our handle. X509Certificate2 certificate = null; bool addedRef = false; RuntimeHelpers.PrepareConstrainedRegions(); try { selfSignedCertHandle.DangerousAddRef(ref addedRef); certificate = new X509Certificate2(selfSignedCertHandle.DangerousGetHandle()); } finally { if (addedRef) { selfSignedCertHandle.DangerousRelease(); } } // If we passed ownership of the key to the certificate, than destroy the key // now so that we don't continue to use it beyond the liftime of the cert. if (creationParameters.TakeOwnershipOfKey) { key.Dispose(); } return(certificate); } }
internal static SafeCertContextHandle GetCertificateContext(X509Certificate certificate) { SafeCertContextHandle certContext = X509Native.DuplicateCertContext(certificate.Handle); // Make sure to keep the X509Certificate object alive until after its certificate context is // duplicated, otherwise it could end up being closed out from underneath us before we get a // chance to duplicate the handle. GC.KeepAlive(certificate); return(certContext); }
internal static CngKey GetCngPrivateKey(X509Certificate2 certificate) { using (var certContext = GetCertificateContext(certificate)) using (SafeNCryptKeyHandle privateKeyHandle = X509Native.AcquireCngPrivateKey(certContext)) { // We need to assert for full trust when opening the CNG key because // CngKey.Open(SafeNCryptKeyHandle) does a full demand for full trust, and we want to allow // access to a certificate's private key by anyone who has access to the certificate itself. new PermissionSet(PermissionState.Unrestricted).Assert(); return(CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None)); } }
internal TimestampInformation(X509Native.AXL_AUTHENTICODE_TIMESTAMPER_INFO timestamper) { m_hashAlgorithmId = timestamper.algHash; m_verificationResult = (SignatureVerificationResult)timestamper.dwError; ulong filetime = ((ulong)((uint)timestamper.ftTimestamp.dwHighDateTime) << 32) | (ulong)((uint)timestamper.ftTimestamp.dwLowDateTime); m_timestamp = DateTime.FromFileTimeUtc((long)filetime); if (timestamper.pChainContext != IntPtr.Zero) { m_timestampChain = new X509Chain(timestamper.pChainContext); } }
public static X509Certificate2 CreateSelfSignedCertificate(this CngKey key, X509CertificateCreationParameters creationParameters) { if (creationParameters == null) { throw new ArgumentNullException("creationParameters"); } using (SafeNCryptKeyHandle keyHandle = key.Handle) { using (SafeCertificateContextHandle selfSignedCertHandle = X509Native.CreateSelfSignedCertificate(keyHandle, creationParameters.SubjectName.RawData, creationParameters.CertificateCreationOptions, X509Native.MapCertificateSignatureAlgorithm(creationParameters.SignatureAlgorithm), creationParameters.StartTime, creationParameters.EndTime, creationParameters.ExtensionsNoDemand)) { // We need to get the raw handle out of the safe handle because X509Certificate2 only // exposes an IntPtr constructor. To do that we'll temporarially bump the ref count on // the handle. // // X509Certificate2 will duplicate the handle value in the .ctor, so once we've created // the certificate object, we can safely drop the ref count and dispose of our handle. bool addedRef = false; RuntimeHelpers.PrepareConstrainedRegions(); try { selfSignedCertHandle.DangerousAddRef(ref addedRef); return(new X509Certificate2(selfSignedCertHandle.DangerousGetHandle())); } finally { if (addedRef) { selfSignedCertHandle.DangerousRelease(); } } } } }
private X509Chain BuildSignatureChain(X509Native.AXL_AUTHENTICODE_SIGNER_INFO signer, XmlElement licenseNode, X509RevocationFlag revocationFlag, X509RevocationMode revocationMode) { Debug.Assert(licenseNode != null, "licenseNode != null"); X509Chain signatureChain = null; if (signer.pChainContext != IntPtr.Zero) { signatureChain = new X509Chain(signer.pChainContext); } else if (signer.dwError == (int)SignatureVerificationResult.UntrustedRootCertificate) { // CertVerifyAuthenticodeLicense will not return the certificate chain for self signed certificates // so we'll need to extract the certificate from the signature ourselves. XmlElement x509Data = licenseNode.SelectSingleNode("r:issuer/ds:Signature/ds:KeyInfo/ds:X509Data", m_namespaceManager) as XmlElement; if (x509Data != null) { XmlNodeList certificateNodes = x509Data.SelectNodes("ds:X509Certificate", m_namespaceManager); // A manifest could have many X509Certificate nodes in its X509Data, which may include the // signing certificate, links on the chain to a root, or certificates not used at all in // the chain. Since we don't know which certificate actually did the signing, we only // process the chain if we have a single certificate. if (certificateNodes.Count == 1 && certificateNodes[0] is XmlElement) { byte[] rawCertificate = Convert.FromBase64String(certificateNodes[0].InnerText.Trim()); X509Certificate2 signingCertificate = new X509Certificate2(rawCertificate); signatureChain = new X509Chain(); signatureChain.ChainPolicy.RevocationFlag = revocationFlag; signatureChain.ChainPolicy.RevocationMode = revocationMode; signatureChain.Build(signingCertificate); } } } return signatureChain; }
private X509Chain BuildSignatureChain(X509Native.AXL_AUTHENTICODE_SIGNER_INFO signer, XmlElement licenseNode, X509RevocationFlag revocationFlag, X509RevocationMode revocationMode) { X509Chain chain = null; if (signer.dwError == -2146762487) { XmlElement element = licenseNode.SelectSingleNode("r:issuer/ds:Signature/ds:KeyInfo/ds:X509Data", this.m_namespaceManager) as XmlElement; if (element != null) { X509Certificate2 certificate = new X509Certificate2(Convert.FromBase64String(element.InnerText.Trim())); chain = new X509Chain { ChainPolicy = { RevocationFlag = revocationFlag, RevocationMode = revocationMode } }; chain.Build(certificate); } return chain; } if (signer.pChainContext != IntPtr.Zero) { chain = new X509Chain(signer.pChainContext); } return chain; }
private TimestampInformation GetTimestampInformation(X509Native.AXL_AUTHENTICODE_TIMESTAMPER_INFO timestamper, XmlElement licenseNode) { Debug.Assert(licenseNode != null, "licenseNode != null"); TimestampInformation timestamp = null; // If the timestamper is a trusted publisher, then CAPI has done the work for us; // If the leaf certificate is not explicitly a trusted publisher, CAPI will not process // the timestamp information so we will verify it ourselves. In any other case, we will // return no timestamp information. if (timestamper.dwError == (int)SignatureVerificationResult.Valid) { timestamp = new TimestampInformation(timestamper); } else if (timestamper.dwError == (int)SignatureVerificationResult.CertificateNotExplicitlyTrusted || timestamper.dwError == (int)SignatureVerificationResult.MissingSignature) { XmlElement timestampElement = licenseNode.SelectSingleNode("r:issuer/ds:Signature/ds:Object/as:Timestamp", m_namespaceManager) as XmlElement; if (timestampElement != null) { // The timestamp is held as a parameter of a base64 encoded PKCS7 message in the signature byte[] timestampBlob = Convert.FromBase64String(timestampElement.InnerText); try { SignedCms timestampCms = new SignedCms(); timestampCms.Decode(timestampBlob); timestampCms.CheckSignature(true); // The SignedCms class does not expose a way to read arbitrary properties from the // message, nor does it expose the HCRYPTMSG to P/Invoke with. We cannot access the // actual timestamp because of this, so for signatures which are not created by a // trusted publisher, we will return a null timestamp. This should be corrected in // v3 of the CLR, as we can extend SignedCms to have the properties we need to // pull all of this information. timestamp = null; } catch (CryptographicException e) { timestamp = new TimestampInformation((SignatureVerificationResult)Marshal.GetHRForException(e)); } } } else { timestamp = null; } return timestamp; }
private TimestampInformation GetTimestampInformation(X509Native.AXL_AUTHENTICODE_TIMESTAMPER_INFO timestamper, XmlElement licenseNode) { TimestampInformation information = null; if (timestamper.dwError == 0) { return new TimestampInformation(timestamper); } if ((timestamper.dwError == -2146762748) || (timestamper.dwError == -2146762496)) { XmlElement element = licenseNode.SelectSingleNode("r:issuer/ds:Signature/ds:Object/as:Timestamp", this.m_namespaceManager) as XmlElement; if (element == null) { return information; } byte[] encodedMessage = Convert.FromBase64String(element.InnerText); try { SignedCms cms = new SignedCms(); cms.Decode(encodedMessage); cms.CheckSignature(true); return null; } catch (CryptographicException exception) { return new TimestampInformation((SignatureVerificationResult) Marshal.GetHRForException(exception)); } } return null; }
public static extern int CertVerifyAuthenticodeLicense(ref CapiNative.CRYPTOAPI_BLOB pLicenseBlob, X509Native.AxlVerificationFlags dwFlags, [In, Out] ref X509Native.AXL_AUTHENTICODE_SIGNER_INFO pSignerInfo, [In, Out] ref X509Native.AXL_AUTHENTICODE_TIMESTAMPER_INFO pTimestamperInfo);
public static extern int CertFreeAuthenticodeTimestamperInfo(ref X509Native.AXL_AUTHENTICODE_TIMESTAMPER_INFO pTimestamperInfo);
public static extern int CertFreeAuthenticodeSignerInfo(ref X509Native.AXL_AUTHENTICODE_SIGNER_INFO pSignerInfo);