--- /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();
+ }
+}