11

以下のコードを使用して、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();
}
4

3 に答える 3

8

私は同じ問題に遭遇し、次の方法ですぐに解決しました。

//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 キーストア エンド エンティティ証明書の発行者名が正しい順序で表示されるようになりました。

乾杯!

于 2012-09-28T18:16:02.917 に答える
7

弾む1.47でも同じ問題がありました。

まず、クラス X500Name と X500Principal に注意する必要があります。SUNクラスとバウンシークラスがあります。全然違います!!

X500Name (弾む) は、X500NameBuilder を使用して作成する必要があります。ただし、文字列を使用して作成する必要がある場合は、属性を RFC2253 の逆順にする必要があります。これは、属性を次の順序にする必要があることを意味します: "CN、L、ST、O、OU、C、STREET、DC、UID "。

たとえば、私の場合、X500Principal (SUN) から X500Name (弾む) を作成する必要があり、それを行う唯一の方法は、属性を出力する 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());
}

それが誰かに役立つことを願っています:)

于 2012-09-18T21:55:21.907 に答える