173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/*
27fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak * Copyright (c) 2003, 2015, 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 Root
2673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpackage sun.security.provider.certpath;
2773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
2873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.io.*;
2973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.*;
3073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertificateException;
3173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertificateParsingException;
3273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPathValidatorException;
3373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CertPathValidatorException.BasicReason;
3473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.CRLReason;
3573405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.TrustAnchor;
3673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.security.cert.X509Certificate;
3773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.ArrayList;
3873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Arrays;
3973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Collections;
4073405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Date;
4173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.HashMap;
4273405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.List;
4373405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport java.util.Map;
4473405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport javax.security.auth.x500.X500Principal;
4573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
4673405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.misc.HexDumpEncoder;
4773405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.action.GetIntegerAction;
4873405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.x509.*;
4973405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootimport sun.security.util.*;
5073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root/**
5273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * This class is used to process an OCSP response.
5373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * The OCSP Response is defined
5473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * in RFC 2560 and the ASN.1 encoding is as follows:
5573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * <pre>
5673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
5773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *  OCSPResponse ::= SEQUENCE {
5873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      responseStatus         OCSPResponseStatus,
5973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
6073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
6173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   OCSPResponseStatus ::= ENUMERATED {
6273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       successful            (0),  --Response has valid confirmations
6373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       malformedRequest      (1),  --Illegal confirmation request
6473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       internalError         (2),  --Internal error in issuer
6573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       tryLater              (3),  --Try again later
6673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *                                   --(4) is not used
6773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       sigRequired           (5),  --Must sign the request
6873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       unauthorized          (6)   --Request unauthorized
6973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   }
7073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
7173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   ResponseBytes ::=       SEQUENCE {
7273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       responseType   OBJECT IDENTIFIER,
7373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       response       OCTET STRING }
7473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
7573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   BasicOCSPResponse       ::= SEQUENCE {
7673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      tbsResponseData      ResponseData,
7773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      signatureAlgorithm   AlgorithmIdentifier,
7873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      signature            BIT STRING,
7973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
8073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
8173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   The value for signature SHALL be computed on the hash of the DER
8273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   encoding ResponseData.
8373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
8473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   ResponseData ::= SEQUENCE {
8573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      version              [0] EXPLICIT Version DEFAULT v1,
8673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      responderID              ResponderID,
8773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      producedAt               GeneralizedTime,
8873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      responses                SEQUENCE OF SingleResponse,
8973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
9073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
9173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   ResponderID ::= CHOICE {
9273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      byName               [1] Name,
9373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      byKey                [2] KeyHash }
9473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
9573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
9673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   (excluding the tag and length fields)
9773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
9873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   SingleResponse ::= SEQUENCE {
9973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      certID                       CertID,
10073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      certStatus                   CertStatus,
10173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      thisUpdate                   GeneralizedTime,
10273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      nextUpdate         [0]       EXPLICIT GeneralizedTime OPTIONAL,
10373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *      singleExtensions   [1]       EXPLICIT Extensions OPTIONAL }
10473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
10573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   CertStatus ::= CHOICE {
10673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       good        [0]     IMPLICIT NULL,
10773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       revoked     [1]     IMPLICIT RevokedInfo,
10873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       unknown     [2]     IMPLICIT UnknownInfo }
10973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
11073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   RevokedInfo ::= SEQUENCE {
11173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       revocationTime              GeneralizedTime,
11273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *       revocationReason    [0]     EXPLICIT CRLReason OPTIONAL }
11373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
11473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *   UnknownInfo ::= NULL -- this can be replaced with an enumeration
11573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
11673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * </pre>
11773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root *
11873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root * @author      Ram Marti
11973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root */
12073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12173405ff8729cca39da90b2e2f604062e323f6f7aKenny Rootpublic final class OCSPResponse {
12273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
12373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    public enum ResponseStatus {
12473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        SUCCESSFUL,            // Response has valid confirmations
12573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        MALFORMED_REQUEST,     // Illegal request
12673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        INTERNAL_ERROR,        // Internal error in responder
12773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        TRY_LATER,             // Try again later
12873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        UNUSED,                // is not used
12973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        SIG_REQUIRED,          // Must sign the request
13073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        UNAUTHORIZED           // Request unauthorized
13173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    };
13273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static ResponseStatus[] rsvalues = ResponseStatus.values();
13373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
13473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final Debug debug = Debug.getInstance("certpath");
13573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final boolean dump = debug != null && Debug.isOn("ocsp");
13673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final ObjectIdentifier OCSP_BASIC_RESPONSE_OID =
13773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        ObjectIdentifier.newInternal(new int[] { 1, 3, 6, 1, 5, 5, 7, 48, 1, 1});
13873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int CERT_STATUS_GOOD = 0;
13973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int CERT_STATUS_REVOKED = 1;
14073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int CERT_STATUS_UNKNOWN = 2;
14173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
14273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // ResponderID CHOICE tags
14373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int NAME_TAG = 1;
14473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int KEY_TAG = 2;
14573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
14673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // Object identifier for the OCSPSigning key purpose
14773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final String KP_OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
14873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
14973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // Default maximum clock skew in milliseconds (15 minutes)
15073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // allowed when checking validity of OCSP responses
15173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int DEFAULT_MAX_CLOCK_SKEW = 900000;
15273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
15373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
1547fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak     * Integer value indicating the maximum allowable clock skew,
1557fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak     * in milliseconds, to be used for the OCSP check.
15673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
15773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static final int MAX_CLOCK_SKEW = initializeClockSkew();
15873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
15973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
16073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Initialize the maximum allowable clock skew by getting the OCSP
16173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * clock skew system property. If the property has not been set, or if its
16273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * value is negative, set the skew to the default.
16373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
16473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static int initializeClockSkew() {
16573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Integer tmp = java.security.AccessController.doPrivileged(
16673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                new GetIntegerAction("com.sun.security.ocsp.clockSkew"));
16773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (tmp == null || tmp < 0) {
16873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return DEFAULT_MAX_CLOCK_SKEW;
16973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
17073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Convert to milliseconds, as the system property will be
17173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // specified in seconds
17273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return tmp * 1000;
17373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
17473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
17573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    // an array of all of the CRLReasons (used in SingleResponse)
17673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private static CRLReason[] values = CRLReason.values();
17773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
17873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final ResponseStatus responseStatus;
17973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final Map<CertId, SingleResponse> singleResponseMap;
18073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final AlgorithmId sigAlgId;
18173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final byte[] signature;
18273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final byte[] tbsResponseData;
18373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private final byte[] responseNonce;
18473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private List<X509CertImpl> certs;
18573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private X509CertImpl signerCert = null;
18673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private X500Principal responderName = null;
18773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private KeyIdentifier responderKeyId = null;
18873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
18973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /*
19073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Create an OCSP response from its ASN.1 DER encoding.
19173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
19273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    OCSPResponse(byte[] bytes) throws IOException {
19373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (dump) {
19473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            HexDumpEncoder hexEnc = new HexDumpEncoder();
19573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("OCSPResponse bytes...\n\n" +
19673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                hexEnc.encode(bytes) + "\n");
19773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
19873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue der = new DerValue(bytes);
19973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (der.tag != DerValue.tag_Sequence) {
20073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Bad encoding in OCSP response: " +
20173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "expected ASN.1 SEQUENCE tag.");
20273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
20373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerInputStream derIn = der.getData();
20473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
20573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responseStatus
20673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        int status = derIn.getEnumerated();
20773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (status >= 0 && status < rsvalues.length) {
20873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responseStatus = rsvalues[status];
20973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
21073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // unspecified responseStatus
21173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Unknown OCSPResponse status: " + status);
21273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
21373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
21473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("OCSP response status: " + responseStatus);
21573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
21673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (responseStatus != ResponseStatus.SUCCESSFUL) {
21773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // no need to continue, responseBytes are not set.
21873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            singleResponseMap = Collections.emptyMap();
21973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certs = new ArrayList<X509CertImpl>();
22073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            sigAlgId = null;
22173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            signature = null;
22273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            tbsResponseData = null;
22373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responseNonce = null;
22473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return;
22573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
22673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
22773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responseBytes
22873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        der = derIn.getDerValue();
22973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (!der.isContextSpecific((byte)0)) {
23073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Bad encoding in responseBytes element " +
23173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "of OCSP response: expected ASN.1 context specific tag 0.");
23273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
23373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue tmp = der.data.getDerValue();
23473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (tmp.tag != DerValue.tag_Sequence) {
23573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Bad encoding in responseBytes element " +
23673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "of OCSP response: expected ASN.1 SEQUENCE tag.");
23773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
23873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
23973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responseType
24073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        derIn = tmp.data;
24173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        ObjectIdentifier responseType = derIn.getOID();
24273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (responseType.equals((Object)OCSP_BASIC_RESPONSE_OID)) {
24373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
24473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("OCSP response type: basic");
24573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
24673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
24773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
24873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("OCSP response type: " + responseType);
24973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
25073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Unsupported OCSP response type: " +
25173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                  responseType);
25273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
25373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
25473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // BasicOCSPResponse
25573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerInputStream basicOCSPResponse =
25673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            new DerInputStream(derIn.getOctetString());
25773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
25873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue[] seqTmp = basicOCSPResponse.getSequence(2);
25973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (seqTmp.length < 3) {
26073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Unexpected BasicOCSPResponse value");
26173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
26273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
26373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue responseData = seqTmp[0];
26473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
26573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Need the DER encoded ResponseData to verify the signature later
26673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        tbsResponseData = seqTmp[0].toByteArray();
26773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
26873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // tbsResponseData
26973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (responseData.tag != DerValue.tag_Sequence) {
27073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Bad encoding in tbsResponseData " +
27173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "element of OCSP response: expected ASN.1 SEQUENCE tag.");
27273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
27373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerInputStream seqDerIn = responseData.data;
27473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue seq = seqDerIn.getDerValue();
27573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
27673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // version
27773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (seq.isContextSpecific((byte)0)) {
27873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // seq[0] is version
27973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (seq.isConstructed() && seq.isContextSpecific()) {
28073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                //System.out.println ("version is available");
28173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                seq = seq.data.getDerValue();
28273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                int version = seq.getInteger();
28373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (seq.data.available() != 0) {
28473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw new IOException("Bad encoding in version " +
28573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        " element of OCSP response: bad format");
28673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
28773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                seq = seqDerIn.getDerValue();
28873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
28973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
29073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
29173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responderID
29273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        short tag = (byte)(seq.tag & 0x1f);
29373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (tag == NAME_TAG) {
29473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responderName = new X500Principal(seq.getData().toByteArray());
29573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
29673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Responder's name: " + responderName);
29773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
29873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else if (tag == KEY_TAG) {
29973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            responderKeyId = new KeyIdentifier(seq.getData().getOctetString());
30073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
30173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Responder's key ID: " +
30273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    Debug.toString(responderKeyId.getIdentifier()));
30373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
30473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
30573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new IOException("Bad encoding in responderID element of " +
30673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "OCSP response: expected ASN.1 context specific tag 0 or 1");
30773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
30873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
30973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // producedAt
31073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        seq = seqDerIn.getDerValue();
31173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
31273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Date producedAtDate = seq.getGeneralizedTime();
31373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("OCSP response produced at: " + producedAtDate);
31473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
31573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
31673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responses
31773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        DerValue[] singleResponseDer = seqDerIn.getSequence(1);
31873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        singleResponseMap = new HashMap<>(singleResponseDer.length);
31973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (debug != null) {
32073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            debug.println("OCSP number of SingleResponses: "
32173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                          + singleResponseDer.length);
32273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
32373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (int i = 0; i < singleResponseDer.length; i++) {
32473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            SingleResponse singleResponse =
32573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                new SingleResponse(singleResponseDer[i]);
32673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            singleResponseMap.put(singleResponse.getCertId(), singleResponse);
32773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
32873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
32973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // responseExtensions
33073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        byte[] nonce = null;
33173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (seqDerIn.available() > 0) {
33273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            seq = seqDerIn.getDerValue();
33373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (seq.isContextSpecific((byte)1)) {
33473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                DerValue[] responseExtDer = seq.data.getSequence(3);
33573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (int i = 0; i < responseExtDer.length; i++) {
33673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    Extension ext = new Extension(responseExtDer[i]);
33773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (debug != null) {
33873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        debug.println("OCSP extension: " + ext);
33973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
34073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // Only the NONCE extension is recognized
34173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (ext.getExtensionId().equals((Object)
34273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        OCSP.NONCE_EXTENSION_OID))
34373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    {
34473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        nonce = ext.getExtensionValue();
34573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else if (ext.isCritical())  {
34673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        throw new IOException(
34773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            "Unsupported OCSP critical extension: " +
34873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            ext.getExtensionId());
34973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
35073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
35173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
35273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
35373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        responseNonce = nonce;
35473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
35573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // signatureAlgorithmId
35673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        sigAlgId = AlgorithmId.parse(seqTmp[1]);
35773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
35873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // signature
35973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        signature = seqTmp[2].getBitString();
36073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
36173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // if seq[3] is available , then it is a sequence of certificates
36273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (seqTmp.length > 3) {
36373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // certs are available
36473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            DerValue seqCert = seqTmp[3];
36573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (!seqCert.isContextSpecific((byte)0)) {
36673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new IOException("Bad encoding in certs element of " +
36773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "OCSP response: expected ASN.1 context specific tag 0.");
36873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
36973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            DerValue[] derCerts = seqCert.getData().getSequence(3);
37073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certs = new ArrayList<X509CertImpl>(derCerts.length);
37173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
37273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (int i = 0; i < derCerts.length; i++) {
37373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    X509CertImpl cert =
37473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        new X509CertImpl(derCerts[i].toByteArray());
37573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    certs.add(cert);
37673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
37773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (debug != null) {
37873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        debug.println("OCSP response cert #" + (i + 1) + ": " +
37973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            cert.getSubjectX500Principal());
38073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
38173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
38273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (CertificateException ce) {
38373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new IOException("Bad encoding in X509 Certificate", ce);
38473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
38573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
38673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certs = new ArrayList<X509CertImpl>();
38773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
38873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
38973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
39073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    void verify(List<CertId> certIds, X509Certificate issuerCert,
39173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                X509Certificate responderCert, Date date, byte[] nonce)
39273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws CertPathValidatorException
39373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    {
39473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        switch (responseStatus) {
39573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            case SUCCESSFUL:
39673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                break;
39773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            case TRY_LATER:
39873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            case INTERNAL_ERROR:
39973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
40073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "OCSP response error: " + responseStatus, null, null, -1,
40173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    BasicReason.UNDETERMINED_REVOCATION_STATUS);
40273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            case UNAUTHORIZED:
40373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            default:
40473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException("OCSP response error: " +
40573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                                     responseStatus);
40673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
40773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
40873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Check that the response includes a response for all of the
40973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // certs that were supplied in the request
41073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (CertId certId : certIds) {
41173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            SingleResponse sr = getSingleResponse(certId);
41273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (sr == null) {
41373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
41473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("No response found for CertId: " + certId);
41573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
41673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
41773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "OCSP response does not include a response for a " +
41873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "certificate supplied in the OCSP request");
41973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
42073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
42173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                debug.println("Status of certificate (with serial number " +
42273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    certId.getSerialNumber() + ") is: " + sr.getCertStatus());
42373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
42473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
42573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
42673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Locate the signer cert
42773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (signerCert == null) {
42873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Add the Issuing CA cert and/or Trusted Responder cert to the list
42973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // of certs from the OCSP response
43073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            try {
43173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                certs.add(X509CertImpl.toImpl(issuerCert));
43273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (responderCert != null) {
43373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    certs.add(X509CertImpl.toImpl(responderCert));
43473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
43573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } catch (CertificateException ce) {
43673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
43773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "Invalid issuer or trusted responder certificate", ce);
43873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
43973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
44073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (responderName != null) {
44173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (X509CertImpl cert : certs) {
44273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (cert.getSubjectX500Principal().equals(responderName)) {
44373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        signerCert = cert;
44473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        break;
44573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
44673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
44773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (responderKeyId != null) {
44873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                for (X509CertImpl cert : certs) {
44973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // Match responder's key identifier against the cert's SKID
45073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // This will match if the SKID is encoded using the 160-bit
45173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // SHA-1 hash method as defined in RFC 5280.
45273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    KeyIdentifier certKeyId = cert.getSubjectKeyId();
45373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (certKeyId != null && responderKeyId.equals(certKeyId)) {
45473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        signerCert = cert;
45573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        break;
45673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else {
45773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // The certificate does not have a SKID or may have
45873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // been using a different algorithm (ex: see RFC 7093).
45973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // Check if the responder's key identifier matches
46073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // against a newly generated key identifier of the
46173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // cert's public key using the 160-bit SHA-1 method.
46273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        try {
46373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            certKeyId = new KeyIdentifier(cert.getPublicKey());
46473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        } catch (IOException e) {
46573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            // ignore
46673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
46773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (responderKeyId.equals(certKeyId)) {
46873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            signerCert = cert;
46973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            break;
47073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
47173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
47273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
47373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
47473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
47573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
47673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Check whether the signer cert returned by the responder is trusted
47773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (signerCert != null) {
47873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Check if the response is signed by the issuing CA
47973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (signerCert.equals(issuerCert)) {
48073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
48173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("OCSP response is signed by the target's " +
48273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "Issuing CA");
48373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
48473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // cert is trusted, now verify the signed response
48573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
48673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Check if the response is signed by a trusted responder
48773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (signerCert.equals(responderCert)) {
48873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
48973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("OCSP response is signed by a Trusted " +
49073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "Responder");
49173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
49273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // cert is trusted, now verify the signed response
49373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
49473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Check if the response is signed by an authorized responder
49573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else if (signerCert.getIssuerX500Principal().equals(
49673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                       issuerCert.getSubjectX500Principal())) {
49773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
49873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // Check for the OCSPSigning key purpose
49973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
50073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    List<String> keyPurposes = signerCert.getExtendedKeyUsage();
50173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (keyPurposes == null ||
50273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        !keyPurposes.contains(KP_OCSP_SIGNING_OID)) {
50373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        throw new CertPathValidatorException(
50473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            "Responder's certificate not valid for signing " +
50573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            "OCSP responses");
50673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
50773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (CertificateParsingException cpe) {
50873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // assume cert is not valid for signing
50973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw new CertPathValidatorException(
51073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "Responder's certificate not valid for signing " +
51173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "OCSP responses", cpe);
51273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
51373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
51473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // Check algorithm constraints specified in security property
51573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // "jdk.certpath.disabledAlgorithms".
51673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                AlgorithmChecker algChecker = new AlgorithmChecker(
51773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                    new TrustAnchor(issuerCert, null));
51873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                algChecker.init(false);
51973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                algChecker.check(signerCert, Collections.<String>emptySet());
52073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
52173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // check the validity
52273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
52373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (date == null) {
52473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        signerCert.checkValidity();
52573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else {
52673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        signerCert.checkValidity(date);
52773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
52873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (CertificateException e) {
52973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw new CertPathValidatorException(
53073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "Responder's certificate not within the " +
53173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "validity period", e);
53273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
53373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
53473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // check for revocation
53573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                //
53673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // A CA may specify that an OCSP client can trust a
53773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // responder for the lifetime of the responder's
53873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // certificate. The CA does so by including the
53973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // extension id-pkix-ocsp-nocheck.
54073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                //
54173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                Extension noCheck =
54273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    signerCert.getExtension(PKIXExtensions.OCSPNoCheck_Id);
54373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (noCheck != null) {
54473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (debug != null) {
54573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        debug.println("Responder's certificate includes " +
54673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            "the extension id-pkix-ocsp-nocheck.");
54773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
54873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
54973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // we should do the revocation checking of the
55073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // authorized responder in a future update.
55173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
55273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
55373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // verify the signature
55473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                try {
55573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    signerCert.verify(issuerCert.getPublicKey());
55673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (debug != null) {
55773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        debug.println("OCSP response is signed by an " +
55873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            "Authorized Responder");
55973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
56073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // cert is trusted, now verify the signed response
56173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
56273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } catch (GeneralSecurityException e) {
56373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    signerCert = null;
56473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
56573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
56673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
56773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "Responder's certificate is not authorized to sign " +
56873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "OCSP responses");
56973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
57073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
57173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
57273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // Confirm that the signed response was generated using the public
57373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        // key from the trusted responder cert
57473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (signerCert != null) {
57573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Check algorithm constraints specified in security property
57673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // "jdk.certpath.disabledAlgorithms".
57773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            AlgorithmChecker.check(signerCert.getPublicKey(), sigAlgId);
57873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
57973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (!verifySignature(signerCert)) {
58073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
58173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    "Error verifying OCSP Response's signature");
58273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
58373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } else {
58473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // Need responder's cert in order to verify the signature
58573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException(
58673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                "Unable to verify OCSP Response's signature");
58773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
58873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
58973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        if (nonce != null) {
59073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (responseNonce != null && !Arrays.equals(nonce, responseNonce)) {
59173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException("Nonces don't match");
59273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
59373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
59473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
5957fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak        // Check freshness of OCSPResponse
5967fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak
59773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        long now = (date == null) ? System.currentTimeMillis() : date.getTime();
59873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Date nowPlusSkew = new Date(now + MAX_CLOCK_SKEW);
59973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        Date nowMinusSkew = new Date(now - MAX_CLOCK_SKEW);
60073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        for (SingleResponse sr : singleResponseMap.values()) {
60173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (debug != null) {
60273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                String until = "";
60373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (sr.nextUpdate != null) {
60473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    until = " until " + sr.nextUpdate;
60573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
6067fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                debug.println("OCSP response validity interval is from " +
6077fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                               sr.thisUpdate + until);
6087fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                debug.println("Checking validity of OCSP response on: " +
6097fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                    new Date(now));
61073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
61173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
6127fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak            // Check that the test date is within the validity interval:
6137fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak            //   [ thisUpdate - MAX_CLOCK_SKEW,
6147fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak            //     MAX(thisUpdate, nextUpdate) + MAX_CLOCK_SKEW ]
6157fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak            if (nowPlusSkew.before(sr.thisUpdate) ||
6167fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                nowMinusSkew.after(
6177fab06bfb1adf7956aaa28375da1cd0935a2d26bPrzemyslaw Szczepaniak                    sr.nextUpdate != null ? sr.nextUpdate : sr.thisUpdate))
61873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            {
61973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new CertPathValidatorException(
62073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                      "Response is unreliable: its validity " +
62173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                      "interval is out-of-date");
62273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
62373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
62473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
62573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
62673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
62773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns the OCSP ResponseStatus.
62873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
62973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    ResponseStatus getResponseStatus() {
63073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return responseStatus;
63173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
63273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
63373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /*
63473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Verify the signature of the OCSP response.
63573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
63673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    private boolean verifySignature(X509Certificate cert)
63773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        throws CertPathValidatorException {
63873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
63973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        try {
64073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            Signature respSignature = Signature.getInstance(sigAlgId.getName());
64173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            respSignature.initVerify(cert.getPublicKey());
64273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            respSignature.update(tbsResponseData);
64373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
64473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (respSignature.verify(signature)) {
64573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
64673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("Verified signature of OCSP Response");
64773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
64873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return true;
64973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
65073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
65173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
65273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println(
65373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        "Error verifying signature of OCSP Response");
65473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
65573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                return false;
65673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
65773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        } catch (InvalidKeyException | NoSuchAlgorithmException |
65873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                 SignatureException e)
65973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        {
66073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            throw new CertPathValidatorException(e);
66173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
66273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
66373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
66473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /**
66573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns the SingleResponse of the specified CertId, or null if
66673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * there is no response for that CertId.
66773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
66873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    SingleResponse getSingleResponse(CertId certId) {
66973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return singleResponseMap.get(certId);
67073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
67173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
67273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /*
67373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * Returns the certificate for the authority that signed the OCSP response.
67473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
67573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    X509Certificate getSignerCertificate() {
67673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        return signerCert; // set in verify()
67773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
67873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
67973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    /*
68073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     * A class representing a single OCSP response.
68173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root     */
68273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    final static class SingleResponse implements OCSP.RevocationStatus {
68373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final CertId certId;
68473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final CertStatus certStatus;
68573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final Date thisUpdate;
68673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final Date nextUpdate;
68773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final Date revocationTime;
68873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final CRLReason revocationReason;
68973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private final Map<String, java.security.cert.Extension> singleExtensions;
69073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
69173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private SingleResponse(DerValue der) throws IOException {
69273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (der.tag != DerValue.tag_Sequence) {
69373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                throw new IOException("Bad ASN.1 encoding in SingleResponse");
69473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
69573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            DerInputStream tmp = der.data;
69673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
69773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            certId = new CertId(tmp.getDerValue().data);
69873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            DerValue derVal = tmp.getDerValue();
69973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            short tag = (byte)(derVal.tag & 0x1f);
70073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (tag ==  CERT_STATUS_REVOKED) {
70173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                certStatus = CertStatus.REVOKED;
70273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                revocationTime = derVal.data.getGeneralizedTime();
70373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (derVal.data.available() != 0) {
70473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    DerValue dv = derVal.data.getDerValue();
70573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    tag = (byte)(dv.tag & 0x1f);
70673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (tag == 0) {
70773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        int reason = dv.data.getEnumerated();
70873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // if reason out-of-range just leave as UNSPECIFIED
70973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (reason >= 0 && reason < values.length) {
71073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            revocationReason = values[reason];
71173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        } else {
71273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            revocationReason = CRLReason.UNSPECIFIED;
71373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
71473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else {
71573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        revocationReason = CRLReason.UNSPECIFIED;
71673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
71773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
71873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    revocationReason = CRLReason.UNSPECIFIED;
71973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
72073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // RevokedInfo
72173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (debug != null) {
72273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("Revocation time: " + revocationTime);
72373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    debug.println("Revocation reason: " + revocationReason);
72473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
72573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
72673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                revocationTime = null;
72773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                revocationReason = CRLReason.UNSPECIFIED;
72873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (tag == CERT_STATUS_GOOD) {
72973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    certStatus = CertStatus.GOOD;
73073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else if (tag == CERT_STATUS_UNKNOWN) {
73173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    certStatus = CertStatus.UNKNOWN;
73273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
73373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    throw new IOException("Invalid certificate status");
73473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
73573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
73673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
73773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            thisUpdate = tmp.getGeneralizedTime();
73873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
73973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (tmp.available() == 0)  {
74073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                // we are done
74173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                nextUpdate = null;
74273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
74373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                derVal = tmp.getDerValue();
74473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                tag = (byte)(derVal.tag & 0x1f);
74573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (tag == 0) {
74673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    // next update
74773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    nextUpdate = derVal.data.getGeneralizedTime();
74873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
74973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    if (tmp.available() == 0)  {
75073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // we are done
75173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    } else {
75273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        derVal = tmp.getDerValue();
75373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        tag = (byte)(derVal.tag & 0x1f);
75473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
75573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
75673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    nextUpdate = null;
75773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
75873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
75973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            // singleExtensions
76073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (tmp.available() > 0) {
76173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                derVal = tmp.getDerValue();
76273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                if (derVal.isContextSpecific((byte)1)) {
76373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    DerValue[] singleExtDer = derVal.data.getSequence(3);
76473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    singleExtensions =
76573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        new HashMap<String, java.security.cert.Extension>
76673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            (singleExtDer.length);
76773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    for (int i = 0; i < singleExtDer.length; i++) {
76873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        Extension ext = new Extension(singleExtDer[i]);
76973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (debug != null) {
77073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            debug.println("OCSP single extension: " + ext);
77173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
77273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // We don't support any extensions yet. Therefore, if it
77373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // is critical we must throw an exception because we
77473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        // don't know how to process it.
77573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        if (ext.isCritical()) {
77673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                            throw new IOException(
77773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                "Unsupported OCSP critical extension: " +
77873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                                ext.getExtensionId());
77973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        }
78073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                        singleExtensions.put(ext.getId(), ext);
78173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    }
78273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                } else {
78373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                    singleExtensions = Collections.emptyMap();
78473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                }
78573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            } else {
78673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                singleExtensions = Collections.emptyMap();
78773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
78873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
78973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
79073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /*
79173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Return the certificate's revocation status code
79273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
79373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public CertStatus getCertStatus() {
79473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return certStatus;
79573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
79673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
79773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        private CertId getCertId() {
79873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return certId;
79973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
80073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
80173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public Date getRevocationTime() {
80273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return (Date) revocationTime.clone();
80373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
80473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
80573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public CRLReason getRevocationReason() {
80673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return revocationReason;
80773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
80873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
80973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override
81073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        public Map<String, java.security.cert.Extension> getSingleExtensions() {
81173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return Collections.unmodifiableMap(singleExtensions);
81273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
81373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root
81473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        /**
81573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         * Construct a string representation of a single OCSP response.
81673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root         */
81773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        @Override public String toString() {
81873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            StringBuilder sb = new StringBuilder();
81973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            sb.append("SingleResponse:  \n");
82073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            sb.append(certId);
82173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            sb.append("\nCertStatus: "+ certStatus + "\n");
82273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (certStatus == CertStatus.REVOKED) {
82373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                sb.append("revocationTime is " + revocationTime + "\n");
82473405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                sb.append("revocationReason is " + revocationReason + "\n");
82573405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
82673405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            sb.append("thisUpdate is " + thisUpdate + "\n");
82773405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            if (nextUpdate != null) {
82873405ff8729cca39da90b2e2f604062e323f6f7aKenny Root                sb.append("nextUpdate is " + nextUpdate + "\n");
82973405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            }
83073405ff8729cca39da90b2e2f604062e323f6f7aKenny Root            return sb.toString();
83173405ff8729cca39da90b2e2f604062e323f6f7aKenny Root        }
83273405ff8729cca39da90b2e2f604062e323f6f7aKenny Root    }
83373405ff8729cca39da90b2e2f604062e323f6f7aKenny Root}
834