证书主题和颁发者中的属性颠倒
我正在尝试使用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这可能会更简单一些。至少在 BC 1.48+ 中,您可以这样构造 X500Name,并且 OID 将以预期的方式排序(或者至少以您指定的方式排序):
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):
我遇到了同样的问题,并通过以下方法快速解决了它:
然后我将其与以下内容一起使用:
Java 密钥库最终实体证书中的颁发者名称现在以正确的顺序显示。
干杯!
I ran into the same issue and resolved it quickly with the following:
I then used it with the following:
The issuer name in the Java Keystore end entity certificate now shows up in the correct order.
Cheers!
我在 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 指令。所以我创建了这个方法:
希望它对某人有用:)
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 :
Hope it'll be useful to someone :)