XmlSignature.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.Security;
  23. import java.security.cert.Certificate;
  24. import java.security.cert.X509Certificate;
  25. import java.util.ArrayList;
  26. import java.util.Collections;
  27. import java.util.List;

  28. import javax.xml.crypto.dsig.CanonicalizationMethod;
  29. import javax.xml.crypto.dsig.DigestMethod;
  30. import javax.xml.crypto.dsig.Reference;
  31. import javax.xml.crypto.dsig.SignatureMethod;
  32. import javax.xml.crypto.dsig.SignedInfo;
  33. import javax.xml.crypto.dsig.Transform;
  34. import javax.xml.crypto.dsig.XMLSignature;
  35. import javax.xml.crypto.dsig.XMLSignatureFactory;
  36. import javax.xml.crypto.dsig.dom.DOMSignContext;
  37. import javax.xml.crypto.dsig.keyinfo.KeyInfo;
  38. import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
  39. import javax.xml.crypto.dsig.spec.TransformParameterSpec;

  40. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  41. import org.openspcoop2.utils.UtilsException;
  42. import org.openspcoop2.utils.certificate.KeyStore;
  43. import org.w3c.dom.Document;
  44. import org.w3c.dom.Element;

  45. /**
  46.  * Signature
  47.  *
  48.  * @author Poli Andrea (apoli@link.it)
  49.  * @author $Author$
  50.  * @version $Rev$, $Date$
  51.  */
  52. public class XmlSignature {

  53.     public static final String DEFAULT_SIGNATURE_METHOD = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; // SignatureMethod.RSA_SHA1
  54.     public static final String DEFAULT_DIGEST_METHOD = DigestMethod.SHA256;
  55.     public static final String DEFAULT_CANONICALIZATION_METHOD = CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS;
  56.    
  57.     private KeyStore keystore;
  58.     private PrivateKey privateKey;
  59.     private String alias;
  60.    
  61.     private String referenceUri;
  62.    
  63.     private java.util.List<Transform> transforms = new ArrayList<Transform>();
  64.    
  65.     private XMLSignatureFactory xmlSignatureFactory;
  66.    
  67.     private javax.xml.crypto.dsig.keyinfo.KeyInfoFactory keyInfoFactory;
  68.    
  69.     private KeyInfo keyInfo;
  70.    
  71.     public XmlSignature(java.security.KeyStore keystore, String alias, String passwordPrivateKey) throws UtilsException{
  72.         this(new KeyStore(keystore), alias, passwordPrivateKey, false);
  73.     }
  74.     public XmlSignature(java.security.KeyStore keystore, String alias, String passwordPrivateKey, boolean addBouncyCastleProvider) throws UtilsException{
  75.         this(new KeyStore(keystore), alias, passwordPrivateKey, addBouncyCastleProvider);
  76.     }
  77.     public XmlSignature(KeyStore keystore, String alias, String passwordPrivateKey) throws UtilsException{
  78.         this(keystore, alias, passwordPrivateKey, false);
  79.     }
  80.     public XmlSignature(KeyStore keystore, String alias, String passwordPrivateKey, boolean addBouncyCastleProvider) throws UtilsException{
  81.         this.keystore = keystore;
  82.         this.privateKey = this.keystore.getPrivateKey(alias, passwordPrivateKey);
  83.         this.alias = alias;
  84.        
  85.         try{
  86.        
  87.             // Providers
  88.             if(addBouncyCastleProvider){
  89.                 BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
  90.                 Security.addProvider(bouncyCastleProvider);
  91.             }
  92.            
  93.             // We assemble the different parts of the Signature element into an XMLSignature object.
  94.             // These objects are all created and assembled using an XMLSignatureFactory object.
  95.             // An application obtains a DOM implementation of XMLSignatureFactory by calling the following line of code:
  96.             this.xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
  97.            
  98.             // *** default init ***
  99.             //The URI of the object to be signed (We specify a URI of "", which implies the root of the document.)
  100.             this.referenceUri = "";
  101.             // A single Transform, the enveloped Transform, which is required for enveloped signatures so that the signature itself is removed before calculating the signature value
  102.             this.addTransform(this.xmlSignatureFactory.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null));
  103.            
  104.         }catch(Exception e){
  105.             throw new UtilsException(e.getMessage(),e);
  106.         }
  107.     }
  108.    
  109.     public String getReferenceUri() {
  110.         return this.referenceUri;
  111.     }
  112.     public void setReferenceUri(String referenceUri) {
  113.         this.referenceUri = referenceUri;
  114.     }
  115.    
  116.     public java.util.List<Transform> getTransforms() {
  117.         return this.transforms;
  118.     }
  119.     public void setTransforms(java.util.List<Transform> transforms) {
  120.         this.transforms = transforms;
  121.     }
  122.     public void addTransform(Transform transform){
  123.         this.transforms.add(transform);
  124.     }
  125.    
  126.     public javax.xml.crypto.dsig.keyinfo.KeyInfoFactory getKeyInfoFactory(){
  127.         if(this.keyInfoFactory==null){
  128.             this.initKeyInfoFactory();
  129.         }
  130.         return this.keyInfoFactory;
  131.     }
  132.     private synchronized void initKeyInfoFactory(){
  133.         if(this.keyInfoFactory==null){
  134.             // Next, we create the optional KeyInfo object, which contains information that enables the recipient to find the key needed to validate the signature.
  135.             // In this example, we add a KeyValue object containing the public key.
  136.             // To create KeyInfo and its various subtypes, we use a KeyInfoFactory object, which can be obtained by invoking the getKeyInfoFactory method of the XMLSignatureFactory, as follows:
  137.             this.keyInfoFactory=this.xmlSignatureFactory.getKeyInfoFactory();
  138.         }
  139.     }
  140.    
  141.     public KeyInfo getKeyInfo() {
  142.         return this.keyInfo;
  143.     }
  144.     public void setKeyInfo(KeyInfo keyInfo) {
  145.         this.keyInfo = keyInfo;
  146.     }
  147.     public void addRSAKeyInfo() throws UtilsException {
  148.         this.addRSAKeyInfo(this.alias);
  149.     }
  150.     public void addRSAKeyInfo(String alias) throws UtilsException {
  151.         try{
  152.             // We then use the KeyInfoFactory to create the KeyValue object and add it to a KeyInfo object:
  153.             javax.xml.crypto.dsig.keyinfo.KeyValue keyValue = this.getKeyInfoFactory().newKeyValue(this.keystore.getCertificate(alias).getPublicKey());
  154.             this.keyInfo = this.getKeyInfoFactory().newKeyInfo(Collections.singletonList(keyValue));
  155.         }catch(Exception e){
  156.             throw new UtilsException(e.getMessage(),e);
  157.         }
  158.        
  159.     }
  160.    
  161.     public void addX509KeyInfo() throws UtilsException {
  162.         this.addX509KeyInfo(this.alias);
  163.     }
  164.     public void addX509KeyInfo(String alias) throws UtilsException {
  165.         try{
  166.             List<Object> x509Content = new ArrayList<>();
  167.             Certificate cert = this.keystore.getCertificate(alias);
  168.             if(cert instanceof X509Certificate){
  169.                 x509Content.add(((X509Certificate)cert).getSubjectX500Principal().getName());
  170.             }
  171.             x509Content.add(cert);
  172.             javax.xml.crypto.dsig.keyinfo.X509Data x509Data = this.getKeyInfoFactory().newX509Data(x509Content);
  173.             this.keyInfo = this.getKeyInfoFactory().newKeyInfo(Collections.singletonList(x509Data));
  174.         }catch(Exception e){
  175.             throw new UtilsException(e.getMessage(),e);
  176.         }
  177.     }
  178.    
  179.    
  180.     public void sign(Document element) throws UtilsException{
  181.         this._sign(element.getDocumentElement(), DEFAULT_SIGNATURE_METHOD, DEFAULT_DIGEST_METHOD, DEFAULT_CANONICALIZATION_METHOD);
  182.     }
  183.     public void sign(Element element) throws UtilsException{
  184.         this._sign(element, DEFAULT_SIGNATURE_METHOD, DEFAULT_DIGEST_METHOD, DEFAULT_CANONICALIZATION_METHOD);
  185.     }
  186.    
  187.     public void sign(Document element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
  188.         this._sign(element.getDocumentElement(), signatureMethod, digestMethod, canonicalizationMethod);
  189.     }
  190.     public void sign(Element element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
  191.         this._sign(element, signatureMethod, digestMethod, canonicalizationMethod);
  192.     }
  193.    
  194.     public void sign(Document element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
  195.         this._sign(element.getDocumentElement(), signatureMethod, digestMethod, canonicalizationMethod);
  196.     }
  197.     public void sign(Element element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
  198.         this._sign(element, signatureMethod, digestMethod, canonicalizationMethod);
  199.     }
  200.    
  201.     private void _sign(Element element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
  202.         try{
  203.             this._sign(element,
  204.                     this.xmlSignatureFactory.newSignatureMethod(signatureMethod, null),
  205.                     this.xmlSignatureFactory.newDigestMethod(digestMethod, null),
  206.                     this.xmlSignatureFactory.newCanonicalizationMethod(canonicalizationMethod,(C14NMethodParameterSpec) null));
  207.         }catch(Exception e){
  208.             throw new UtilsException(e.getMessage(),e);
  209.         }
  210.     }
  211.     private void _sign(Element element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
  212.         try{
  213.            
  214.             // We create an XML Digital Signature XMLSignContext containing input parameters for generating the signature.
  215.             // Since we are using DOM, we instantiate a DOMSignContext (a subclass of XMLSignContext), and pass it two parameters,
  216.             // the private key that will be used to sign the document and the root of the document to be signed:
  217.             DOMSignContext domSignContext = new DOMSignContext(this.privateKey, element);
  218.                    
  219.             // We create a Reference object che indica l'elemento da firmare
  220.             Reference signedReference = this.xmlSignatureFactory.newReference(
  221.                     this.referenceUri,
  222.                     digestMethod,
  223.                     this.transforms, null, null);

  224.             // Next, we create the SignedInfo object, which is the object that is actually signed
  225.             SignedInfo signedInfo = this.xmlSignatureFactory.newSignedInfo(
  226.                         canonicalizationMethod,
  227.                         signatureMethod,
  228.                         Collections.singletonList(signedReference)); // A list of References da firmare
  229.            
  230.             // Finally, we create the XMLSignature object, passing as parameters the SignedInfo and KeyInfo objects that we created earlier:
  231.             XMLSignature xmlSignatureEngine = this.xmlSignatureFactory.newXMLSignature(signedInfo,this.keyInfo);
  232.            
  233.             // Notice that we haven't actually generated the signature yet; we'll do that in the next step.
  234.             // Now we are ready to generate the signature, which we do by invoking the sign method on the XMLSignature object, and pass it the signing context as follows:
  235.             xmlSignatureEngine.sign(domSignContext);
  236.            
  237.         }catch(Exception e){
  238.             throw new UtilsException(e.getMessage(),e);
  239.         }
  240.     }


  241. }