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)); } } } }
public unsafe X509Certificate2 GenerateCertificate(X509Certificate2 issuingCertificate, PrivateKey privateKey, X500DistinguishedName dn, string[] dnsNames, 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); 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 signatureAlgorithm = new CRYPT_ALGORITHM_IDENTIFIER { pszObjId = issuingCertificate.SignatureAlgorithm.Value }; using (var signingKey = ExtractKey(issuingCertificate)) { 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), 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 = signatureAlgorithm; 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, KeySpec.NONE, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signatureAlgorithm, IntPtr.Zero, IntPtr.Zero, ref size)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var buffer = Marshal.AllocHGlobal((int) size); if (!Crypt32.CryptSignAndEncodeCertificate(signingKey.Handle, KeySpec.NONE, EncodingType.X509_ASN_ENCODING, CERT_INFO_TYPE, ref certInfo, ref signatureAlgorithm, 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.Handle.IsNCryptKey ? KeySpec.NONE : KeySpec.AT_KEYEXCHANGE, 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); } } }
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); } } }
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.Handle.IsNCryptKey ? KeySpec.NONE : KeySpec.AT_KEYEXCHANGE, 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); } } } }