package at.gv.egovernment.moa.spss.util; import iaik.asn1.ObjectID; import iaik.asn1.structures.Name; import iaik.asn1.structures.PolicyInformation; import iaik.utils.RFC2253NameParser; import iaik.utils.RFC2253NameParserException; import iaik.x509.X509Certificate; import iaik.x509.X509ExtensionInitException; import iaik.x509.extensions.CertificatePolicies; import iaik.x509.extensions.qualified.QCStatements; import iaik.x509.extensions.qualified.structures.QCStatement; import iaik.x509.extensions.qualified.structures.etsi.QcEuCompliance; import iaik.x509.extensions.qualified.structures.etsi.QcEuSSCD; import java.net.URI; import java.security.Principal; import java.util.Arrays; import java.util.Date; import java.util.List; import at.gv.egovernment.moa.sig.tsl.TslConstants; import at.gv.egovernment.moa.sig.tsl.engine.data.ITslEndEntityResult; import at.gv.egovernment.moa.sig.tsl.exception.TslException; import at.gv.egovernment.moa.sig.tsl.utils.MiscUtil; import at.gv.egovernment.moa.spss.api.common.TslInfos; import at.gv.egovernment.moa.spss.api.impl.TslInfosImpl; import at.gv.egovernment.moa.spss.server.config.ConfigurationProvider; import at.gv.egovernment.moa.spss.tsl.TSLServiceFactory; import at.gv.egovernment.moaspss.logging.LogMsg; import at.gv.egovernment.moaspss.logging.Logger; public class CertificateUtils { /** * Verifies if the given certificate contains QCP+ statement * @param cert X509Certificate * @return true if the given certificate contains QCP+ statement, else false */ private static boolean checkQCPPlus(X509Certificate cert) { Logger.debug("Checking QCP+ extension"); String OID_QCPPlus = "0.4.0.1456.1.1"; try { CertificatePolicies certPol = (CertificatePolicies) cert.getExtension(CertificatePolicies.oid); if (certPol == null) { Logger.debug("No CertificatePolicies extension found"); return false; } PolicyInformation[] polInfo = certPol.getPolicyInformation(); if (polInfo == null) { Logger.debug("No policy information found"); return false; } for (int i = 0; i < polInfo.length; i++) { ObjectID oid = polInfo[i].getPolicyIdentifier(); String oidStr = oid.getID(); if (oidStr.compareToIgnoreCase(OID_QCPPlus) == 0) { Logger.debug("QCP+ extension found"); return true; } } Logger.debug("No QCP+ extension found"); return false; } catch (X509ExtensionInitException e) { Logger.debug("No QCP+ extension found"); return false; } } /** * Verifies if the given certificate contains QCP statement * @param cert X509Certificate * @return true if the given certificate contains QCP statement, else false */ private static boolean checkQCP(X509Certificate cert) { Logger.debug("Checking QCP extension"); String OID_QCP = "0.4.0.1456.1.2"; try { CertificatePolicies certPol = (CertificatePolicies) cert.getExtension(CertificatePolicies.oid); if (certPol == null) { Logger.debug("No CertificatePolicies extension found"); return false; } PolicyInformation[] polInfo = certPol.getPolicyInformation(); if (polInfo == null) { Logger.debug("No policy information found"); return false; } for (int i = 0; i < polInfo.length; i++) { ObjectID oid = polInfo[i].getPolicyIdentifier(); String oidStr = oid.getID(); if (oidStr.compareToIgnoreCase(OID_QCP) == 0) { Logger.debug("QCP extension found"); return true; } } Logger.debug("No QCP extension found"); return false; } catch (X509ExtensionInitException e) { Logger.debug("No QCP extension found"); return false; } } /** * Verifies if the given certificate contains QcEuCompliance statement * @param cert X509Certificate * @return true if the given certificate contains QcEuCompliance statement, else false */ private static boolean checkQcEuCompliance(X509Certificate cert) { Logger.debug("Checking QcEUCompliance extension"); try { QCStatements qcStatements = (QCStatements) cert.getExtension(QCStatements.oid); if (qcStatements == null) { Logger.debug("No QcStatements extension found"); return false; } QCStatement qcEuCompliance = qcStatements.getQCStatements(QcEuCompliance.statementID); if (qcEuCompliance != null) { Logger.debug("QcEuCompliance extension found"); return true; } Logger.debug("No QcEuCompliance extension found"); return false; } catch (X509ExtensionInitException e) { Logger.debug("No QcEuCompliance extension found"); return false; } } /** * Verifies if the given certificate contains QcEuSSCD statement * @param cert X509Certificate * @return true if the given certificate contains QcEuSSCD statement, else false */ private static boolean checkQcEuSSCD(X509Certificate cert) { Logger.debug("Checking QcEuSSCD extension"); try { QCStatements qcStatements = (QCStatements) cert.getExtension(QCStatements.oid); if (qcStatements == null) { Logger.debug("No QcStatements extension found"); return false; } QCStatement qcEuSSCD = qcStatements.getQCStatements(QcEuSSCD.statementID); if (qcEuSSCD != null) { Logger.debug("QcEuSSCD extension found"); return true; } Logger.debug("No QcEuSSCD extension found"); return false; } catch (X509ExtensionInitException e) { Logger.debug("No QcEuSSCD extension found"); return false; } } public static QCSSCDResult checkQCSSCD(X509Certificate[] chain, Date signingTime, boolean isTSLenabledTrustprofile, ConfigurationProvider config) { try { if (isTSLenabledTrustprofile) { if (signingTime == null) { signingTime = new Date(); Logger.debug("TSL check without signingTime --> use current time for evaluation"); } ITslEndEntityResult tslCheckResult = TSLServiceFactory.getTSLServiceClient().evaluate( Arrays.asList(chain), signingTime, TslConstants.CHAIN_MODEL); if (tslCheckResult != null) { URI tslServiceTypeIdentifier = tslCheckResult.getEvaluatedServiceTypeIdentifier(); List tslCertificateQualifier = tslCheckResult.getEvaluatedQualifier(); // QC evaluation flags boolean qc = false; boolean qcSourceTSL = false; boolean qcDisallowedFromTSL = false; // SSCD/QSCD evaluation flags boolean sscd = false; boolean sscdSourceTSL = false; //check QC List allowedQCQualifier = config.getTSLConfiguration().getQualifierForQC(); for (URI el : allowedQCQualifier) { if (el.equals(tslServiceTypeIdentifier)) { qcSourceTSL = true; qc = true; } } //check SSCD/QSCD qualifiers and mark result acording this check List allowedSSCDQualifier = config.getTSLConfiguration().getQualifierForSSCD(); if (tslCertificateQualifier != null && allowedSSCDQualifier != null) { for (URI allowedSSCD : allowedSSCDQualifier) { for (URI certSSCD : tslCertificateQualifier) { if (allowedSSCD.equals(certSSCD)) { sscdSourceTSL = true; sscd = true; } } } } //check additional flags in TSP qualifiers for this certificate if (tslCertificateQualifier != null) { for (URI qEl : tslCertificateQualifier) { //check if SSCD/QSCD status must be used from cert if (qEl.equals( TslConstants.SSCD_QUALIFIER_SORT_TO_URI.get( TslConstants.SSCD_QUALIFIER_SHORT.QCQSCDStatusAsInCert)) || qEl.equals(TslConstants.SSCD_QUALIFIER_SORT_TO_URI.get( TslConstants.SSCD_QUALIFIER_SHORT.QCSSCDStatusAsInCert))) { sscdSourceTSL = false; sscd = false; //check if extentsion includes a NotQualified flag } else if (qEl.equals( TslConstants.SSCD_QUALIFIER_SORT_TO_URI.get( TslConstants.SSCD_QUALIFIER_SHORT.NotQualified))) { qc = false; qcSourceTSL = false; qcDisallowedFromTSL = true; Logger.info("TSL mark this certificate explicitly as 'NotQualified'!"); } } } /* * This block is removes with MOA-SP 3.1 because if TSL support is enabled for the requested TrustProfile * QC evaluation is ONLY allowed from TSL information!!! Because with eIDAS regulation and July 01. 2016 * the Trust-Status List is constitutive. */ // //evaluate QC statement according previous selected information // if (qcSourceTSL) // Logger.debug("Certificate is QC (Source: TSL)"); // // else { // // // // if TSL return no service-type identifier us information from certificate // if (tslServiceTypeIdentifier == null || // MiscUtil.isEmpty(tslServiceTypeIdentifier.toString())) { // // try certificate extensions QCP and QcEuCompliance // Logger.debug("QC check via TSL returned false - checking certificate extensions"); // boolean checkQCP = CertificateUtils.checkQCP(chain[0]); // boolean checkQcEuCompliance = CertificateUtils.checkQcEuCompliance(chain[0]); // // if ((checkQCP || checkQcEuCompliance) && !qcDisallowedFromTSL) { // Logger.debug("Certificate is QC (Source: Certificate)"); // qc = true; // // } // } // } //evaluate SSCD/QSCD results according previous selected information if (sscdSourceTSL) Logger.debug("Certificate is SSCD (Source: TSL)"); else { // if SSCD check via TSL returns false // try certificate extensions QCP+ and QcEuSSCD Logger.debug("SSCD check via TSL returned false - checking certificate extensions"); boolean checkQCPPlus = CertificateUtils.checkQCPPlus(chain[0]); boolean checkQcEuSSCD = CertificateUtils.checkQcEuSSCD(chain[0]); if (checkQCPPlus || checkQcEuSSCD) { Logger.debug("Certificate is SSCD (Source: Certificate)"); sscd = true; } } //build basic result QCSSCDResult result = new QCSSCDResult(qc, qcSourceTSL, sscd, sscdSourceTSL); //add additinal information TslInfos extTslInfos = new TslInfosImpl( tslCheckResult.getTerritory(), tslCheckResult.getTspStatus(), tslServiceTypeIdentifier.toString(), tslCertificateQualifier, tslCheckResult.getAdditionalServiceInformation()); result.setTslInfos(extTslInfos); return result; } else { Logger.debug("Qualifier check via TSL return null - checking certificate extensions without QC evaluation"); return parseInfosFromCertificate(chain, false); } } else Logger.info("TSL support is not enabled - checking certificate extensions with QC evaluation "); return parseInfosFromCertificate(chain, true); } catch (TslException e) { MessageProvider msg = MessageProvider.getInstance(); Logger.error(new LogMsg(msg.getMessage("tsl.01", null)), e); return new QCSSCDResult(); } } private static QCSSCDResult parseInfosFromCertificate(X509Certificate[] chain, boolean performQCEvaluation) { boolean qc = false; boolean sscd = false; // Trustprofile is not TSL enabled - use certificate extensions only if (performQCEvaluation) { // perform QC check // try certificate extensions QCP and QcEuCompliance boolean checkQCP = CertificateUtils.checkQCP(chain[0]); boolean checkQcEuCompliance = CertificateUtils.checkQcEuCompliance(chain[0]); if (checkQCP || checkQcEuCompliance) qc = true; } // perform SSCD check // try certificate extensions QCP+ and QcEuSSCD boolean checkQCPPlus = CertificateUtils.checkQCPPlus(chain[0]); boolean checkQcEuSSCD = CertificateUtils.checkQcEuSSCD(chain[0]); if (checkQCPPlus || checkQcEuSSCD) sscd = true; return new QCSSCDResult(qc, false, sscd, false); } /** * Gets the country from the certificate issuer * @param cert X509 certificate * @return Country code from the certificate issuer */ public static String getIssuerCountry(X509Certificate cert) { String country = null; Principal issuerdn = cert.getIssuerX500Principal(); RFC2253NameParser nameParser = new RFC2253NameParser(issuerdn.getName()); try { Name name = nameParser.parse(); country = name.getRDN(ObjectID.country); } catch (RFC2253NameParserException e) { Logger.warn("Could not get country code from issuer."); } return country; } }