Wednesday, March 26, 2014

EJBCA Enterprise 6.1.0 released

The PrimeKey EJBCA® team is happy to announce the release of EJBCA Enterprise 6.1.0.
This release resolves several issues, with a few highlights: Increased performance through OCSP improvements; Key Recovery improvements; support for EAC 2.10 (ePassport) access control templates.
Running on the latest technology platforms, EJBCA Enterprise v.6 is so flexible it is suitable for any organization, cloud, social or mobile system. Faster, more resource efficient, more secure and more user friendly than ever.

EJBCA Enterprise *6.1.0* release notes

A maintenance release containing 32 new features and improvements, below a selection of the most noteworthy:
  • New features

    • New OCSP features related to RFC 6960, minimizing size of OCSP responses.
    • Implemented OCSP signing algorithm selection from client requested algorithms.
    • CVC certificate profiles (ePassport PKI) now supports EAC 2.10 access control templates.
  • Improvements

    • OCSP improvements with more cache control settings.
    • Improvements to Key Recovery, enabling encryption key rollover and providing more information about encryption keys.
    • Ability to build and install EJBCA on Windows platforms.
    • The ManagementCA created during default install, now uses SHA256WithRSA.
    • EJBCA compiles cleanly with Java 8, WildFly 8 and Glassfish 4 (running on those platforms however, is not yet supported).
    • EJBCA can now use certificate serial number longer than 64 bits.
    • Many reported minor issues have been fixed, as well as minor GUI improvements.

More information

Basic information on EJBCA Enterprise PKI is available here. For entire technical details view the changelog in the PrimeKey Issue Tracker.
EJBCA is a registered trademark of PrimeKey Solutions AB in the EU, the United States, Japan and certain other countries.

Wednesday, March 12, 2014

Using CMP with BouncyCastle Java API

Introduction

A convenient method to enroll for certificates and do automatic certificate renewal, is to use the BouncyCastle API to implement a client that uses the CMP (RFC4210) protocol. In this example the implementation is done using java code and you need a CA that supports the CMP protocol on the server side.

Using the CMP protocol is a good way to integrate clients and RAs in a PKI, and BouncyCastle API is a great tool for this task. By the way, BouncyCastle needs your support to fund a FIPS certification. Help spread the word.

A short background on CMP

The open source CA EJBCA, implements many standard PKI protocols, CMP being one of them.

In the early days of CMP there were mainly commercial SDK implementations, and only a single open source instance (written in C). As always, that slowed down adoption. Nowadays, there is full support for CMP in the governing de-facto standard java crypto API BouncyCastle. No more excuses not to use CMP! :-)

Described more in detail in a previous blog post is CMP and its implementation in EJBCA.

Examples on how to use BouncyCastle CMP API

Here, I will show two different enrollment types (with source code) for the client implementation: 1) an RA using a shared secret authentication and 2) a client using certificate authentication.
These are by no means everything you can do. The RA can also use certificate authentication, or you can do nested messages with multiple layers of authentication. And many, many more! Only your imagination sets the limits :-).

All mentioned configurations can be active at the same time when using EJBCA 6. For complete documentation, see the Admin Guide at EJBCA.org.

Enrollment type 1) RA with shared secret authentication

Using an RA means the RA is configured to order certificates for its clients. The clients themselves will not be pre-registered by the CA, but will be added by the RA when it enrolls for the client.

To create a CMP enrollment message for an RA, using BouncyCastle:

CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(BigInteger.valueOf(certReqId));
X509NameEntryConverter dnconverter = new X509DefaultEntryConverter();
X500Name issuerDN = X500Name.getInstance(new X509Name("CN=AdminCA1").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);
// RAVerified POP
msgbuilder.setProofOfPossessionRaVerified();
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);
// Key Id used (required) by the recipient to do a lot of stuff
pbuilder.setSenderKID("KeyId".getBytes());
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);
JcePKMACValuesCalculator jcePkmacCalc = new JcePKMACValuesCalculator();
final AlgorithmIdentifier digAlg = new AlgorithmIdentifier("1.3.14.3.2.26"); // SHA1
final AlgorithmIdentifier macAlg = new AlgorithmIdentifier("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);
       
The above requires a CMP alias with approximately the following EJBCA configuration:
  • RA mode.
  • HMAC authentication module.
  • Specified secret 'password1'.
  • DN parts with CN as RA name generation scheme.

Enrollment type 2) Pre-registered client with certificate authentication

Using a client means that the client is already registered and present on the CA, able to authenticate itself with a certificate. The certificate can be generated by other means than the CA, or be imported into EJBCA.

To generate a signature protected CMP enrollment message using BouncyCastle:
       
CertificateRequestMessageBuilder msgbuilder = new CertificateRequestMessageBuilder(BigInteger.valueOf(certReqId));
X509NameEntryConverter dnconverter = new X509DefaultEntryConverter();
X500Name issuerDN = X500Name.getInstance(new X509Name("CN=AdminCA1").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("BC");
ContentSigner popsigner = new JcaContentSignerBuilder("SHA1withRSA").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);
       

The above requires a CMP alias with approximately the following EJBCA configuration (use a new CMP alias so you can run this and the previous config in parallell):
  • Client mode.
  • EndEntityCertificate authentication module.
  • CN as extract username component.

About the author

Tomas Gustavsson, CTO of PrimeKey, founder of EJBCA
Contact me at tomas(at)primekey.se.
Follow me on Twitter.