XmlSignature.java
- /*
- * GovWay - A customizable API Gateway
- * https://govway.org
- *
- * Copyright (c) 2005-2025 Link.it srl (https://link.it).
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3, as published by
- * the Free Software Foundation.
- *
- * 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/>.
- *
- */
- package org.openspcoop2.utils.security;
- import java.security.PrivateKey;
- import java.security.Security;
- import java.security.cert.Certificate;
- import java.security.cert.X509Certificate;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import javax.xml.crypto.dsig.CanonicalizationMethod;
- import javax.xml.crypto.dsig.DigestMethod;
- import javax.xml.crypto.dsig.Reference;
- import javax.xml.crypto.dsig.SignatureMethod;
- import javax.xml.crypto.dsig.SignedInfo;
- import javax.xml.crypto.dsig.Transform;
- import javax.xml.crypto.dsig.XMLSignature;
- import javax.xml.crypto.dsig.XMLSignatureFactory;
- import javax.xml.crypto.dsig.dom.DOMSignContext;
- import javax.xml.crypto.dsig.keyinfo.KeyInfo;
- import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
- import javax.xml.crypto.dsig.spec.TransformParameterSpec;
- import org.bouncycastle.jce.provider.BouncyCastleProvider;
- import org.openspcoop2.utils.UtilsException;
- import org.openspcoop2.utils.certificate.KeyStore;
- import org.w3c.dom.Document;
- import org.w3c.dom.Element;
- /**
- * Signature
- *
- * @author Poli Andrea (apoli@link.it)
- * @author $Author$
- * @version $Rev$, $Date$
- */
- public class XmlSignature {
- public static final String DEFAULT_SIGNATURE_METHOD = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; // SignatureMethod.RSA_SHA1
- public static final String DEFAULT_DIGEST_METHOD = DigestMethod.SHA256;
- public static final String DEFAULT_CANONICALIZATION_METHOD = CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS;
-
- private KeyStore keystore;
- private PrivateKey privateKey;
- private String alias;
-
- private String referenceUri;
-
- private java.util.List<Transform> transforms = new ArrayList<Transform>();
-
- private XMLSignatureFactory xmlSignatureFactory;
-
- private javax.xml.crypto.dsig.keyinfo.KeyInfoFactory keyInfoFactory;
-
- private KeyInfo keyInfo;
-
- public XmlSignature(java.security.KeyStore keystore, String alias, String passwordPrivateKey) throws UtilsException{
- this(new KeyStore(keystore), alias, passwordPrivateKey, false);
- }
- public XmlSignature(java.security.KeyStore keystore, String alias, String passwordPrivateKey, boolean addBouncyCastleProvider) throws UtilsException{
- this(new KeyStore(keystore), alias, passwordPrivateKey, addBouncyCastleProvider);
- }
- public XmlSignature(KeyStore keystore, String alias, String passwordPrivateKey) throws UtilsException{
- this(keystore, alias, passwordPrivateKey, false);
- }
- public XmlSignature(KeyStore keystore, String alias, String passwordPrivateKey, boolean addBouncyCastleProvider) throws UtilsException{
- this.keystore = keystore;
- this.privateKey = this.keystore.getPrivateKey(alias, passwordPrivateKey);
- this.alias = alias;
-
- try{
-
- // Providers
- if(addBouncyCastleProvider){
- BouncyCastleProvider bouncyCastleProvider = new BouncyCastleProvider();
- Security.addProvider(bouncyCastleProvider);
- }
-
- // We assemble the different parts of the Signature element into an XMLSignature object.
- // These objects are all created and assembled using an XMLSignatureFactory object.
- // An application obtains a DOM implementation of XMLSignatureFactory by calling the following line of code:
- this.xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM");
-
- // *** default init ***
- //The URI of the object to be signed (We specify a URI of "", which implies the root of the document.)
- this.referenceUri = "";
- // A single Transform, the enveloped Transform, which is required for enveloped signatures so that the signature itself is removed before calculating the signature value
- this.addTransform(this.xmlSignatureFactory.newTransform(Transform.ENVELOPED,(TransformParameterSpec) null));
-
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
- public String getReferenceUri() {
- return this.referenceUri;
- }
- public void setReferenceUri(String referenceUri) {
- this.referenceUri = referenceUri;
- }
-
- public java.util.List<Transform> getTransforms() {
- return this.transforms;
- }
- public void setTransforms(java.util.List<Transform> transforms) {
- this.transforms = transforms;
- }
- public void addTransform(Transform transform){
- this.transforms.add(transform);
- }
-
- public javax.xml.crypto.dsig.keyinfo.KeyInfoFactory getKeyInfoFactory(){
- if(this.keyInfoFactory==null){
- this.initKeyInfoFactory();
- }
- return this.keyInfoFactory;
- }
- private synchronized void initKeyInfoFactory(){
- if(this.keyInfoFactory==null){
- // Next, we create the optional KeyInfo object, which contains information that enables the recipient to find the key needed to validate the signature.
- // In this example, we add a KeyValue object containing the public key.
- // 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:
- this.keyInfoFactory=this.xmlSignatureFactory.getKeyInfoFactory();
- }
- }
-
- public KeyInfo getKeyInfo() {
- return this.keyInfo;
- }
- public void setKeyInfo(KeyInfo keyInfo) {
- this.keyInfo = keyInfo;
- }
- public void addRSAKeyInfo() throws UtilsException {
- this.addRSAKeyInfo(this.alias);
- }
- public void addRSAKeyInfo(String alias) throws UtilsException {
- try{
- // We then use the KeyInfoFactory to create the KeyValue object and add it to a KeyInfo object:
- javax.xml.crypto.dsig.keyinfo.KeyValue keyValue = this.getKeyInfoFactory().newKeyValue(this.keystore.getCertificate(alias).getPublicKey());
- this.keyInfo = this.getKeyInfoFactory().newKeyInfo(Collections.singletonList(keyValue));
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
-
- }
-
- public void addX509KeyInfo() throws UtilsException {
- this.addX509KeyInfo(this.alias);
- }
- public void addX509KeyInfo(String alias) throws UtilsException {
- try{
- List<Object> x509Content = new ArrayList<>();
- Certificate cert = this.keystore.getCertificate(alias);
- if(cert instanceof X509Certificate){
- x509Content.add(((X509Certificate)cert).getSubjectX500Principal().getName());
- }
- x509Content.add(cert);
- javax.xml.crypto.dsig.keyinfo.X509Data x509Data = this.getKeyInfoFactory().newX509Data(x509Content);
- this.keyInfo = this.getKeyInfoFactory().newKeyInfo(Collections.singletonList(x509Data));
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
-
-
- public void sign(Document element) throws UtilsException{
- this._sign(element.getDocumentElement(), DEFAULT_SIGNATURE_METHOD, DEFAULT_DIGEST_METHOD, DEFAULT_CANONICALIZATION_METHOD);
- }
- public void sign(Element element) throws UtilsException{
- this._sign(element, DEFAULT_SIGNATURE_METHOD, DEFAULT_DIGEST_METHOD, DEFAULT_CANONICALIZATION_METHOD);
- }
-
- public void sign(Document element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
- this._sign(element.getDocumentElement(), signatureMethod, digestMethod, canonicalizationMethod);
- }
- public void sign(Element element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
- this._sign(element, signatureMethod, digestMethod, canonicalizationMethod);
- }
-
- public void sign(Document element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
- this._sign(element.getDocumentElement(), signatureMethod, digestMethod, canonicalizationMethod);
- }
- public void sign(Element element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
- this._sign(element, signatureMethod, digestMethod, canonicalizationMethod);
- }
-
- private void _sign(Element element, String signatureMethod, String digestMethod, String canonicalizationMethod) throws UtilsException{
- try{
- this._sign(element,
- this.xmlSignatureFactory.newSignatureMethod(signatureMethod, null),
- this.xmlSignatureFactory.newDigestMethod(digestMethod, null),
- this.xmlSignatureFactory.newCanonicalizationMethod(canonicalizationMethod,(C14NMethodParameterSpec) null));
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- private void _sign(Element element, SignatureMethod signatureMethod, DigestMethod digestMethod, CanonicalizationMethod canonicalizationMethod) throws UtilsException{
- try{
-
- // We create an XML Digital Signature XMLSignContext containing input parameters for generating the signature.
- // Since we are using DOM, we instantiate a DOMSignContext (a subclass of XMLSignContext), and pass it two parameters,
- // the private key that will be used to sign the document and the root of the document to be signed:
- DOMSignContext domSignContext = new DOMSignContext(this.privateKey, element);
-
- // We create a Reference object che indica l'elemento da firmare
- Reference signedReference = this.xmlSignatureFactory.newReference(
- this.referenceUri,
- digestMethod,
- this.transforms, null, null);
- // Next, we create the SignedInfo object, which is the object that is actually signed
- SignedInfo signedInfo = this.xmlSignatureFactory.newSignedInfo(
- canonicalizationMethod,
- signatureMethod,
- Collections.singletonList(signedReference)); // A list of References da firmare
-
- // Finally, we create the XMLSignature object, passing as parameters the SignedInfo and KeyInfo objects that we created earlier:
- XMLSignature xmlSignatureEngine = this.xmlSignatureFactory.newXMLSignature(signedInfo,this.keyInfo);
-
- // Notice that we haven't actually generated the signature yet; we'll do that in the next step.
- // 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:
- xmlSignatureEngine.sign(domSignContext);
-
- }catch(Exception e){
- throw new UtilsException(e.getMessage(),e);
- }
- }
- }