--- /dev/null 2017-07-18 10:08:09.829212503 -0300 +++ new/src/java.base/share/classes/sun/security/ssl/CertificateAuthoritiesExtension.java 2017-07-18 14:02:00.222797128 -0300 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017, Red Hat, Inc. and/or its affiliates. + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ssl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLProtocolException; +import javax.net.ssl.CertificateAuthority; + +/** + * {@code CertificateAuthoritiesExtension} class represents the + * Certificate Authorities TLS extension (TLS 1.3), specified by + * TLS 1.3. + *

+ * Clients and servers may optionally use this extension to provide the + * other side information regarding its trusted certification authorities + * (either root or subordinate), as a hint for certificate selection. + * This decreases the probability of a handshake failure caused by an + * untrusted certificate chain. + * + * @see CertificateAuthority + * + * @author Martin Balao (mbalao@redhat.com) + */ + +final class CertificateAuthoritiesExtension extends HelloExtension { + + private final CertificateAuthority[] certificateAuthorities; + + private final int certificateAuthoritiesLength; // in bytes + + static CertificateAuthority[] parseCertificateAuthorities( + byte[] certificateAuthoritiesRawData) throws IOException { + final List parsedCertificateAuthorities = new ArrayList<>(); + int parsedCertificateAuthoritiesPtr = 0; + while (parsedCertificateAuthoritiesPtr < certificateAuthoritiesRawData.length) { + final int parsedCertificateAuthorityLength = + (certificateAuthoritiesRawData[parsedCertificateAuthoritiesPtr] << 8) + + certificateAuthoritiesRawData[parsedCertificateAuthoritiesPtr + 1]; + parsedCertificateAuthoritiesPtr += 2; // 2 bytes for length + final CertificateAuthorityImpl ca = + new CertificateAuthorityImpl(certificateAuthoritiesRawData, + parsedCertificateAuthoritiesPtr, parsedCertificateAuthorityLength); + parsedCertificateAuthoritiesPtr += parsedCertificateAuthorityLength; + parsedCertificateAuthorities.add(ca); + } + final CertificateAuthority[] parsedCertificateAuthoritiesArray = + new CertificateAuthority[parsedCertificateAuthorities.size()]; + return parsedCertificateAuthorities.toArray(parsedCertificateAuthoritiesArray); + } + + CertificateAuthoritiesExtension(HandshakeInStream s, int len) throws IOException { + super(ExtensionType.EXT_CERTIFICATE_AUTHORITIES); + + // check the extension length + if (len >= 2) { + certificateAuthoritiesLength = s.getInt16(); + if (certificateAuthoritiesLength != len - 2 || certificateAuthoritiesLength < 1) { + // Lengths must be consistent. + throw new SSLProtocolException("Malformed " + type + " extension"); + } + final byte[] certificateAuthoritiesRawData = new byte[certificateAuthoritiesLength]; + if (s.read(certificateAuthoritiesRawData, 0, + certificateAuthoritiesRawData.length) != certificateAuthoritiesRawData.length) { + throw new SSLProtocolException("Error when reading Certificate Authorities data"); + } + certificateAuthorities = parseCertificateAuthorities(certificateAuthoritiesRawData); + } else if (len == 0) { + certificateAuthoritiesLength = 0; + certificateAuthorities = null; + } else { + throw new SSLProtocolException("Malformed " + type + " extension"); + } + } + + CertificateAuthoritiesExtension(CertificateAuthority[] certificateAuthorities) { + super(ExtensionType.EXT_CERTIFICATE_AUTHORITIES); + this.certificateAuthorities = certificateAuthorities; + if (this.certificateAuthorities != null) { + int certificateAuthoritiesTotalLength = 0; + for (CertificateAuthority ca : this.certificateAuthorities) { + certificateAuthoritiesTotalLength += ca.getEncoded().length; + } + if (certificateAuthoritiesTotalLength + 2 > 0xFFFF) { + // extension_data has a ceiling of 2^16-1 bytes, and 2 bytes are + // reserved for authorities length + throw new IllegalArgumentException( + "Certificate Authorities data length cannot exceed (65535 - 2) bytes."); + } + certificateAuthoritiesLength = certificateAuthoritiesTotalLength; + } else { + certificateAuthoritiesLength = 0; + } + } + + @Override + int length() { + int baseLength = 2 + 2; // extension_type + extension_data length + if (certificateAuthoritiesLength == 0) { + return baseLength; + } + // baseLength + authorities length + Certificate Authorities + // data length + return baseLength + 2 + certificateAuthoritiesLength; + } + + @Override + void send(HandshakeOutStream s) throws IOException { + + // ExtensionType extension_type; + s.putInt16(type.id); + + // opaque extension_data<0..2^16-1>; + // extension_data is CertificateAuthoritiesExtension + // + if (certificateAuthoritiesLength > 0) { + + // extension_data length + // 2 bytes for authorities length + s.putInt16(certificateAuthoritiesLength + 2); + + // struct { + // DistinguishedName authorities<3..2^16-1>; + // } CertificateAuthoritiesExtension; + // + s.putInt16(certificateAuthoritiesLength); + + for (CertificateAuthority ca : certificateAuthorities) { + final byte[] caData = ca.getEncoded(); + s.write(caData, 0, caData.length); + } + } else { + s.putInt16(0); // extension_data length is 0 + } + } + + CertificateAuthority[] getCertificateAuthorities() { + return certificateAuthorities; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Extension " + type); + return sb.toString(); + } +}