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

no.difi.oxalis.as2.util.SMimeBC 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 no.difi.oxalis.api.lang.OxalisSecurityException;
import no.difi.oxalis.as2.code.Disposition;
import no.difi.oxalis.as2.lang.OxalisAs2InboundException;
import no.difi.oxalis.commons.bouncycastle.BCHelper;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERUTCTime;
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaCertStore;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
import org.bouncycastle.util.Store;

import java.io.IOException;
import java.security.PrivateKey;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

public class SMimeBC {

    private static JcaX509CertificateConverter x509CertificateConverter;

    static {
        BCHelper.registerProvider();

        x509CertificateConverter = new JcaX509CertificateConverter()
                .setProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    /**
     * http://stackoverflow.com/a/31557473/135001
     */
    public static X509Certificate verifySignature(Map hashes, byte[] signature)
            throws OxalisSecurityException, OxalisAs2InboundException {
        try {
            CMSSignedData signedData = new CMSSignedData(hashes, signature);

            Store store = signedData.getCertificates();
            SignerInformationStore signerInformationStore = signedData.getSignerInfos();

            for (SignerInformation signerInformation : signerInformationStore.getSigners()) {
                Collection certCollection = store.getMatches(signerInformation.getSID());

                Iterator certificateIterator = certCollection.iterator();

                if (!certificateIterator.hasNext())
                    throw new OxalisAs2InboundException(Disposition.AUTHENTICATION_FAILED, "Unable to find certificate in signature.", null);

                X509CertificateHolder certificateHolder = certificateIterator.next();
                X509Certificate certificate = x509CertificateConverter.getCertificate(certificateHolder);

                SignerInformationVerifier verifier = getSignerInfoVerifierBuilder().build(certificate);

                if (signerInformation.verify(verifier))
                    return certificate;
            }

            throw new OxalisSecurityException("Unable to verify signature.");
        } catch (CMSSignerDigestMismatchException e) {
            throw new OxalisSecurityException("Invalid message digest.", e);
        } catch (CMSException | CertificateException | OperatorCreationException e) {
            throw new OxalisSecurityException(e.getMessage(), e);
        }
    }

    public static byte[] createSignature(byte[] digest, SMimeDigestMethod digestMethod, PrivateKey privateKey,
                                         X509Certificate certificate) throws OxalisSecurityException {
        try {
            ASN1EncodableVector signedAttributes = new ASN1EncodableVector();
            signedAttributes.add(new Attribute(CMSAttributes.contentType, new DERSet(digestMethod.getOid())));
            signedAttributes.add(new Attribute(CMSAttributes.messageDigest, new DERSet(new DEROctetString(digest))));
            signedAttributes.add(new Attribute(CMSAttributes.signingTime, new DERSet(new DERUTCTime(new Date()))));

            AttributeTable signedAttributesTable = new AttributeTable(signedAttributes);
            signedAttributesTable.toASN1EncodableVector();
            DefaultSignedAttributeTableGenerator signedAttributeGenerator = new DefaultSignedAttributeTableGenerator(signedAttributesTable);

            /* Build the SignerInfo generator builder, that will build the generator... that will generate the SignerInformation... */
            SignerInfoGeneratorBuilder signerInfoBuilder = new SignerInfoGeneratorBuilder(new JcaDigestCalculatorProviderBuilder().setProvider(BouncyCastleProvider.PROVIDER_NAME).build());
            signerInfoBuilder.setSignedAttributeGenerator(signedAttributeGenerator);
            CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
            JcaContentSignerBuilder contentSigner = new JcaContentSignerBuilder(digestMethod.getMethod()).setProvider(BouncyCastleProvider.PROVIDER_NAME);

            generator.addSignerInfoGenerator(signerInfoBuilder.build(contentSigner.build(privateKey), new X509CertificateHolder(certificate.getEncoded())));
            generator.addCertificates(new JcaCertStore(Collections.singletonList(certificate)));

            return generator.generate(new CMSAbsentContent()).getEncoded();
        } catch (CMSException | IOException | CertificateEncodingException | OperatorCreationException e) {
            throw new OxalisSecurityException(e.getMessage(), e);
        }
    }

    private static JcaSimpleSignerInfoVerifierBuilder getSignerInfoVerifierBuilder() {
        return new JcaSimpleSignerInfoVerifierBuilder()
                .setProvider(BouncyCastleProvider.PROVIDER_NAME);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy