FileDocCategorySizeDatePackage
SMIMECheckSignature.javaAPI DocApache James 2.3.110055Fri Jan 12 12:56:30 GMT 2007org.apache.james.transport.mailets.smime

SMIMECheckSignature

public class SMIMECheckSignature extends org.apache.mailet.GenericMailet

Verifies the s/mime signature of a message. The s/mime signing ensure that the private key owner is the real sender of the message. To be checked by this mailet the s/mime signature must contain the actual signature, the signer's certificate and optionally a set of certificate that can be used to create a chain of trust that starts from the signer's certificate and leads to a known trusted certificate.

This check is composed by two steps: firstly it's ensured that the signature is valid, then it's checked if a chain of trust starting from the signer certificate and that leads to a trusted certificate can be created. The first check verifies that the the message has not been modified after the signature was put and that the signer's certificate was valid at the time of the signing. The latter should ensure that the signer is who he declare to be.

The results of the checks perfomed by this mailet are wrote as a mail attribute which default name is org.apache.james.SMIMECheckSignature (it can be changed using the mailet parameter mailAttribute). After the check this attribute will contain a list of SMIMESignerInfo object, one for each message's signer. These objects contain the signer's certificate and the trust path.

Optionally, specifying the parameter strip, the signature of the message can be stripped after the check. The message will become a standard message without an attached s/mime signature.

The configuration parameter of this mailet are summerized below. The firsts defines the location, the format and the password of the keystore containing the certificates that are considered trusted. Note: only the trusted certificate entries are read, the key ones are not.

  • keyStoreType (default: jks): Certificate store format . "jks" is the standard java certificate store format, but pkcs12 is also quite common and compatible with standard email clients like Outlook Express and Thunderbird.
  • keyStoreFileName (default: JAVA_HOME/jre/lib/security/cacert): Certificate store path.
  • keyStorePassword (default: ""): Certificate store password.
Other parameters configure the behavior of the mailet:
  • strip (default: false): Defines if the s/mime signature of the message have to be stripped after the check or not. Possible values are true and false.
  • mailAttribute (default: org.apache.james.SMIMECheckSignature): specifies in which attribute the check results will be written.
  • onlyTrusted (default: true): Usually a message signature to be considered by this mailet as authentic must be valid and trusted. Setting this mailet parameter to "false" the last condition is relaxed and also "untrusted" signature are considered will be considered as authentic.

Fields Summary
protected org.apache.james.security.KeyStoreHolder
trustedCertificateStore
protected boolean
stripSignature
protected boolean
onlyTrusted
protected String
mailAttribute
Constructors Summary
public SMIMECheckSignature()

    
      
        super();

    
Methods Summary
public voidinit()

        MailetConfig config = getMailetConfig();

        String stripSignatureConf = config.getInitParameter("strip");
        if (stripSignatureConf != null) stripSignature = Boolean.valueOf(stripSignatureConf).booleanValue();
        
        String onlyTrustedConf = config.getInitParameter("onlyTrusted");
        if (onlyTrustedConf != null) onlyTrusted = Boolean.valueOf(onlyTrustedConf).booleanValue();
        
        String mailAttributeConf = config.getInitParameter("mailAttribute");
        if (mailAttributeConf != null) mailAttribute = mailAttributeConf;
        
        
        String type = config.getInitParameter("keyStoreType");
        String file = config.getInitParameter("keyStoreFileName");
        String password = config.getInitParameter("keyStorePassword");
        
        try {
            if (file != null) trustedCertificateStore = new KeyStoreHolder(file, password, type);
            else {
                log("No trusted store path specified, using default store.");
                trustedCertificateStore = new KeyStoreHolder(password);
            }
        } catch (Exception e) {
            throw new MessagingException("Error loading the trusted certificate store", e);
        }

    
public voidservice(org.apache.mailet.Mail mail)

see
org.apache.mailet.Matcher#match(org.apache.mailet.Mail)

        // I extract the MimeMessage from the mail object and I check if the
        // mime type of the mail is one of the mime types that can contain a
        // signature.
        MimeMessage message = mail.getMessage();

        // strippedMessage will contain the signed content of the message 
        MimeBodyPart strippedMessage =null;
        
        List signers=null;
        
        try {
            Object obj = message.getContent();
            SMIMESigned signed;
            if (obj instanceof MimeMultipart) signed = new SMIMESigned((MimeMultipart)message.getContent());
            else if (obj instanceof SMIMESigned) signed = (SMIMESigned) obj;                
            else if (obj instanceof byte[]) signed = new SMIMESigned(message);
            else signed = null;
            
            if (signed != null) {
                signers = trustedCertificateStore.verifySignatures(signed);
                strippedMessage = signed.getContent();
            } else log("Content not identified as signed");
            
            // These errors are logged but they don't cause the 
            // message to change its state. The message 
            // is considered as not signed and the process will
            // go on.
        } catch (CMSException e) {
            log("Error during the analysis of the signed message", e);
            signers = null;
        } catch (IOException e) {
            log("IO error during the analysis of the signed message", e);
            signers = null;
        } catch (SMIMEException e) {
            log("Error during the analysis of the signed message", e);
            signers = null;
        } catch (Exception e) {
            e.printStackTrace();
            log("Generic error occured during the analysis of the message", e);
            signers = null;
        }
        
        // If at least one mail signer is found 
        // the mail attributes are set.
        if (signers != null) {
            ArrayList signerinfolist = new ArrayList();

            for (Iterator iter = signers.iterator(); iter.hasNext();) {
                SMIMESignerInfo info = (SMIMESignerInfo) iter.next();

                if (info.isSignValid()
                        && (!onlyTrusted || info.getCertPath() != null)) {
                    signerinfolist.add((X509Certificate) info.getSignerCertificate());
                }
            }

            if (signerinfolist.size() > 0) {
                mail.setAttribute(mailAttribute, signerinfolist);
            } else {
                // if no valid signers are found the message is not modified.
                strippedMessage = null;
            }
        }

        if (stripSignature && strippedMessage != null) {
            try {
                Object obj = strippedMessage.getContent();
                if (obj instanceof Multipart) {
                    message.setContent((Multipart) obj);
                } else {
                    message.setContent(obj, strippedMessage.getContentType());
                }
                message.saveChanges();
                mail.setMessage(message);
            } catch (Exception e) {
                throw new MessagingException(
                        "Error during the extraction of the signed content from the message.",
                        e);
            }
        }