I wasted lots of time looking for this topic so I will share it.
The problem was that I want to envelope a signature from a signed document into a PKCS#7 but I only had public certificate and signature b64 encoded.
My comments come with /* comment */ format
This is the solution (I got from http://forum.java.sun.com/thread.jspa?forumID=9&threadID=496528):
// using BouncyCastl clasess for PKCS#7 Format
CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
/* I had to remove this because I don't want to use private key. I don't even have it */
//gen.addSigner(privKey, cert, CMSSignedDataGenerator.DIGEST_MD5);
X509Certificate cert = null;
try {
/* You must get the certificate from another place. I have this class to do It */
cert = new MyKeyStore.getCertificate("MyEntity");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return;
}
/* I've got the public Certificate */
ArrayList certList = new ArrayList();
certList.add(cert);
/* Must do this if you don't add it to $JAVA/jre/lib/security/java security
My gentoo system has :
/opt/blackdown-jdk-1.4.2.01/jre/lib/security/java.security
*/
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
/* This will fail without above line */
CertStore certs = null;
try {
certs = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC");
} catch (InvalidAlgorithmParameterException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (NoSuchProviderException e1) {
e1.printStackTrace();
return;
}
try {
gen.addCertificatesAndCRLs( certs );
} catch (CertStoreException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (CMSException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
CMSProcessableByteArray process = null;
try {
/* FirmText = B64encoded signature of the file so I had to decode first
Encoding.Base64decodeBinary - This class is also mine and returns a byte[] with decoded bytes
*/
process = new CMSProcessableByteArray(Encoding.Base64decodeBinary(FirmText));
} catch (Exception e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
CMSSignedData data = null;
try {
data = gen.generate(process, "BC");
} catch (NoSuchAlgorithmException e4) {
// TODO Auto-generated catch block
e4.printStackTrace();
} catch (NoSuchProviderException e4) {
// TODO Auto-generated catch block
e4.printStackTrace();
} catch (CMSException e4) {
// TODO Auto-generated catch block
e4.printStackTrace();
}
/* Now we store the PKCS7 to a file... But you can encode b64 to store in a DataBase or whatever */
FileOutputStream contentStream = null;
try {
contentStream = new FileOutputStream("test.p7");
} catch (FileNotFoundException e5) {
// TODO Auto-generated catch block
e5.printStackTrace();
}
try {
contentStream.write(data.getEncoded());
} catch (IOException e6) {
// TODO Auto-generated catch block
e6.printStackTrace();
}
try {
contentStream.close();
} catch (IOException e7) {
// TODO Auto-generated catch block
e7.printStackTrace();
}
This works!!!
You can check it out with:
openssl pkcs7 -inform DER -in test.p7 -print_certs -text -noout
It will show you lots of info.
I hope it helps.