CertificateInfo.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.certificate;

  21. import java.io.Serializable;
  22. import java.math.BigInteger;
  23. import java.security.InvalidAlgorithmParameterException;
  24. import java.security.InvalidKeyException;
  25. import java.security.KeyStoreException;
  26. import java.security.MessageDigest;
  27. import java.security.NoSuchAlgorithmException;
  28. import java.security.NoSuchProviderException;
  29. import java.security.SignatureException;
  30. import java.security.cert.CertPathValidator;
  31. import java.security.cert.CertPathValidatorException;
  32. import java.security.cert.CertStore;
  33. import java.security.cert.CertificateEncodingException;
  34. import java.security.cert.CertificateException;
  35. import java.security.cert.CertificateExpiredException;
  36. import java.security.cert.CertificateFactory;
  37. import java.security.cert.CertificateNotYetValidException;
  38. import java.security.cert.CertificateParsingException;
  39. import java.security.cert.PKIXParameters;
  40. import java.util.ArrayList;
  41. import java.util.Date;
  42. import java.util.Enumeration;
  43. import java.util.List;

  44. import javax.security.auth.x500.X500Principal;

  45. import org.openspcoop2.utils.LoggerWrapperFactory;
  46. import org.openspcoop2.utils.UtilsException;
  47. import org.openspcoop2.utils.date.DateManager;
  48. import org.openspcoop2.utils.io.Base64Utilities;

  49. /**
  50.  * CertificateInfo
  51.  *
  52.  * @author Poli Andrea (apoli@link.it)
  53.  * @author $Author$
  54.  * @version $Rev$, $Date$
  55.  */
  56. public class CertificateInfo implements Serializable {

  57.     /**
  58.      *
  59.      */
  60.     private static final long serialVersionUID = 1L;
  61.    
  62.     private java.security.cert.X509Certificate certificate;

  63.     private String name;
  64.    
  65.     private byte[] digest;
  66.     private String digestBase64Encoded;
  67.    
  68.     public CertificateInfo(java.security.cert.X509Certificate certificate, String name) {
  69.         this.certificate = certificate;
  70.         this.name = name;
  71.     }

  72.     public String getName() {
  73.         return this.name;
  74.     }
  75.    
  76.     public CertificatePrincipal getSubject() {
  77.         if(this.certificate.getSubjectX500Principal()!=null) {
  78.             return new CertificatePrincipal(this.certificate.getSubjectX500Principal(), PrincipalType.SUBJECT);
  79.         }
  80.         return null;
  81.     }
  82.    
  83.     public CertificatePrincipal getIssuer() {
  84.         if(this.certificate.getIssuerX500Principal()!=null) {
  85.             return new CertificatePrincipal(this.certificate.getIssuerX500Principal(), PrincipalType.ISSUER);
  86.         }
  87.         return null;
  88.     }
  89.    
  90.     public String getSerialNumber() {
  91.         if(this.certificate.getSerialNumber()!=null) {
  92.             return this.certificate.getSerialNumber().toString();
  93.         }
  94.         else {
  95.             return null;
  96.         }
  97.     }
  98.     public String getSerialNumberHex() {
  99.         if(this.certificate.getSerialNumber()!=null) {
  100.             return this.certificate.getSerialNumber().toString(16);
  101.         }
  102.         else {
  103.             return null;
  104.         }
  105.     }
  106.     public String getSerialNumberHex(String delimiter) {
  107.         if(this.certificate.getSerialNumber()!=null) {
  108.             return formatSerialNumberHex(this.certificate.getSerialNumber(), delimiter);
  109.         }
  110.         else {
  111.             return null;
  112.         }
  113.     }
  114.     public static String formatSerialNumberHex(String serialNumber) {
  115.         return (new BigInteger(serialNumber)).toString(16);
  116.     }
  117.     public static String formatSerialNumberHex(String serialNumber, String delimiter) {
  118.         return formatSerialNumberHex(new BigInteger(serialNumber), delimiter);
  119.     }
  120.     public static String formatSerialNumberHex(BigInteger bi, String delimiter) {
  121.         byte[] bytes = bi.toByteArray();
  122.         StringBuilder sb = new StringBuilder();
  123.         for (byte b : bytes) {
  124.             String f = "%02X"+delimiter;
  125.             sb.append(String.format(f, b));
  126.         }
  127.         String s = sb.toString();
  128.         if(s.endsWith(delimiter) && s.length()>delimiter.length()) {
  129.             return s.substring(0, (s.length()-delimiter.length()));
  130.         }
  131.         else {
  132.             return s;
  133.         }
  134.     }
  135.    
  136.     public java.security.cert.X509Certificate getCertificate() {
  137.         return this.certificate;
  138.     }
  139.    
  140.     public String getPEMEncoded() throws UtilsException {
  141.         return CertificateUtils.toPEM(this.certificate);
  142.     }
  143.     public byte[] getEncoded() throws UtilsException {
  144.         try {
  145.             return this.certificate.getEncoded();
  146.         }catch(Exception e) {
  147.             throw new UtilsException(e.getMessage(), e);
  148.         }
  149.     }
  150.    
  151.     public byte[] digest() throws CertificateException {
  152.         return this.digest("MD5");
  153.     }
  154.     public byte[] digest(String algoritmo) throws CertificateException {
  155.         if(this.digest==null) {
  156.             this.initDigest(algoritmo);
  157.         }
  158.         return this.digest;
  159.     }
  160.     private synchronized void initDigest(String algoritmo) throws CertificateException {
  161.         try {
  162.             if(this.digest==null) {
  163.                 MessageDigest digestEngine = org.openspcoop2.utils.digest.MessageDigestFactory.getMessageDigest(algoritmo);
  164.                 digestEngine.update(this.certificate.getEncoded());
  165.                 this.digest = digestEngine.digest();
  166.             }
  167.         }catch(Exception e) {
  168.             throw new CertificateException(e.getMessage(),e);
  169.         }
  170.     }
  171.    
  172.     public String digestBase64Encoded() throws CertificateException {
  173.         return this.digestBase64Encoded("MD5");
  174.     }
  175.     public String digestBase64Encoded(String algoritmo) throws CertificateException {
  176.         if(this.digestBase64Encoded==null) {
  177.             this.initDigestBase64Encoded(algoritmo);
  178.         }
  179.         return this.digestBase64Encoded;
  180.     }
  181.     private synchronized void initDigestBase64Encoded(String algoritmo) throws CertificateException {
  182.         try {
  183.             if(this.digestBase64Encoded==null) {
  184.                 this.digestBase64Encoded = Base64Utilities.encodeAsString(this.digest(algoritmo));
  185.             }
  186.         }catch(Exception e) {
  187.             throw new CertificateException(e.getMessage(),e);
  188.         }
  189.     }
  190.    
  191.     public Date getNotAfter() {
  192.         return this.certificate.getNotAfter();
  193.     }
  194.    
  195.     public Date getNotBefore() {
  196.         return this.certificate.getNotBefore();
  197.     }
  198.    
  199.     public String getSigAlgName() {
  200.         return this.certificate.getSigAlgName();
  201.     }
  202.    
  203.     public String getType() {
  204.         return this.certificate.getType();
  205.     }
  206.    
  207.     public int getVersion() {
  208.         return this.certificate.getVersion();
  209.     }
  210.    
  211.     public List<KeyUsage> getKeyUsage(){
  212.         return KeyUsage.getKeyUsage(this.certificate);
  213.     }
  214.     public boolean[] getKeyUsageAsMap() {
  215.         return this.certificate.getKeyUsage();
  216.     }
  217.     public boolean hasKeyUsage(KeyUsage keyUsage) {
  218.         return keyUsage.hasKeyUsage(this.certificate);
  219.     }
  220.     public boolean hasKeyUsage(String keyUsage) {
  221.         return hasKeyUsage(KeyUsage.valueOf(keyUsage.toUpperCase()));
  222.     }
  223.     public boolean hasKeyUsageByArrayBooleanPosition(int arrayBooleanPosition) {
  224.         return KeyUsage.existsKeyUsageByArrayBooleanPosition(this.certificate, arrayBooleanPosition);
  225.     }
  226.     public boolean hasKeyUsageByBouncycastleCode(int bouncycastelValue) throws CertificateEncodingException {
  227.         return KeyUsage.existsKeyUsageByBouncycastleCode(this.certificate.getEncoded(), bouncycastelValue);
  228.     }
  229.    
  230.     public List<ExtendedKeyUsage> getExtendedKeyUsage() throws CertificateParsingException{
  231.         return ExtendedKeyUsage.getKeyUsage(this.certificate);
  232.     }
  233.     public List<String> getExtendedKeyUsageByOID() throws CertificateParsingException {
  234.         return this.certificate.getExtendedKeyUsage();
  235.     }
  236.     public boolean hasExtendedKeyUsage(ExtendedKeyUsage keyUsage) throws CertificateParsingException {
  237.         return keyUsage.hasKeyUsage(this.certificate);
  238.     }
  239.     public boolean hasExtendedKeyUsage(String keyUsage) throws CertificateParsingException {
  240.         return hasExtendedKeyUsage(ExtendedKeyUsage.valueOf(keyUsage.toUpperCase()));
  241.     }
  242.     public boolean hasExtendedKeyUsageByOID(String oid) throws CertificateParsingException {
  243.         return ExtendedKeyUsage.existsKeyUsageByOID(this.certificate,oid);
  244.     }
  245.     public boolean hasExtendedKeyUsageByBouncycastleKeyPurposeId(String oid) throws CertificateEncodingException {
  246.         return ExtendedKeyUsage.existsKeyUsageByBouncycastleKeyPurposeId(this.certificate.getEncoded(),oid);
  247.     }
  248.    
  249.     public List<CertificatePolicy> getCertificatePolicies() throws CertificateEncodingException {
  250.         return CertificatePolicy.getCertificatePolicies(this.certificate.getEncoded());
  251.     }
  252.     public CertificatePolicy getCertificatePolicy(String oid) throws CertificateParsingException, CertificateEncodingException {
  253.         return getCertificatePolicyByOID(oid);
  254.     }
  255.     public CertificatePolicy getCertificatePolicyByOID(String oid) throws CertificateParsingException, CertificateEncodingException {
  256.         if(oid==null) {
  257.             throw new CertificateParsingException("Param oid undefined");
  258.         }
  259.         List<CertificatePolicy> l = getCertificatePolicies();
  260.         if(l!=null && !l.isEmpty()) {
  261.             for (CertificatePolicy certificatePolicy : l) {
  262.                 if(oid.equals(certificatePolicy.getOID())) {
  263.                     return certificatePolicy;
  264.                 }
  265.             }
  266.         }
  267.         return null;
  268.     }
  269.     public boolean hasCertificatePolicy(String oid) throws CertificateParsingException, CertificateEncodingException {
  270.         if(oid==null) {
  271.             throw new CertificateParsingException("Param oid undefined");
  272.         }
  273.         return this.getCertificatePolicyByOID(oid)!=null;
  274.     }
  275.    
  276.     public BasicConstraints getBasicConstraints() throws CertificateParsingException, CertificateEncodingException {
  277.         return BasicConstraints.getBasicConstraints(this.certificate.getEncoded());
  278.     }
  279.     public boolean isCA() throws CertificateParsingException, CertificateEncodingException {
  280.         BasicConstraints bc = this.getBasicConstraints();
  281.         return bc !=null && bc.isCA();
  282.     }
  283.     public long getPathLen() throws CertificateParsingException, CertificateEncodingException {
  284.         BasicConstraints bc = this.getBasicConstraints();
  285.         return bc !=null ? bc.getPathLen() : -1;
  286.     }
  287.    
  288.     public AuthorityKeyIdentifier getAuthorityKeyIdentifier() throws CertificateParsingException, CertificateEncodingException {
  289.         return AuthorityKeyIdentifier.getAuthorityKeyIdentifier(this.certificate.getEncoded());
  290.     }
  291.    
  292.     public AuthorityInformationAccess getAuthorityInformationAccess() throws CertificateParsingException, CertificateEncodingException {
  293.         return AuthorityInformationAccess.getAuthorityInformationAccess(this.certificate.getEncoded());
  294.     }
  295.    
  296.     public CRLDistributionPoints getCRLDistributionPoints() throws CertificateEncodingException {
  297.         return CRLDistributionPoints.getCRLDistributionPoints(this.certificate.getEncoded());
  298.     }
  299.    
  300.     public SubjectAlternativeNames getSubjectAlternativeNames() throws CertificateEncodingException {
  301.         return SubjectAlternativeNames.getSubjectAlternativeNames(this.certificate.getEncoded());
  302.     }
  303.     public List<String> getAlternativeNames() throws CertificateEncodingException {
  304.         SubjectAlternativeNames subjectAlternativeNames = this.getSubjectAlternativeNames();
  305.         return subjectAlternativeNames !=null ? subjectAlternativeNames.getAlternativeNames() : null;
  306.     }
  307.    
  308.     public Extensions getExtensions() throws CertificateEncodingException {
  309.         return Extensions.getExtensions(this.certificate.getEncoded());
  310.     }
  311.    
  312.     /**
  313.      * Utility method to test if a certificate is self-issued. This is
  314.      * the case iff the subject and issuer X500Principals are equal.
  315.      */
  316.     public boolean isSelfIssued() {
  317.         X500Principal subject = this.certificate.getSubjectX500Principal();
  318.         X500Principal issuer = this.certificate.getIssuerX500Principal();
  319.         return subject.equals(issuer);
  320.     }

  321.     /**
  322.      * Utility method to test if a certificate is self-signed. This is
  323.      * the case iff the subject and issuer X500Principals are equal
  324.      * AND the certificate's subject public key can be used to verify
  325.      * the certificate. In case of exception, returns false.
  326.      */
  327.     public boolean isSelfSigned() {
  328.         return this.isSelfSigned(null);
  329.     }
  330.     public boolean isSelfSigned(String sigProvider) {
  331.         if (isSelfIssued()) {
  332.             try {
  333.                 if (sigProvider == null) {
  334.                     this.certificate.verify(this.certificate.getPublicKey());
  335.                 } else {
  336.                     this.certificate.verify(this.certificate.getPublicKey(), sigProvider);
  337.                 }
  338.                 return true;
  339.             } catch (Exception e) {
  340.                 // In case of exception, return false
  341.             }
  342.         }
  343.         return false;
  344.     }
  345.    
  346.     public boolean isValid() {
  347.         try {
  348.             this.certificate.checkValidity(DateManager.getDate());
  349.             return true;
  350.         }catch(Exception e) {
  351.             return false;
  352.         }
  353.     }
  354.     public void checkValid() throws CertificateExpiredException, CertificateNotYetValidException {
  355.         checkValid(DateManager.getDate());
  356.     }
  357.     public void checkValid(Date date) throws CertificateExpiredException, CertificateNotYetValidException {
  358.         this.certificate.checkValidity(date!=null ? date : DateManager.getDate());
  359.     }
  360.    
  361.     public boolean isValid(CertStore crlCertstore, KeyStore trustStore) {
  362.         try {
  363.             this.checkValid(crlCertstore, trustStore);
  364.             return true;
  365.         }catch(Exception e) {
  366.             return false;
  367.         }
  368.     }
  369.     public void checkValid(CertStore crlCertstore, KeyStore trustStore) throws CertPathValidatorException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, SecurityException, NoSuchAlgorithmException {
  370.         checkValid(crlCertstore, trustStore, DateManager.getDate());
  371.     }
  372.     public void checkValid(CertStore crlCertstore, KeyStore trustStore, Date date) throws CertPathValidatorException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, SecurityException, NoSuchAlgorithmException {
  373.         PKIXParameters pkixParameters = new PKIXParameters(trustStore.getKeystore());
  374.         pkixParameters.setDate(date!=null ? date : DateManager.getDate()); // per validare i certificati scaduti
  375.         pkixParameters.addCertStore(crlCertstore);
  376.         pkixParameters.setRevocationEnabled(true);
  377.         CertPathValidator certPathValidator = org.openspcoop2.utils.certificate.CertificateFactory.getCertPathValidator();
  378.         List<java.security.cert.Certificate> lCertificate = new ArrayList<>();
  379.         lCertificate.add(this.certificate);
  380.         CertificateFactory certificateFactory = org.openspcoop2.utils.certificate.CertificateFactory.getCertificateFactory();
  381.         certPathValidator.validate(certificateFactory.generateCertPath(lCertificate), pkixParameters);
  382.     }
  383.    
  384.     public boolean isVerified(KeyStore trustStore, boolean checkSameCertificateInTrustStore) {
  385.         try {
  386.             Enumeration<String> aliasesEnum = trustStore.aliases();
  387.             while (aliasesEnum.hasMoreElements()) {
  388.                 String alias = aliasesEnum.nextElement();
  389.                 java.security.cert.Certificate certificateReaded = trustStore.getCertificate(alias);
  390.                 if(checkSameCertificateInTrustStore && this.equalsEngine(certificateReaded)) {
  391.                     return true;
  392.                 }
  393.                 if(this.isVerified(certificateReaded)) {
  394.                     return true;
  395.                 }
  396.             }
  397.         }catch(Exception e) {
  398.             // ignore
  399.         }
  400.         return false;
  401.     }
  402.     public boolean isVerified(CertificateInfo caCert) {
  403.         return this.isVerified(caCert.getCertificate());
  404.     }
  405.     public boolean isVerified(java.security.cert.Certificate caCert) {
  406.         try {
  407.             this.certificate.verify(caCert.getPublicKey());
  408.             return true;
  409.         }catch(Exception e) {
  410.             return false;
  411.         }
  412.     }
  413.     public void verify(CertificateInfo caCert) throws InvalidKeyException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
  414.         verify(caCert.getCertificate());
  415.     }
  416.     public void verify(java.security.cert.Certificate caCert) throws InvalidKeyException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException {
  417.         this.certificate.verify(caCert.getPublicKey());
  418.     }
  419.    
  420.     @Override
  421.     public boolean equals(Object certificate) {
  422.         return this.equalsEngine(certificate);
  423.     }
  424.     private boolean equalsEngine(Object certificate) {
  425.         if(certificate instanceof java.security.cert.X509Certificate) {
  426.             java.security.cert.X509Certificate x509 = (java.security.cert.X509Certificate) certificate;
  427.             return this.equals(x509, true);
  428.         }
  429.         else if(certificate instanceof java.security.cert.Certificate) {
  430.             if(this.getCertificate()!=null) {
  431.                 java.security.cert.Certificate cer = (java.security.cert.Certificate) certificate;
  432.                 return this.getCertificate().equals(cer);
  433.             }
  434.         }
  435.         else if(certificate instanceof CertificateInfo) {
  436.             CertificateInfo c = (CertificateInfo) certificate;
  437.             return this.equals(c.getCertificate(), true);
  438.         }
  439.         return false;
  440.     }
  441.     /** GiĆ  gestite nell'equals(Object)
  442.     public boolean equals(java.security.cert.X509Certificate certificate) {
  443.         return this.equals(certificate, true);
  444.     }
  445.     public boolean equals(CertificateInfo certificate) {
  446.         return this.equals(certificate.getCertificate(), true);
  447.     }*/
  448.    
  449.     public boolean equals(java.security.cert.X509Certificate certificate, boolean strictVerifier) {
  450.         CertificateInfo certificateCheck = new CertificateInfo(certificate, "check");
  451.         return this.equals(certificateCheck, strictVerifier);
  452.     }
  453.     public boolean equals(CertificateInfo certificate, boolean strictVerifier) {
  454.         if(strictVerifier) {
  455.             return this.getCertificate().equals(certificate.getCertificate());
  456.         }
  457.         else {
  458.             try {
  459.                 boolean checkIssuer = this.getIssuer().getNameNormalized().equals(certificate.getIssuer().getNameNormalized());
  460.                 boolean checkSubject = this.getSubject().getNameNormalized().equals(certificate.getSubject().getNameNormalized());
  461.                 return checkIssuer && checkSubject;
  462.             }catch(Exception e) {
  463.                 LoggerWrapperFactory.getLogger(CertificateInfo.class.getName()).error(e.getMessage(),e);
  464.                 return false;
  465.             }
  466.         }
  467.     }
  468.    
  469.     public boolean equals(X500Principal principal) {
  470.         if(principal==null) {
  471.             return false;
  472.         }
  473.         X500Principal subject = this.certificate.getSubjectX500Principal();
  474.         return principal.equals(subject);
  475.     }
  476.    
  477.     @Override
  478.     public String toString() {
  479.         StringBuilder bf = new StringBuilder();
  480.         CertificateUtils.printCertificate(bf, this.certificate, this.name);
  481.         return bf.toString();
  482.     }
  483.    
  484.     @Override
  485.     public int hashCode() {
  486.         return this.toString().hashCode();
  487.     }
  488. }