2011-09-27 23 views
5

我試圖用下面的代碼生成帶有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(); 
} 

回答

5

我遇到了同樣的問題,並以下列快速解決它:

//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 Keystore最終實體證書中的頒發者名稱現在顯示按正確順序排列。

乾杯!

3

我有同樣的問題,有彈性的1.47。

首先,您必須注意類X500Name和X500Principal。有SUN課程和有彈性課程。他們完全不同!

X500Name(bouncy)應該使用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()); 
} 

希望它會是一個人:)有用

5

這可能有點簡單。至少在BC 1.48+,你可以這樣構造X500Name,並且OID將以預期的方式(或至少,你指定它們的方式)排序:

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

我認爲它應該是答案 – mlapeyre