PKCS7Signature.java

  1. /*
  2.  * GovWay - A customizable API Gateway
  3.  * https://govway.org
  4.  *
  5.  * Copyright (c) 2005-2025 Link.it srl (https://link.it).
  6.  *
  7.  * This program is free software: you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License version 3, as published by
  9.  * the Free Software Foundation.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  *
  19.  */


  20. package org.openspcoop2.utils.security;

  21. import java.security.PrivateKey;
  22. import java.security.Provider;
  23. import java.security.Security;
  24. import java.security.cert.Certificate;
  25. import java.util.ArrayList;
  26. import java.util.List;

  27. import javax.xml.crypto.dsig.SignatureMethod;

  28. import org.bouncycastle.cert.X509CertificateHolder;
  29. import org.bouncycastle.cert.jcajce.JcaCertStore;
  30. import org.bouncycastle.cms.CMSProcessableByteArray;
  31. import org.bouncycastle.cms.CMSSignedData;
  32. import org.bouncycastle.cms.CMSSignedDataGenerator;
  33. import org.bouncycastle.cms.CMSTypedData;
  34. import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder;
  35. import org.bouncycastle.operator.ContentSigner;
  36. import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  37. import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;
  38. import org.bouncycastle.util.Store;
  39. import org.openspcoop2.utils.UtilsException;
  40. import org.openspcoop2.utils.certificate.KeyStore;
  41. import org.openspcoop2.utils.certificate.KeystoreType;

  42. /**
  43.  * Signature
  44.  *
  45.  * @author Poli Andrea (apoli@link.it)
  46.  * @author $Author$
  47.  * @version $Rev$, $Date$
  48.  */
  49. public class PKCS7Signature {

  50.     public static final String DEFAULT_SIGNATURE_METHOD = SignatureMethod.RSA_SHA256;
  51.    
  52.     private PrivateKey privateKey;
  53.     private Certificate certificate;
  54.     private Provider provider;
  55.    
  56.     public PKCS7Signature(KeyStore keystore, String alias, String passwordPrivateKey) throws UtilsException{
  57.         boolean useKeystoreProvider = false;
  58.         if(keystore!=null && KeystoreType.PKCS11.getNome().equalsIgnoreCase(keystore.getKeystoreType())) {
  59.             useKeystoreProvider = true;
  60.             // Prendo il provider dal keystore per PKCS11, il cui provider implementa l'algoritmo di firma specifica per la chiave memorizzata nel dispositivo.
  61.         }
  62.         init(keystore, alias, passwordPrivateKey, useKeystoreProvider);
  63.     }
  64.     public PKCS7Signature(KeyStore keystore, String alias, String passwordPrivateKey, boolean useKeystoreProvider) throws UtilsException{
  65.         init(keystore, alias, passwordPrivateKey, useKeystoreProvider);
  66.     }
  67.     public PKCS7Signature(KeyStore keystore, String alias, String passwordPrivateKey, boolean useBouncyCastle, boolean addBouncyCastleProvider) throws UtilsException{
  68.         this(keystore, alias, passwordPrivateKey);
  69.         if(useBouncyCastle) {
  70.             if(addBouncyCastleProvider) {
  71.                 this.provider = Security.getProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  72.                 if(this.provider==null) {
  73.                     Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
  74.                     this.provider = Security.getProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  75.                 }
  76.             }
  77.             else {
  78.                 this.provider = Security.getProvider(org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME);
  79.             }
  80.         }
  81.     }
  82.     private void init(KeyStore keystore, String alias, String passwordPrivateKey, boolean useKeystoreProvider) throws UtilsException {
  83.         if(keystore==null) {
  84.             throw new UtilsException("Keystore undefined");
  85.         }
  86.         this.privateKey = keystore.getPrivateKey(alias, passwordPrivateKey);
  87.         this.certificate = keystore.getCertificate(alias);
  88.        
  89.         if(useKeystoreProvider) {
  90.             this.provider = keystore.getKeystoreProvider();
  91.        
  92.             // Prendere il provider dal keystore serve per PKCS11 il cui provider implementa l'algoritmo di firma specifica per la chiave memorizzata nel dispositivo.
  93.             // Per gli altri tipi di keystore, nei quali tipicamente il provider è la SUN, non deve essere usata questa opzione altrimenti si ottiene l'errore:
  94.             //    no such algorithm: SHA256WITHRSA for provider SUN
  95.             // Per quei tipi di keystore devono essere usati i costruttori in cui viene usato bouncy castle
  96.             // o il costruttore senza parametri relativi al provider, il quale utilizza quello il provider più corretto preente nella JVM.
  97.         }
  98.     }
  99.    
  100.     public byte[] sign(String data, String charsetName, String algorithm) throws UtilsException{
  101.         try{
  102.             return this.sign(data.getBytes(charsetName), algorithm);
  103.         }catch(Exception e){
  104.             throw new UtilsException(e.getMessage(),e);
  105.         }
  106.     }
  107.    
  108.     public byte[] sign(byte[] data, String algorithm) throws UtilsException{
  109.         try{
  110.             if(algorithm==null) {
  111.                 algorithm = DEFAULT_SIGNATURE_METHOD;
  112.             }
  113.            
  114.             List<X509CertificateHolder> certList = new ArrayList<>();
  115.             CMSTypedData msg = new CMSProcessableByteArray(data); // Data to sign

  116.             X509CertificateHolder cert = new X509CertificateHolder(this.certificate.getEncoded());
  117.             certList.add(cert); // Adding the X509 Certificate

  118.             Store<?> certs = new JcaCertStore(certList);

  119.             CMSSignedDataGenerator gen = new CMSSignedDataGenerator();
  120.             // Initializing the the BC's Signer
  121.             JcaContentSignerBuilder cs = new JcaContentSignerBuilder(algorithm);
  122.             if(this.provider!=null) {
  123.                 cs.setProvider(this.provider);
  124.             }
  125.             ContentSigner sha1Signer = cs.build(this.privateKey);

  126.             JcaDigestCalculatorProviderBuilder builder = new JcaDigestCalculatorProviderBuilder();
  127.             if(this.provider!=null) {
  128.                 builder.setProvider(this.provider);
  129.             }
  130.             gen.addSignerInfoGenerator(
  131.                     new JcaSignerInfoGeneratorBuilder(builder.build())
  132.                             .build(sha1Signer, cert));
  133.             // adding the certificate
  134.             gen.addCertificates(certs);
  135.             // Getting the signed data
  136.             CMSSignedData sigData = gen.generate(msg, true);

  137.             return sigData.getEncoded();
  138.            
  139.         }catch(Exception e){
  140.             throw new UtilsException(e.getMessage(),e);
  141.         }
  142.     }

  143. }