org.bouncycastle.mail.smime.SMIMESigned Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of bcjmail-fips Show documentation
Show all versions of bcjmail-fips Show documentation
The Bouncy Castle Java APIs for doing S/MIME with the Jakarta Mail APIs. The APIs are designed primarily to be used in conjunction with the BC FIPS provider. The APIs may also be used with other providers although if being used in a FIPS context it is the responsibility of the user to ensure that any other providers used are FIPS certified and used appropriately.
package org.bouncycastle.mail.smime;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.AccessController;
import java.security.PrivilegedAction;
import jakarta.activation.CommandMap;
import jakarta.activation.MailcapCommandMap;
import jakarta.mail.MessagingException;
import jakarta.mail.Part;
import jakarta.mail.Session;
import jakarta.mail.internet.MimeBodyPart;
import jakarta.mail.internet.MimeMessage;
import jakarta.mail.internet.MimeMultipart;
import jakarta.mail.internet.MimePart;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.CMSProcessable;
import org.bouncycastle.cms.CMSSignedData;
/**
* general class for handling a pkcs7-signature message.
*
* A simple example of usage - note, in the example below the validity of
* the certificate isn't verified, just the fact that one of the certs
* matches the given signer...
*
*
* CertStore certs = s.getCertificates("Collection", "BC");
* SignerInformationStore signers = s.getSignerInfos();
* Collection c = signers.getSigners();
* Iterator it = c.iterator();
*
* while (it.hasNext())
* {
* SignerInformation signer = (SignerInformation)it.next();
* Collection certCollection = certs.getCertificates(signer.getSID());
*
* Iterator certIt = certCollection.iterator();
* X509Certificate cert = (X509Certificate)certIt.next();
*
* if (signer.verify(cert.getPublicKey()))
* {
* verified++;
* }
* }
*
*
* Note: if you are using this class with AS2 or some other protocol
* that does not use 7bit as the default content transfer encoding you
* will need to use the constructor that allows you to specify the default
* content transfer encoding, such as "binary".
*
*/
public class SMIMESigned
extends CMSSignedData
{
Object message;
MimeBodyPart content;
private static InputStream getInputStream(
Part bodyPart)
throws MessagingException
{
try
{
if (bodyPart.isMimeType("multipart/signed"))
{
throw new MessagingException("attempt to create signed data object from multipart content - use MimeMultipart constructor.");
}
return bodyPart.getInputStream();
}
catch (IOException e)
{
throw new MessagingException("can't extract input stream: " + e);
}
}
static
{
final MailcapCommandMap mc = (MailcapCommandMap)CommandMap.getDefaultCommandMap();
mc.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
mc.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
mc.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
mc.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
mc.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
AccessController.doPrivileged(new PrivilegedAction()
{
public Object run()
{
CommandMap.setDefaultCommandMap(mc);
return null;
}
});
}
/**
* base constructor using a defaultContentTransferEncoding of 7bit
*
* @exception MessagingException on an error extracting the signature or
* otherwise processing the message.
* @exception CMSException if some other problem occurs.
*/
public SMIMESigned(
MimeMultipart message)
throws MessagingException, CMSException
{
super(new CMSProcessableBodyPartInbound(message.getBodyPart(0)), getInputStream(message.getBodyPart(1)));
this.message = message;
this.content = (MimeBodyPart)message.getBodyPart(0);
}
/**
* base constructor with settable contentTransferEncoding
*
* @param message the signed message
* @param defaultContentTransferEncoding new default to use
* @exception MessagingException on an error extracting the signature or
* otherwise processing the message.
* @exception CMSException if some other problem occurs.
*/
public SMIMESigned(
MimeMultipart message,
String defaultContentTransferEncoding)
throws MessagingException, CMSException
{
super(new CMSProcessableBodyPartInbound(message.getBodyPart(0), defaultContentTransferEncoding), getInputStream(message.getBodyPart(1)));
this.message = message;
this.content = (MimeBodyPart)message.getBodyPart(0);
}
/**
* base constructor for a signed message with encapsulated content.
*
* @exception MessagingException on an error extracting the signature or
* otherwise processing the message.
* @exception SMIMEException if the body part encapsulated in the message cannot be extracted.
* @exception CMSException if some other problem occurs.
*/
public SMIMESigned(
Part message)
throws MessagingException, CMSException, SMIMEException
{
super(getInputStream(message));
this.message = message;
CMSProcessable cont = this.getSignedContent();
if (cont != null)
{
byte[] contBytes = (byte[])cont.getContent();
this.content = SMIMEUtil.toMimeBodyPart(contBytes);
}
}
/**
* return the content that was signed.
*/
public MimeBodyPart getContent()
{
return content;
}
/**
* Return the content that was signed as a mime message.
*
* @param session
* @return a MimeMessage holding the content.
* @throws MessagingException
*/
public MimeMessage getContentAsMimeMessage(Session session)
throws MessagingException, IOException
{
Object content = getSignedContent().getContent();
byte[] contentBytes = null;
if (content instanceof byte[])
{
contentBytes = (byte[])content;
}
else if (content instanceof MimePart)
{
MimePart part = (MimePart)content;
ByteArrayOutputStream out;
if (part.getSize() > 0)
{
out = new ByteArrayOutputStream(part.getSize());
}
else
{
out = new ByteArrayOutputStream();
}
part.writeTo(out);
contentBytes = out.toByteArray();
}
else
{
String type = "";
if (content != null)
{
type = content.getClass().getName();
}
throw new MessagingException(
"Could not transfrom content of type "
+ type
+ " into MimeMessage.");
}
if (contentBytes != null)
{
ByteArrayInputStream in = new ByteArrayInputStream(contentBytes);
return new MimeMessage(session, in);
}
return null;
}
/**
* return the content that was signed - depending on whether this was
* unencapsulated or not it will return a MimeMultipart or a MimeBodyPart
*/
public Object getContentWithSignature()
{
return message;
}
}