/************************************************************************* * Copyright 2009-2016 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.crypto; import java.nio.charset.StandardCharsets; import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.Collections; import java.util.EnumSet; import java.util.Set; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSProcessableByteArray; import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.Store; /** * Utility class for creating PKCS7 signed data. * * You can verify signatures using openssl: * * openssl smime -verify -in PKCS7 -inform DER -content DATA -certfile CERTIFICATE -noverify * * where PKCS7 is a file containing the output from signing, DATA is the * optional signed data (not needed unless the signature is detached) and * CERTIFICATE is the optional PEM encoded certificate (not needed if the * certificate is included in the signed data) */ public class Pkcs7 { private static final String PROVIDER = "BC"; public enum Option { /** * Create a detached signature, do not include the signed content */ Detached, /** * Include the full certificate in the signed output */ IncludeCertificate, } /** * Create PKCS7 signed data with the default options * * @param data The data to sign * @param key The key to use for signing * @param certificate The certificate to use for signature verification * @return The signed data * @throws Exception If an error occurs */ public static byte[] sign( final String data, final PrivateKey key, final X509Certificate certificate ) throws Exception { return sign( data.getBytes( StandardCharsets.UTF_8 ), key, certificate, EnumSet.noneOf( Option.class ) ); } /** * Create PKCS7 signed data with the given options * * @param data The data to sign * @param key The key to use for signing * @param certificate The certificate to use for signature verification * @param options Signing options * @return The signed data * @throws Exception If an error occurs */ public static byte[] sign( final String data, final PrivateKey key, final X509Certificate certificate, final Set<Option> options ) throws Exception { return sign( data.getBytes( StandardCharsets.UTF_8 ), key, certificate, options ); } /** * Create PKCS7 signed data with the given options * * @param data The data to sign * @param key The key to use for signing * @param certificate The certificate to use for signature verification * @param options Signing options * @return The signed data * @throws Exception If an error occurs */ public static byte[] sign( final byte[] data, final PrivateKey key, final X509Certificate certificate, final Set<Option> options ) throws Exception { final CMSTypedData msg = new CMSProcessableByteArray( data ); final ContentSigner sha1Signer = new JcaContentSignerBuilder( "SHA1with" + certificate.getPublicKey( ).getAlgorithm( ) ) .setProvider( PROVIDER ) .setSecureRandom( Crypto.getSecureRandomSupplier( ).get( ) ) .build( key ); final CMSSignedDataGenerator gen = new CMSSignedDataGenerator( ); gen.addSignerInfoGenerator( new JcaSignerInfoGeneratorBuilder( new JcaDigestCalculatorProviderBuilder( ).setProvider( PROVIDER ).build( ) ) .build( sha1Signer, certificate ) ); if ( options.contains( Option.IncludeCertificate ) ) { final Store certs = new JcaCertStore( Collections.singleton( certificate ) ); gen.addCertificates( certs ); } final CMSSignedData sigData = gen.generate( msg, !options.contains( Option.Detached ) ); return sigData.getEncoded(); } }