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