Атрибуты в субъекте сертификата и издателе поменялись местами

Я пытаюсь сгенерировать сертификаты X509 с помощью bouncycastle 1.46 с кодом ниже. У меня проблема в том, что когда сертификат записывается в 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();
}

person Maurice Perry    schedule 27.09.2011    source источник


Ответы (3)


Я столкнулся с той же проблемой и быстро решил ее следующим образом:

//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 теперь отображается в правильном порядке.

Ваше здоровье!

person SRosonina    schedule 28.09.2012

Это может быть немного проще. По крайней мере, в BC 1.48+ вы можете построить X500Name таким образом, и OID будут упорядочены ожидаемым образом (или, по крайней мере, так, как вы их укажете):

final X500Name subject = new X500Name(RFC4519Style.INSTANCE, "CN=test,O=gina");
person MushyMiddle    schedule 06.07.2016
comment
Я думаю, это должен быть ответ - person mlapeyre; 23.06.2017

У меня была такая же проблема с bouncy 1.47.

Во-первых, вы должны быть осторожны с классами X500Name и X500Principal. Есть классы SUN и классы бодрости. Они совсем другие!!

X500Name (bouncy) должен быть создан с помощью X500NameBuilder. Но если вам нужно создать его с помощью строки, ваши атрибуты должны быть в порядке, обратном RFC2253, это означает, что ваши атрибуты должны быть в следующем порядке: «CN, L, ST, O, OU, C, STREET, DC, UID ".

Это неудобно, потому что, например, в моем случае мне пришлось создать X500Name (bouncy) из X500Principal (SUN), и единственный способ сделать это — использовать метод 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());
}

Надеюсь кому-то будет полезно :)

person Ghetolay    schedule 18.09.2012
comment
заказ не был бы проблемой для меня, если бы проверка сертификата прошла успешно. провел часы отладки рукопожатия SSL, пока не обнаружил, что сертификат не может быть найден, потому что порядок атрибутов был обратным. большой фейспалм здесь! - person benez; 22.05.2018