Java中带有Bouncy Castle的自签名X509证书

Java中带有Bouncy Castle的自签名X509证书,java,cryptography,certificate,bouncycastle,x509,Java,Cryptography,Certificate,Bouncycastle,X509,我需要用Java中的Bouncy Castle创建一个自签名X509证书,但我尝试包含的每个类都不推荐使用。 我怎样才能解决这个问题?还有其他的课程吗? 谢谢。注意:此答案使用了旧版本的库。 以下是我使用的内容(BouncyCastle v1.38版): 对于certGen.generate(keyPair.getPrivate(),“BC”)要工作,必须将BouncyCastle添加为安全提供程序 我确认它与这个maven依赖项一起工作: <dependency> <

我需要用Java中的Bouncy Castle创建一个自签名X509证书,但我尝试包含的每个类都不推荐使用。 我怎样才能解决这个问题?还有其他的课程吗?
谢谢。

注意:此答案使用了旧版本的库。

以下是我使用的内容(BouncyCastle v1.38版):

对于
certGen.generate(keyPair.getPrivate(),“BC”)要工作,必须将BouncyCastle添加为安全提供程序

我确认它与这个maven依赖项一起工作:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk16</artifactId>
    <version>1.38</version>
</dependency>

org.bouncycastle
bcprov-jdk16
1.38
使用Bouncycastle最新版本-1.55 1.66 通过@Bewusstsein更新答案。截至本答案(2017年5月11日)的最新版本中不推荐使用bouncycastle类。如果您使用的是1.55或更高版本:

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));
}
public static Certificate selfSign(KeyPair KeyPair,String subjectDN)抛出运算符CreationException、CertificateException、IOException
{
Provider bcProvider=新的BouncyCastleProvider();
Security.addProvider(bcProvider);
long now=System.currentTimeMillis();
日期开始日期=新日期(现在);
X500Name dnName=新的X500Name(主题DN);

BigInteger certSerialNumber=新的BigInteger(Long.toString(now));//这是一个完整的自签名ECDSA证书生成器,它可以在客户端和服务器端的TLS连接中创建可用的证书。它是用BouncyCastle 1.57测试的。类似的代码可以用于创建RSA证书

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();

这是BouncyCastle it self用于生成X.509证书的代码。 您将需要从BC获得一个数据库来使用它。 有关如何使用它的更多详细信息,请查看问题(主类)


编辑:我记不清我到底是从哪个BC测试中获得的,但这里有一些类似的内容

根据证书的预期用途,您可能需要添加更多扩展(使用addExtension,如答案所示)。当前2015年3月版本的Bouncycastle for Java为1.52。能否将此代码转换为SSCCE?我无法找到您需要的依赖项used@Dipu完成了,我刚刚测试了它,它对我有效。学习经验:使用
SubjectPublicKeyInfo SubjectPublicKeyInfo=SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
或您的X.509证书将与Java密钥库不兼容。问题是公钥的密钥生成算法与签名算法本身不同。有趣的是,尝试
AlgorithmIdentifier AlgorithmIdentifier=新算法标识符(PKCSObjectIdentifiers.rsaEncryption,DERNull.INSTANCE)
直接失败。重新使用您的代码。请注意,它与您的原始代码一起失败。不过,感谢您确保我不必亲自从base中找出这个问题。请求对此答案进行投票,希望您能获得更多的代表。@Bodewes您是对的,我没有通过存储在密钥库中来测试它。感谢您对它进行测试。Th更正后的代码现在应该可以与Java密钥库一起使用。您可以在其他答案中使用更正后的代码。它可以工作!我必须将
“EC”
替换为
“RSA”
替换为
keypairGen.initialize(512,random);
将“SHA256withECDSA”
替换为
“SHA256withRSA”
但是。@EvgeniyPhilippov请不要发布不安全的参数(RSA要求密钥大小为2048位或更多)没有任何警告。我只是注意到我投了反对票——我不知道是怎么发生的——一定是误点击。除非问题被编辑,否则我无法撤销这一点——也许你可以编辑它,比如说,一条评论,说明代码的来源——然后我可以撤销我的反对票。很抱歉,这以前从未发生过!@Rodney没问题,谢谢对于答案,我编辑它
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();
    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;
    }
}