Self signed X509 Certificate with Bouncy Castle in Java

后端 未结 4 619
旧时难觅i
旧时难觅i 2020-11-27 18:43

I need to create a self signed X509 Certificate with Bouncy Castle in Java, but every class I try to include is deprecated. How can I solve this? Is there some other class

相关标签:
4条回答
  • 2020-11-27 19:05

    Using Bouncycastle latest version - 1.55 1.66

    Update to the answer by @Bewusstsein. The bouncycastle classes are deprecated in the latest version as of this answer (5/11/2017). If you are using version 1.55 or later:

    public static Certificate selfSign(KeyPair keyPair, String subjectDN) throws OperatorCreationException, CertificateException, IOException
    {
        Provider bcProvider = new BouncyCastleProvider();
        Security.addProvider(bcProvider);
    
        long now = System.currentTimeMillis();
        Date startDate = new Date(now);
    
        X500Name dnName = new X500Name(subjectDN);
        BigInteger certSerialNumber = new BigInteger(Long.toString(now)); // <-- Using the current timestamp as the certificate serial number
    
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startDate);
        calendar.add(Calendar.YEAR, 1); // <-- 1 Yr validity
    
        Date endDate = calendar.getTime();
    
        String signatureAlgorithm = "SHA256WithRSA"; // <-- Use appropriate signature algorithm based on your keyPair algorithm.
    
        ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(keyPair.getPrivate());
    
        JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(dnName, certSerialNumber, startDate, endDate, dnName, keyPair.getPublic());
    
        // Extensions --------------------------
    
        // Basic Constraints
        BasicConstraints basicConstraints = new BasicConstraints(true); // <-- true for CA, false for EndEntity
    
        certBuilder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints); // Basic Constraints is usually marked as critical.
    
        // -------------------------------------
    
        return new JcaX509CertificateConverter().setProvider(bcProvider).getCertificate(certBuilder.build(contentSigner));
    }
    
    0 讨论(0)
  • 2020-11-27 19:08

    This is the code used from BouncyCastle it self to generate X.509 Certificates. You will need this and this library from BC to use it. For further details on how to use it, maybe take a look at this question (Main class).

        public class BCCertGen {
        public static String _country = "Westeros",
                             _organisation = "Targaryen",
                             _location = "Valyria",
                             _state = "Essos",
                             _issuer = "Some Trusted CA";
    
        public BCCertGen(String country, String organisation, String location, String state, String issuer){
            _country = country;
            _organisation = organisation;
            _location = location;
            _state = state;
            _issuer = issuer;
        }
        public static X509Certificate generate(PrivateKey privKey, PublicKey pubKey, int duration, String signAlg, boolean isSelfSigned) throws Exception{
            Provider BC = new BouncyCastleProvider();
    
            // distinguished name table.
            X500NameBuilder builder = createStdBuilder();
    
            // create the certificate
            ContentSigner sigGen = new JcaContentSignerBuilder(signAlg).build(privKey);
            X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
                    new X500Name("cn="+_issuer),    //Issuer
                    BigInteger.valueOf(1),      //Serial
                    new Date(System.currentTimeMillis() - 50000),   //Valid from
                    new Date((long)(System.currentTimeMillis() + duration*8.65*Math.pow(10,7))),    //Valid to
                    builder.build(),    //Subject
                    pubKey              //Publickey to be associated with the certificate
            );
    
            X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
    
            cert.checkValidity(new Date());
    
            if (isSelfSigned) {
                // check verifies in general
                cert.verify(pubKey);
                // check verifies with contained key
                cert.verify(cert.getPublicKey());
            }
    
            ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded());
            CertificateFactory fact = CertificateFactory.getInstance("X.509", BC);
    
            return (X509Certificate) fact.generateCertificate(bIn);
        }
    
        private static X500NameBuilder createStdBuilder() {
            X500NameBuilder builder = new X500NameBuilder(RFC4519Style.INSTANCE);
    
            builder.addRDN(RFC4519Style.c, _country);
            builder.addRDN(RFC4519Style.o, _organisation);
            builder.addRDN(RFC4519Style.l, _location);
            builder.addRDN(RFC4519Style.st, _state);
    
            return builder;
        }
    }
    

    EDIT: I can't remember from which BC test I took it exactly, but here is something similar https://github.com/bcgit/bc-java/blob/master/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/KeyStoreTest.java

    0 讨论(0)
  • 2020-11-27 19:16

    Here's a complete self-signed ECDSA certificate generator that creates certificates usable in TLS connections on both client and server side. It was tested with BouncyCastle 1.57. Similar code can be used to create RSA certificates.

    SecureRandom random = new SecureRandom();
    
    // create keypair
    KeyPairGenerator keypairGen = KeyPairGenerator.getInstance("EC");
    keypairGen.initialize(256, random);
    KeyPair keypair = keypairGen.generateKeyPair();
    
    // fill in certificate fields
    X500Name subject = new X500NameBuilder(BCStyle.INSTANCE)
        .addRDN(BCStyle.CN, "stackoverflow.com")
        .build();
    byte[] id = new byte[20];
    random.nextBytes(id);
    BigInteger serial = new BigInteger(160, random);
    X509v3CertificateBuilder certificate = new JcaX509v3CertificateBuilder(
        subject,
        serial,
        Date.from(LocalDate.of(2000, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()),
        Date.from(LocalDate.of(2035, 1, 1).atStartOfDay(ZoneOffset.UTC).toInstant()),
        subject,
        keypair.getPublic());
    certificate.addExtension(Extension.subjectKeyIdentifier, false, id);
    certificate.addExtension(Extension.authorityKeyIdentifier, false, id);
    BasicConstraints constraints = new BasicConstraints(true);
    certificate.addExtension(
        Extension.basicConstraints,
        true,
        constraints.getEncoded());
    KeyUsage usage = new KeyUsage(KeyUsage.keyCertSign | KeyUsage.digitalSignature);
    certificate.addExtension(Extension.keyUsage, false, usage.getEncoded());
    ExtendedKeyUsage usageEx = new ExtendedKeyUsage(new KeyPurposeId[] {
        KeyPurposeId.id_kp_serverAuth,
        KeyPurposeId.id_kp_clientAuth
    });
    certificate.addExtension(
        Extension.extendedKeyUsage,
        false,
        usageEx.getEncoded());
    
    // build BouncyCastle certificate
    ContentSigner signer = new JcaContentSignerBuilder("SHA256withECDSA")
        .build(keypair.getPrivate());
    X509CertificateHolder holder = certificate.build(signer);
    
    // convert to JRE certificate
    JcaX509CertificateConverter converter = new JcaX509CertificateConverter();
    converter.setProvider(new BouncyCastleProvider());
    X509Certificate x509 = converter.getCertificate(holder);
    
    // serialize in DER format
    byte[] serialized = x509.getEncoded();
    
    0 讨论(0)
  • 2020-11-27 19:21

    BEWARE: This answer uses an old version of the library with 11 CVEs.

    Here's what i'm using (with BouncyCastle v1.38):

    import java.math.BigInteger;
    import java.security.InvalidKeyException;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.NoSuchAlgorithmException;
    import java.security.NoSuchProviderException;
    import java.security.SecureRandom;
    import java.security.Security;
    import java.security.SignatureException;
    import java.util.Date;
    
    import javax.security.auth.x500.X500Principal;
    
    import java.security.cert.CertificateEncodingException;
    import java.security.cert.X509Certificate;
    
    import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
    import org.bouncycastle.asn1.x509.KeyPurposeId;
    import org.bouncycastle.asn1.x509.X509Extensions;
    import org.bouncycastle.asn1.x509.X509Name;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.bouncycastle.x509.X509V3CertificateGenerator;
    
    public class BouncyCastle {
    
        public static void main(String[] args) throws CertificateEncodingException, InvalidKeyException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
            X509Certificate selfSignedX509Certificate = new BouncyCastle().generateSelfSignedX509Certificate();
            System.out.println(selfSignedX509Certificate);
        }
    
        public X509Certificate generateSelfSignedX509Certificate() throws CertificateEncodingException, InvalidKeyException, IllegalStateException,
                NoSuchProviderException, NoSuchAlgorithmException, SignatureException {
            addBouncyCastleAsSecurityProvider();
    
            // generate a key pair
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
            keyPairGenerator.initialize(4096, new SecureRandom());
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
    
            // build a certificate generator
            X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
            X500Principal dnName = new X500Principal("cn=example");
    
            // add some options
            certGen.setSerialNumber(BigInteger.valueOf(System.currentTimeMillis()));
            certGen.setSubjectDN(new X509Name("dc=name"));
            certGen.setIssuerDN(dnName); // use the same
            // yesterday
            certGen.setNotBefore(new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000));
            // in 2 years
            certGen.setNotAfter(new Date(System.currentTimeMillis() + 2 * 365 * 24 * 60 * 60 * 1000));
            certGen.setPublicKey(keyPair.getPublic());
            certGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
            certGen.addExtension(X509Extensions.ExtendedKeyUsage, true,
                    new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping));
    
            // finally, sign the certificate with the private key of the same KeyPair
            X509Certificate cert = certGen.generate(keyPair.getPrivate(), "BC");
            return cert;
        }
    
        public void addBouncyCastleAsSecurityProvider() {
            Security.addProvider(new BouncyCastleProvider());
        }
    }
    

    For certGen.generate(keyPair.getPrivate(), "BC"); to work, BouncyCastle has to be added as a Security Provider.

    I confirmed that it works with this maven dependency:

    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk16</artifactId>
        <version>1.38</version>
    </dependency>
    
    0 讨论(0)
提交回复
热议问题