Example usage for org.bouncycastle.asn1.x509 GeneralName getName

List of usage examples for org.bouncycastle.asn1.x509 GeneralName getName

Introduction

In this page you can find the example usage for org.bouncycastle.asn1.x509 GeneralName getName.

Prototype

public ASN1Encodable getName() 

Source Link

Usage

From source file:eu.europa.ec.markt.dss.validation102853.cades.CAdESSignature.java

License:Open Source License

static String getCanonicalizedName(final GeneralNames generalNames) {

    final GeneralName[] names = generalNames.getNames();
    final TreeMap<String, String> treeMap = new TreeMap<String, String>();
    for (final GeneralName name : names) {

        final String ldapString = String.valueOf(name.getName());
        LOG.debug("ldapString to canonicalize: {} ", ldapString);
        try {//from   ww  w .  j  a  v a2s  .  co  m

            final LdapName ldapName = new LdapName(ldapString);
            final List<Rdn> rdns = ldapName.getRdns();
            for (final Rdn rdn : rdns) {

                treeMap.put(rdn.getType().toLowerCase(), String.valueOf(rdn.getValue()).toLowerCase());
            }
        } catch (InvalidNameException e) {
            throw new DSSException(e);
        }
    }
    final StringBuilder stringBuilder = new StringBuilder();
    for (final Map.Entry<String, String> entry : treeMap.entrySet()) {

        stringBuilder.append(entry.getKey()).append('=').append(entry.getValue()).append('|');
    }
    final String canonicalizedName = stringBuilder.toString();
    LOG.debug("canonicalizedName: {} ", canonicalizedName);
    return canonicalizedName;

    /*
            final X500Principal x500Name = new X500Principal(name);
            final String canonicalizedNameCANONICAL = x500Name.getName(X500Principal.CANONICAL);
            System.out.println("===== CANONICAL ==== " + canonicalizedNameCANONICAL);
            final String canonicalizedNameRFC1779 = x500Name.getName(X500Principal.RFC1779);
            System.out.println("===== RFC1779   ==== " + canonicalizedNameRFC1779);
            final String canonicalizedNameRFC2253 = x500Name.getName(X500Principal.RFC2253);
            System.out.println("===== RFC2253   ==== " + canonicalizedNameRFC2253);
            return canonicalizedNameRFC2253;
    */
}

From source file:eu.europa.ec.markt.dss.validation102853.crl.CommonCRLSource.java

License:Open Source License

private void checkCriticalExtensions(final X509CRL x509CRL, final List<String> dpUrlStringList,
        final CRLValidity crlValidity) {

    final Set<String> criticalExtensionOIDs = x509CRL.getCriticalExtensionOIDs();
    if (criticalExtensionOIDs == null || criticalExtensionOIDs.size() == 0) {
        crlValidity.unknownCriticalExtension = false;
        return;//  www . j av a2s  . c om
    }
    final String issuingDistributionPointOid = PKIXExtensions.IssuingDistributionPoint_Id.toString();
    for (final String criticalExtensionOID : criticalExtensionOIDs) {

        if (issuingDistributionPointOid.equals(criticalExtensionOID)) {

            final byte[] extensionValue = x509CRL.getExtensionValue(issuingDistributionPointOid);
            final ASN1OctetString asn1OctetStringExtensionValue = ASN1OctetString.getInstance(extensionValue);
            final IssuingDistributionPoint issuingDistributionPoint = IssuingDistributionPoint
                    .getInstance(asn1OctetStringExtensionValue.getOctets());
            final boolean onlyAttributeCerts = issuingDistributionPoint.onlyContainsAttributeCerts();
            final boolean onlyCaCerts = issuingDistributionPoint.onlyContainsCACerts();
            final boolean onlyUserCerts = issuingDistributionPoint.onlyContainsUserCerts();
            final boolean indirectCrl = issuingDistributionPoint.isIndirectCRL();
            final ReasonFlags reasonFlags = issuingDistributionPoint.getOnlySomeReasons();
            final DistributionPointName distributionPointName = issuingDistributionPoint.getDistributionPoint();

            boolean urlFound = false;
            if (FULL_NAME == distributionPointName.getType()) {

                final GeneralNames generalNames = (GeneralNames) distributionPointName.getName();
                if (generalNames != null) {

                    final GeneralName[] names = generalNames.getNames();
                    if (names != null && names.length > 0) {
                        for (final GeneralName generalName : names) {
                            if (uniformResourceIdentifier == generalName.getTagNo()) {

                                final String name = generalName.getName().toString();
                                if (DSSUtils.isNotEmpty(dpUrlStringList) && dpUrlStringList.contains(name)) {
                                    urlFound = true;
                                }
                            }
                        }
                    }
                }
            }
            if (!(onlyAttributeCerts && onlyCaCerts && onlyUserCerts && indirectCrl) && reasonFlags == null
                    && urlFound) {
                crlValidity.unknownCriticalExtension = false;
            }
            continue;
        }
        crlValidity.unknownCriticalExtension = true;
    }
}

