All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.difi.oxalis.as2.util.SMimeMessageFactory Maven / Gradle / Ivy

/*
 * Copyright 2010-2017 Norwegian Agency for Public Management and eGovernment (Difi)
 *
 * Licensed under the EUPL, Version 1.1 or – as soon they
 * will be approved by the European Commission - subsequent
 * versions of the EUPL (the "Licence");
 *
 * You may not use this work except in compliance with the Licence.
 *
 * You may obtain a copy of the Licence at:
 *
 * https://joinup.ec.europa.eu/community/eupl/og_page/eupl
 *
 * Unless required by applicable law or agreed to in
 * writing, software distributed under the Licence is
 * distributed on an "AS IS" basis,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
 * express or implied.
 * See the Licence for the specific language governing
 * permissions and limitations under the Licence.
 */

package no.difi.oxalis.as2.util;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import no.difi.oxalis.api.lang.OxalisSecurityException;
import no.difi.oxalis.api.lang.OxalisTransmissionException;
import no.difi.oxalis.commons.bouncycastle.BCHelper;
import no.difi.vefa.peppol.common.model.Digest;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.mail.smime.SMIMEException;
import org.bouncycastle.mail.smime.SMIMESignedGenerator;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.util.Store;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.MimeType;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Properties;

/**
 * Creates signed Mime messages
 */
@Singleton
public class SMimeMessageFactory {

    private final PrivateKey privateKey;

    private final X509Certificate ourCertificate;

    private final static Session session = Session.getDefaultInstance(System.getProperties(), null);

    static {
        BCHelper.registerProvider();
    }

    @Inject
    public SMimeMessageFactory(PrivateKey privateKey, X509Certificate ourCertificate) {
        this.privateKey = privateKey;
        this.ourCertificate = ourCertificate;
    }

    /**
     * Creates an S/MIME message from the supplied String, having the supplied MimeType as the "content-type".
     *
     * @param msg      holds the payload of the message
     * @param mimeType the MIME type to be used as the "Content-Type"
     */
    public MimeMessage createSignedMimeMessage(final String msg, MimeType mimeType, SMimeDigestMethod digestMethod)
            throws OxalisTransmissionException {
        return createSignedMimeMessage(new ByteArrayInputStream(msg.getBytes()), mimeType, digestMethod);
    }

    /**
     * Creates a new S/MIME message having the supplied MimeType as the "content-type"
     */
    public MimeMessage createSignedMimeMessage(final InputStream inputStream, MimeType mimeType,
                                               SMimeDigestMethod digestMethod) throws OxalisTransmissionException {
        MimeBodyPart mimeBodyPart = MimeMessageHelper.createMimeBodyPart(inputStream, mimeType.toString());
        return createSignedMimeMessage(mimeBodyPart, digestMethod);
    }

    /**
     * Creates an S/MIME message using the supplied MimeBodyPart. The signature is generated using the private key
     * as supplied in the constructor. Our certificate, which is required to verify the signature is enclosed.
     */
    public MimeMessage createSignedMimeMessage(MimeBodyPart mimeBodyPart, SMimeDigestMethod digestMethod)
            throws OxalisTransmissionException {

        //
        // S/MIME capabilities are required, but we simply supply an empty vector
        //
        ASN1EncodableVector signedAttrs = new ASN1EncodableVector();

        //
        // create the generator for creating an smime/signed message
        //
        SMIMESignedGenerator smimeSignedGenerator = new SMIMESignedGenerator("binary"); //also see CMSSignedGenerator ?

        //
        // add a signer to the generator - this specifies we are using SHA1 and
        // adding the smime attributes above to the signed attributes that
        // will be generated as part of the signature. The encryption algorithm
        // used is taken from the key - in this RSA with PKCS1Padding
        //
        try {
            smimeSignedGenerator.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder()
                    .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                    .setSignedAttributeGenerator(new AttributeTable(signedAttrs))
                    // .build("SHA1withRSA", privateKey, ourCertificate));
                    .build(digestMethod.getMethod(), privateKey, ourCertificate));
        } catch (OperatorCreationException e) {
            throw new OxalisTransmissionException("Unable to add Signer information. " + e.getMessage(), e);
        } catch (CertificateEncodingException e) {
            throw new OxalisTransmissionException(String.format(
                    "Certificate encoding problems while adding signer information. %s", e.getMessage()), e);
        }

        //
        // create a CertStore containing the certificates we want carried
        // in the signature
        //
        Store certs;
        try {
            certs = new JcaCertStore(Collections.singleton(ourCertificate));
        } catch (CertificateEncodingException e) {
            throw new OxalisTransmissionException("Unable to create JcaCertStore with our certificate. " + e.getMessage(), e);
        }
        smimeSignedGenerator.addCertificates(certs);

        //
        // Signs the supplied MimeBodyPart
        //
        MimeMultipart mimeMultipart;
        try {
            mimeMultipart = smimeSignedGenerator.generate(mimeBodyPart);
        } catch (SMIMEException e) {
            throw new OxalisTransmissionException("Unable to generate signed mime multipart." + e.getMessage(), e);
        }

        //
        // Get a Session object and create the mail message
        //
        Properties props = System.getProperties();
        Session session = Session.getDefaultInstance(props, null);

        MimeMessage mimeMessage = new MimeMessage(session);

        try {
            mimeMessage.setContent(mimeMultipart, mimeMultipart.getContentType());
        } catch (MessagingException e) {
            throw new OxalisTransmissionException("Unable to  set Content type of MimeMessage. " + e.getMessage(), e);
        }
        try {
            mimeMessage.saveChanges();
        } catch (MessagingException e) {
            throw new OxalisTransmissionException("Unable to save changes to Mime message. " + e.getMessage(), e);
        }

        return mimeMessage;
    }

    public MimeMessage createSignedMimeMessageNew(MimeBodyPart mimeBodyPart, Digest digest, SMimeDigestMethod digestMethod)
            throws OxalisTransmissionException {
        try {
            MimeMultipart mimeMultipart = new MimeMultipart();
            mimeMultipart.setSubType("signed");
            mimeMultipart.addBodyPart(mimeBodyPart);

            MimeBodyPart signaturePart = new MimeBodyPart();
            DataSource dataSource = new ByteArrayDataSource(SMimeBC.createSignature(digest.getValue(), digestMethod, privateKey, ourCertificate), "application/pkcs7-signature");
            signaturePart.setDataHandler(new DataHandler(dataSource));
            signaturePart.setHeader("Content-Type", "application/pkcs7-signature; name=smime.p7s; smime-type=signed-data");
            signaturePart.setHeader("Content-Transfer-Encoding", "base64");
            signaturePart.setHeader("Content-Disposition", "attachment; filename=\"smime.p7s\"");
            signaturePart.setHeader("Content-Description", "S/MIME Cryptographic Signature");
            mimeMultipart.addBodyPart(signaturePart);

            MimeMessage mimeMessage = new MimeMessage(session);
            mimeMessage.setContent(mimeMultipart, mimeMultipart.getContentType());
            mimeMessage.saveChanges();

            return mimeMessage;
        } catch (MessagingException | OxalisSecurityException e) {
            throw new OxalisTransmissionException(e.getMessage(), e);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy