MerlinKeystore.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.Serializable;
  22. import java.security.Key;
  23. import java.security.KeyStore;
  24. import java.security.cert.Certificate;
  25. import java.util.Properties;

  26. import org.openspcoop2.core.commons.DBUtils;
  27. import org.openspcoop2.security.SecurityException;
  28. import org.openspcoop2.utils.certificate.KeystoreType;
  29. import org.openspcoop2.utils.certificate.byok.BYOKRequestParams;
  30. import org.openspcoop2.utils.certificate.hsm.HSMManager;

  31. /**
  32.  * MerlinKeystore
  33.  *
  34.  * @author Andrea Poli (apoli@link.it)
  35.  * @author $Author$
  36.  * @version $Rev$, $Date$
  37.  */
  38. public class MerlinKeystore implements Serializable {

  39.     /**
  40.      *
  41.      */
  42.     private static final long serialVersionUID = 1L;
  43.    
  44.     private transient org.openspcoop2.utils.certificate.KeyStore ks = null;
  45.    
  46.     private byte[] ksBytes;
  47.     private String tipoStore = null;
  48.     private String pathStore = null;
  49.     private String passwordStore = null;
  50.     private String passwordPrivateKey = null;
  51.    
  52.     private boolean hsm;
  53.    
  54.     @Override
  55.     public String toString() {
  56.         StringBuilder bf = new StringBuilder();
  57.         bf.append("KeyStore (").append(this.tipoStore).append(") ").append(this.pathStore);
  58.         return bf.toString();
  59.     }
  60.    
  61.     public MerlinKeystore(String propertyFilePath) throws SecurityException{
  62.         this.initMerlinKeystoreEngine(propertyFilePath, null, false,
  63.                 null);
  64.     }
  65.     public MerlinKeystore(String propertyFilePath,
  66.             BYOKRequestParams requestParams) throws SecurityException{
  67.         this.initMerlinKeystoreEngine(propertyFilePath, null, false,
  68.                 requestParams);
  69.     }
  70.     public MerlinKeystore(String propertyFilePath,String passwordPrivateKey) throws SecurityException{
  71.         this.initMerlinKeystoreEngine(propertyFilePath, passwordPrivateKey, true,
  72.                 null);
  73.     }
  74.     public MerlinKeystore(String propertyFilePath,String passwordPrivateKey,
  75.             BYOKRequestParams requestParams) throws SecurityException{
  76.         this.initMerlinKeystoreEngine(propertyFilePath, passwordPrivateKey, true,
  77.                 requestParams);
  78.     }
  79.     private void initMerlinKeystoreEngine(String propertyFilePath,String passwordPrivateKey, boolean privatePasswordRequired,
  80.             BYOKRequestParams requestParams) throws SecurityException{
  81.        
  82.         Properties propStore = StoreUtils.readProperties("PropertyFilePath", propertyFilePath);
  83.         this.initMerlinKeystoreEngine(propStore,passwordPrivateKey, privatePasswordRequired,
  84.                 requestParams);
  85.                
  86.     }
  87.    
  88.     public MerlinKeystore(Properties propStore) throws SecurityException{
  89.         this.initMerlinKeystoreEngine(propStore,null, false,
  90.                 null);
  91.     }
  92.     public MerlinKeystore(Properties propStore,
  93.             BYOKRequestParams requestParams) throws SecurityException{
  94.         this.initMerlinKeystoreEngine(propStore,null, false,
  95.                 requestParams);
  96.     }
  97.     public MerlinKeystore(Properties propStore,String passwordPrivateKey) throws SecurityException{
  98.         this.initMerlinKeystoreEngine(propStore,passwordPrivateKey, true,
  99.                 null);
  100.     }
  101.     public MerlinKeystore(Properties propStore,String passwordPrivateKey,
  102.             BYOKRequestParams requestParams) throws SecurityException{
  103.         this.initMerlinKeystoreEngine(propStore,passwordPrivateKey, true,
  104.                 requestParams);
  105.     }
  106.     private void initMerlinKeystoreEngine(Properties propStore,String passwordPrivateKey, boolean privatePasswordRequired,
  107.             BYOKRequestParams requestParams) throws SecurityException{
  108.        
  109.         try{
  110.             if(propStore==null){
  111.                 throw new SecurityException("Properties per lo Store non indicato");
  112.             }
  113.            
  114.             this.tipoStore = propStore.getProperty(KeystoreConstants.PROPERTY_KEYSTORE_TYPE);
  115.             if(this.tipoStore!=null){
  116.                 this.tipoStore = this.tipoStore.trim();
  117.             }else{
  118.                 this.tipoStore = KeyStore.getDefaultType();
  119.             }
  120.            
  121.             this.pathStore = propStore.getProperty(KeystoreConstants.PROPERTY_KEYSTORE_PATH);
  122.            
  123.             this.passwordStore = propStore.getProperty(KeystoreConstants.PROPERTY_KEYSTORE_PASSWORD);
  124.                        
  125.             init(passwordPrivateKey, privatePasswordRequired,
  126.                     requestParams);
  127.            
  128.         }catch(Exception e){
  129.             throw new SecurityException(e.getMessage(),e);
  130.         }
  131.        
  132.     }
  133.        
  134.     public MerlinKeystore(String pathStore,String tipoStore,String passwordStore) throws SecurityException{
  135.         initMerlinKeystoreEngine(pathStore,tipoStore,passwordStore,null, false,
  136.                 null);
  137.     }
  138.     public MerlinKeystore(String pathStore,String tipoStore,String passwordStore,
  139.             BYOKRequestParams requestParams) throws SecurityException{
  140.         initMerlinKeystoreEngine(pathStore,tipoStore,passwordStore,null, false,
  141.                 requestParams);
  142.     }
  143.     public MerlinKeystore(String pathStore,String tipoStore,String passwordStore,String passwordPrivateKey) throws SecurityException{
  144.         initMerlinKeystoreEngine(pathStore,tipoStore,passwordStore,passwordPrivateKey, true,
  145.                 null);
  146.     }
  147.     public MerlinKeystore(String pathStore,String tipoStore,String passwordStore,String passwordPrivateKey,
  148.             BYOKRequestParams requestParams) throws SecurityException{
  149.         initMerlinKeystoreEngine(pathStore,tipoStore,passwordStore,passwordPrivateKey, true,
  150.                 requestParams);
  151.     }
  152.     public void initMerlinKeystoreEngine(String pathStore,String tipoStore,String passwordStore,String passwordPrivateKey, boolean privatePasswordRequired,
  153.             BYOKRequestParams requestParams) throws SecurityException{
  154.            
  155.         this.pathStore = pathStore;
  156.         this.tipoStore = tipoStore;
  157.         this.passwordStore = passwordStore;
  158.        
  159.         init(passwordPrivateKey, privatePasswordRequired,
  160.                 requestParams);
  161.        
  162.     }
  163.    
  164.     public MerlinKeystore(byte[]bytesKeystore,String tipoStore,String passwordStore) throws SecurityException{
  165.         initMerlinKeystoreEngine(bytesKeystore,tipoStore,passwordStore,null, false,
  166.                 null);
  167.     }
  168.     public MerlinKeystore(byte[]bytesKeystore,String tipoStore,String passwordStore,
  169.             BYOKRequestParams requestParams) throws SecurityException{
  170.         initMerlinKeystoreEngine(bytesKeystore,tipoStore,passwordStore,null, false,
  171.                 requestParams);
  172.     }
  173.     public MerlinKeystore(byte[]bytesKeystore,String tipoStore,String passwordStore,String passwordPrivateKey) throws SecurityException{
  174.         initMerlinKeystoreEngine(bytesKeystore,tipoStore,passwordStore,passwordPrivateKey, true,
  175.                 null);
  176.     }
  177.     public MerlinKeystore(byte[]bytesKeystore,String tipoStore,String passwordStore,String passwordPrivateKey,
  178.             BYOKRequestParams requestParams) throws SecurityException{
  179.         initMerlinKeystoreEngine(bytesKeystore,tipoStore,passwordStore,passwordPrivateKey, true,
  180.                 requestParams);
  181.     }
  182.     public void initMerlinKeystoreEngine(byte[]bytesKeystore,String tipoStore,String passwordStore,String passwordPrivateKey, boolean privatePasswordRequired,
  183.             BYOKRequestParams requestParams) throws SecurityException{
  184.            
  185.         this.ksBytes = bytesKeystore;
  186.         this.tipoStore = tipoStore;
  187.         this.passwordStore = passwordStore;
  188.        
  189.         init(passwordPrivateKey, privatePasswordRequired,
  190.                 requestParams);
  191.        
  192.     }
  193.    
  194.     private void init(String passwordPrivateKey, boolean privatePasswordRequired,
  195.             BYOKRequestParams requestParams) throws SecurityException{
  196.         try{
  197.             if(this.tipoStore==null){
  198.                 throw new SecurityException("Tipo dello Store non indicato");
  199.             }
  200.             if(this.passwordStore==null){
  201.                 boolean required = true;
  202.                 if(KeystoreType.JKS.isType(this.tipoStore)) {
  203.                     required = DBUtils.isKeystoreJksPasswordRequired();
  204.                 }
  205.                 else if(KeystoreType.PKCS12.isType(this.tipoStore)) {
  206.                     required = DBUtils.isKeystorePkcs12PasswordRequired();
  207.                 }
  208.                 if(required) {
  209.                     throw new SecurityException("Password dello Store non indicata");
  210.                 }
  211.             }
  212.            
  213.             HSMManager hsmManager = HSMManager.getInstance();
  214.             if(hsmManager!=null) {
  215.                 this.hsm = hsmManager.existsKeystoreType(this.tipoStore);
  216.             }
  217.            
  218.             if(!this.hsm) {
  219.                 initKsBytes(requestParams);
  220.             }
  221.            
  222.             this.initKS();
  223.            
  224.             initPrivateKey(passwordPrivateKey, privatePasswordRequired);
  225.            
  226.         }catch(Exception e){
  227.             throw new SecurityException(e.getMessage(),e);
  228.         }
  229.     }
  230.     private void initPrivateKey(String passwordPrivateKey, boolean privatePasswordRequired) throws SecurityException {
  231.         if(passwordPrivateKey==null && privatePasswordRequired){
  232.            
  233.             boolean required = true;
  234.             if(KeystoreType.JKS.isType(this.tipoStore)) {
  235.                 required = DBUtils.isKeystoreJksKeyPasswordRequired();
  236.             }
  237.             else if(KeystoreType.PKCS12.isType(this.tipoStore)) {
  238.                 required = DBUtils.isKeystorePkcs12KeyPasswordRequired();
  239.             }
  240.             if(required) {
  241.                 if(this.pathStore!=null) {
  242.                     throw new SecurityException("Password chiave privata non indicata per lo Store ["+this.pathStore+"] ");
  243.                 }
  244.                 else {
  245.                     throw new SecurityException("Password chiave privata non indicata per lo Store ");
  246.                 }
  247.             }
  248.         }
  249.         this.passwordPrivateKey = passwordPrivateKey;
  250.     }
  251.    
  252.     private void initKsBytes(BYOKRequestParams requestParams) throws SecurityException {
  253.        
  254.         if(this.ksBytes==null && this.pathStore==null){
  255.             throw new SecurityException("Path per lo Store non indicato");
  256.         }

  257.         if(this.ksBytes==null) {
  258.             this.ksBytes = StoreUtils.readContent("Path", this.pathStore);
  259.         }
  260.        
  261.         if(requestParams!=null) {
  262.             this.ksBytes = StoreUtils.unwrapBYOK(this.ksBytes, requestParams);
  263.         }
  264.     }
  265.    
  266.     public boolean isHsm() {
  267.         return this.hsm;
  268.     }

  269.     private void checkInit() throws SecurityException{
  270.         if(this.ks==null) {
  271.             this.initKS();
  272.         }
  273.     }
  274.     private synchronized void initKS() throws SecurityException{
  275.         if(this.ks==null) {
  276.             try{
  277.                 if(this.hsm) {
  278.                     this.ks = HSMManager.getInstance().getKeystore(this.tipoStore);
  279.                 }
  280.                 else {
  281.                                        
  282.                     this.ks = new org.openspcoop2.utils.certificate.KeyStore(this.ksBytes, this.tipoStore, this.passwordStore);
  283.                    
  284.                     // non utilizzabile in hsm, si ottiene errore: java.lang.UnsupportedOperationException: trusted certificates may only be set by token initialization application
  285.                     // at jdk.crypto.cryptoki/sun.security.pkcs11.P11KeyStore.engineSetEntry(P11KeyStore.java:1022)
  286.                     FixTrustAnchorsNotEmpty.addCertificate(this.ks.getKeystore());
  287.                 }
  288.             }
  289.             catch(Exception e){
  290.                 throw new SecurityException(e.getMessage(),e);
  291.             }
  292.         }
  293.     }
  294.    
  295.    
  296.     public Key getKey(String alias) throws SecurityException {
  297.         return this.getKey(alias, this.passwordPrivateKey);
  298.     }
  299.     public Key getKey(String alias, String password) throws SecurityException {
  300.         if(alias==null) {
  301.             throw new SecurityException("Alias della chiave non fornita");
  302.         }
  303.         if(password==null) {
  304.             boolean required = true;
  305.             if(KeystoreType.JKS.isType(this.tipoStore)) {
  306.                 required = DBUtils.isKeystoreJksKeyPasswordRequired();
  307.             }
  308.             else if(KeystoreType.PKCS12.isType(this.tipoStore)) {
  309.                 required = DBUtils.isKeystorePkcs12KeyPasswordRequired();
  310.             }
  311.             if(required) {
  312.                 throw new SecurityException("Password della chiave non fornita");
  313.             }
  314.         }
  315.         this.checkInit(); // per ripristino da Serializable
  316.         try {
  317.             return this.ks.getPrivateKey(alias, password);
  318.         }catch(Exception e){
  319.             throw new SecurityException(e.getMessage(),e);
  320.         }
  321.     }
  322.    
  323.     public Certificate getCertificate(String alias) throws SecurityException {
  324.         if(alias==null) {
  325.             throw new SecurityException("Alias non fornito");
  326.         }
  327.         this.checkInit(); // per ripristino da Serializable
  328.         try{
  329.             return this.ks.getCertificate(alias);
  330.         }catch(Exception e){
  331.             throw new SecurityException(e.getMessage(),e);
  332.         }
  333.     }

  334.     public org.openspcoop2.utils.certificate.KeyStore getKeyStore() throws SecurityException {
  335.         this.checkInit(); // per ripristino da Serializable
  336.         try{
  337.             return this.ks;
  338.         }catch(Exception e){
  339.             throw new SecurityException(e.getMessage(),e);
  340.         }
  341.     }

  342. }