public unsafe X509Certificate2 GenerateCertificateAuthority(PrivateKey privateKey, X500DistinguishedName dn, HashAlgorithm signatureAlgorithm, DateTime?notBefore = null, DateTime?notAfter = null) { { fixed(byte *dnPtr = dn.RawData) { var blob = new NATIVE_CRYPTOAPI_BLOB { cbData = (uint)dn.RawData.Length, pbData = dnPtr }; var signatureAlgorithmIdentifier = new CRYPT_ALGORITHM_IDENTIFIER { pszObjId = HashAlgorithmToSignatureAlgorithm(privateKey, signatureAlgorithm) }; using (var extensions = new MarshalX509ExtensionCollection()) { using (extensions.Freeze()) { extensions.Add(new X509BasicConstraintsExtension(true, true, 1, true)); extensions.Add(new X509KeyUsageExtension(X509KeyUsageFlags.CrlSign | X509KeyUsageFlags.KeyCertSign, true)); extensions.Add(new X509EnhancedKeyUsageExtension(new OidCollection { new Oid(OIDs.EKU_SERVER) }, false)); using (var publicKey = privateKey.ToPublicKey()) { using (var sha1 = new SHA1CryptoServiceProvider()) { var pubKeyHash = sha1.ComputeHash(publicKey.Key); extensions.Add(new X509SubjectKeyIdentifierExtension(pubKeyHash, false)); extensions.Add(new X509AuthorityKeyIdentifierExtension(pubKeyHash, null)); } } } var certExtensions = extensions.Extensions; 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 }; var beginning = new SYSTEMTIME(notBefore ?? DateTime.UtcNow.AddHours(-1)); var expiration = new SYSTEMTIME(notAfter ?? DateTime.UtcNow.AddHours(-1).AddYears(30)); var certContext = Crypt32.CertCreateSelfSignCertificate(privateKey.Handle, ref blob, SelfSignFlags.NONE, ref keyProvInfo, ref signatureAlgorithmIdentifier, beginning, expiration, ref certExtensions); if (certContext == IntPtr.Zero) { throw new Win32Exception(Marshal.GetLastWin32Error()); } return(new X509Certificate2(certContext)); } } } }