Path: blob/master/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java
41159 views
/*1* Copyright (c) 2020, 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.security.cert.X509Certificate;30import java.text.MessageFormat;31import java.util.*;32import javax.net.ssl.SSLProtocolException;33import javax.security.auth.x500.X500Principal;34import sun.security.ssl.SSLExtension.ExtensionConsumer;35import sun.security.ssl.SSLExtension.SSLExtensionSpec;36import sun.security.ssl.SSLHandshake.HandshakeMessage;3738/**39* Pack of the "certificate_authorities" extensions.40*/41final class CertificateAuthoritiesExtension {42static final HandshakeProducer chNetworkProducer =43new CHCertificateAuthoritiesProducer();44static final ExtensionConsumer chOnLoadConsumer =45new CHCertificateAuthoritiesConsumer();4647static final HandshakeProducer crNetworkProducer =48new CRCertificateAuthoritiesProducer();49static final ExtensionConsumer crOnLoadConsumer =50new CRCertificateAuthoritiesConsumer();5152static final SSLStringizer ssStringizer =53new CertificateAuthoritiesStringizer();5455/**56* The "certificate_authorities" extension.57*/58static final class CertificateAuthoritiesSpec implements SSLExtensionSpec {59final List<byte[]> authorities; // certificate authorities6061private CertificateAuthoritiesSpec(List<byte[]> authorities) {62this.authorities = authorities;63}6465private CertificateAuthoritiesSpec(HandshakeContext hc,66ByteBuffer m) throws IOException {67if (m.remaining() < 3) { // 2: the length of the list68// 1: at least one byte authorities69throw hc.conContext.fatal(Alert.DECODE_ERROR,70new SSLProtocolException(71"Invalid certificate_authorities extension: " +72"insufficient data"));73}7475int listLen = Record.getInt16(m);76if (listLen == 0) {77throw hc.conContext.fatal(Alert.DECODE_ERROR,78"Invalid certificate_authorities extension: " +79"no certificate authorities");80}8182if (listLen > m.remaining()) {83throw hc.conContext.fatal(Alert.DECODE_ERROR,84"Invalid certificate_authorities extension: " +85"insufficient data");86}8788this.authorities = new LinkedList<>();89while (listLen > 0) {90// opaque DistinguishedName<1..2^16-1>;91byte[] encoded = Record.getBytes16(m);92listLen -= (2 + encoded.length);93authorities.add(encoded);94}95}9697private static List<byte[]> getEncodedAuthorities(98X509Certificate[] trustedCerts) {99List<byte[]> authorities = new ArrayList<>(trustedCerts.length);100int sizeAccount = 0;101for (X509Certificate cert : trustedCerts) {102X500Principal x500Principal = cert.getSubjectX500Principal();103byte[] encodedPrincipal = x500Principal.getEncoded();104sizeAccount += encodedPrincipal.length;105if (sizeAccount > 0xFFFF) { // the size limit of this extension106// If there too many trusts CAs such that they exceed the107// size limit of the extension, enabling this extension108// does not really make sense as there is no way to109// indicate the peer certificate selection accurately.110// In such cases, the extension is just ignored, rather111// than fatal close, for better compatibility and112// interoperability.113return Collections.emptyList();114}115116if (encodedPrincipal.length != 0) {117authorities.add(encodedPrincipal);118}119}120121return authorities;122}123124X500Principal[] getAuthorities() {125X500Principal[] principals = new X500Principal[authorities.size()];126int i = 0;127for (byte[] encoded : authorities) {128principals[i++] = new X500Principal(encoded);129}130131return principals;132}133134@Override135public String toString() {136MessageFormat messageFormat = new MessageFormat(137"\"certificate authorities\": '['\n{0}']'", Locale.ENGLISH);138StringBuilder builder = new StringBuilder(512);139for (byte[] encoded : authorities) {140X500Principal principal = new X500Principal(encoded);141builder.append(principal.toString());142builder.append("\n");143}144Object[] messageFields = {145Utilities.indent(builder.toString())146};147148return messageFormat.format(messageFields);149}150}151152private static final153class CertificateAuthoritiesStringizer implements SSLStringizer {154@Override155public String toString(HandshakeContext hc, ByteBuffer buffer) {156try {157return (new CertificateAuthoritiesSpec(hc, buffer))158.toString();159} catch (IOException ioe) {160// For debug logging only, so please swallow exceptions.161return ioe.getMessage();162}163}164}165166/**167* Network data producer of a "certificate_authorities" extension in168* the ClientHello handshake message.169*/170private static final171class CHCertificateAuthoritiesProducer implements HandshakeProducer {172173// Prevent instantiation of this class.174private CHCertificateAuthoritiesProducer() {175// blank176}177178@Override179public byte[] produce(ConnectionContext context,180HandshakeMessage message) throws IOException {181// The producing happens in client side only.182ClientHandshakeContext chc = (ClientHandshakeContext)context;183184// Is it a supported and enabled extension?185if (!chc.sslConfig.isAvailable(186SSLExtension.CH_CERTIFICATE_AUTHORITIES)) {187if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {188SSLLogger.fine(189"Ignore unavailable " +190"certificate_authorities extension");191}192193return null; // ignore the extension194}195196// Produce the extension.197X509Certificate[] caCerts =198chc.sslContext.getX509TrustManager().getAcceptedIssuers();199if (caCerts.length == 0) {200if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {201SSLLogger.fine(202"No available certificate authorities");203}204205return null; // ignore the extension206}207208List<byte[]> encodedCAs =209CertificateAuthoritiesSpec.getEncodedAuthorities(caCerts);210if (encodedCAs.isEmpty()) {211if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {212SSLLogger.warning(213"The number of CAs exceeds the maximum size" +214"of the certificate_authorities extension");215}216217return null; // ignore the extension218}219220CertificateAuthoritiesSpec spec =221new CertificateAuthoritiesSpec(encodedCAs);222223int vectorLen = 0;224for (byte[] encoded : spec.authorities) {225vectorLen += encoded.length + 2;226}227228byte[] extData = new byte[vectorLen + 2];229ByteBuffer m = ByteBuffer.wrap(extData);230Record.putInt16(m, vectorLen);231for (byte[] encoded : spec.authorities) {232Record.putBytes16(m, encoded);233}234235// Update the context.236chc.handshakeExtensions.put(237SSLExtension.CH_CERTIFICATE_AUTHORITIES, spec);238239return extData;240}241}242243/**244* Network data consumer of a "certificate_authorities" extension in245* the ClientHello handshake message.246*/247private static final248class CHCertificateAuthoritiesConsumer implements ExtensionConsumer {249250// Prevent instantiation of this class.251private CHCertificateAuthoritiesConsumer() {252// blank253}254255@Override256public void consume(ConnectionContext context,257HandshakeMessage message, ByteBuffer buffer) throws IOException {258259// The consuming happens in server side only.260ServerHandshakeContext shc = (ServerHandshakeContext)context;261262// Is it a supported and enabled extension?263if (!shc.sslConfig.isAvailable(264SSLExtension.CH_CERTIFICATE_AUTHORITIES)) {265if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {266SSLLogger.fine(267"Ignore unavailable " +268"certificate_authorities extension");269}270271return; // ignore the extension272}273274// Parse the extension.275CertificateAuthoritiesSpec spec =276new CertificateAuthoritiesSpec(shc, buffer);277278// Update the context.279shc.peerSupportedAuthorities = spec.getAuthorities();280shc.handshakeExtensions.put(281SSLExtension.CH_CERTIFICATE_AUTHORITIES, spec);282283// No impact on session resumption.284}285}286287/**288* Network data producer of a "certificate_authorities" extension in289* the CertificateRequest handshake message.290*/291private static final292class CRCertificateAuthoritiesProducer implements HandshakeProducer {293294// Prevent instantiation of this class.295private CRCertificateAuthoritiesProducer() {296// blank297}298299@Override300public byte[] produce(ConnectionContext context,301HandshakeMessage message) throws IOException {302// The producing happens in server side only.303ServerHandshakeContext shc = (ServerHandshakeContext)context;304305// Is it a supported and enabled extension?306if (!shc.sslConfig.isAvailable(307SSLExtension.CR_CERTIFICATE_AUTHORITIES)) {308if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {309SSLLogger.fine(310"Ignore unavailable " +311"certificate_authorities extension");312}313314return null; // ignore the extension315}316317// Produce the extension.318X509Certificate[] caCerts =319shc.sslContext.getX509TrustManager().getAcceptedIssuers();320if (caCerts.length == 0) {321if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {322SSLLogger.fine(323"No available certificate authorities");324}325326return null; // ignore the extension327}328329List<byte[]> encodedCAs =330CertificateAuthoritiesSpec.getEncodedAuthorities(caCerts);331if (encodedCAs.isEmpty()) {332if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {333SSLLogger.warning(334"Too many certificate authorities to use " +335"the certificate_authorities extension");336}337338return null; // ignore the extension339}340341CertificateAuthoritiesSpec spec =342new CertificateAuthoritiesSpec(encodedCAs);343344int vectorLen = 0;345for (byte[] encoded : spec.authorities) {346vectorLen += encoded.length + 2;347}348349byte[] extData = new byte[vectorLen + 2];350ByteBuffer m = ByteBuffer.wrap(extData);351Record.putInt16(m, vectorLen);352for (byte[] encoded : spec.authorities) {353Record.putBytes16(m, encoded);354}355356// Update the context.357shc.handshakeExtensions.put(358SSLExtension.CR_CERTIFICATE_AUTHORITIES, spec);359360return extData;361}362}363364/**365* Network data consumer of a "certificate_authorities" extension in366* the CertificateRequest handshake message.367*/368private static final369class CRCertificateAuthoritiesConsumer implements ExtensionConsumer {370371// Prevent instantiation of this class.372private CRCertificateAuthoritiesConsumer() {373// blank374}375376@Override377public void consume(ConnectionContext context,378HandshakeMessage message, ByteBuffer buffer) throws IOException {379380// The consuming happens in client side only.381ClientHandshakeContext chc = (ClientHandshakeContext)context;382383// Is it a supported and enabled extension?384if (!chc.sslConfig.isAvailable(385SSLExtension.CR_CERTIFICATE_AUTHORITIES)) {386if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {387SSLLogger.fine(388"Ignore unavailable " +389"certificate_authorities extension");390}391392return; // ignore the extension393}394395// Parse the extension.396CertificateAuthoritiesSpec spec =397new CertificateAuthoritiesSpec(chc, buffer);398399// Update the context.400chc.peerSupportedAuthorities = spec.getAuthorities();401chc.handshakeExtensions.put(402SSLExtension.CR_CERTIFICATE_AUTHORITIES, spec);403404// No impact on session resumption.405}406}407}408409410