From source file:eu.europa.esig.dss.DSSASN1Utils.java

License:Open Source License

/**
 * This method can be removed the simple IssuerSerial verification can be
 * performed. In fact the hash verification is sufficient.
 *
 * @param generalNames//from w w w  . j  av  a 2 s.c om
 * @return
 */
public static String getCanonicalizedName(final GeneralNames generalNames) {
    GeneralName[] names = generalNames.getNames();
    TreeMap<String, String> treeMap = new TreeMap<String, String>();
    for (GeneralName name : names) {
        String ldapString = String.valueOf(name.getName());
        LOG.debug("ldapString to canonicalize: {} ", ldapString);
        try {
            LdapName ldapName = new LdapName(ldapString);
            List<Rdn> rdns = ldapName.getRdns();
            for (final Rdn rdn : rdns) {
                treeMap.put(rdn.getType().toLowerCase(), String.valueOf(rdn.getValue()).toLowerCase());
            }
        } catch (InvalidNameException e) {
            throw new DSSException(e);
        }
    }
    StringBuilder stringBuilder = new StringBuilder();
    for (Entry<String, String> entry : treeMap.entrySet()) {
        stringBuilder.append(entry.getKey()).append('=').append(entry.getValue()).append('|');
    }
    final String canonicalizedName = stringBuilder.toString();
    LOG.debug("canonicalizedName: {} ", canonicalizedName);
    return canonicalizedName;
}

From source file:eu.europa.esig.dss.xades.validation.XAdESSignature.java

License:Open Source License

@Override
public void checkSigningCertificate() {

    final CandidatesForSigningCertificate candidates = getCandidatesForSigningCertificate();
    /**//from w  w  w  . j  ava  2s  .  c  o  m
     * The ../SignedProperties/SignedSignatureProperties/SigningCertificate element MAY contain references and
     * digests values of other certificates (that
     * MAY form a chain up to the point of trust).
     */
    boolean isEn319132 = false;
    NodeList list = DSSXMLUtils.getNodeList(signatureElement, xPathQueryHolder.XPATH_SIGNING_CERTIFICATE_CERT);
    int length = list.getLength();
    if (length == 0) {
        list = DSSXMLUtils.getNodeList(signatureElement, xPathQueryHolder.XPATH_SIGNING_CERTIFICATE_CERT_V2);
        length = list.getLength();
        isEn319132 = true;
    }
    if (length == 0) {
        final CertificateValidity theCertificateValidity = candidates.getTheCertificateValidity();
        final CertificateToken certificateToken = theCertificateValidity == null ? null
                : theCertificateValidity.getCertificateToken();
        // The check need to be done at the level of KeyInfo
        for (final Reference reference : references) {

            final String uri = reference.getURI();
            if (!uri.startsWith("#")) {
                continue;
            }

            final String id = uri.substring(1);
            final Element element = signatureElement.getOwnerDocument().getElementById(id);
            // final Element element =
            // DSSXMLUtils.getElement(signatureElement, "");
            if (!hasSignatureAsParent(element)) {

                continue;
            }
            if ((certificateToken != null) && id.equals(certificateToken.getXmlId())) {

                theCertificateValidity.setSigned(element.getNodeName());
                return;
            }
        }
    }
    // This Map contains the list of the references to the certificate which
    // were already checked and which correspond to a certificate.
    Map<Element, Boolean> alreadyProcessedElements = new HashMap<Element, Boolean>();

    final List<CertificateValidity> certificateValidityList = candidates.getCertificateValidityList();
    for (final CertificateValidity certificateValidity : certificateValidityList) {

        final CertificateToken certificateToken = certificateValidity.getCertificateToken();
        for (int ii = 0; ii < length; ii++) {

            certificateValidity.setAttributePresent(true);
            final Element element = (Element) list.item(ii);
            if (alreadyProcessedElements.containsKey(element)) {
                continue;
            }
            final Element certDigestElement = DSSXMLUtils.getElement(element,
                    xPathQueryHolder.XPATH__CERT_DIGEST);
            certificateValidity.setDigestPresent(certDigestElement != null);

            final Element digestMethodElement = DSSXMLUtils.getElement(certDigestElement,
                    xPathQueryHolder.XPATH__DIGEST_METHOD);
            if (digestMethodElement == null) {
                continue;
            }
            final String xmlAlgorithmName = digestMethodElement.getAttribute(XMLE_ALGORITHM);
            // The default algorithm is used in case of bad encoded
            // algorithm name
            final DigestAlgorithm digestAlgorithm = DigestAlgorithm.forXML(xmlAlgorithmName,
                    DigestAlgorithm.SHA1);

            final Element digestValueElement = DSSXMLUtils.getElement(element,
                    xPathQueryHolder.XPATH__CERT_DIGEST_DIGEST_VALUE);
            if (digestValueElement == null) {
                continue;
            }
            // That must be a binary comparison
            final byte[] storedBase64DigestValue = DSSUtils
                    .base64StringToBase64Binary(digestValueElement.getTextContent());

            /**
             * Step 1:<br>
             * Take the first child of the property and check that the content of ds:DigestValue matches the result
             * of digesting <i>the candidate for</i>
             * the signing certificate with the algorithm indicated in ds:DigestMethod. If they do not match, take
             * the next child and repeat this step until
             * a matching child element has been found or all children of the element have been checked. If they do
             * match, continue with step 2. If the last
             * element is reached without finding any match, the validation of this property shall be taken as
             * failed and INVALID/FORMAT_FAILURE is
             * returned.
             */
            final byte[] digest = DSSUtils.digest(digestAlgorithm, certificateToken.getEncoded());
            final byte[] recalculatedBase64DigestValue = Base64.encodeBase64(digest);
            certificateValidity.setDigestEqual(false);
            BigInteger serialNumber = new BigInteger("0");
            if (Arrays.equals(recalculatedBase64DigestValue, storedBase64DigestValue)) {
                X500Principal issuerName = null;
                if (isEn319132) {
                    final Element issuerNameEl = DSSXMLUtils.getElement(element,
                            xPathQueryHolder.XPATH__X509_ISSUER_V2);
                    if (issuerNameEl != null) {
                        final String textContent = issuerNameEl.getTextContent();

                        ASN1InputStream is = null;
                        GeneralName name = null;
                        ASN1Integer serial = null;
                        try {
                            is = new ASN1InputStream(Base64.decodeBase64(textContent));
                            ASN1Sequence seq = (ASN1Sequence) is.readObject();
                            ASN1Sequence obj = (ASN1Sequence) seq.getObjectAt(0);
                            name = GeneralName.getInstance(obj.getObjectAt(0));
                            serial = (ASN1Integer) seq.getObjectAt(1);
                        } catch (IOException e) {
                            LOG.error("Unable to decode textContent " + textContent + " : " + e.getMessage(),
                                    e);
                        } finally {
                            IOUtils.closeQuietly(is);
                        }

                        try {
                            issuerName = new X500Principal(name.getName().toASN1Primitive().getEncoded());
                        } catch (Exception e) {
                            LOG.error("Unable to decode X500Principal : " + e.getMessage(), e);
                        }

                        try {
                            serialNumber = serial.getValue();
                        } catch (Exception e) {
                            LOG.error("Unable to decode serialNumber : " + e.getMessage(), e);
                        }

                    }
                } else {
                    final Element issuerNameEl = DSSXMLUtils.getElement(element,
                            xPathQueryHolder.XPATH__X509_ISSUER_NAME);
                    // This can be allayed when the distinguished name is not
                    // correctly encoded
                    // final String textContent =
                    // DSSUtils.unescapeMultiByteUtf8Literals(issuerNameEl.getTextContent());
                    final String textContent = issuerNameEl.getTextContent();

                    issuerName = DSSUtils.getX500PrincipalOrNull(textContent);

                    final Element serialNumberEl = DSSXMLUtils.getElement(element,
                            xPathQueryHolder.XPATH__X509_SERIAL_NUMBER);
                    final String serialNumberText = serialNumberEl.getTextContent();
                    // serial number can contain leading and trailing whitespace.
                    serialNumber = new BigInteger(serialNumberText.trim());
                }
                final X500Principal candidateIssuerName = certificateToken.getIssuerX500Principal();

                final boolean issuerNameMatches = DSSUtils.x500PrincipalAreEquals(candidateIssuerName,
                        issuerName);
                if (!issuerNameMatches) {
                    final String c14nCandidateIssuerName = candidateIssuerName.getName(X500Principal.CANONICAL);
                    LOG.info("candidateIssuerName: " + c14nCandidateIssuerName);
                    final String c14nIssuerName = issuerName == null ? ""
                            : issuerName.getName(X500Principal.CANONICAL);
                    LOG.info("issuerName         : " + c14nIssuerName);
                }

                final BigInteger candidateSerialNumber = certificateToken.getSerialNumber();
                final boolean serialNumberMatches = candidateSerialNumber.equals(serialNumber);

                certificateValidity.setDigestEqual(true);
                certificateValidity.setSerialNumberEqual(serialNumberMatches);
                certificateValidity.setDistinguishedNameEqual(issuerNameMatches);
                // The certificate was identified
                alreadyProcessedElements.put(element, true);
                // If the signing certificate is not set yet then it must be
                // done now. Actually if the signature is tempered then the
                // method checkSignatureIntegrity cannot set the signing
                // certificate.
                if (candidates.getTheCertificateValidity() == null) {
                    candidates.setTheCertificateValidity(certificateValidity);
                }
                break;
            }
        }
    }
}

