/// <summary> /// Take an existing certificate, clone its details and resign with a new root CA /// </summary> /// <param name="toClone">The certificate to clone</param> /// <param name="rootCert">The root CA certificate to sign with</param> /// <param name="newSerial">True to generate a new serial for this certificate</param> /// <param name="rsaKeySize">The size of the RSA key to generate</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns></returns> public static X509Certificate2 CloneAndSignCertificate(X509Certificate toClone, X509Certificate2 rootCert, bool newSerial, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { X509Certificate2 cert2 = new X509Certificate2(toClone); X509ExtensionCollection extensions = new X509ExtensionCollection(); foreach (var ext in cert2.Extensions) { // Remove CRL distribution locations and authority information, they tend to break SSL negotiation if ((ext.Oid.Value != szOID_CRL_DISTRIBUTION) && (ext.Oid.Value != szOID_AUTHORITY_INFO)) { extensions.Add(ext); } } return builder.CreateCert(rootCert, cert2.SubjectName, newSerial ? null : cert2.GetSerialNumber(), false, rsaKeySize, hashAlgorithm, cert2.NotBefore, cert2.NotAfter, extensions); }
private static string HashAlgorithmToOID(CertificateHashAlgorithm hashAlgorithm) { switch (hashAlgorithm) { case CertificateHashAlgorithm.Sha1: return(CryptoApiMethods.szOID_RSA_SHA1RSA); case CertificateHashAlgorithm.Sha256: return(CryptoApiMethods.szOID_RSA_SHA256RSA); case CertificateHashAlgorithm.Sha384: return(CryptoApiMethods.szOID_RSA_SHA384RSA); case CertificateHashAlgorithm.Sha512: return(CryptoApiMethods.szOID_RSA_SHA512RSA); case CertificateHashAlgorithm.Md5: return(CryptoApiMethods.szOID_RSA_MD5RSA); default: throw new ArgumentException(Properties.Resources.NativeCertificateBuilder_InvalidHashAlgorithm, "hashAlgorithm"); } }
private static string HashAlgorithmToName(CertificateHashAlgorithm hashAlgorithm) { switch (hashAlgorithm) { case CertificateHashAlgorithm.Sha1: return("SHA1WITHRSA"); case CertificateHashAlgorithm.Sha256: return("SHA256WITHRSA"); case CertificateHashAlgorithm.Sha384: return("SHA384WITHRSA"); case CertificateHashAlgorithm.Sha512: return("SHA512WITHRSA"); case CertificateHashAlgorithm.Md5: return("MD5WITHRSA"); default: throw new ArgumentException("hashAlgorithm"); } }
private static string HashAlgorithmToName(CertificateHashAlgorithm hashAlgorithm) { switch (hashAlgorithm) { case CertificateHashAlgorithm.Sha1: return("SHA1WITHRSA"); case CertificateHashAlgorithm.Sha256: return("SHA256WITHRSA"); case CertificateHashAlgorithm.Sha384: return("SHA384WITHRSA"); case CertificateHashAlgorithm.Sha512: return("SHA512WITHRSA"); case CertificateHashAlgorithm.Md5: return("MD5WITHRSA"); default: throw new ArgumentException(Properties.Resources.NativeCertificateBuilder_InvalidHashAlgorithm, "hashAlgorithm"); } }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="hashAlgorithm">The hash algorithm for the certificate</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <returns>The created X509 certificate</returns> public static X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions) { return(CertificateBuilder.CreateCert(issuer, subjectName, serialNumber, keySize, hashAlgorithm, notBefore, notAfter, extensions)); }
/// <summary> /// Generate a self-signed CA certificate /// </summary> /// <param name="subject">The X500 subject string</param> /// <param name="rsaKeySize">The size of the RSA key to generate</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>An X509Certificate2 object containing the full certificate</returns> public static X509Certificate2 GenerateCACert(string subject, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { X509ExtensionCollection exts = new X509ExtensionCollection(); DateTime dt = DateTime.Now.AddYears(-1); exts.Add(new X509BasicConstraintsExtension(true, false, 0, false)); return(CertificateBuilder.CreateCert(null, new X500DistinguishedName(subject), null, rsaKeySize, hashAlgorithm, dt, dt.AddYears(10), exts)); }
/// <summary> /// Take an existing certificate, clone its details and resign with a new root CA /// </summary> /// <param name="toClone">The certificate to clone</param> /// <param name="rootCert">The root CA certificate to sign with</param> /// <param name="newSerial">True to generate a new serial for this certificate</param> /// <param name="rsaKeySize">The size of the RSA key to generate</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns></returns> public static X509Certificate2 CloneAndSignCertificate(X509Certificate toClone, X509Certificate2 rootCert, bool newSerial, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { X509Certificate2 cert2 = new X509Certificate2(toClone.Export(X509ContentType.Cert)); X509ExtensionCollection extensions = new X509ExtensionCollection(); foreach (var ext in cert2.Extensions) { // Remove CRL distribution locations and authority information, they tend to break SSL negotiation if ((ext.Oid.Value != szOID_CRL_DISTRIBUTION) && (ext.Oid.Value != szOID_AUTHORITY_INFO)) { extensions.Add(ext); } } return(CertificateBuilder.CreateCert(rootCert, cert2.SubjectName, newSerial ? null : cert2.GetSerialNumber(), rsaKeySize, hashAlgorithm, cert2.NotBefore, cert2.NotAfter, extensions)); }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>The created X509 certificate</returns> public SystemX509.X509Certificate2 CreateCert(SystemX509.X509Certificate2 issuer, SystemX509.X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, SystemX509.X509ExtensionCollection extensions) { X509V3CertificateGenerator builder = new X509V3CertificateGenerator(); AsymmetricAlgorithm subjectKey = CreateRSAKey(keySize, signature); AsymmetricAlgorithm signKey = issuer == null ? subjectKey : issuer.PrivateKey; if (signKey == null) { throw new ArgumentException(Properties.Resources.CreateCert_NoPrivateKey); } AsymmetricCipherKeyPair bcSubjectKey = GetRsaKeyPair((RSACryptoServiceProvider)subjectKey); AsymmetricCipherKeyPair bcSignKey = GetRsaKeyPair((RSACryptoServiceProvider)signKey); X509Name issuerNameObj = issuer == null?X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)) : X509Name.GetInstance(Asn1Object.FromByteArray(issuer.SubjectName.RawData)); X509Name subjectNameObj = X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)); BigInteger subjectSerial = new BigInteger(1, serialNumber != null ? serialNumber : Guid.NewGuid().ToByteArray()); BigInteger issuerSerial = issuer == null ? subjectSerial : new BigInteger(1, issuer.GetSerialNumber()); builder.SetIssuerDN(issuerNameObj); builder.SetSubjectDN(subjectNameObj); builder.SetSerialNumber(subjectSerial); builder.SetSignatureAlgorithm(HashAlgorithmToName(hashAlgorithm)); builder.SetNotBefore(notBefore.ToUniversalTime()); builder.SetNotAfter(notAfter.ToUniversalTime()); builder.SetPublicKey(bcSubjectKey.Public); SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSignKey.Public); AuthorityKeyIdentifier authKeyId = new AuthorityKeyIdentifier(info, new GeneralNames(new GeneralName(issuerNameObj)), issuerSerial); SubjectKeyIdentifier subjectKeyid = new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSubjectKey.Public)); builder.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authKeyId); builder.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, true, subjectKeyid); if (extensions != null) { foreach (SystemX509.X509Extension ext in extensions) { if (!ext.Oid.Value.Equals(X509Extensions.AuthorityKeyIdentifier.Id) && !ext.Oid.Value.Equals(X509Extensions.SubjectKeyIdentifier.Id) && !ext.Oid.Value.Equals(szOID_AUTHORITY_KEY_IDENTIFIER2)) { Asn1InputStream istm = new Org.BouncyCastle.Asn1.Asn1InputStream(ext.RawData); Asn1Object obj = istm.ReadObject(); builder.AddExtension(ext.Oid.Value, ext.Critical, obj); } } } X509Certificate cert = builder.Generate(bcSignKey.Private); SystemX509.X509Certificate2 ret = new SystemX509.X509Certificate2(cert.GetEncoded(), (string)null, SystemX509.X509KeyStorageFlags.Exportable); ret.PrivateKey = subjectKey; return(ret); }
private static string HashAlgorithmToOID(CertificateHashAlgorithm hashAlgorithm) { switch (hashAlgorithm) { case CertificateHashAlgorithm.Sha1: return CryptoApiMethods.szOID_RSA_SHA1RSA; case CertificateHashAlgorithm.Sha256: return CryptoApiMethods.szOID_RSA_SHA256RSA; case CertificateHashAlgorithm.Sha384: return CryptoApiMethods.szOID_RSA_SHA384RSA; case CertificateHashAlgorithm.Sha512: return CryptoApiMethods.szOID_RSA_SHA512RSA; case CertificateHashAlgorithm.Md5: return CryptoApiMethods.szOID_RSA_MD5RSA; default: throw new ArgumentException(Properties.Resources.NativeCertificateBuilder_InvalidHashAlgorithm, "hashAlgorithm"); } }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>The created X509 certificate</returns> public SystemX509.X509Certificate2 CreateCert(SystemX509.X509Certificate2 issuer, SystemX509.X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, SystemX509.X509ExtensionCollection extensions) { X509V3CertificateGenerator builder = new X509V3CertificateGenerator(); AsymmetricAlgorithm subjectKey = CreateRSAKey(keySize, signature); AsymmetricAlgorithm signKey = issuer == null ? subjectKey : issuer.PrivateKey; if (signKey == null) { throw new ArgumentException(Properties.Resources.CreateCert_NoPrivateKey); } AsymmetricCipherKeyPair bcSubjectKey = GetRsaKeyPair((RSACryptoServiceProvider)subjectKey); AsymmetricCipherKeyPair bcSignKey = GetRsaKeyPair((RSACryptoServiceProvider)signKey); X509Name issuerNameObj = issuer == null ? X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)) : X509Name.GetInstance(Asn1Object.FromByteArray(issuer.SubjectName.RawData)); X509Name subjectNameObj = X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)); BigInteger subjectSerial = new BigInteger(1, serialNumber != null ? serialNumber : Guid.NewGuid().ToByteArray()); BigInteger issuerSerial = issuer == null ? subjectSerial : new BigInteger(1, issuer.GetSerialNumber()); builder.SetIssuerDN(issuerNameObj); builder.SetSubjectDN(subjectNameObj); builder.SetSerialNumber(subjectSerial); builder.SetSignatureAlgorithm(HashAlgorithmToName(hashAlgorithm)); builder.SetNotBefore(notBefore.ToUniversalTime()); builder.SetNotAfter(notAfter.ToUniversalTime()); builder.SetPublicKey(bcSubjectKey.Public); SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSignKey.Public); AuthorityKeyIdentifier authKeyId = new AuthorityKeyIdentifier(info, new GeneralNames(new GeneralName(issuerNameObj)), issuerSerial); SubjectKeyIdentifier subjectKeyid = new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSubjectKey.Public)); builder.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authKeyId); builder.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, true, subjectKeyid); if (extensions != null) { foreach (SystemX509.X509Extension ext in extensions) { if (!ext.Oid.Value.Equals(X509Extensions.AuthorityKeyIdentifier.Id) && !ext.Oid.Value.Equals(X509Extensions.SubjectKeyIdentifier.Id) && !ext.Oid.Value.Equals(szOID_AUTHORITY_KEY_IDENTIFIER2)) { Asn1InputStream istm = new Org.BouncyCastle.Asn1.Asn1InputStream(ext.RawData); Asn1Object obj = istm.ReadObject(); builder.AddExtension(ext.Oid.Value, ext.Critical, obj); } } } X509Certificate cert = builder.Generate(bcSignKey.Private); SystemX509.X509Certificate2 ret = new SystemX509.X509Certificate2(cert.GetEncoded(), (string)null, SystemX509.X509KeyStorageFlags.Exportable); ret.PrivateKey = subjectKey; return ret; }
private static ISignatureFactory CreateSignatureFactory(CertificateHashAlgorithm hash_algorithm, AsymmetricCipherKeyPair key, SecureRandom random) { return(new Asn1SignatureFactory(HashAlgorithmToName(hash_algorithm), key.Private, random)); }
/// <summary> /// Generate a self-signed CA certificate /// </summary> /// <param name="subject">The X500 subject string</param> /// <param name="rsaKeySize">The size of the RSA key to generate</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>An X509Certificate2 object containing the full certificate</returns> public static X509Certificate2 GenerateCACert(string subject, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { X509ExtensionCollection exts = new X509ExtensionCollection(); DateTime dt = DateTime.Now.AddYears(-1); exts.Add(new X509BasicConstraintsExtension(true, false, 0, false)); return builder.CreateCert(null, new X500DistinguishedName(subject), null, false, rsaKeySize, hashAlgorithm, dt, dt.AddYears(10), exts); }
/// <summary> /// Encode and sign a CERT_INFO structure /// </summary> /// <param name="key">Key to sign the certificate with</param> /// <param name="certInfo">The CERT_INFO structure to sign</param> /// <param name="hashAlgorithm"></param> /// <returns></returns> private byte[] EncodeAndSignCertInfo(RSACryptoServiceProvider key, CryptoApiMethods.CERT_INFO certInfo, CertificateHashAlgorithm hashAlgorithm) { byte[] ret = null; CryptoApiMethods.SafeCryptProviderHandle hProv = new CryptoApiMethods.SafeCryptProviderHandle(); try { hProv = OpenRSAProvider(key.CspKeyContainerInfo.ProviderName, key.CspKeyContainerInfo.KeyContainerName); ret = EncodeAndSignCertInfo(hProv, certInfo, key.CspKeyContainerInfo.KeyNumber == KeyNumber.Signature ? true : false, hashAlgorithm); } finally { if (!hProv.IsInvalid) { hProv.Close(); } } return(ret); }
/// <summary> /// Encode and sign a CERT_INFO structure /// </summary> /// <param name="hProv"></param> /// <param name="certInfo"></param> /// <param name="signature">True encodes with a AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="hashAlgorithm"></param> /// <returns></returns> private byte[] EncodeAndSignCertInfo(CryptoApiMethods.SafeCryptProviderHandle hProv, CryptoApiMethods.CERT_INFO certInfo, bool signature, CertificateHashAlgorithm hashAlgorithm) { CryptoApiMethods.CALG keyType = signature ? CryptoApiMethods.CALG.AT_SIGNATURE : CryptoApiMethods.CALG.AT_KEYEXCHANGE; byte[] ret = null; uint certLen = 0; IntPtr certInfoPtr = IntPtr.Zero; CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER(); //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign; //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA; //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA; SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm); try { certInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(certInfo)); Marshal.StructureToPtr(certInfo, certInfoPtr, false); if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING, new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, null, ref certLen)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } ret = new byte[certLen]; if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING, new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, ret, ref certLen)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { Marshal.DestroyStructure(certInfoPtr, certInfo.GetType()); Marshal.FreeHGlobal(certInfoPtr); } return(ret); }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>The created X509 certificate</returns> public X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions) { CryptoApiMethods.CERT_INFO certInfo = new CryptoApiMethods.CERT_INFO(); RSACryptoServiceProvider key = CreateRSAKey(keySize, signature); IntPtr publicKeyInfoPtr = IntPtr.Zero; X509Certificate2 cert = null; List<X509Extension> newExts = null; if (extensions != null) { foreach (X509Extension ext in extensions) { if (ext.RawData == null) { throw new ArgumentException(Properties.Resources.CreateCert_NeedEncodedData); } } } try { if (serialNumber == null) { serialNumber = Guid.NewGuid().ToByteArray(); } certInfo.dwVersion = (uint)CryptoApiMethods.CertVersion.CERT_V3; certInfo.SerialNumber = new CryptoApiMethods.CRYPTOAPI_BLOB(serialNumber); certInfo.Subject = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData); if (issuer == null) { // Self-signed certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData); } else { certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(issuer.SubjectName.RawData); } // Never seems to need these set to anything valid? certInfo.SubjectUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB(); certInfo.IssuerUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB(); certInfo.NotBefore = DateTimeToFileTime(notBefore); certInfo.NotAfter = DateTimeToFileTime(notAfter); certInfo.SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER(); // Doesn't seem to work properly with standard szOID_RSA_SHA1RSA //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign; //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA; //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA; certInfo.SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm); // Add extension fields publicKeyInfoPtr = ExportPublicKeyInfo(key); certInfo.SubjectPublicKeyInfo = (CryptoApiMethods.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(publicKeyInfoPtr, typeof(CryptoApiMethods.CERT_PUBLIC_KEY_INFO)); newExts = new List<X509Extension>(); if (extensions != null) { // Filter out some extensions we don't want newExts.AddRange( extensions.Cast<X509Extension>().Where( x => !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER) && !x.Oid.Value.Equals(CryptoApiMethods.szOID_SUBJECT_KEY_IDENTIFIER) && !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER2))); } if (issuer != null) { newExts.Add(CreateAuthorityKeyInfo2(issuer.GetSerialNumber(), issuer.SubjectName, (RSACryptoServiceProvider)issuer.PrivateKey)); } else { newExts.Add(CreateAuthorityKeyInfo2(serialNumber, subjectName, key)); } newExts.Add(new X509SubjectKeyIdentifierExtension(HashPublicKeyInfo(key), false)); certInfo.rgExtension = MarshalExtensions(newExts.ToArray()); certInfo.cExtension = (uint)newExts.Count; byte[] certData = EncodeAndSignCertInfo(issuer != null ? issuer.PrivateKey as RSACryptoServiceProvider : key, certInfo, hashAlgorithm); cert = new X509Certificate2(certData, (string)null, X509KeyStorageFlags.Exportable); cert.PrivateKey = key; } finally { if (certInfo.rgExtension != IntPtr.Zero) { Marshal.FreeHGlobal(certInfo.rgExtension); } if (certInfo.Subject != null) { certInfo.Subject.Release(); } if (certInfo.Issuer != null) { certInfo.Issuer.Release(); } if (publicKeyInfoPtr != IntPtr.Zero) { Marshal.FreeHGlobal(publicKeyInfoPtr); } } return cert; }
/// <summary> /// Encode and sign a CERT_INFO structure /// </summary> /// <param name="hProv"></param> /// <param name="certInfo"></param> /// <param name="signature">True encodes with a AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="hashAlgorithm"></param> /// <returns></returns> private byte[] EncodeAndSignCertInfo(CryptoApiMethods.SafeCryptProviderHandle hProv, CryptoApiMethods.CERT_INFO certInfo, bool signature, CertificateHashAlgorithm hashAlgorithm) { CryptoApiMethods.CALG keyType = signature ? CryptoApiMethods.CALG.AT_SIGNATURE : CryptoApiMethods.CALG.AT_KEYEXCHANGE; byte[] ret = null; uint certLen = 0; IntPtr certInfoPtr = IntPtr.Zero; CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER(); //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign; //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA; //SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA; SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm); try { certInfoPtr = Marshal.AllocHGlobal(Marshal.SizeOf(certInfo)); Marshal.StructureToPtr(certInfo, certInfoPtr, false); if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING, new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, null, ref certLen)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } ret = new byte[certLen]; if (!CryptoApiMethods.CryptSignAndEncodeCertificate(hProv, keyType, CryptoApiMethods.CertEncoding.X509_ASN_ENCODING, new IntPtr((int)CryptoApiMethods.StructType.X509_CERT_TO_BE_SIGNED), certInfoPtr, SignatureAlgorithm, IntPtr.Zero, ret, ref certLen)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } } finally { Marshal.DestroyStructure(certInfoPtr, certInfo.GetType()); Marshal.FreeHGlobal(certInfoPtr); } return ret; }
/// <summary> /// Encode and sign a CERT_INFO structure /// </summary> /// <param name="key">Key to sign the certificate with</param> /// <param name="certInfo">The CERT_INFO structure to sign</param> /// <param name="hashAlgorithm"></param> /// <returns></returns> private byte[] EncodeAndSignCertInfo(RSACryptoServiceProvider key, CryptoApiMethods.CERT_INFO certInfo, CertificateHashAlgorithm hashAlgorithm) { byte[] ret = null; CryptoApiMethods.SafeCryptProviderHandle hProv = new CryptoApiMethods.SafeCryptProviderHandle(); try { hProv = OpenRSAProvider(key.CspKeyContainerInfo.ProviderName, key.CspKeyContainerInfo.KeyContainerName); ret = EncodeAndSignCertInfo(hProv, certInfo, key.CspKeyContainerInfo.KeyNumber == KeyNumber.Signature ? true : false, hashAlgorithm); } finally { if (!hProv.IsInvalid) { hProv.Close(); } } return ret; }
/// <summary> /// Generate a self signed certificate including a private key /// </summary> /// <param name="subject">The X500 subject string</param> /// <param name="rsaKeySize">Specify the RSA key size in bits</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>An X509Certificate2 object containing the full certificate</returns> public static X509Certificate2 GenerateSelfSignedCert(string subject, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { DateTime dt = DateTime.Now; return(CertificateBuilder.CreateCert(null, new X500DistinguishedName(subject), null, rsaKeySize, hashAlgorithm, dt, dt.AddYears(10), null)); }
private static string HashAlgorithmToName(CertificateHashAlgorithm hashAlgorithm) { switch (hashAlgorithm) { case CertificateHashAlgorithm.Sha1: return "SHA1WITHRSA"; case CertificateHashAlgorithm.Sha256: return "SHA256WITHRSA"; case CertificateHashAlgorithm.Sha384: return "SHA384WITHRSA"; case CertificateHashAlgorithm.Sha512: return "SHA512WITHRSA"; case CertificateHashAlgorithm.Md5: return "MD5WITHRSA"; default: throw new ArgumentException(Properties.Resources.NativeCertificateBuilder_InvalidHashAlgorithm, "hashAlgorithm"); } }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>The created X509 certificate</returns> public X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions) { CryptoApiMethods.CERT_INFO certInfo = new CryptoApiMethods.CERT_INFO(); RSACryptoServiceProvider key = CreateRSAKey(keySize, signature); IntPtr publicKeyInfoPtr = IntPtr.Zero; X509Certificate2 cert = null; List <X509Extension> newExts = null; if (extensions != null) { foreach (X509Extension ext in extensions) { if (ext.RawData == null) { throw new ArgumentException(Properties.Resources.CreateCert_NeedEncodedData); } } } try { if (serialNumber == null) { serialNumber = Guid.NewGuid().ToByteArray(); } certInfo.dwVersion = (uint)CryptoApiMethods.CertVersion.CERT_V3; certInfo.SerialNumber = new CryptoApiMethods.CRYPTOAPI_BLOB(serialNumber); certInfo.Subject = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData); if (issuer == null) { // Self-signed certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(subjectName.RawData); } else { certInfo.Issuer = new CryptoApiMethods.CRYPTOAPI_BLOB(issuer.SubjectName.RawData); } // Never seems to need these set to anything valid? certInfo.SubjectUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB(); certInfo.IssuerUniqueId = new CryptoApiMethods.CRYPT_BIT_BLOB(); certInfo.NotBefore = DateTimeToFileTime(notBefore); certInfo.NotAfter = DateTimeToFileTime(notAfter); certInfo.SignatureAlgorithm = new CryptoApiMethods.CRYPT_ALGORITHM_IDENTIFIER(); // Doesn't seem to work properly with standard szOID_RSA_SHA1RSA //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_OIWSEC_sha1RSASign; //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA1RSA; //certInfo.SignatureAlgorithm.pszObjId = CryptoApiMethods.szOID_RSA_SHA512RSA; certInfo.SignatureAlgorithm.pszObjId = HashAlgorithmToOID(hashAlgorithm); // Add extension fields publicKeyInfoPtr = ExportPublicKeyInfo(key); certInfo.SubjectPublicKeyInfo = (CryptoApiMethods.CERT_PUBLIC_KEY_INFO)Marshal.PtrToStructure(publicKeyInfoPtr, typeof(CryptoApiMethods.CERT_PUBLIC_KEY_INFO)); newExts = new List <X509Extension>(); if (extensions != null) { // Filter out some extensions we don't want newExts.AddRange( extensions.Cast <X509Extension>().Where( x => !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER) && !x.Oid.Value.Equals(CryptoApiMethods.szOID_SUBJECT_KEY_IDENTIFIER) && !x.Oid.Value.Equals(CryptoApiMethods.szOID_AUTHORITY_KEY_IDENTIFIER2))); } if (issuer != null) { newExts.Add(CreateAuthorityKeyInfo2(issuer.GetSerialNumber(), issuer.SubjectName, (RSACryptoServiceProvider)issuer.PrivateKey)); } else { newExts.Add(CreateAuthorityKeyInfo2(serialNumber, subjectName, key)); } newExts.Add(new X509SubjectKeyIdentifierExtension(HashPublicKeyInfo(key), false)); certInfo.rgExtension = MarshalExtensions(newExts.ToArray()); certInfo.cExtension = (uint)newExts.Count; byte[] certData = EncodeAndSignCertInfo(issuer != null ? issuer.PrivateKey as RSACryptoServiceProvider : key, certInfo, hashAlgorithm); cert = new X509Certificate2(certData, (string)null, X509KeyStorageFlags.Exportable); cert.PrivateKey = key; } finally { if (certInfo.rgExtension != IntPtr.Zero) { Marshal.FreeHGlobal(certInfo.rgExtension); } if (certInfo.Subject != null) { certInfo.Subject.Release(); } if (certInfo.Issuer != null) { certInfo.Issuer.Release(); } if (publicKeyInfoPtr != IntPtr.Zero) { Marshal.FreeHGlobal(publicKeyInfoPtr); } } return(cert); }
/// <summary> /// Generate a self signed certificate including a private key /// </summary> /// <param name="subject">The X500 subject string</param> /// <param name="signature">True create a cert with an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="rsaKeySize">Specify the RSA key size in bits</param> /// <param name="hashAlgorithm">Specify the signature hash algorithm</param> /// <returns>An X509Certificate2 object containing the full certificate</returns> public static X509Certificate2 GenerateSelfSignedCert(string subject, bool signature, int rsaKeySize, CertificateHashAlgorithm hashAlgorithm) { DateTime dt = DateTime.Now; return builder.CreateCert(null, new X500DistinguishedName(subject), null, signature, rsaKeySize, hashAlgorithm, dt, dt.AddYears(10), null); }
///// <summary> ///// Create a new certificate ///// </summary> ///// <param name="issuer">Issuer certificate, if null then self-sign</param> ///// <param name="subjectName">Subject name</param> ///// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> ///// <param name="keySize">Size of RSA key</param> ///// <param name="notBefore">Start date of certificate</param> ///// <param name="notAfter">End date of certificate</param> ///// <param name="extensions">Array of extensions, if null then no extensions</param> ///// <param name="hashAlgorithm">Specify the signature hash algorithm</param> ///// <returns>The created X509 certificate</returns> public static SystemX509.X509Certificate2 CreateCert(SystemX509.X509Certificate2 issuer, SystemX509.X500DistinguishedName subjectName, byte[] serialNumber, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, SystemX509.X509ExtensionCollection extensions) { SecureRandom random = new SecureRandom(); X509V3CertificateGenerator builder = new X509V3CertificateGenerator(); AsymmetricCipherKeyPair bcSubjectKey = CreateRSAKey(keySize, random); AsymmetricCipherKeyPair bcSignKey = issuer == null ? bcSubjectKey : issuer.GetBCPrivateKey(); if (bcSignKey == null) { throw new ArgumentException("issuer"); } X509Name issuerNameObj = issuer == null?X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)) : X509Name.GetInstance(Asn1Object.FromByteArray(issuer.SubjectName.RawData)); X509Name subjectNameObj = X509Name.GetInstance(Asn1Object.FromByteArray(subjectName.RawData)); BigInteger subjectSerial = new BigInteger(1, serialNumber != null ? serialNumber : Guid.NewGuid().ToByteArray()); BigInteger issuerSerial = issuer == null ? subjectSerial : new BigInteger(1, issuer.GetSerialNumber()); builder.SetIssuerDN(issuerNameObj); builder.SetSubjectDN(subjectNameObj); builder.SetSerialNumber(subjectSerial); builder.SetNotBefore(notBefore.ToUniversalTime()); builder.SetNotAfter(notAfter.ToUniversalTime()); builder.SetPublicKey(bcSubjectKey.Public); SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSignKey.Public); AuthorityKeyIdentifier authKeyId = new AuthorityKeyIdentifier(info, new GeneralNames(new GeneralName(issuerNameObj)), issuerSerial); SubjectKeyIdentifier subjectKeyid = new SubjectKeyIdentifier(SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(bcSubjectKey.Public)); builder.AddExtension(X509Extensions.AuthorityKeyIdentifier.Id, true, authKeyId); builder.AddExtension(X509Extensions.SubjectKeyIdentifier.Id, true, subjectKeyid); if (extensions != null) { foreach (SystemX509.X509Extension ext in extensions) { if (!ext.Oid.Value.Equals(X509Extensions.AuthorityKeyIdentifier.Id) && !ext.Oid.Value.Equals(X509Extensions.SubjectKeyIdentifier.Id) && !ext.Oid.Value.Equals(szOID_AUTHORITY_KEY_IDENTIFIER2)) { Asn1InputStream istm = new Asn1InputStream(ext.RawData); Asn1Object obj = istm.ReadObject(); builder.AddExtension(ext.Oid.Value, ext.Critical, obj); } } } X509Certificate cert = builder.Generate(CreateSignatureFactory(hashAlgorithm, bcSignKey, random)); Pkcs12StoreBuilder pkcs = new Pkcs12StoreBuilder(); Pkcs12Store store = pkcs.Build(); X509CertificateEntry entry = new X509CertificateEntry(cert); store.SetCertificateEntry("main", entry); AsymmetricKeyEntry key_entry = new AsymmetricKeyEntry(bcSubjectKey.Private); store.SetKeyEntry("main", key_entry, new[] { entry }); MemoryStream stm = new MemoryStream(); store.Save(stm, new char[0], new SecureRandom()); return(new SystemX509.X509Certificate2(stm.ToArray(), String.Empty, SystemX509.X509KeyStorageFlags.Exportable)); }
/// <summary> /// Create a new certificate /// </summary> /// <param name="issuer">Issuer certificate, if null then self-sign</param> /// <param name="subjectName">Subject name</param> /// <param name="serialNumber">Serial number of certificate, if null then will generate a new one</param> /// <param name="signature">If true create an AT_SIGNATURE key, otherwise AT_EXCHANGE</param> /// <param name="keySize">Size of RSA key</param> /// <param name="hashAlgorithm">The hash algorithm for the certificate</param> /// <param name="notBefore">Start date of certificate</param> /// <param name="notAfter">End date of certificate</param> /// <param name="extensions">Array of extensions, if null then no extensions</param> /// <returns>The created X509 certificate</returns> public static X509Certificate2 CreateCert(X509Certificate2 issuer, X500DistinguishedName subjectName, byte[] serialNumber, bool signature, int keySize, CertificateHashAlgorithm hashAlgorithm, DateTime notBefore, DateTime notAfter, X509ExtensionCollection extensions) { return builder.CreateCert(issuer, subjectName, serialNumber, signature, keySize, hashAlgorithm, notBefore, notAfter, extensions); }