173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/*
273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is free software; you can redistribute it and/or modify it
673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * under the terms of the GNU General Public License version 2 only, as
773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * published by the Free Software Foundation.  Oracle designates this
873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * particular file as subject to the "Classpath" exception as provided
973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * by Oracle in the LICENSE file that accompanied this code.
1073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This code is distributed in the hope that it will be useful, but WITHOUT
1273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * version 2 for more details (a copy is included in the LICENSE file that
1573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * accompanied this code).
1673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
1773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * You should have received a copy of the GNU General Public License version
1873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * 2 along with this work; if not, write to the Free Software Foundation,
1973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
2173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * or visit www.oracle.com if you need additional information or have any
2373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * questions.
2473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
2573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpackage sun.security.provider.certpath;
2673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.InputStream;
2873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.IOException;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.OutputStream;
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.URI;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.URL;
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.net.HttpURLConnection;
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertificateException;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPathValidatorException;
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPathValidatorException.BasicReason;
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CRLReason;
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.Extension;
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509Certificate;
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Arrays;
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Collections;
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Date;
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.List;
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Map;
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport static sun.security.provider.certpath.OCSPResponse.*;
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.action.GetIntegerAction;
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.Debug;
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.ObjectIdentifier;
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.AccessDescription;
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.AuthorityInfoAccessExtension;
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.GeneralName;
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.GeneralNameInterface;
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.URIName;
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.X509CertImpl;
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This is a class that checks the revocation status of a certificate(s) using
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * OCSP. It is not a PKIXCertPathChecker and therefore can be used outside of
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * the CertPathValidator framework. It is useful when you want to
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * just check the revocation status of a certificate, and you don't want to
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * incur the overhead of validating all of the certificates in the
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * associated certificate chain.
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author Sean Mullan
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpublic final class OCSP {
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static final ObjectIdentifier NONCE_EXTENSION_OID =
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        ObjectIdentifier.newInternal(new int[]{ 1, 3, 6, 1, 5, 5, 7, 48, 1, 2});
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Debug debug = Debug.getInstance("certpath");
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int DEFAULT_CONNECT_TIMEOUT = 15000;
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Integer value indicating the timeout length, in seconds, to be
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * used for the OCSP check. A timeout of zero is interpreted as
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * an infinite timeout.
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int CONNECT_TIMEOUT = initializeTimeout();
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Initialize the timeout length by getting the OCSP timeout
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * system property. If the property has not been set, or if its
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * value is negative, set the timeout length to the default.
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static int initializeTimeout() {
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Integer tmp = java.security.AccessController.doPrivileged(
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                new GetIntegerAction("com.sun.security.ocsp.timeout"));
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (tmp == null || tmp < 0) {
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return DEFAULT_CONNECT_TIMEOUT;
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Convert to milliseconds, as the system property will be
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // specified in seconds
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return tmp * 1000;
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private OCSP() {}
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Obtains the revocation status of a certificate using OCSP using the most
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * common defaults. The OCSP responder URI is retrieved from the
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * certificate's AIA extension. The OCSP responder certificate is assumed
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * to be the issuer's certificate (or issued by the issuer CA).
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param cert the certificate to be checked
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param issuerCert the issuer certificate
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return the RevocationStatus
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws IOException if there is an exception connecting to or
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    communicating with the OCSP responder
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertPathValidatorException if an exception occurs while
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    encoding the OCSP Request or validating the OCSP Response
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public static RevocationStatus check(X509Certificate cert,
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         X509Certificate issuerCert)
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws IOException, CertPathValidatorException {
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        CertId certId = null;
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        URI responderURI = null;
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            X509CertImpl certImpl = X509CertImpl.toImpl(cert);
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responderURI = getResponderURI(certImpl);
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (responderURI == null) {
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    ("No OCSP Responder URI in certificate");
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (CertificateException | IOException e) {
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("Exception while encoding OCSPRequest", e);
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        OCSPResponse ocspResponse = check(Collections.singletonList(certId),
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responderURI, issuerCert, null, null,
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Collections.<Extension>emptyList());
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return (RevocationStatus)ocspResponse.getSingleResponse(certId);
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Obtains the revocation status of a certificate using OCSP.
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param cert the certificate to be checked
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param issuerCert the issuer certificate
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param responderURI the URI of the OCSP responder
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param responderCert the OCSP responder's certificate
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param date the time the validity of the OCSP responder's certificate
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    should be checked against. If null, the current time is used.
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return the RevocationStatus
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws IOException if there is an exception connecting to or
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    communicating with the OCSP responder
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertPathValidatorException if an exception occurs while
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    encoding the OCSP Request or validating the OCSP Response
15173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
15273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public static RevocationStatus check(X509Certificate cert,
15373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         X509Certificate issuerCert,
15473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         URI responderURI,
15573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         X509Certificate responderCert,
15673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         Date date)
15773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws IOException, CertPathValidatorException
15873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
15973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return check(cert, issuerCert, responderURI, responderCert, date,
16073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                     Collections.<Extension>emptyList());
16173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
16273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
16373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // Called by com.sun.deploy.security.TrustDecider
16473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public static RevocationStatus check(X509Certificate cert,
16573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         X509Certificate issuerCert,
16673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         URI responderURI,
16773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         X509Certificate responderCert,
16873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                         Date date, List<Extension> extensions)
16973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws IOException, CertPathValidatorException
17073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
17173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        CertId certId = null;
17273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
17373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            X509CertImpl certImpl = X509CertImpl.toImpl(cert);
17473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certId = new CertId(issuerCert, certImpl.getSerialNumberObject());
17573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (CertificateException | IOException e) {
17673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException
17773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("Exception while encoding OCSPRequest", e);
17873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
17973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        OCSPResponse ocspResponse = check(Collections.singletonList(certId),
18073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responderURI, issuerCert, responderCert, date, extensions);
18173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return (RevocationStatus) ocspResponse.getSingleResponse(certId);
18273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
18373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
18473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
18573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Checks the revocation status of a list of certificates using OCSP.
18673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
18773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param certs the CertIds to be checked
18873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param responderURI the URI of the OCSP responder
18973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param issuerCert the issuer's certificate
19073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param responderCert the OCSP responder's certificate
19173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param date the time the validity of the OCSP responder's certificate
19273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    should be checked against. If null, the current time is used.
19373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return the OCSPResponse
19473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws IOException if there is an exception connecting to or
19573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    communicating with the OCSP responder
19673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @throws CertPathValidatorException if an exception occurs while
19773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *    encoding the OCSP Request or validating the OCSP Response
19873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
19973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static OCSPResponse check(List<CertId> certIds, URI responderURI,
20073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                              X509Certificate issuerCert,
20173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                              X509Certificate responderCert, Date date,
20273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                              List<Extension> extensions)
20373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws IOException, CertPathValidatorException
20473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
20573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        byte[] bytes = null;
20673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        OCSPRequest request = null;
20773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
20873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            request = new OCSPRequest(certIds, extensions);
20973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            bytes = request.encodeBytes();
21073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (IOException ioe) {
21173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException
21273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("Exception while encoding OCSPRequest", ioe);
21373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
21473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
21573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        InputStream in = null;
21673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        OutputStream out = null;
21773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        byte[] response = null;
21873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
21973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            URL url = responderURI.toURL();
22073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
22173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("connecting to OCSP service at: " + url);
22273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
22373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            HttpURLConnection con = (HttpURLConnection)url.openConnection();
22473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setConnectTimeout(CONNECT_TIMEOUT);
22573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setReadTimeout(CONNECT_TIMEOUT);
22673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setDoOutput(true);
22773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setDoInput(true);
22873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setRequestMethod("POST");
22973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setRequestProperty
23073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("Content-type", "application/ocsp-request");
23173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            con.setRequestProperty
23273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ("Content-length", String.valueOf(bytes.length));
23373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            out = con.getOutputStream();
23473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            out.write(bytes);
23573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            out.flush();
23673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Check the response
23773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null &&
23873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                con.getResponseCode() != HttpURLConnection.HTTP_OK) {
23973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Received HTTP error: " + con.getResponseCode()
24073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    + " - " + con.getResponseMessage());
24173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
24273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            in = con.getInputStream();
24373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            int contentLength = con.getContentLength();
24473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (contentLength == -1) {
24573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                contentLength = Integer.MAX_VALUE;
24673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
24773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            response = new byte[contentLength > 2048 ? 2048 : contentLength];
24873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            int total = 0;
24973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            while (total < contentLength) {
25073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                int count = in.read(response, total, response.length - total);
25173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (count < 0)
25273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    break;
25373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
25473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                total += count;
25573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (total >= response.length && total < contentLength) {
25673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    response = Arrays.copyOf(response, total * 2);
25773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
25873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
25973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            response = Arrays.copyOf(response, total);
26073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (IOException ioe) {
26173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException(
26273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "Unable to determine revocation status due to network error",
26373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                ioe, null, -1, BasicReason.UNDETERMINED_REVOCATION_STATUS);
26473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } finally {
26573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (in != null) {
26673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
26773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    in.close();
26873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (IOException ioe) {
26973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw ioe;
27073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
27173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
27273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (out != null) {
27373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
27473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    out.close();
27573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (IOException ioe) {
27673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw ioe;
27773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
27873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
27973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
28073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
28173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        OCSPResponse ocspResponse = null;
28273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
28373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            ocspResponse = new OCSPResponse(response);
28473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (IOException ioe) {
28573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // response decoding exception
28673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException(ioe);
28773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
28873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
28973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // verify the response
29073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        ocspResponse.verify(certIds, issuerCert, responderCert, date,
29173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            request.getNonce());
29273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
29373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return ocspResponse;
29473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
29573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
29673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
29773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns the URI of the OCSP Responder as specified in the
29873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * certificate's Authority Information Access extension, or null if
29973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * not specified.
30073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     *
30173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @param cert the certificate
30273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * @return the URI of the OCSP Responder, or null if not specified
30373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
30473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // Called by com.sun.deploy.security.TrustDecider
30573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public static URI getResponderURI(X509Certificate cert) {
30673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
30773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return getResponderURI(X509CertImpl.toImpl(cert));
30873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (CertificateException ce) {
30973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // treat this case as if the cert had no extension
31073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return null;
31173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
31273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
31373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
31473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    static URI getResponderURI(X509CertImpl certImpl) {
31573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
31673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Examine the certificate's AuthorityInfoAccess extension
31773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        AuthorityInfoAccessExtension aia =
31873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certImpl.getAuthorityInfoAccessExtension();
31973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (aia == null) {
32073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return null;
32173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
32273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
32373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        List<AccessDescription> descriptions = aia.getAccessDescriptions();
32473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (AccessDescription description : descriptions) {
32573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (description.getAccessMethod().equals((Object)
32673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                AccessDescription.Ad_OCSP_Id)) {
32773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
32873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                GeneralName generalName = description.getAccessLocation();
32973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (generalName.getType() == GeneralNameInterface.NAME_URI) {
33073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    URIName uri = (URIName) generalName.getName();
33173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    return uri.getURI();
33273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
33373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
33473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
33573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return null;
33673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
33773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
33873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
33973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * The Revocation Status of a certificate.
34073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
34173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public static interface RevocationStatus {
34273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        public enum CertStatus { GOOD, REVOKED, UNKNOWN };
34373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
34473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /**
34573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Returns the revocation status.
34673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
34773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        CertStatus getCertStatus();
34873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /**
34973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Returns the time when the certificate was revoked, or null
35073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * if it has not been revoked.
35173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
35273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Date getRevocationTime();
35373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /**
35473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Returns the reason the certificate was revoked, or null if it
35573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * has not been revoked.
35673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
35773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        CRLReason getRevocationReason();
35873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
35973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /**
36073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Returns a Map of additional extensions.
36173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
36273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Map<String, Extension> getSingleExtensions();
36373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
36473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
365