-
Notifications
You must be signed in to change notification settings - Fork 1.1k
BC "Version 2" The post BC 1.46 changes
The changes to the APIs around 1.46/1.47 were the result of us having to work around the idiosyncrasies of multiple providers as well as trying to find ways to accommodate some of the newer cryptography APIs that are appearing for small devices. These are often not JCE/JCA provider based, and are generally targeted to specific functionality. Requests for this kind of functionality have been increasing in respect to the lightweight APIs as well, largely due to the market evolving from the devices with single threaded VMs and a 32k footprint of 10 years ago to substantially larger and fully featured VMs we have today.
Broadly speaking the "Version 2" APIs are built around the idea of operators, which are interfaces that provide specific types of cryptographic functionality. CMS, CRMF, CMP, TSP, and OCSP messages, to name but a few, as well as certificates, can then be built by providing the appropriate operators to meet the requirements of the protocol.
The result of this is that it is now possible to create things like certificates and CMS messages using the BC lightweight API, and this document is meant to provide some help in seeing how that is done.
For the purposes of the final 1.* release of BC, version 1.46, the version 2 APIs are included in the bcmail package. From 1.47, the version 2 APIs are in the pcpkix packages, and bcmail now only contains the S/MIME package.
Core to creating a certificate is the ability to create a signature.
In the version 2 API an example of certificate creation looks as follows:
ContentSigner sigGen = ...;
SubjectPublicKeyInfo subPubKeyInfo = ....;
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
X509v1CertificateBuilder v1CertGen = new X509v1CertificateBuilder(
new X500Name("CN=Test"),
BigInteger.ONE,
startDate, endDate,
new X500Name("CN=Test"),
subPubKeyInfo);
X509CertificateHolder certHolder = v1CertGen.build(sigGen);
We'll start by looking at sigGen
first. In a situation where you're using the JCA a builder is provider for creating objects with the ContentSigner
interface which have underlying implementations using the JCA. This class is the JcaContentSignerBuilder
and in the case where we wanted to create a SHA1withRSA signer, we might create sigGen
as follows:
sigGen = new JcaContentSignerBuilder("SHA1withRSA").setProvider("BC").build(privKey);
In the above case privKey
is simply the PrivateKey
object representing the private key we are signing with.
Of course we may actually be wanting to do this using the BC lightweight API. In this case we can use the BcRSAContentSignerBuilder
. In this case the code for creating a SHA1withRSA signature might look as follows:
AlgorithmIdentifier sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find("SHA1withRSA");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
sigGen = new BcRSAContentSignerBuilder(sigAlgId, digAlgId).build(lwPrivKey);
where lwPrivKey
is an RSA private key as described in the BC lightweight API.
Where this gets more interesting is we can now also apply our sigGen
value to signing a CMS message as follows:
X509CertificateHolder sigCert = ...;
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
gen.addSignerInfoGenerator(
new SignerInfoGeneratorBuilder(new BcDigestCalculatorProvider())
.build(sigGen, sigCert));
Of course it might be the case that you do not wish to use either the JCA or the BC lightweight API. If this is the case, then it is just a matter of implementing the ContentSigner
interface.
Of course having created a signature it's useful to be able to verify it.
Verification is a little bit more involved than signature creation, the issue being that you really need to know what kind of signature you are trying to verify before you can make sense of it.
In the case of certificates the X509CertificateHolder
class provides a method, isSignatureValid
which allows you to verify the signature on the certificate the holder class contains. The isSignatureValid
method takes a ContentVerifierProvider
class, and queries it to create a content verifier capable of verifying the content (in the this case the TBSCertificate
structure) and the signature match.
Standard implementations providing the core functionality are provided for both lightweight and provider based implementations.
In the case of the lightweight API, assuming we have a suitable public key in the lwPubKey
object, the code for doing the signature verification looks as follows:
ContentVerifierProvider contentVerifierProvider = new BcRSAContentVerifierProviderBuilder(
new DefaultDigestAlgorithmIdentifierFinder())
.build(lwPubKey);
if (!certHolder.isSignatureValid(contentVerifierProvider))
{
System.err.println("signature invalid");
}
A more general class is provided for use with the JCA - in the simple case all you need to do is specify which provider you want to use as follows:
ContentVerifierProvider contentVerifierProvider = new JcaContentVerifierProviderBuilder()
.setProvider("BC").build(pubKey);
if (!certHolder.isSignatureValid(contentVerifierProvider))
{
System.err.println("signature invalid");
}
Verifying the signature on a SignerInformation
object is a little more complicated as for the most part it requires a separate digest calculator to be available as well. Code for doing this using the general lightweight API to process RSA signatures looks like this:
if (signer.verify(new BcRSASignerInfoVerifierBuilder(new DefaultDigestAlgorithmIdentifierFinder(), new BcDigestCalculatorProvider()).build(cert))))
{
System.err.println("signer verified");
}
Of course if you know the digest algorithms to expect it is possible to implement your own DigestCalculatorProvider
that is restricted to the necessary algorithms.
In the case of a JCA/JCE provider based solution, where the same provider can be used for both signature verification and digest calculation, you can use the following:
if (signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert))
{
System.err.println("signer verified);
}
In the case where you need to use different providers or even a provider/lightweight combination you can use the SignerInformationVerifier
class to create a verifier.
The certificate generation example about could also have been written as:
ContentSigner sigGen = ...;
PublicKey publicKey = ....;
Date startDate = new Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000);
Date endDate = new Date(System.currentTimeMillis() + 365 * 24 * 60 * 60 * 1000);
X509v1CertificateBuilder v1CertGen = new JcaX509v1CertificateBuilder(
new X500Principal("CN=Test"),
BigInteger.ONE,
startDate, endDate,
new X500Principal("CN=Test"),
publicKey);
X509CertificateHolder certHolder = v1CertGen.build(sigGen);
likewise in the CMS signing example the required X509CertificateHolder
could be created from a JCA X509Certificate
so the declaration of sigCert
would appear as:
X509Certificate origCert = ...;
X509CertificateHolder sigCert = new JcaX509CertificateHolder(origCert);
On the other hand you might only have a byte code representation of the certificate available. In this case you might have said:
byte[] sigCertEnc = ....;
X509CertificateHolder sigCert = new X509CertificateHolder(sigCertEnc);
The following packages contain version 2 implementations:
-
org.bouncycastle.cert
- certificate/CRL/attribute certificate generation. -
org.bouncycastle.cert.jcajce
- JCA/JCE helper classes for certificate/crl/attribute certificate processing. -
org.bouncycastle.cert.cmp
- CMP certificate management protocol. -
org.bouncycastle.cert.crmf
- CRMF certificate request messaging. -
org.bouncycastle.cert.crmf.jcajce
- JCA/JCE helper classes for CRMF. -
org.bouncycastle.cert.ocsp
- OCSP online certificate status protocol. -
org.bouncycastle.cert.ocsp.jcajce
- JCA/JCE helper classes for OCSP. -
org.bouncycastle.pkcs
- PKCS#10 certification request messaging. -
org.bouncycastle.pkcs.jcajce
- JCA/JCE helper classes for PKCS#10. -
org.bouncycastle.cms
- CMS Cryptographic Message Syntax. -
org.bouncycastle.cms.bc
- lightweight API helper classes for CMS. -
org.bouncycastle.cms.jcajce
- JCA/JCE helper classes for CMS. -
org.bouncycastle.operator
- generic operator classes and helpers. -
org.bouncycastle.operator.bc
- lightweight helper classes for operators. -
org.bouncycastle.operator.jcejce
- JCA/JCE helper classes for operators. -
org.bouncycastle.mail.smime
- S/MIME secure mime implementation. -
org.bouncycastle.tsp
- TSP Time Stamp Protocol implementation.
org.bouncycastle.cert.test.CertTest
org.bouncycastle.cert.cmp.test.AllTests
org.bouncycastle.cms.test.NewAuthenticatedDataStreamTest
org.bouncycastle.cms.test.NewAuthenticatedDataTest
org.bouncycastle.cms.test.NewEnvelopedDataStreamTest
org.bouncycastle.cms.test.NewEnvelopedDataTest
org.bouncycastle.cms.test.NewSignedDataStreamTest
org.bouncycastle.cms.test.NesSignedDataTest
org.bouncycastle.cert.crmf.test.AllTests
org.bouncycastle.cert.ocsp.test.OCSPTest
org.bouncycastle.cert.test.PKCS10Test
org.bouncycastle.mail.smime.test.NewSMIMEEnvelopedTest
org.bouncycastle.mail.smime.test.NewSMIMESignedTest
org.bouncycastle.tsp.test.NewTSPTest