From source file:mitm.common.security.certificate.AltNamesInspector.java

License:Open Source License

/**
 * Use this constructor for ASN1Utils.getExtensionValue(X509Extension, String)
 * @param altName//from  w  ww . ja v a2  s.c  om
 */
public AltNamesInspector(ASN1Sequence altName) {
    if (altName != null) {
        Collection<List<?>> altNames = new LinkedList<List<?>>();

        for (int i = 0; i < altName.size(); i++) {
            GeneralName generalName = GeneralName.getInstance(altName.getObjectAt(i));

            ASN1Encodable obj = generalName.getName();

            String value;

            switch (generalName.getTagNo()) {
            case rfc822NameTag:
            case dnsNameTag:
            case uniformResourceIdentifierTag:
                value = DERIA5String.getInstance(obj).getString();
                break;
            default:
                value = obj.toString();
            }

            List<Object> list = new LinkedList<Object>();

            list.add(generalName.getTagNo());
            list.add(value);

            altNames.add(list);
        }

        parseAltNames(altNames);
    }
}

From source file:mitm.common.security.certificate.X509ExtensionInspectorTest.java

License:Open Source License

@Test
public void testAuthoritykeyIdentifier() throws Exception {
    X509Certificate certificate = TestUtils
            .loadCertificate("test/resources/testdata/certificates/" + "mitm-test-ca.cer");

    AuthorityKeyIdentifier authorityKeyIdentifier = X509CertificateInspector
            .getAuthorityKeyIdentifier(certificate);

    assertNotNull(authorityKeyIdentifier);
    assertEquals(1, authorityKeyIdentifier.getAuthorityCertIssuer().getNames().length);

    GeneralName name = authorityKeyIdentifier.getAuthorityCertIssuer().getNames()[0];
    assertEquals(GeneralName.directoryName, name.getTagNo());
    assertEquals("C=NL,ST=NH,L=Amsterdam,CN=MITM Test Root,E=root@example.com",
            X500Name.getInstance(name.getName()).toString());
    assertEquals("115FCAC409FB2022B7D06920A00FE42",
            BigIntegerUtils.hexEncode(authorityKeyIdentifier.getAuthorityCertSerialNumber()));

    // another cert
    certificate = TestUtils.loadCertificate("test/resources/testdata/certificates/" + "ldap-crl.cer");

    authorityKeyIdentifier = X509CertificateInspector.getAuthorityKeyIdentifier(certificate);

    assertNotNull(authorityKeyIdentifier);
    assertEquals("37509F5DEF72162D12C7D46C408B1F65F550A8F9",
            HexUtils.hexEncode(authorityKeyIdentifier.getKeyIdentifier()));
}

