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();
}
The certificate includes information about the key, information about the identity of its owner (called the subject), and the digital signature of an entity that has verified the certificate's contents (called the issuer).
Some of the most common RDNs and their explanations are as follows: CN : CommonName. OU : OrganizationalUnit. O : Organization.
Subject is the certificate's common name and is a critical property for the certificate in a lot of cases if it's a server certificate and clients are looking for a positive identification. As an example on an SSL certificate for a web site the subject would be the domain name of the web site.
I ran into the same issue and resolved it quickly with the following:
//CREATES AN X500 CA SUBJECT FOR ISSUER
X500Name issuerName = new JcaX509CertificateHolder((X509Certificate) caCert).getSubject();
I then used it with the following:
//CONSTRUCTS THE X509 CERTIFIFATE OBJECT
X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(
issuerName,
serialNumber,
startDate, endDate,
DevCsr.getSubject(),
DevCsr.getSubjectPublicKeyInfo());
The issuer name in the Java Keystore end entity certificate now shows up in the correct order.
Cheers!
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):
final X500Name subject = new X500Name(RFC4519Style.INSTANCE, "CN=test,O=gina");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With