private static X509Certificate GenerateCertificate(Org.BouncyCastle.Security.SecureRandom random, string subjectName, AsymmetricCipherKeyPair subjectKeyPair, BigInteger subjectSerialNumber, string[] subjectAlternativeNames, string issuerName, AsymmetricCipherKeyPair issuerKeyPair, BigInteger issuerSerialNumber, bool isCertificateAuthority, KeyPurposeID[] usages, int expiresIn) { var certificateGenerator = new X509V3CertificateGenerator(); certificateGenerator.SetSerialNumber(subjectSerialNumber); // Set the signature algorithm. This is used to generate the thumbprint which is then signed // with the issuer's private key. We'll use SHA-256, which is (currently) considered fairly strong. const string signatureAlgorithm = "SHA256WithRSA"; certificateGenerator.SetSignatureAlgorithm(signatureAlgorithm); var issuerDN = new X509Name(issuerName); certificateGenerator.SetIssuerDN(issuerDN); // Note: The subject can be omitted if you specify a subject alternative name (SAN). var subjectDN = new X509Name(subjectName); certificateGenerator.SetSubjectDN(subjectDN); // Our certificate needs valid from/to values. var notBefore = DateTime.UtcNow.Date; var notAfter = notBefore.AddYears(expiresIn); certificateGenerator.SetNotBefore(notBefore); certificateGenerator.SetNotAfter(notAfter); // The subject's public key goes in the certificate. certificateGenerator.SetPublicKey(subjectKeyPair.Public); certificateGenerator.AddAuthorityKeyIdentifier(issuerDN, issuerKeyPair, issuerSerialNumber); certificateGenerator.AddSubjectKeyIdentifier(subjectKeyPair); certificateGenerator.AddBasicConstraints(isCertificateAuthority); if (usages != null && usages.Any()) { certificateGenerator.AddExtendedKeyUsage(usages); } if (subjectAlternativeNames != null && subjectAlternativeNames.Any()) { certificateGenerator.AddSubjectAlternativeNames(subjectAlternativeNames); } // The certificate is signed with the issuer's private key. var certificate = certificateGenerator.Generate(issuerKeyPair.Private, random); return(certificate); }