/// <summary> /// Create new certificate that is signed with private key from signing certificate that resides /// in Windows certificate store on local machine in intermediate certificate authorities. /// The private key does NOT have to be exportable. /// </summary> /// <param name="subject"></param> /// <param name="publicKeyBase64DerEncoded"></param> /// <param name="signingCertificate"></param> /// <returns>Freshly created certificate in PEM format</returns> public string CreateCertificate(DistinguishedName subject, string publicKeyBase64DerEncoded, X509Certificate2 signingCertificate) { var definition = new CertificateDefinition { Subject = ToX509Name(subject), SubjectAltNames = ToSans(subject.SubjectAltNames), PublicKey = ToPublicKey(publicKeyBase64DerEncoded), SigningCertificate = signingCertificate }; X509Certificate certificate = CreateCertificate(definition); return(ToPem(certificate)); }
public X509Certificate CreateCertificate(CertificateDefinition definition) { var randomGenerator = new CryptoApiRandomGenerator(); BigInteger serialNumber = CreateSerialNumber(randomGenerator); if (definition.SigningCertificate == null) { throw new CertificateIssuerException("Cannot create certificate without signing certificate (null)."); } (AsymmetricCipherKeyPair caKeyPair, X509Name issuer) = GetSigningKeyPair(definition.SigningCertificate); var publicKeyForNewCert = PublicKeyFactory.CreateKey(definition.PublicKey); var certGen = new X509V3CertificateGenerator(); certGen.SetSerialNumber(serialNumber); certGen.SetIssuerDN(issuer); certGen.SetSubjectDN(definition.Subject); certGen.SetPublicKey(publicKeyForNewCert); var now = DateTime.Now; certGen.SetNotBefore(now.Subtract(new TimeSpan(0, 0, 10, 0))); // start 10 min before now // add max 2 weeks from now but not more then L2 expiration date var certExpirationDate = now.Add(definition.ExpireIn); var signingCertificateNotAfter = definition.SigningCertificate.NotAfter; if (signingCertificateNotAfter < now) { throw new CertificateIssuerException( "Cannot create derived certificate because signing certificate already expired. Signing certificate subject name: " + definition.SigningCertificate?.SubjectName.Name); } if (certExpirationDate > signingCertificateNotAfter) { certExpirationDate = signingCertificateNotAfter; } certGen.SetNotAfter(certExpirationDate); // certGen.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false)); AddExtensionSubjectKeyIdentifier(certGen, publicKeyForNewCert); AddExtensionAuthorityKeyIdentifier(certGen, caKeyPair); AddExtensionSubjectAltNames(certGen, definition.SubjectAltNames); // var s = @"file:////my-CA.com/CertEnroll/my-CA.com_my-Dev%20L2%20CA.crt"; // AddExtensionAuthorityInfo(certGen, s); // string certificateTemplateExtension = "IPSECIntermediateOffline"; // AddExtensionCertificateTemplateName(certGen, certificateTemplateExtension); // var crl = @"file:////my-CA.com/CertEnroll/my-Dev%20L2%20CA.crl"; // AddExtensionCrlDistributionPoints(certGen, crl); // other supported algorithms: /* SHA1withECDSA * SHA224withECDSA * SHA256withECDSA * SHA384withECDSA * SHA512withECDSA * NONEwithECDSA */ const string algorithm = "SHA256WITHECDSA"; // This is the most interesting part where we use our custom signature factory that utilizes // the custom private key PksEcPrivateKey ISignatureFactory signatureFactory = new PksAsn1SignatureFactory(algorithm, caKeyPair.Private, new SecureRandom(randomGenerator)); X509Certificate cert = certGen.Generate(signatureFactory); return(cert); }