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
);