Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ssl/CertificateStatus.java
38830 views
/*1* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.ssl;2627import java.io.IOException;28import java.nio.ByteBuffer;29import java.text.MessageFormat;30import java.util.List;31import java.util.ArrayList;32import java.util.Locale;33import javax.net.ssl.SSLHandshakeException;34import java.security.cert.X509Certificate;35import sun.security.provider.certpath.OCSPResponse;36import sun.security.ssl.SSLHandshake.HandshakeMessage;37import static sun.security.ssl.CertStatusExtension.*;38import static sun.security.ssl.CertificateMessage.*;3940/**41* Consumers and producers for the CertificateStatus handshake message.42* This message takes one of two related but slightly different forms,43* depending on the type of stapling selected by the server. The message44* data will be of the form(s):45*46* [status_request, RFC 6066]47*48* struct {49* CertificateStatusType status_type;50* select (status_type) {51* case ocsp: OCSPResponse;52* } response;53* } CertificateStatus;54*55* opaque OCSPResponse<1..2^24-1>;56*57* [status_request_v2, RFC 6961]58*59* struct {60* CertificateStatusType status_type;61* select (status_type) {62* case ocsp: OCSPResponse;63* case ocsp_multi: OCSPResponseList;64* } response;65* } CertificateStatus;66*67* opaque OCSPResponse<0..2^24-1>;68*69* struct {70* OCSPResponse ocsp_response_list<1..2^24-1>;71* } OCSPResponseList;72*/73final class CertificateStatus {74static final SSLConsumer handshakeConsumer =75new CertificateStatusConsumer();76static final HandshakeProducer handshakeProducer =77new CertificateStatusProducer();78static final HandshakeAbsence handshakeAbsence =79new CertificateStatusAbsence();8081/**82* The CertificateStatus handshake message.83*/84static final class CertificateStatusMessage extends HandshakeMessage {8586final CertStatusRequestType statusType;87int encodedResponsesLen = 0;88int messageLength = -1;89final List<byte[]> encodedResponses = new ArrayList<>();9091CertificateStatusMessage(HandshakeContext handshakeContext) {92super(handshakeContext);9394ServerHandshakeContext shc =95(ServerHandshakeContext)handshakeContext;9697// Get the Certificates from the SSLContextImpl amd the Stapling98// parameters99StatusResponseManager.StaplingParameters stapleParams =100shc.stapleParams;101if (stapleParams == null) {102throw new IllegalArgumentException(103"Unexpected null stapling parameters");104}105106X509Certificate[] certChain =107(X509Certificate[])shc.handshakeSession.getLocalCertificates();108if (certChain == null) {109throw new IllegalArgumentException(110"Unexpected null certificate chain");111}112113// Walk the certificate list and add the correct encoded responses114// to the encoded responses list115statusType = stapleParams.statReqType;116if (statusType == CertStatusRequestType.OCSP) {117// Just worry about the first cert in the chain118byte[] resp = stapleParams.responseMap.get(certChain[0]);119if (resp == null) {120// A not-found return status means we should include121// a zero-length response in CertificateStatus.122// This is highly unlikely to happen in practice.123resp = new byte[0];124}125encodedResponses.add(resp);126encodedResponsesLen += resp.length + 3;127} else if (statusType == CertStatusRequestType.OCSP_MULTI) {128for (X509Certificate cert : certChain) {129byte[] resp = stapleParams.responseMap.get(cert);130if (resp == null) {131resp = new byte[0];132}133encodedResponses.add(resp);134encodedResponsesLen += resp.length + 3;135}136} else {137throw new IllegalArgumentException(138"Unsupported StatusResponseType: " + statusType);139}140141messageLength = messageLength();142}143144CertificateStatusMessage(HandshakeContext handshakeContext,145ByteBuffer m) throws IOException {146super(handshakeContext);147148statusType = CertStatusRequestType.valueOf((byte)Record.getInt8(m));149if (statusType == CertStatusRequestType.OCSP) {150byte[] respDER = Record.getBytes24(m);151// Convert the incoming bytes to a OCSPResponse strucutre152if (respDER.length > 0) {153encodedResponses.add(respDER);154encodedResponsesLen = 3 + respDER.length;155} else {156throw handshakeContext.conContext.fatal(157Alert.HANDSHAKE_FAILURE,158"Zero-length OCSP Response");159}160} else if (statusType == CertStatusRequestType.OCSP_MULTI) {161int respListLen = Record.getInt24(m);162encodedResponsesLen = respListLen;163164// Add each OCSP reponse into the array list in the order165// we receive them off the wire. A zero-length array is166// allowed for ocsp_multi, and means that a response for167// a given certificate is not available.168while (respListLen > 0) {169byte[] respDER = Record.getBytes24(m);170encodedResponses.add(respDER);171respListLen -= (respDER.length + 3);172}173174if (respListLen != 0) {175throw handshakeContext.conContext.fatal(176Alert.INTERNAL_ERROR,177"Bad OCSP response list length");178}179} else {180throw handshakeContext.conContext.fatal(181Alert.HANDSHAKE_FAILURE,182"Unsupported StatusResponseType: " + statusType);183}184messageLength = messageLength();185}186187@Override188public SSLHandshake handshakeType() {189return SSLHandshake.CERTIFICATE_STATUS;190}191192@Override193public int messageLength() {194int len = 1;195196if (messageLength == -1) {197if (statusType == CertStatusRequestType.OCSP) {198len += encodedResponsesLen;199} else if (statusType == CertStatusRequestType.OCSP_MULTI) {200len += 3 + encodedResponsesLen;201}202messageLength = len;203}204205return messageLength;206}207208@Override209public void send(HandshakeOutStream s) throws IOException {210s.putInt8(statusType.id);211if (statusType == CertStatusRequestType.OCSP) {212s.putBytes24(encodedResponses.get(0));213} else if (statusType == CertStatusRequestType.OCSP_MULTI) {214s.putInt24(encodedResponsesLen);215for (byte[] respBytes : encodedResponses) {216if (respBytes != null) {217s.putBytes24(respBytes);218} else {219s.putBytes24(null);220}221}222} else {223// It is highly unlikely that we will fall into this section224// of the code.225throw new SSLHandshakeException("Unsupported status_type: " +226statusType.id);227}228}229230@Override231public String toString() {232StringBuilder sb = new StringBuilder();233234// Stringify the encoded OCSP response list235for (byte[] respDER : encodedResponses) {236if (respDER.length > 0) {237try {238OCSPResponse oResp = new OCSPResponse(respDER);239sb.append(oResp.toString()).append("\n");240} catch (IOException ioe) {241sb.append("OCSP Response Exception: ").append(ioe)242.append("\n");243}244} else {245sb.append("<Zero-length entry>\n");246}247}248249MessageFormat messageFormat = new MessageFormat(250"\"CertificateStatus\": '{'\n" +251" \"type\" : \"{0}\",\n" +252" \"responses \" : [\n" + "{1}\n" + " ]\n" +253"'}'",254Locale.ENGLISH);255Object[] messageFields = {256statusType.name,257Utilities.indent(Utilities.indent(sb.toString()))258};259260return messageFormat.format(messageFields);261}262}263264/**265* The CertificateStatus handshake message consumer.266*/267private static final class CertificateStatusConsumer268implements SSLConsumer {269// Prevent instantiation of this class.270private CertificateStatusConsumer() {271// blank272}273274@Override275public void consume(ConnectionContext context,276ByteBuffer message) throws IOException {277ClientHandshakeContext chc = (ClientHandshakeContext)context;278CertificateStatusMessage cst =279new CertificateStatusMessage(chc, message);280281// Log the message282if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {283SSLLogger.fine(284"Consuming server CertificateStatus handshake message",285cst);286}287288// Pin the received responses to the SSLSessionImpl. It will289// be retrieved by the X509TrustManagerImpl during the certificate290// checking phase.291chc.handshakeSession.setStatusResponses(cst.encodedResponses);292293// Now perform the check294T12CertificateConsumer.checkServerCerts(chc, chc.deferredCerts);295296// Update the handshake consumers to remove this message, indicating297// that it has been processed.298chc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE_STATUS.id);299}300}301302/**303* The CertificateStatus handshake message consumer.304*/305private static final class CertificateStatusProducer306implements HandshakeProducer {307// Prevent instantiation of this class.308private CertificateStatusProducer() {309// blank310}311312@Override313public byte[] produce(ConnectionContext context,314HandshakeMessage message) throws IOException {315// Only the server-side should be a producer of this message316ServerHandshakeContext shc = (ServerHandshakeContext)context;317318// If stapling is not active, immediately return without producing319// a message or any further processing.320if (!shc.staplingActive) {321return null;322}323324// Create the CertificateStatus message from info in the325CertificateStatusMessage csm = new CertificateStatusMessage(shc);326if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {327SSLLogger.fine(328"Produced server CertificateStatus handshake message", csm);329}330331// Output the handshake message.332csm.write(shc.handshakeOutput);333shc.handshakeOutput.flush();334335// The handshake message has been delivered.336return null;337}338}339340private static final class CertificateStatusAbsence341implements HandshakeAbsence {342// Prevent instantiation of this class343private CertificateStatusAbsence() {344// blank345}346347@Override348public void absent(ConnectionContext context,349HandshakeMessage message) throws IOException {350ClientHandshakeContext chc = (ClientHandshakeContext)context;351352// Processing should only continue if stapling is active353if (chc.staplingActive) {354// Because OCSP stapling is active, it means two things355// if we're here: 1) The server hello asserted the356// status_request[_v2] extension. 2) The CertificateStatus357// message was not sent. This means that cert path checking358// was deferred, but must happen immediately.359if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {360SSLLogger.fine("Server did not send CertificateStatus, " +361"checking cert chain without status info.");362}363T12CertificateConsumer.checkServerCerts(chc, chc.deferredCerts);364}365}366}367}368369370371