From source file:mitm.common.security.crl.CRLDistributionPointsInspector.java

License:Open Source License

public static Set<String> getURIDistributionPointNames(CRLDistPoint crlDistPoint) throws CRLException {
    try {//from  ww  w.  ja va 2 s. com
        Set<String> uris = new HashSet<String>();

        if (crlDistPoint == null) {
            return uris;
        }

        DistributionPoint[] distributionPoints = crlDistPoint.getDistributionPoints();

        if (distributionPoints != null) {
            for (DistributionPoint distributionPoint : distributionPoints) {
                if (distributionPoint == null) {
                    logger.debug("Distributionpoint is null.");
                    continue;
                }

                DistributionPointName distributionPointName = distributionPoint.getDistributionPoint();

                /* We will only return full names containing URIs */
                if (distributionPointName != null
                        && distributionPointName.getType() == DistributionPointName.FULL_NAME) {
                    ASN1Encodable name = distributionPointName.getName();

                    if (name != null) {
                        GeneralName[] names = GeneralNames.getInstance(name).getNames();

                        for (GeneralName generalName : names) {
                            if (generalName != null
                                    && generalName.getTagNo() == GeneralName.uniformResourceIdentifier
                                    && generalName.getName() != null) {
                                String uri = DERIA5String.getInstance(generalName.getName()).getString();

                                uris.add(uri);
                            }
                        }
                    }
                }
            }
        }

        return uris;
    } catch (IllegalArgumentException e) {
        /*
         * Can be thrown when the CRL dist. point contains illegal ASN1.
         */
        throw new CRLException("Error getting the CRL distribution point names.", e);
    }
}

From source file:mitm.common.security.crl.PKIXRevocationChecker.java

License:Open Source License

private boolean hasMatchingName(X500Name name, GeneralName[] generalNames) {
    if (name == null || generalNames == null) {
        return false;
    }//from  w  w w  .  j  av  a2  s.  c  om

    for (GeneralName generalName : generalNames) {
        /* 
         * we only need to compare directoryNames
         */
        if (generalName.getTagNo() == GeneralName.directoryName) {
            if (name.equals(X500Name.getInstance(generalName.getName()))) {
                return true;
            }
        }
    }

    return false;
}

From source file:net.felsing.client_cert.utilities.CertificateFabric.java

License:Open Source License

