MerlinProvider.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.security.keystore;

  21. import java.io.IOException;
  22. import java.security.KeyStore;
  23. import java.security.PrivateKey;
  24. import java.util.HashMap;
  25. import java.util.Properties;

  26. import org.apache.wss4j.common.crypto.PasswordEncryptor;
  27. import org.apache.wss4j.common.ext.WSSecurityException;
  28. import org.apache.wss4j.common.ext.WSSecurityException.ErrorCode;
  29. import org.openspcoop2.core.config.MessageSecurity;
  30. import org.openspcoop2.core.config.MessageSecurityFlow;
  31. import org.openspcoop2.core.config.MessageSecurityFlowParameter;
  32. import org.openspcoop2.protocol.sdk.state.RequestInfo;
  33. import org.openspcoop2.security.keystore.cache.GestoreKeystoreCache;
  34. import org.openspcoop2.utils.certificate.KeystoreType;
  35. import org.openspcoop2.utils.certificate.byok.BYOKProvider;
  36. import org.openspcoop2.utils.certificate.byok.BYOKRequestParams;

  37. /**
  38.  * Implementazione che estente l'implementazione di default e permette di caricare keystore utilizzando la cache o il binario passato direttamente.
  39.  *
  40.  * @author Poli Andrea (apoli@link.it)
  41.  * @author $Author$
  42.  * @version $Rev$, $Date$
  43.  */
  44. public class MerlinProvider extends org.apache.wss4j.common.crypto.Merlin {

  45.     private static boolean useBouncyCastleProvider = false;
  46.     public static boolean isUseBouncyCastleProvider() {
  47.         return useBouncyCastleProvider;
  48.     }
  49.     public static void setUseBouncyCastleProvider(boolean useBouncyCastleProvider) {
  50.         MerlinProvider.useBouncyCastleProvider = useBouncyCastleProvider;
  51.     }
  52.    
  53.     public MerlinProvider() {
  54.         super();
  55.     }

  56.     public MerlinProvider(Properties properties, ClassLoader loader, PasswordEncryptor passwordEncryptor)
  57.             throws WSSecurityException, IOException {
  58.         super(properties, loader, passwordEncryptor);
  59.     }

  60.     private org.openspcoop2.utils.certificate.KeyStore op2KeyStore;
  61.     private org.openspcoop2.utils.certificate.KeyStore op2TrustStore;
  62.     public org.openspcoop2.utils.certificate.KeyStore getOp2KeyStore() {
  63.         return this.op2KeyStore;
  64.     }
  65.     public org.openspcoop2.utils.certificate.KeyStore getOp2TrustStore() {
  66.         return this.op2TrustStore;
  67.     }

  68.     private Boolean useBouncyCastleProviderDirective = null;
  69.    
  70.     public static String readPrefix(Properties properties) {
  71.         for (Object key : properties.keySet()) {
  72.             if (key instanceof String) {
  73.                 String propKey = (String)key;
  74.                 if (propKey.startsWith(PREFIX)) {
  75.                     return PREFIX;
  76.                 } else if (propKey.startsWith(OLD_PREFIX)) {
  77.                     return OLD_PREFIX;
  78.                 }
  79.             }
  80.         }
  81.         return PREFIX;
  82.     }
  83.    
  84.     private static final String TRUST_STORE_REF = "truststore";
  85.     private static final String KEY_STORE_REF = "keystore";
  86.     private String getError(String tipoStore, String location) {
  87.         if(location!=null) {
  88.             return "Accesso al "+tipoStore+" '"+location+"' non riuscito";
  89.         }
  90.         else {
  91.             return "Accesso al "+tipoStore+" non riuscito";
  92.         }
  93.     }
  94.    
  95.     public static final String SUFFIX_BYOK = ".byok";
  96.    
  97.     public static final String X509_CRL_FILE_VALIDATE_ONLY_END_ENTITY = X509_CRL_FILE + ".validateOnlyEndEntity";
  98.    
  99.     private static final String TRUE = "true";
  100.     private static final String FALSE = "false";
  101.    
  102.     @Override
  103.     public void loadProperties(Properties properties, ClassLoader loader, PasswordEncryptor passwordEncryptor)
  104.             throws WSSecurityException, IOException {

  105.         if (properties == null) {
  106.             return;
  107.         }
  108.         this.properties = properties;
  109.         this.passwordEncryptor = passwordEncryptor;

  110.         String prefix = readPrefix(properties);

  111.        
  112.         //
  113.         // Load the RequestInfo
  114.         //
  115.         RequestInfo requestInfo = null;
  116.         Object requestInfoObject = properties.get(KeystoreConstants.PROPERTY_REQUEST_INFO);
  117.         if(requestInfoObject instanceof RequestInfo) {
  118.             requestInfo = (RequestInfo) requestInfoObject;
  119.         }
  120.        

  121.         //
  122.         // Load the KeyStore
  123.         //
  124.         String keyStoreLocation = properties.getProperty(prefix + KEYSTORE_FILE);
  125.         if (keyStoreLocation == null) {
  126.             keyStoreLocation = properties.getProperty(prefix + OLD_KEYSTORE_FILE);
  127.         }
  128.         Object keyStoreArchiveObject = properties.get(prefix + KeystoreConstants.KEYSTORE);
  129.         byte [] keyStoreArchive = null;
  130.         if(keyStoreArchiveObject instanceof byte[]) {
  131.             keyStoreArchive = (byte[]) keyStoreArchiveObject;
  132.         }
  133.        
  134.         String keyStorePassword = properties.getProperty(prefix + KEYSTORE_PASSWORD);
  135.         if (keyStorePassword != null) {
  136.             keyStorePassword = keyStorePassword.trim();
  137.             keyStorePassword = decryptPassword(keyStorePassword, passwordEncryptor);
  138.         }
  139.         String keyStoreType = properties.getProperty(prefix + KEYSTORE_TYPE, KeyStore.getDefaultType());
  140.         if (keyStoreType != null) {
  141.             keyStoreType = keyStoreType.trim();
  142.         }
  143.                
  144.         if (keyStoreLocation != null) {
  145.        
  146.             String keyStoreByokPolicy = properties.getProperty(prefix + KEYSTORE_FILE+SUFFIX_BYOK);
  147.             BYOKRequestParams byokParams = null;
  148.             if (keyStoreByokPolicy == null) {
  149.                 keyStoreByokPolicy = properties.getProperty(prefix + OLD_KEYSTORE_FILE+SUFFIX_BYOK);
  150.             }
  151.             if (keyStoreByokPolicy != null) {
  152.                 keyStoreByokPolicy = keyStoreByokPolicy.trim();
  153.                 if(BYOKProvider.isPolicyDefined(keyStoreByokPolicy)){
  154.                     try {
  155.                         byokParams = BYOKProvider.getBYOKRequestParamsByUnwrapBYOKPolicy(keyStoreByokPolicy,
  156.                                 requestInfo!=null && requestInfo.getDynamicMap()!=null ? requestInfo.getDynamicMap() : new HashMap<>() );
  157.                     }catch(Exception e) {
  158.                         throw new IOException(e.getMessage(),e);
  159.                     }
  160.                 }
  161.             }
  162.            
  163.             // rimuovo la proprietà per non farla trovare quando chiamo il super.loadProperties
  164.             this.properties.remove(prefix + KEYSTORE_FILE);
  165.             this.properties.remove(prefix + OLD_KEYSTORE_FILE);
  166.        
  167.             // il set 'privatePasswordSet' e' stato riportato poichè eliminando sopra le due proprietà, questo codice non verra utilizzato nel super.loadProperties
  168.             String privatePasswd = properties.getProperty(prefix + KEYSTORE_PRIVATE_PASSWORD);
  169.             if (privatePasswd != null) {
  170.                 this.privatePasswordSet = true;
  171.             }
  172.            
  173.            
  174.             keyStoreLocation = keyStoreLocation.trim();

  175.             try {
  176.                 MerlinKeystore merlinKs = GestoreKeystoreCache.getMerlinKeystore(requestInfo, keyStoreLocation, keyStoreType,
  177.                         keyStorePassword, byokParams);
  178.                 if(merlinKs==null) {
  179.                     throw new IOException(getError(KEY_STORE_REF,keyStoreLocation));
  180.                 }
  181.                 if(merlinKs.getKeyStore()==null) {
  182.                     throw new IOException(getError(KEY_STORE_REF,keyStoreLocation));
  183.                 }
  184.                 this.op2KeyStore = merlinKs.getKeyStore();
  185.                 this.keystore = this.op2KeyStore.getKeystore();
  186.             }catch(Exception e) {
  187.                 throw new IOException("[Keystore-File] '"+keyStoreLocation+"' "+e.getMessage(),e);
  188.             }

  189.         }
  190.         else if (keyStoreArchive != null) {
  191.             try {
  192.                 MerlinKeystore merlinKs = GestoreKeystoreCache.getMerlinKeystore(requestInfo, keyStoreArchive, keyStoreType,
  193.                         keyStorePassword);
  194.                 if(merlinKs==null) {
  195.                     throw new IOException(getError(KEY_STORE_REF,null));
  196.                 }
  197.                 if(merlinKs.getKeyStore()==null) {
  198.                     throw new IOException(getError(KEY_STORE_REF,null));
  199.                 }
  200.                 this.op2KeyStore = merlinKs.getKeyStore();
  201.                 this.keystore = this.op2KeyStore.getKeystore();
  202.             }catch(Exception e) {
  203.                 throw new IOException("[Keystore-Archive] "+e.getMessage(),e);
  204.             }
  205.         }
  206.        

  207.         //
  208.         // Load the TrustStore
  209.         //
  210.        
  211.         String trustStoreLocation = properties.getProperty(prefix + TRUSTSTORE_FILE);
  212.         Object trustStoreArchiveObject = properties.get(prefix + KeystoreConstants.TRUSTSTORE);
  213.         byte [] trustStoreArchive = null;
  214.         if(trustStoreArchiveObject instanceof byte[]) {
  215.             trustStoreArchive = (byte[]) trustStoreArchiveObject;
  216.         }
  217.        
  218.         String trustStorePassword = properties.getProperty(prefix + TRUSTSTORE_PASSWORD);
  219.         if (trustStorePassword != null) {
  220.             trustStorePassword = trustStorePassword.trim();
  221.             trustStorePassword = decryptPassword(trustStorePassword, passwordEncryptor);
  222.         }
  223.         String trustStoreType = properties.getProperty(prefix + TRUSTSTORE_TYPE, KeyStore.getDefaultType());
  224.         if (trustStoreType != null) {
  225.             trustStoreType = trustStoreType.trim();
  226.         }
  227.        
  228.         if (trustStoreLocation != null) {
  229.            
  230.             // rimuovo la proprietà per non farla trovare quando chiamo il super.loadProperties
  231.             this.properties.remove(prefix + TRUSTSTORE_FILE);
  232.        
  233.             // il set 'loadCACerts' e' stato riportato poichè eliminando sopra le due proprietà, questo codice non verra utilizzato nel super.loadProperties
  234.             this.loadCACerts = false;
  235.            
  236.             trustStoreLocation = trustStoreLocation.trim();

  237.             try {
  238.                 MerlinTruststore merlinTs = GestoreKeystoreCache.getMerlinTruststore(requestInfo, trustStoreLocation, trustStoreType,
  239.                         trustStorePassword);
  240.                 if(merlinTs==null) {
  241.                     throw new IOException(getError(TRUST_STORE_REF,trustStoreLocation));
  242.                 }
  243.                 if(merlinTs.getTrustStore()==null) {
  244.                     throw new IOException(getError(TRUST_STORE_REF,trustStoreLocation));
  245.                 }
  246.                 this.op2TrustStore = merlinTs.getTrustStore();
  247.                 this.truststore = this.op2TrustStore.getKeystore();
  248.             }catch(Exception e) {
  249.                 throw new IOException("[Truststore-File] '"+trustStoreLocation+"' "+e.getMessage(),e);
  250.             }

  251.         }
  252.         else if (trustStoreArchive != null) {
  253.             try {
  254.                 MerlinTruststore merlinTs = GestoreKeystoreCache.getMerlinTruststore(requestInfo, trustStoreArchive, trustStoreType,
  255.                         trustStorePassword);
  256.                 if(merlinTs==null) {
  257.                     throw new IOException(getError(TRUST_STORE_REF,null));
  258.                 }
  259.                 if(merlinTs.getTrustStore()==null) {
  260.                     throw new IOException(getError(TRUST_STORE_REF,null));
  261.                 }
  262.                 this.op2TrustStore = merlinTs.getTrustStore();
  263.                 this.truststore = this.op2TrustStore.getKeystore();
  264.             }catch(Exception e) {
  265.                 throw new IOException("[Truststore-Archive] "+e.getMessage(),e);
  266.             }
  267.         }
  268.        
  269.         if(this.truststore!=null) {
  270.            
  271.             // Devo evitare che venga eseguito il loadCerts quando invoco super.loadProperties
  272.            
  273.             properties.remove(prefix + LOAD_CA_CERTS);
  274.             properties.setProperty(prefix + LOAD_CA_CERTS, FALSE);
  275.            
  276.         }
  277.        


  278.         //
  279.         // Load the CRL file(s)
  280.         //
  281.         String crlLocations = properties.getProperty(prefix + X509_CRL_FILE);
  282.         if (crlLocations != null) {
  283.            
  284.             // rimuovo la proprietà per non farla trovare quando chiamo il super.loadProperties
  285.             this.properties.remove(prefix + X509_CRL_FILE);
  286.            
  287.             CRLCertstore crlCertstore = null;
  288.             try {
  289.                 crlCertstore = GestoreKeystoreCache.getCRLCertstore(requestInfo, crlLocations);
  290.                 if(crlCertstore==null) {
  291.                     throw new IOException("Accesso alle crl '"+crlLocations+"' non riuscito");
  292.                 }
  293.                 this.crlCertStore = crlCertstore.getCertStore();
  294.             }catch(Exception e) {
  295.                 throw new IOException("[CRLCertstore] "+e.getMessage(),e);
  296.             }

  297.             String useBouncyCastleProviderProperty = properties.getProperty(prefix + "useBouncyCastleProvider");
  298.             if (useBouncyCastleProviderProperty != null) {
  299.                 if(TRUE.equalsIgnoreCase(useBouncyCastleProviderProperty.trim())) {
  300.                     this.useBouncyCastleProviderDirective = true;
  301.                 }
  302.                 else if(FALSE.equalsIgnoreCase(useBouncyCastleProviderProperty.trim())) {
  303.                     this.useBouncyCastleProviderDirective = false;
  304.                 }
  305.             }
  306.            
  307.             String validateOnlyEndEntity = properties.getProperty(prefix + X509_CRL_FILE_VALIDATE_ONLY_END_ENTITY);
  308.             if (validateOnlyEndEntity != null) {
  309.                 if(TRUE.equalsIgnoreCase(validateOnlyEndEntity.trim())) {
  310.                     this.setValidateOnlyEndEntity(true);
  311.                 }
  312.                 else if(FALSE.equalsIgnoreCase(validateOnlyEndEntity.trim())) {
  313.                     this.setValidateOnlyEndEntity(false);
  314.                 }
  315.             }
  316.             else if(crlCertstore!=null && crlCertstore.getWrappedCRLCertStore()!=null && crlCertstore.getWrappedCRLCertStore().countCrls()==1) {
  317.                 // per default si assume che venga fornito solo il file CRL del certificato finale
  318.                 this.setValidateOnlyEndEntity(true);
  319.             }
  320.            
  321.         }



  322.         //
  323.         // Super
  324.         //
  325.         super.loadProperties(properties, loader, passwordEncryptor);
  326.     }

  327.     /**@Override
  328.     public PrivateKey getPrivateKey(PublicKey publicKey, CallbackHandler callbackHandler) throws WSSecurityException {
  329.         System.out.println("@@@ getPrivateKey PUBLIC KEY, CALLBACK");
  330.         return super.getPrivateKey(publicKey, callbackHandler);
  331.     }*/

  332.     @Override
  333.     public PrivateKey getPrivateKey(String alias, String password) throws WSSecurityException {
  334.         /**System.out.println("@@@ getPrivateKey arg0["+alias+"] arg1["+password+"]");*/
  335.         if(this.op2KeyStore!=null) {
  336.             try {
  337.                 return this.op2KeyStore.getPrivateKey(alias, password);
  338.             }catch(Exception e) {
  339.                 throw new WSSecurityException(ErrorCode.SECURITY_ERROR,e);
  340.             }
  341.         }
  342.         return super.getPrivateKey(alias, password);
  343.     }

  344.     /**@Override
  345.     public PrivateKey getPrivateKey(X509Certificate x509, CallbackHandler callbackHandler) throws WSSecurityException {
  346.         System.out.println("@@@ getPrivateKey X509Certificatw, CALLBACK");
  347.         return super.getPrivateKey(x509, callbackHandler);
  348.     }*/
  349.    
  350.     @Override
  351.     public String getCryptoProvider() {
  352.         boolean useBC = (this.useBouncyCastleProviderDirective!=null && this.useBouncyCastleProviderDirective)
  353.                 ||
  354.                 (MerlinProvider.useBouncyCastleProvider);
  355.         if(useBC) {
  356.             if(this.truststore!=null && this.truststore.getType()!=null && this.truststore.getType().equalsIgnoreCase(KeystoreType.PKCS11.getNome())) {
  357.                 useBC=false;
  358.             }
  359.             if(this.keystore!=null && this.keystore.getType()!=null && this.keystore.getType().equalsIgnoreCase(KeystoreType.PKCS11.getNome())) {
  360.                 useBC=false;
  361.             }
  362.         }
  363.         if(useBC) {
  364.             return org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
  365.         }
  366.         else {
  367.             return super.getCryptoProvider();
  368.         }
  369.     }
  370.    
  371.     public static void correctProviderName(MessageSecurity messageSecurity){
  372.         if(messageSecurity!=null) {
  373.             MessageSecurityFlow request = messageSecurity.getRequestFlow();
  374.             correctProviderNameRequestFlow(request);
  375.            
  376.             MessageSecurityFlow response = messageSecurity.getResponseFlow();
  377.             correctProviderNameResponseFlow(response);
  378.         }
  379.     }
  380.     private static void correctProviderNameRequestFlow(MessageSecurityFlow request){
  381.         if(request!=null && request.sizeParameterList()>0) {
  382.             for (MessageSecurityFlowParameter param : request.getParameterList()) {
  383.                 if(param.getNome()!=null && param.getNome().trim().endsWith(KeystoreConstants.PROPERTY_PROVIDER) &&
  384.                         param.getValore()!=null && KeystoreConstants.OLD_PROVIDER_GOVWAY.equals(param.getValore().trim()) ) {
  385.                     param.setValore(KeystoreConstants.PROVIDER_GOVWAY);
  386.                 }
  387.             }
  388.         }
  389.     }
  390.     private static void correctProviderNameResponseFlow(MessageSecurityFlow response){
  391.         if(response!=null && response.sizeParameterList()>0) {
  392.             for (MessageSecurityFlowParameter param : response.getParameterList()) {
  393.                 if(param.getNome()!=null && param.getNome().trim().endsWith(KeystoreConstants.PROPERTY_PROVIDER) &&
  394.                         param.getValore()!=null && KeystoreConstants.OLD_PROVIDER_GOVWAY.equals(param.getValore().trim()) ) {
  395.                     param.setValore(KeystoreConstants.PROVIDER_GOVWAY);
  396.                 }
  397.             }
  398.         }
  399.     }
  400. }