CMP Client Support

This page provides some code sample and other information required when creating a CMP client. These code sample are not maintained, and may not be in accordance with future versions of BouncyCastle. 

HMAC protected (RA mode) certificate request (initial) message

// Just preparations
final BigInteger certReqId = BigInteger.valueOf(1);
final byte[] senderNonce = "12345".getBytes();
final byte[] transactionId = "23456".getBytes();
KeyPairGenerator kpi = KeyPairGenerator.getInstance("RSA");
kpi.initialize(1024);
KeyPair keyPair = kpi.generateKeyPair();
// Now on to the CMP 
CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(certReqId);
X500Name issuerDN = new X500Name("CN=ManagementCA");
X500Name subjectDN = new X500Name("CN=user");
msgbuilder.setIssuer(issuerDN);
msgbuilder.setSubject(subjectDN);
final byte[]                  bytes = keyPair.getPublic().getEncoded();
final ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
final ASN1InputStream         dIn = new ASN1InputStream(bIn);
final SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject());
dIn.close();
msgbuilder.setPublicKey(keyInfo);
GeneralName sender = new GeneralName(subjectDN);
msgbuilder.setAuthInfoSender(sender);
// RAVerified POP
msgbuilder.setProofOfPossessionRaVerified();
CertificateRequestMessage msg = msgbuilder.build();
org.bouncycastle.asn1.crmf.CertReqMessages msgs = new org.bouncycastle.asn1.crmf.CertReqMessages(msg.toASN1Structure());
org.bouncycastle.asn1.cmp.PKIBody pkibody = new org.bouncycastle.asn1.cmp.PKIBody(org.bouncycastle.asn1.cmp.PKIBody.TYPE_INIT_REQ, msgs);
// Message protection and final message
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
// Key Id used (required) by the recipient to do a lot of stuff
pbuilder.setSenderKID("KeyID".getBytes());
pbuilder.setBody(pkibody);
JcePKMACValuesCalculator jcePkmacCalc = new JcePKMACValuesCalculator();
final AlgorithmIdentifier digAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.26")); // SHA1
final AlgorithmIdentifier macAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.2.7")); // HMAC/SHA1
jcePkmacCalc.setup(digAlg, macAlg);
PKMACBuilder macbuilder = new PKMACBuilder(jcePkmacCalc);
MacCalculator macCalculator = macbuilder.build("password".toCharArray());
ProtectedPKIMessage message = pbuilder.build(macCalculator);

HMAC protected (RA mode) revocation request message

// Just preparations
final byte[] senderNonce = "12345".getBytes();
final byte[] transactionId = "23456".getBytes();
BigInteger serNo = new BigInteger("aabbccdd");
X500Name issuerDN = new X500Name("CN=ManagementCA");
X500Name userDN = new X500Name("CN=user");
// Cert template too tell which cert we want to revoke
CertTemplateBuilder myCertTemplate = new CertTemplateBuilder();
myCertTemplate.setIssuer(issuerDN);
myCertTemplate.setSubject(userDN);
myCertTemplate.setSerialNumber(new ASN1Integer(serNo));
// Extension telling revocation reason
ExtensionsGenerator extgen = new ExtensionsGenerator();
CRLReason crlReason = CRLReason.lookup(CRLReason.cessationOfOperation);
extgen.addExtension(Extension.reasonCode, false, crlReason);        
Extensions exts = extgen.generate();
ASN1EncodableVector v = new ASN1EncodableVector();
v.add(myCertTemplate.build());
v.add(exts);
ASN1Sequence seq = new DERSequence(v);
RevDetails myRevDetails = RevDetails.getInstance(seq);
RevReqContent myRevReqContent = new RevReqContent(myRevDetails);
PKIBody myPKIBody = new PKIBody(PKIBody.TYPE_REVOCATION_REQ, myRevReqContent); // revocation request
// Message protection and final message
GeneralName sender = new GeneralName(userDN);
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
// Key Id used (required) by the recipient to do a lot of stuff
pbuilder.setSenderKID("KeyId".getBytes());
pbuilder.setBody(myPKIBody);
JcePKMACValuesCalculator jcePkmacCalc = new JcePKMACValuesCalculator();
final AlgorithmIdentifier digAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.3.14.3.2.26")); // SHA1
final AlgorithmIdentifier macAlg = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.840.113549.2.7")); // HMAC/SHA1
jcePkmacCalc.setup(digAlg, macAlg);
PKMACBuilder macbuilder = new PKMACBuilder(jcePkmacCalc);
MacCalculator macCalculator = macbuilder.build("password".toCharArray());
ProtectedPKIMessage message = pbuilder.build(macCalculator);

Signature protected (Client mode) message

CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(BigInteger.valueOf(certReqId));
X509NameEntryConverter dnconverter = new X509DefaultEntryConverter();
X500Name issuerDN = X500Name.getInstance(new X509Name("CN=ManagementCA").toASN1Object());
X500Name subjectDN = X500Name.getInstance(new X509Name("CN=user", dnconverter).toASN1Object());
msgbuilder.setIssuer(issuerDN);
msgbuilder.setSubject(subjectDN);
final byte[]                  bytes = keyPair.getPublic().getEncoded();
final ByteArrayInputStream    bIn = new ByteArrayInputStream(bytes);
final ASN1InputStream         dIn = new ASN1InputStream(bIn);
final SubjectPublicKeyInfo keyInfo = new SubjectPublicKeyInfo((ASN1Sequence)dIn.readObject());
msgbuilder.setPublicKey(keyInfo);
GeneralName sender = new GeneralName(subjectDN);
msgbuilder.setAuthInfoSender(sender);
Control control = new RegTokenControl("foo123");
msgbuilder.addControl(control);
Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
ContentSigner popsigner = new JcaContentSignerBuilder("SHA256withRSA").setProvider(prov).build(keyPair.getPrivate());
msgbuilder.setProofOfPossessionSigningKeySigner(popsigner);
CertificateRequestMessage msg = msgbuilder.build();
GeneralName recipient = new GeneralName(issuerDN);
ProtectedPKIMessageBuilder pbuilder = new ProtectedPKIMessageBuilder(sender, recipient);
pbuilder.setMessageTime(new Date());
// senderNonce
pbuilder.setSenderNonce(senderNonce);
// TransactionId
pbuilder.setTransactionID(transactionId);
org.bouncycastle.asn1.crmf.CertReqMessages msgs = new org.bouncycastle.asn1.crmf.CertReqMessages(msg.toASN1Structure());
org.bouncycastle.asn1.cmp.PKIBody pkibody = new org.bouncycastle.asn1.cmp.PKIBody(org.bouncycastle.asn1.cmp.PKIBody.TYPE_INIT_REQ, msgs);
pbuilder.setBody(pkibody);
ContentSigner msgsigner = new JcaContentSignerBuilder("SHA1withRSA").setProvider(prov).build(keyPair.getPrivate());
ProtectedPKIMessage message = pbuilder.build(msgsigner);

Message with Multiple Signatures

Sample code for a signature protected NestedMessageContent message:

String subjectDN = "CN=bogusSubjectNested";
final byte[] nonce = "sendernonce".getBytes();
final byte[] transid = "trandis".getBytes();

PKIMessage crmfMsg = createCrmfReq();
//Signing crmfMsg
KeyPair eeKeys = getAdminKeys();
Certificate adminCert = getAdminCertificate();
ByteArrayInputStream    bIn = new ByteArrayInputStream(adminCert.getEncoded());
ASN1InputStream         dIn = new ASN1InputStream(bIn);
ASN1Sequence extraAdminCertSeq = (ASN1Sequence)dIn.readObject();
X509CertificateStructure extraCert = new X509CertificateStructure(ASN1Sequence.getInstance(extraAdminCertSeq));
crmfMsg.addExtraCert(extraCert);

final Signature sig = Signature.getInstance(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(eekeys.getPrivate());
sig.update(crmfMsg.getProtectedBytes());
byte[] eeSignature = sig.sign();
crmfMsg.setProtection(new DERBitString(eeSignature));

PKIHeader myPKIHeader = new PKIHeader(new DERInteger(2), new GeneralName(new X509Name(subjectDN)), new GeneralName(new X509Name(((X509Certificate)cacert).getSubjectDN().getName())));
myPKIHeader.setMessageTime(new DERGeneralizedTime(new Date()));
// senderNonce
myPKIHeader.setSenderNonce(new DEROctetString(nonce));
// TransactionId
myPKIHeader.setTransactionID(new DEROctetString(transid));

PKIBody myPKIBody = new PKIBody(crmfMsg, 20); // NestedMessageContent
PKIMessage myPKIMessage = new PKIMessage(myPKIHeader, myPKIBody);
//Signing myPKIMessage
KeyPair raKeys = getRAKeys();
final Signature sig = Signature.getInstance(PKCSObjectIdentifiers.sha256WithRSAEncryption.getId(), BouncyCastleProvider.PROVIDER_NAME);
sig.initSign(rakeys.getPrivate());
sig.update(myPKIMessage.getProtectedBytes());
byte[] eeSignature = sig.sign();
myPKIMessage.setProtection(new DERBitString(eeSignature));

final ByteArrayOutputStream bao = new ByteArrayOutputStream();
final DEROutputStream out = new DEROutputStream(bao);
out.writeObject(myPKIMessage);
final byte[] ba = bao.toByteArray();
// Send request and receive response
final byte[] resp = sendCmpHttp(ba, 200);