private void getSubjectAlternativeNames(PKCS10CertificationRequest csr) {
    subjectAlternativeNames = new ArrayList<>(new ArrayList<>());
    // GeneralName.otherName is lowest and
    // GeneralName.registeredID is highest id
    for (int i = GeneralName.otherName; i <= GeneralName.registeredID; i++) {
        subjectAlternativeNames.add(new ArrayList<>());
    }/*from w  w  w .j a  va 2  s.c om*/

    try {
        Attribute[] certAttributes = csr.getAttributes();
        for (Attribute attribute : certAttributes) {
            if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) {
                // @ToDo: Is there really one object only?
                Extensions extensions = Extensions.getInstance(attribute.getAttrValues().getObjectAt(0));
                GeneralNames gns = GeneralNames.fromExtensions(extensions, Extension.subjectAlternativeName);
                if (gns != null) {
                    GeneralName[] names = gns.getNames();
                    for (GeneralName name : names) {
                        subjectAlternativeNames.get(name.getTagNo()).add(name.getName().toString());
                    }
                }
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

From source file:net.java.sip.communicator.impl.certificate.CertificateServiceImpl.java

License:Apache License

public X509TrustManager getTrustManager(final Iterable<String> identitiesToTest,
        final CertificateMatcher clientVerifier, final CertificateMatcher serverVerifier)
        throws GeneralSecurityException {
    // obtain the default X509 trust manager
    X509TrustManager defaultTm = null;
    TrustManagerFactory tmFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());

    //workaround for https://bugs.openjdk.java.net/browse/JDK-6672015
    KeyStore ks = null;/*ww w . j a  va  2s.  co  m*/
    String tsType = System.getProperty("javax.net.ssl.trustStoreType", null);
    if ("Windows-ROOT".equals(tsType)) {
        try {
            ks = KeyStore.getInstance(tsType);
            ks.load(null, null);
            int numEntries = keyStoreAppendIndex(ks);
            logger.info(
                    "Using Windows-ROOT. Aliases sucessfully renamed on " + numEntries + " root certificates.");
        } catch (Exception e) {
            logger.error("Could not rename Windows-ROOT aliases", e);
        }
    }

    tmFactory.init(ks);
    for (TrustManager m : tmFactory.getTrustManagers()) {
        if (m instanceof X509TrustManager) {
            defaultTm = (X509TrustManager) m;
            break;
        }
    }
    if (defaultTm == null)
        throw new GeneralSecurityException("No default X509 trust manager found");

    final X509TrustManager tm = defaultTm;

    return new X509TrustManager() {
        private boolean serverCheck;

        public X509Certificate[] getAcceptedIssuers() {
            return tm.getAcceptedIssuers();
        }

        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            serverCheck = true;
            checkCertTrusted(chain, authType);
        }

        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            serverCheck = false;
            checkCertTrusted(chain, authType);
        }

        private void checkCertTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            // check and default configurations for property
            // if missing default is null - false
            String defaultAlwaysTrustMode = CertificateVerificationActivator.getResources()
                    .getSettingsString(CertificateService.PNAME_ALWAYS_TRUST);

            if (config.getBoolean(PNAME_ALWAYS_TRUST, Boolean.parseBoolean(defaultAlwaysTrustMode)))
                return;

            try {
                // check the certificate itself (issuer, validity)
                try {
                    chain = tryBuildChain(chain);
                } catch (Exception e) {
                } // don't care and take the chain as is

                if (serverCheck)
                    tm.checkServerTrusted(chain, authType);
                else
                    tm.checkClientTrusted(chain, authType);

                if (identitiesToTest == null || !identitiesToTest.iterator().hasNext())
                    return;
                else if (serverCheck)
                    serverVerifier.verify(identitiesToTest, chain[0]);
                else
                    clientVerifier.verify(identitiesToTest, chain[0]);

                // ok, globally valid cert
            } catch (CertificateException e) {
                String thumbprint = getThumbprint(chain[0], THUMBPRINT_HASH_ALGORITHM);
                String message = null;
                List<String> propNames = new LinkedList<String>();
                List<String> storedCerts = new LinkedList<String>();
                String appName = R.getSettingsString("service.gui.APPLICATION_NAME");

                if (identitiesToTest == null || !identitiesToTest.iterator().hasNext()) {
                    String propName = PNAME_CERT_TRUST_PREFIX + ".server." + thumbprint;
                    propNames.add(propName);

                    message = R.getI18NString("service.gui." + "CERT_DIALOG_DESCRIPTION_TXT_NOHOST",
                            new String[] { appName });

                    // get the thumbprints from the permanent allowances
                    String hashes = config.getString(propName);
                    if (hashes != null)
                        for (String h : hashes.split(","))
                            storedCerts.add(h);

                    // get the thumbprints from the session allowances
                    List<String> sessionCerts = sessionAllowedCertificates.get(propName);
                    if (sessionCerts != null)
                        storedCerts.addAll(sessionCerts);
                } else {
                    if (serverCheck) {
                        message = R.getI18NString("service.gui." + "CERT_DIALOG_DESCRIPTION_TXT",
                                new String[] { appName, identitiesToTest.toString() });
                    } else {
                        message = R.getI18NString("service.gui." + "CERT_DIALOG_PEER_DESCRIPTION_TXT",
                                new String[] { appName, identitiesToTest.toString() });
                    }
                    for (String identity : identitiesToTest) {
                        String propName = PNAME_CERT_TRUST_PREFIX + ".param." + identity;
                        propNames.add(propName);

                        // get the thumbprints from the permanent allowances
                        String hashes = config.getString(propName);
                        if (hashes != null)
                            for (String h : hashes.split(","))
                                storedCerts.add(h);

                        // get the thumbprints from the session allowances
                        List<String> sessionCerts = sessionAllowedCertificates.get(propName);
                        if (sessionCerts != null)
                            storedCerts.addAll(sessionCerts);
                    }
                }

                if (!storedCerts.contains(thumbprint)) {
                    switch (verify(chain, message)) {
                    case DO_NOT_TRUST:
                        logger.info("Untrusted certificate", e);
                        throw new CertificateException("The peer provided certificate with Subject <"
                                + chain[0].getSubjectDN() + "> is not trusted", e);
                    case TRUST_ALWAYS:
                        for (String propName : propNames) {
                            String current = config.getString(propName);
                            String newValue = thumbprint;
                            if (current != null)
                                newValue += "," + current;
                            config.setProperty(propName, newValue);
                        }
                        break;
                    case TRUST_THIS_SESSION_ONLY:
                        for (String propName : propNames)
                            getSessionCertEntry(propName).add(thumbprint);
                        break;
                    }
                }
                // ok, we've seen this certificate before
            }
        }

        private X509Certificate[] tryBuildChain(X509Certificate[] chain)
                throws IOException, URISyntaxException, CertificateException {
            // Only try to build chains for servers that send only their
            // own cert, but no issuer. This also matches self signed (will
            // be ignored later) and Root-CA signed certs. In this case we
            // throw the Root-CA away after the lookup
            if (chain.length != 1)
                return chain;

            // ignore self signed certs
            if (chain[0].getIssuerDN().equals(chain[0].getSubjectDN()))
                return chain;

            // prepare for the newly created chain
            List<X509Certificate> newChain = new ArrayList<X509Certificate>(chain.length + 4);
            for (X509Certificate cert : chain) {
                newChain.add(cert);
            }

            // search from the topmost certificate upwards
            CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
            X509Certificate current = chain[chain.length - 1];
            boolean foundParent;
            int chainLookupCount = 0;
            do {
                foundParent = false;
                // extract the url(s) where the parent certificate can be
                // found
                byte[] aiaBytes = current.getExtensionValue(Extension.authorityInfoAccess.getId());
                if (aiaBytes == null)
                    break;

                AuthorityInformationAccess aia = AuthorityInformationAccess
                        .getInstance(X509ExtensionUtil.fromExtensionValue(aiaBytes));

                // the AIA may contain different URLs and types, try all
                // of them
                for (AccessDescription ad : aia.getAccessDescriptions()) {
                    // we are only interested in the issuer certificate,
                    // not in OCSP urls the like
                    if (!ad.getAccessMethod().equals(AccessDescription.id_ad_caIssuers))
                        continue;

                    GeneralName gn = ad.getAccessLocation();
                    if (!(gn.getTagNo() == GeneralName.uniformResourceIdentifier
                            && gn.getName() instanceof DERIA5String))
                        continue;

                    URI uri = new URI(((DERIA5String) gn.getName()).getString());
                    // only http(s) urls; LDAP is taken care of in the
                    // default implementation
                    if (!(uri.getScheme().equalsIgnoreCase("http") || uri.getScheme().equals("https")))
                        continue;

                    X509Certificate cert = null;

                    // try to get cert from cache first to avoid consecutive
                    // (slow) http lookups
                    AiaCacheEntry cache = aiaCache.get(uri);
                    if (cache != null && cache.cacheDate.after(new Date())) {
                        cert = cache.cert;
                    } else {
                        // download if no cache entry or if it is expired
                        if (logger.isDebugEnabled())
                            logger.debug("Downloading parent certificate for <" + current.getSubjectDN()
                                    + "> from <" + uri + ">");
                        try {
                            InputStream is = HttpUtils.openURLConnection(uri.toString()).getContent();
                            cert = (X509Certificate) certFactory.generateCertificate(is);
                        } catch (Exception e) {
                            logger.debug("Could not download from <" + uri + ">");
                        }
                        // cache for 10mins
                        aiaCache.put(uri,
                                new AiaCacheEntry(new Date(new Date().getTime() + 10 * 60 * 1000), cert));
                    }
                    if (cert != null) {
                        if (!cert.getIssuerDN().equals(cert.getSubjectDN())) {
                            newChain.add(cert);
                            foundParent = true;
                            current = cert;
                            break; // an AD was valid, ignore others
                        } else
                            logger.debug("Parent is self-signed, ignoring");
                    }
                }
                chainLookupCount++;
            } while (foundParent && chainLookupCount < 10);
            chain = newChain.toArray(chain);
            return chain;
        }
    };
}