07-14-2010 07:03 PM
Hello,
I have met some problem in using the CMS API, Now I got the Inputstream from the server which contains the encrypt information which can give me an certificate. Here is my plan, first I want to get the CMSSignedDataInputStream, and then with this inputStream, I want then get the CMSEnvelopedDataInputStream. Then get the certificates.
Here comes the problem, I succeeded get the CMSSignedDataInputStream with the keyStore. But I do not know how to do with the inputStream to get the CMSEnvelopedDataInputStream. I tried to find the informations from Google.Is there someone know how to do this. Any useful information or links can be helpful. thanks advance, by the way sorry for my poor English. I really need some help![]()
07-15-2010 02:32 AM - edited 07-15-2010 08:09 AM
I don't know, is this a right way to parse CMS message, but here is come code for you:
Base64InputStream b64is = new Base64InputStream(new ByteArrayInputStream(bytes));
try {
try {
CMSContext context = CMSInputStream.getCMSContext(b64is);
CMSInputStream cisPrototype = CMSInputStream.getCMSInputStream(context, DeviceKeyStore.getInstance(), null, true);
try {
if (cisPrototype instanceof CMSSignedDataInputStream) {
CMSSignedDataInputStream cis = (CMSSignedDataInputStream) cisPrototype;
CMSInputStream internalStream = cis.getCMSInputStream();
MIMEInputStream mis = new MIMEInputStream(internalStream);
try {
String contType = mis.getContentType();
System.out.println("content-type:" + contType);
String contentDisposition = mis.getHeader("Content-Disposition");
System.out.println("content-disposition:" + contentDisposition);
String charset = mis.getContentTypeParameter("charset");
System.out.println("charset:" + charset);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
try {
int len = 0;
do {
len = mis.read(buffer, 0, buffer.length);
baos.write(buffer, 0, len);
} while (len == buffer.length);
} finally {
baos.close();
}
String string;
if (charset == null) {
string = new String(baos.toByteArray());
} else {
string = new String(baos.toByteArray(), charset);
}
System.out.println("string:" + string);
} finally {
mis.close();
}
}
} finally {
cisPrototype.close();
}
} finally {
b64is.close();
}
} catch (Exception e) {
e.printStackTrace();
}
07-15-2010 03:45 AM
Thank you very much for your reply, AnisimovSPB. Nice code, but I have always got the problem that when I succeded get the CMSSignedDataInputStream, I want do the next thing that I use the method getCMSInputStream() with the CMSSignedDataInputStream that I got, it gave me always a null.
Dose anyone know that what wrong with this CMSSignedDataInputStream, by the way I use the keyStore like this RIMKeyStore rks = new RIMKeyStore("xxx"); and after that I add the information by useing the set.
Thanks advance and I hope you all have a nice day.
07-15-2010 09:00 AM
As far as I understand, you should always use current instance of DeviceKeyStore because BlackBerry searches appropriate certificates from the real keystore to check SMIME signature when you call CMSSignedDataInputStream.verify(CMSEntityIdentifie
Debugging the work of S/MIME library in JDE I realized that it always uses DeviceKeyStore instance during SMIME body verification. Every time I open SMIME message I sent it does something like this:
CMSContext context = CMSInputStream.getContext(Base64InputStream);
CMSInputStream cis = CMSInputStream.getCMSInputStream(context, DeviceKeyStore.getInstance(), null, true); // cis is usually an instance of CMSSignedDataInputStream
if (cis.isDataPresent()) {
... do something ..
if (cis.isSignedReceiptRequested()) {
... do something ...
}
CMSInputStream internalStream = cis.getCMSInputStream();
MIMETypeInputStream mis = new MIMEInputStream(internalStream);
... do something ...
}
If you want to see, how SMIME library checks SMIME message signatures and body, you should do the next things:
1) Download AEP SMIME Package
2) Install "net_rim_bb_smime.cod" .cod module into your simulator (just run the simulator and select File -> Load Java Program
3a) Install CA certificate (.cer file), then create a key pair, create public key X509 certificate which is signed by your CA and then install your private key with your public key certificate into your DeviceKeyStore using DeviceKeyStore.getInstance().set(...) method
or (more simple way)
3b) Create a key pair, then create self-signed X509 Certificate (using X509Certificate.create(..) method) and then install private key with your public key certificate into your DeviceKeyStore using DeviceKeyStore.getInstance().set(...) method
4) Select your certificate in S/MIME options
5) Go to blackberry email client, compose new email message choosing "Sign" SMIME option.
6) Send message
7) Make sure that you are in debug mode
8) Order the JDE to stop when a net.rim.device.api.crypto.cms.CMSSignedDataInputSt
9) Open the email you signed and sent
10) Observe
))
My revelation was the BB never searches digest algorithm via it's name and OID (in CMSUtilities.getSignatureDigest() method). It is a disappointing imperfection, because it doesn't let me add new digest algorithms using OIDs.add(...) and DigestFactory.register(...) methods.
07-15-2010 09:28 AM
It is also possible that you have zero-sized byte array of your SMIME message part. If so you need to download the remainder from your server with AttachmentDownloadManager or using "Message.addMessageListener(MessageListener)" and "Transport.more(BodyPart, boolean)" methods.