我正在尝试使用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();
}
答案 0 :(得分:6)
这可能有点简单。至少在BC 1.48+中,您可以这样构造X500Name,并且OID将以预期的方式(或者至少以您指定的方式)进行排序:
final X500Name subject = new X500Name(RFC4519Style.INSTANCE, "CN=test,O=gina");
答案 1 :(得分: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结束实体证书中的颁发者名称现在以正确的顺序显示。
干杯!
答案 2 :(得分:4)
我和弹性1.47有同样的问题。
首先,您必须小心X500Name和X500Principal类。有SUN课程和充气课程。他们是完全不同的!!
应使用X500NameBuilder创建X500Name(bouncy)。 但是如果需要使用String创建它,那么您的属性必须与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());
}
希望它对某人有用:)