Páginas

Friday, July 23, 2010

DER Signing using Java and Bouncy Castle

Following my last post about DER coding in Java, I will now explain how to sign an object, using java.security.PrivateKey, java.security.cert.X509Certificate and the TSL standard as pointed in that post.

The TSL signature is an enveloped signature, that can be described by the following picture:


First let's assume that we have some previously initialized variables:
  • tslDER - Unsigned TSL object (instance of DEREncodable)
  • privateKey - Private key being used to sign
  • cert - PKI Certificate of the signer (this one is optional, but recommended)
Now let's define the algorithms used for signing and message digesting:

AlgorithmIdentifier sigAlg = new AlgorithmIdentifier(ObjectIdentifiers.getAlgorithmOID(sigAlgorithm));
ASN1Set sigAlgs = new DERSet(sigAlg);
AlgorithmIdentifier digestAlg = new AlgorithmIdentifier(ObjectIdentifiers.getAlgorithmOID(digestAlgorithm));
ASN1Set digestAlgs = new DERSet(digestAlg);


The getAlgorithmOID is a method that given a String returns the matching Object Identifier or throws an Exception.

After that, let's define the identification of the signer:

SignerIdentifier sid = null;
String[] names = cert.getIssuerDN().getName().split(",");

ASN1EncodableVector vec = new ASN1EncodableVector();
for (String name : names)
{
    ASN1EncodableVector nameVec = new ASN1EncodableVector();
    String[] vals = name.split("=");
    nameVec.add((DEREncodable) X509Name.DefaultLookUp.get(vals[0].trim().toLowerCase()));
    nameVec.add(new DERPrintableString(vals[1]));
    vec.add(new DERSequence(nameVec));
}

ASN1Set attr = new DERSet(vec);
X509Name issuer = new X509Name(new DERSequence(attr));
sid = new SignerIdentifier(new IssuerAndSerialNumber(issuer, cert.getSerialNumber()));


Now the encapsulated content info:

ContentInfo encapContent = new ContentInfo(ObjectIdentifiers.id_eContentType_signedTSL, tslDER);

The next step is building the byte array to be signed:


MessageDigest md = MessageDigest.getInstance(digestAlgorithm);
md.reset();
md.update(tslDER.getDERObject().getEncoded());

ASN1EncodableVector attrs = new ASN1EncodableVector();

ASN1EncodableVector contentTypeAttr = new ASN1EncodableVector();
contentTypeAttr.add(ObjectIdentifiers.id_contentType);
contentTypeAttr.add(ObjectIdentifiers.id_eContentType_signedTSL);
attrs.add(new DERSequence(contentTypeAttr));

ASN1EncodableVector messageDigestAttr = new ASN1EncodableVector();
messageDigestAttr.add(ObjectIdentifiers.id_messageDigest);
messageDigestAttr.add(new DEROctetString(md.digest()));
attrs.add(new DERSequence(messageDigestAttr));

ASN1Set signedAttr = new DERSet(attrs);

md.reset();
md.update(tslDER.getDERObject().getDEREncoded());
md.update(signedAttr.getDEREncoded());
byte[] data = md.digest();


And to finalize the signature:


Signature sig = Signature.getInstance(sigAlgorithm);
sig.initSign(privateKey);
sig.update(data);
byte[] signed = sig.sign();

SignerInfo signerInfo = new SignerInfo(sid, digestAlg, signedAttr, sigAlg, new DEROctetString(signed), null);
ASN1Set signerInfos = new DERSet(signerInfo);

ASN1Set certs = new DERSet(new DEROctetString(cert.getEncoded()));

SignedData signedData = new SignedData(digestAlgs, encapContent, certs, null, signerInfos);
ContentInfo content = new ContentInfo(CMSObjectIdentifiers.signedData, signedData);

1 comment:

theLittleCandle said...
This comment has been removed by the author.