/// <summary> /// Encodes a CERT_INFO. /// </summary> public static void Encode_CERT_INFO(CERT_INFO info, out IntPtr pEncoded, out int encodedSize) { pEncoded = IntPtr.Zero; encodedSize = 0; IntPtr pData = IntPtr.Zero; int dwDataSize = 0; GCHandle hData = GCHandle.Alloc(info); try { // calculate amount of memory required. int bResult = Win32.CryptEncodeObjectEx( Win32.X509_ASN_ENCODING, (IntPtr)Win32.X509_CERT_CRL_TO_BE_SIGNED, hData.AddrOfPinnedObject(), 0, IntPtr.Zero, IntPtr.Zero, ref dwDataSize); if (bResult == 0) { throw GetLastError(StatusCodes.BadEncodingError, "Could not get size for CRL_INFO."); } // allocate memory. pData = Marshal.AllocHGlobal(dwDataSize); // decode blob. bResult = Win32.CryptEncodeObjectEx( Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING, (IntPtr)Win32.X509_CERT_CRL_TO_BE_SIGNED, hData.AddrOfPinnedObject(), 0, IntPtr.Zero, pData, ref dwDataSize); if (bResult == 0) { throw GetLastError(StatusCodes.BadEncodingError, "Could not encoder CRL_INFO."); } // return results. pEncoded = pData; encodedSize = dwDataSize; pData = IntPtr.Zero; } finally { if (hData.IsAllocated) { hData.Free(); } if (pData != IntPtr.Zero) { Marshal.FreeHGlobal(pData); } } }
private static SafeCertContextHandle GetSignerInPKCS7Store(SafeCertStoreHandle hCertStore, SafeCryptMsgHandle hCryptMsg) { // make sure that there is at least one signer of the certificate store int dwSigners; int cbSigners = sizeof(int); if (!Interop.crypt32.CryptMsgGetParam(hCryptMsg, CryptMessageParameterType.CMSG_SIGNER_COUNT_PARAM, 0, out dwSigners, ref cbSigners)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; if (dwSigners == 0) { throw ErrorCode.CRYPT_E_SIGNER_NOT_FOUND.ToCryptographicException(); } // get the first signer from the store, and use that as the loaded certificate int cbData = 0; if (!Interop.crypt32.CryptMsgGetParam(hCryptMsg, CryptMessageParameterType.CMSG_SIGNER_INFO_PARAM, 0, null, ref cbData)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; byte[] cmsgSignerBytes = new byte[cbData]; if (!Interop.crypt32.CryptMsgGetParam(hCryptMsg, CryptMessageParameterType.CMSG_SIGNER_INFO_PARAM, 0, cmsgSignerBytes, ref cbData)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; CERT_INFO certInfo = default(CERT_INFO); unsafe { fixed(byte *pCmsgSignerBytes = cmsgSignerBytes) { CMSG_SIGNER_INFO_Partial *pCmsgSignerInfo = (CMSG_SIGNER_INFO_Partial *)pCmsgSignerBytes; certInfo.Issuer.cbData = pCmsgSignerInfo->Issuer.cbData; certInfo.Issuer.pbData = pCmsgSignerInfo->Issuer.pbData; certInfo.SerialNumber.cbData = pCmsgSignerInfo->SerialNumber.cbData; certInfo.SerialNumber.pbData = pCmsgSignerInfo->SerialNumber.pbData; } SafeCertContextHandle pCertContext = null; if (!Interop.crypt32.CertFindCertificateInStore(hCertStore, CertFindType.CERT_FIND_SUBJECT_CERT, &certInfo, ref pCertContext)) { throw Marshal.GetHRForLastWin32Error().ToCryptographicException(); } ; return(pCertContext); } }
internal static CERT_EXTENSION FindExtension(SafeCertContextHandle certificateContext, string extensionOid) { Debug.Assert(certificateContext != null, "certificateContext != null"); Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid, "!certificateContext.IsClosed && !certificateContext.IsInvalid"); Debug.Assert(!String.IsNullOrEmpty(extensionOid), "!String.IsNullOrEmpty(extensionOid)"); Debug.Assert(HasExtension(certificateContext, extensionOid), "HasExtension(extensionOid)"); CERT_INFO certInfo = GetCertInfo(certificateContext); IntPtr extension = UnsafeNativeMethods.CertFindExtension(extensionOid, certInfo.cExtension, certInfo.rgExtension); return((CERT_EXTENSION)Marshal.PtrToStructure(extension, typeof(CERT_EXTENSION))); }
internal static bool HasExtension(SafeCertContextHandle certificateContext, string extensionOid) { Debug.Assert(certificateContext != null, "certificateContext != null"); Debug.Assert(!certificateContext.IsClosed && !certificateContext.IsInvalid, "!certificateContext.IsClosed && !certificateContext.IsInvalid"); Debug.Assert(!String.IsNullOrEmpty(extensionOid), "!String.IsNullOrEmpty(extensionOid)"); CERT_INFO certInfo = GetCertInfo(certificateContext); if (certInfo.cExtension == 0) { return(false); } return(UnsafeNativeMethods.CertFindExtension(extensionOid, certInfo.cExtension, certInfo.rgExtension) != IntPtr.Zero); }
public unsafe X509Certificate2 GenerateCertificate(X509Certificate2 issuingCertificate, PrivateKey privateKey, X500DistinguishedName dn, string[] dnsNames, IPAddress[] ipAddresses = null, HashAlgorithm?signatureAlgorithm = null, DateTime?notBefore = null, DateTime?notAfter = null) { if (!issuingCertificate.HasPrivateKey) { throw new ArgumentException("Issuing certificate must have a private key.", nameof(issuingCertificate)); } IntPtr basicEncodedDataPtr = IntPtr.Zero, certExtensionPtr = IntPtr.Zero; var serialNumber = new byte[16]; var rng = RandomNumberGenerator.Create(); rng.GetNonZeroBytes(serialNumber); serialNumber[15] &= 0x7F; fixed(byte *dnPtr = dn.RawData, issuerDnPtr = issuingCertificate.SubjectName.RawData, serialNumberPtr = serialNumber) { try { var blob = new NATIVE_CRYPTOAPI_BLOB { cbData = (uint)dn.RawData.Length, pbData = dnPtr }; var signingSignatureAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER { pszObjId = issuingCertificate.SignatureAlgorithm.Value }; using (var signingKey = ExtractKey(issuingCertificate)) { var signingAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER { pszObjId = signatureAlgorithm != null?HashAlgorithmToSignatureAlgorithm(signingKey, signatureAlgorithm.Value) : issuingCertificate.SignatureAlgorithm.Value }; using (PublicKeyInfo publicKey = privateKey.ToPublicKey(), signingPublicKey = signingKey.ToPublicKey()) { using (var extensions = new MarshalX509ExtensionCollection()) { using (extensions.Freeze()) { var usage = X509KeyUsageFlags.DigitalSignature; if (privateKey.AlgorithmGroup == AlgorithmGroup.RSA) { //Key encipherment is not valid for DSA/ECDSA usage |= X509KeyUsageFlags.KeyEncipherment; } extensions.Add(new X509BasicConstraintsExtension(false, false, 0, true)); extensions.Add(new X509KeyUsageExtension(usage, true)); extensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid(OIDs.EKU_SERVER) }, false)); extensions.Add(new X509SubjectAlternativeNameExtension(DnsAltNamesFromArray(dnsNames, ipAddresses ?? new IPAddress[0]), false)); using (var sha1 = new SHA1CryptoServiceProvider()) { var issuingKeyId = sha1.ComputeHash(signingPublicKey.Key); extensions.Add(new X509SubjectKeyIdentifierExtension(sha1.ComputeHash(publicKey.Key), false)); extensions.Add(new X509AuthorityKeyIdentifierExtension(issuingKeyId, null)); } } var certInfo = new CERT_INFO(); certInfo.Subject = blob; certInfo.SerialNumber = new NATIVE_CRYPTOAPI_BLOB { cbData = (uint)serialNumber.Length, pbData = serialNumberPtr }; certInfo.SubjectPublicKeyInfo = publicKey.PublicKey; certInfo.dwVersion = CertificateVersion.CERT_V3; certInfo.Issuer = new NATIVE_CRYPTOAPI_BLOB { cbData = (uint)issuingCertificate.SubjectName.RawData.Length, pbData = issuerDnPtr }; certInfo.SignatureAlgorithm = signingAlgorithmIdentifier; certInfo.NotAfter = FileTimeHelper.ToFileTimeStructureUtc(notAfter ?? DateTime.Now.AddHours(-1).AddYears(5)); certInfo.NotBefore = FileTimeHelper.ToFileTimeStructureUtc(notBefore ?? DateTime.Now.AddHours(-1)); certInfo.cExtension = extensions.Extensions.cExtension; certInfo.rgExtension = extensions.Extensions.rgExtension; var size = 0u; var CERT_INFO_TYPE = (IntPtr)2; if (!Crypt32.CryptSignAndEncodeCertificate(signingKey.Handle, signingKey.KeySpec, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signingSignatureAlgorithmIdentifier, IntPtr.Zero, IntPtr.Zero, ref size)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var buffer = Marshal.AllocHGlobal((int)size); if (!Crypt32.CryptSignAndEncodeCertificate(signingKey.Handle, signingKey.KeySpec, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signingSignatureAlgorithmIdentifier, IntPtr.Zero, buffer, ref size)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } const int CERT_KEY_PROV_INFO_PROP_ID = 2; var certificate = new X509Certificate2(SerializeCertificate(buffer, size)); var keyProvInfo = new CRYPT_KEY_PROV_INFO { cProvParam = 0, dwKeySpec = privateKey.KeySpec, dwProvType = privateKey.Handle.IsNCryptKey ? ProviderType.CNG : ProviderType.PROV_RSA_AES, pwszProvName = privateKey.ProviderName, dwFlags = 0, pwszContainerName = privateKey.Name }; if (!Crypt32.CertSetCertificateContextProperty(certificate.Handle, CERT_KEY_PROV_INFO_PROP_ID, 0u, ref keyProvInfo)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(new X509Certificate2(certificate)); } } } } finally { Marshal.FreeHGlobal(basicEncodedDataPtr); Marshal.FreeHGlobal(certExtensionPtr); } } }
// // This returns an allocated native memory block. Its lifetime (and that of any allocated subblocks it may point to) is that of "hb". // private static unsafe CERT_ID EncodeRecipientId(CmsRecipient recipient, SafeCertContextHandle hCertContext, CERT_CONTEXT* pCertContext, CERT_INFO* pCertInfo, HeapBlockRetainer hb) { CERT_ID recipientId = default(CERT_ID); SubjectIdentifierType type = recipient.RecipientIdentifierType; switch (type) { case SubjectIdentifierType.IssuerAndSerialNumber: { recipientId.dwIdChoice = CertIdChoice.CERT_ID_ISSUER_SERIAL_NUMBER; recipientId.u.IssuerSerialNumber.Issuer = pCertInfo->Issuer; recipientId.u.IssuerSerialNumber.SerialNumber = pCertInfo->SerialNumber; break; } case SubjectIdentifierType.SubjectKeyIdentifier: { byte[] ski = hCertContext.GetSubjectKeyIdentifer(); IntPtr pSki = hb.AllocBytes(ski); recipientId.dwIdChoice = CertIdChoice.CERT_ID_KEY_IDENTIFIER; recipientId.u.KeyId.cbData = (uint)(ski.Length); recipientId.u.KeyId.pbData = pSki; break; } default: // The public contract for CmsRecipient guarantees that SubjectKeyIdentifier and IssuerAndSerialNumber are the only two possibilities. Debug.Fail($"Unexpected SubjectIdentifierType: {type}"); throw new NotSupportedException(SR.Format(SR.Cryptography_Cms_Invalid_Subject_Identifier_Type, type)); } return recipientId; }