证书主题和颁发者中的属性颠倒

发布于 2024-12-06 14:22:00 字数 3274 浏览 3 评论 0原文

我正在尝试使用 bouncycastle 1.46 生成 X509 证书,代码如下。 我遇到的问题是,当证书写入 JKS 然后重新读取时,DN 会颠倒。 例如,如果我运行下面的代码,我会得到以下输出:

CN=test,O=gina
CN=test,O=gina
CN=test,O=gina
O=gina, CN=test

有人知道这个的原因吗?如何避免呢? 提前致谢。

代码:

public static void main(String[] args) {
    try {
        Security.addProvider(new BouncyCastleProvider());

        KeyPair pair = generateKeyPair("RSA", 1024);
        X500Name principal = new X500Name("cn=test,o=gina");
        System.out.println(principal);
        BigInteger sn = BigInteger.valueOf(1234);
        Date start = today();
        Date end = addYears(start, 2);
        X509Certificate cert = generateCert(principal, pair, sn, start, end,
                "SHA1withRSA");
        cert.verify(pair.getPublic());
        System.out.println(cert.getSubjectDN());

        // Store the certificate in the JKS
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(null, null);
        ks.setKeyEntry("alias", pair.getPrivate(), KEY_PWD,
                new X509Certificate[] {cert});
        X509Certificate c
                = (X509Certificate)ks.getCertificateChain("alias")[0];
        System.out.println(c.getSubjectDN());
        OutputStream out = new FileOutputStream("text.jks");
        try {
            ks.store(out, KEYSTORE_PWD);
        } finally {
            out.close();
        }

        // Reread the JKS
        ks = KeyStore.getInstance("JKS");
        InputStream in = new FileInputStream("text.jks");
        try {
            ks.load(in, KEYSTORE_PWD);
        } finally {
            in.close();
        }
        c = (X509Certificate)ks.getCertificateChain("alias")[0];
        c.verify(pair.getPublic());
        System.out.println(c.getSubjectDN());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static X509Certificate generateCert(X500Name principal,
        KeyPair pair, BigInteger sn, Date start, Date end, String sigalg)
        throws OperatorCreationException, CertificateException {
    JcaX509v3CertificateBuilder certGen
            = new JcaX509v3CertificateBuilder(principal, sn, start, end,
                    principal, pair.getPublic());
    JcaContentSignerBuilder builder
            = new JcaContentSignerBuilder(sigalg);
    builder.setProvider("BC");
    ContentSigner signr = builder.build(pair.getPrivate());
    X509CertificateHolder certHolder = certGen.build(signr);
    JcaX509CertificateConverter conv
            = new JcaX509CertificateConverter();
    conv.setProvider("BC");
    return conv.getCertificate(certHolder);
}

private static KeyPair generateKeyPair(String algorithm, int keySize)
        throws NoSuchAlgorithmException {
    KeyPairGenerator gen = KeyPairGenerator.getInstance(algorithm);
    gen.initialize(keySize);
    return gen.generateKeyPair();
}

private static Date today() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

private static Date addYears(Date date, int count) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.add(Calendar.YEAR, count);
    return cal.getTime();
}

I am trying to generate X509 certificates with bouncycastle 1.46, with the code below.
The issue I have is that when a certificate is written in a JKS and then reread, the DNs are reversed.
For instance, if I run the code below, I get the following output:

CN=test,O=gina
CN=test,O=gina
CN=test,O=gina
O=gina, CN=test

Does anybody know the reason for this? how to avoid it?
Thanks in advance.

Code:

public static void main(String[] args) {
    try {
        Security.addProvider(new BouncyCastleProvider());

        KeyPair pair = generateKeyPair("RSA", 1024);
        X500Name principal = new X500Name("cn=test,o=gina");
        System.out.println(principal);
        BigInteger sn = BigInteger.valueOf(1234);
        Date start = today();
        Date end = addYears(start, 2);
        X509Certificate cert = generateCert(principal, pair, sn, start, end,
                "SHA1withRSA");
        cert.verify(pair.getPublic());
        System.out.println(cert.getSubjectDN());

        // Store the certificate in the JKS
        KeyStore ks = KeyStore.getInstance("JKS");
        ks.load(null, null);
        ks.setKeyEntry("alias", pair.getPrivate(), KEY_PWD,
                new X509Certificate[] {cert});
        X509Certificate c
                = (X509Certificate)ks.getCertificateChain("alias")[0];
        System.out.println(c.getSubjectDN());
        OutputStream out = new FileOutputStream("text.jks");
        try {
            ks.store(out, KEYSTORE_PWD);
        } finally {
            out.close();
        }

        // Reread the JKS
        ks = KeyStore.getInstance("JKS");
        InputStream in = new FileInputStream("text.jks");
        try {
            ks.load(in, KEYSTORE_PWD);
        } finally {
            in.close();
        }
        c = (X509Certificate)ks.getCertificateChain("alias")[0];
        c.verify(pair.getPublic());
        System.out.println(c.getSubjectDN());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static X509Certificate generateCert(X500Name principal,
        KeyPair pair, BigInteger sn, Date start, Date end, String sigalg)
        throws OperatorCreationException, CertificateException {
    JcaX509v3CertificateBuilder certGen
            = new JcaX509v3CertificateBuilder(principal, sn, start, end,
                    principal, pair.getPublic());
    JcaContentSignerBuilder builder
            = new JcaContentSignerBuilder(sigalg);
    builder.setProvider("BC");
    ContentSigner signr = builder.build(pair.getPrivate());
    X509CertificateHolder certHolder = certGen.build(signr);
    JcaX509CertificateConverter conv
            = new JcaX509CertificateConverter();
    conv.setProvider("BC");
    return conv.getCertificate(certHolder);
}

private static KeyPair generateKeyPair(String algorithm, int keySize)
        throws NoSuchAlgorithmException {
    KeyPairGenerator gen = KeyPairGenerator.getInstance(algorithm);
    gen.initialize(keySize);
    return gen.generateKeyPair();
}

private static Date today() {
    Calendar cal = Calendar.getInstance();
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    return cal.getTime();
}

private static Date addYears(Date date, int count) {
    Calendar cal = Calendar.getInstance();
    cal.setTime(date);
    cal.add(Calendar.YEAR, count);
    return cal.getTime();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

埋情葬爱 2024-12-13 14:22:00

这可能会更简单一些。至少在 BC 1.48+ 中,您可以这样构造 X500Name,并且 OID 将以预期的方式排序(或者至少以您指定的方式排序):

final X500Name subject = new X500Name(RFC4519Style.INSTANCE, "CN=test,O=gina");

This may be a bit simpler. At least in BC 1.48+, you can construct the X500Name thusly, and the OIDs will be ordered in the expected way (or at least, the way you specify them):

final X500Name subject = new X500Name(RFC4519Style.INSTANCE, "CN=test,O=gina");
妄想挽回 2024-12-13 14:22:00

我遇到了同样的问题,并通过以下方法快速解决了它:

//CREATES AN X500 CA SUBJECT FOR ISSUER

X500Name issuerName = new JcaX509CertificateHolder((X509Certificate) caCert).getSubject();

然后我将其与以下内容一起使用:

//CONSTRUCTS THE X509 CERTIFIFATE OBJECT

X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
issuerName, 
serialNumber, 
startDate, endDate, 
DevCsr.getSubject(), 
DevCsr.getSubjectPublicKeyInfo());

Java 密钥库最终实体证书中的颁发者名称现在以正确的顺序显示。

干杯!

I ran into the same issue and resolved it quickly with the following:

//CREATES AN X500 CA SUBJECT FOR ISSUER

X500Name issuerName = new JcaX509CertificateHolder((X509Certificate) caCert).getSubject();

I then used it with the following:

//CONSTRUCTS THE X509 CERTIFIFATE OBJECT

X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
issuerName, 
serialNumber, 
startDate, endDate, 
DevCsr.getSubject(), 
DevCsr.getSubjectPublicKeyInfo());

The issuer name in the Java Keystore end entity certificate now shows up in the correct order.

Cheers!

初雪 2024-12-13 14:22:00

我在 bouncy 1.47 上也遇到了同样的问题。

首先,您必须小心 X500Name 和 X500Principal 类。有SUN课程和弹跳课程。他们完全不同!!

X500Name (bouncy) 应使用 X500NameBuilder 创建。
但是如果您需要使用字符串创建它,那么您的属性必须采用 RFC2253 的相反顺序,这意味着您的属性必须采用以下顺序:“ CN、L、ST、O、OU、C、STREET、DC、UID ”。

这并不方便,因为,例如,在我的例子中,我必须从 X500Principal (SUN) 创建一个 X500Name (bouncy),唯一的方法是使用 X500Principal:getName() 方法,该方法根据 X500Principal:getName() 打印属性符合 RFC2253 指令。所以我创建了这个方法:

private org.bouncycastle.asn1.x500.X500Name toBouncyX500Name( javax.security.auth.x500.X500Principal principal) {

    String name = principal.getName();

    String[] RDN = name.split(",");

    StringBuffer buf = new StringBuffer(name.length());
    for(int i = RDN.length - 1; i >= 0; i--){
        if(i != RDN.length - 1)
            buf.append(',');

        buf.append(RDN[i]);
    }

    return new X500Name(buf.toString());
}

希望它对某人有用:)

I had the same problem with bouncy 1.47.

First you must be careful with the classes X500Name and X500Principal. There are the SUN classes and the bouncy classes. They are totally different !!

X500Name (bouncy) should be created using X500NameBuilder.
But If you need to create it using a String then your attributes must be in the reverse order of RFC2253, this means your attributes must be in this order : " CN, L, ST, O, OU, C, STREET, DC, UID ".

This is not convenient because, for example, in my case, I had to create a X500Name (bouncy) from a X500Principal (SUN) and the only way to do it was to use the X500Principal:getName() method which print the attributes according to RFC2253 order. So I created this method :

private org.bouncycastle.asn1.x500.X500Name toBouncyX500Name( javax.security.auth.x500.X500Principal principal) {

    String name = principal.getName();

    String[] RDN = name.split(",");

    StringBuffer buf = new StringBuffer(name.length());
    for(int i = RDN.length - 1; i >= 0; i--){
        if(i != RDN.length - 1)
            buf.append(',');

        buf.append(RDN[i]);
    }

    return new X500Name(buf.toString());
}

Hope it'll be useful to someone :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文