I generated a ca-certificate and a key with openssl.
openssl genrsa -aes256 -out $CANAME.key 4096
openssl req -x509 -new -nodes -key $CANAME.key -sha256 -days 1826 -out $CANAME.crt -subj '/CN=MyOrg Root CA/C=AT/ST=Vienna/L=Vienna/O=MyOrg'
Now I want to sign CSRs with those.
I found this question, but I can't use the accepted answer, because the class PKCS10CertificationRequestHolder
seems not to exist anymore.
Based on the seconds answer I created this service.
public class SignService {
private PrivateKey privateKey;
private X509CertificateHolder certificateHolder;
public SignService(
String caPathKey,
String caCert,
String caKeyPassword
) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
loadPrivateKey(caPathKey, caKeyPassword);
PEMParser pemParser = new PEMParser(new FileReader(caCert));
this.certificateHolder = (X509CertificateHolder) pemParser.readObject();
}
private void loadPrivateKey(String caPathKey, String caKeyPassword) throws IOException {
PEMParser pemParser = new PEMParser(new FileReader(caPathKey));
Object object = pemParser.readObject();
JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
KeyPair kp;
if (object instanceof PEMEncryptedKeyPair)
{
// Encrypted key - we will use provided password
PEMEncryptedKeyPair ckp = (PEMEncryptedKeyPair) object;
PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(caKeyPassword.toCharArray());
kp = converter.getKeyPair(ckp.decryptKeyPair(decProv));
}
else
{
// Unencrypted key - no password needed
PEMKeyPair ukp = (PEMKeyPair) object;
kp = converter.getKeyPair(ukp);
}
this.privateKey = kp.getPrivate();
}
public String signCRT(String crs_str) throws NoSuchProviderException, IOException, KeyStoreException, NoSuchAlgorithmException, OperatorCreationException, CMSException {
PemReader p = new PemReader(new StringReader(crs_str));
PemObject pemObject = p.readPemObject();
PKCS10CertificationRequest csr = new PKCS10CertificationRequest(pemObject.getContent());
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
X500Name issuer = certificateHolder.getIssuer();
BigInteger serial = new BigInteger(32, new SecureRandom());
Date from = new Date();
Date to = new Date(System.currentTimeMillis() + (365 * 86400000L));
X509v3CertificateBuilder certgen = new X509v3CertificateBuilder(issuer, serial, from, to, csr.getSubject(), csr.getSubjectPublicKeyInfo());
certgen.addExtension(X509Extension.basicConstraints, false, new BasicConstraints(false));
certgen.addExtension(X509Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(csr.getSubjectPublicKeyInfo().getEncoded()));
certgen.addExtension(X509Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(new GeneralNames(new GeneralName(this.certificateHolder.getSubject())), certificateHolder.getSerialNumber()));
ContentSigner signer = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(PrivateKeyFactory.createKey(this.privateKey.getEncoded()));
X509CertificateHolder holder = certgen.build(signer);
byte[] certencoded = holder.toASN1Structure().getEncoded();
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
signer = new JcaContentSignerBuilder("SHA1withRSA").build(this.privateKey);
generator.addSignerInfoGenerator(new JcaSignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().build()).build(signer, this.certificateHolder));
generator.addCertificate(new X509CertificateHolder(certencoded));
generator.addCertificate(new X509CertificateHolder(this.certificateHolder.getEncoded()));
CMSTypedData content = new CMSProcessableByteArray(certencoded);
CMSSignedData signeddata = generator.generate(content, true);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write("-----BEGIN PKCS #7 SIGNED DATA-----\n".getBytes("ISO-8859-1"));
byte[] cert_encoded = Base64.encode(signeddata.getEncoded());
for (int i = 0; i < cert_encoded.length; i++) {
if (i > 0 && i % 63 == 0) {
out.write('\n');
}
out.write(cert_encoded[i]);
}
out.write("\n-----END PKCS #7 SIGNED DATA-----\n".getBytes("ISO-8859-1"));
out.close();
return new String(out.toByteArray(), "ISO-8859-1");
}
}
The method signCrt
does not throw any exceptions and returns a string (I am not sure what).
I can't verify it or even show any information about the certificate.
This openssl command works with the same csr file, I want to do the same thing from java.
openssl x509 -req -in test.csr -CA $CANAME.crt -CAkey $CANAME.key -CAcreateserial -out openssl-signed.crt -days 730 -sha256
The certificate created with openssl is much smaller the of my java method (Don't know of this is a useful information).