All Downloads are FREE. Search and download functionalities are using the official Maven repository.

no.digipost.security.ocsp.OcspLookup Maven / Gradle / Ivy

/**
 * Copyright (C) Posten Norge AS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package no.digipost.security.ocsp;

import no.digipost.security.DigipostSecurityException;
import no.digipost.security.Sha1Calculator;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.ocsp.OCSPObjectIdentifiers;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.ocsp.CertificateID;
import org.bouncycastle.cert.ocsp.OCSPException;
import org.bouncycastle.cert.ocsp.OCSPReqBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.util.Enumeration;
import java.util.Optional;

import static no.digipost.security.DigipostSecurity.describe;
import static org.apache.http.client.methods.RequestBuilder.post;

/**
 * Online Certificate Status Protocol (OCSP) is an automated certificate checking
 * network protocol. One can query an OCSP responder for the status of a certificate. The responder
 * returns whether the certificate is still trusted by the CA that issued it.
 *
 * @see Internet Engineering Task Force (IETF) RFC6960
 */
public final class OcspLookup {

    static final String AUTHORITY_INFO_ACCESS_OID = "1.3.6.1.5.5.7.1.1";

    private static final Logger LOG = LoggerFactory.getLogger(OcspLookup.class);


    /**
     * Prepare a new OCSP lookup request for the given certificate.
     *
     * @param certificate the certificate to lookup. It must contain an OCSP responder URI.
     * @param issuer the issuer of the certificate.
     * @return an OCSP request, ready to be {@link OcspLookup#executeUsing(CloseableHttpClient) executed},
     *         or {@link Optional#empty()} of no OCSP responder URI was found, or any other error occuring.
     */
    public static Optional newLookup(X509Certificate certificate, X509Certificate issuer) {
        byte[] authorityInfoAccessValue = certificate.getExtensionValue(AUTHORITY_INFO_ACCESS_OID);
        if (authorityInfoAccessValue == null) {
            return Optional.empty();
        }

        String ocspResponderUri;
        try {
            ocspResponderUri = extractResponderUri(authorityInfoAccessValue);
        } catch (RuntimeException e) {
            LOG.warn("Failed to extract OCSP uri from " + describe(certificate), e);
            return Optional.empty();
        }

        try {
            CertificateID certificateId = new CertificateID(new Sha1Calculator(), new X509CertificateHolder(issuer.getEncoded()), certificate.getSerialNumber());
            return Optional.of(new OcspLookup(ocspResponderUri, certificateId));
        } catch (OCSPException | CertificateEncodingException | IOException e) {
            LOG.warn("Failed to create certificate ID from issuer " + issuer + " and certificate " + describe(certificate), e);
            return Optional.empty();
        }
    }

    private static String extractResponderUri(byte[] authorityInfoAccessValue) {
        try {
            DEROctetString base = (DEROctetString) ASN1Primitive.fromByteArray(authorityInfoAccessValue);
            DLSequence seq = (DLSequence) ASN1Primitive.fromByteArray(base.getOctets());
            Enumeration objects = seq.getObjects();
            while (objects.hasMoreElements()) {
                Object elm = objects.nextElement();
                if (elm instanceof DLSequence) {
                    ASN1Encodable id = ((DLSequence)elm).getObjectAt(0);
                    if (OCSPObjectIdentifiers.id_pkix_ocsp.equals(id)) {
                        DERTaggedObject dt = (DERTaggedObject)((DLSequence)elm).getObjectAt(1);
                        DEROctetString dos =  (DEROctetString)dt.getObjectParser(dt.getTagNo(), true);
                        return new String(dos.getOctets());
                    }
                }
            }
            throw new DigipostSecurityException("Object identifier " + OCSPObjectIdentifiers.id_pkix_ocsp + " not found");
        } catch (IOException e) {
            throw new DigipostSecurityException("Object identifier " + OCSPObjectIdentifiers.id_pkix_ocsp + " not found", e);
        }
    }



    public final String uri;
    public final CertificateID certificateId;

    private OcspLookup(String uri, CertificateID certificateId) {
        this.certificateId = certificateId;
        this.uri = uri;
    }

    /**
     * Execute the OCSP lookup request.
     *
     * @param client the http client to use for executing the lookup request.
     * @return the {@link OcspResult result} of the OCSP lookup.
     */
    public OcspResult executeUsing(CloseableHttpClient client) {
        try {
            HttpEntity ocspRequestEntity = new ByteArrayEntity(new OCSPReqBuilder().addRequest(certificateId).build().getEncoded());
            HttpUriRequest ocspRequest = post().setUri(uri)
                    .addHeader("Content-Type", "application/ocsp-request")
                    .setEntity(ocspRequestEntity).build();
            return new OcspResult(uri, client.execute(ocspRequest));
        } catch (OCSPException | IOException e) {
            throw new DigipostSecurityException(e);
        }
    }

    @Override
    public String toString() {
        return "OCSP-lookup to responder uri " + uri;
    }


}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy