Mercurial > hg > openjdk > jdk8u > jdk
changeset 14134:17ce8aaff4bd
8245467: Remove 8u TLSv1.2 implementation files
Reviewed-by: mbalao
author | abakhtin |
---|---|
date | Wed, 20 May 2020 17:28:12 +0300 |
parents | 84c5676f140b |
children | d0b56fcd1708 |
files | src/share/classes/sun/security/ssl/ALPNExtension.java src/share/classes/sun/security/ssl/Alerts.java src/share/classes/sun/security/ssl/AppInputStream.java src/share/classes/sun/security/ssl/AppOutputStream.java src/share/classes/sun/security/ssl/Authenticator.java src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java src/share/classes/sun/security/ssl/ByteBufferInputStream.java src/share/classes/sun/security/ssl/CipherBox.java src/share/classes/sun/security/ssl/CipherSuite.java src/share/classes/sun/security/ssl/CipherSuiteList.java src/share/classes/sun/security/ssl/ClientHandshaker.java src/share/classes/sun/security/ssl/DHClientKeyExchange.java src/share/classes/sun/security/ssl/DHCrypt.java src/share/classes/sun/security/ssl/Debug.java src/share/classes/sun/security/ssl/ECDHClientKeyExchange.java src/share/classes/sun/security/ssl/ECDHCrypt.java src/share/classes/sun/security/ssl/EllipticCurvesExtension.java src/share/classes/sun/security/ssl/EllipticPointFormatsExtension.java src/share/classes/sun/security/ssl/EngineArgs.java src/share/classes/sun/security/ssl/EngineInputRecord.java src/share/classes/sun/security/ssl/EngineOutputRecord.java src/share/classes/sun/security/ssl/EngineWriter.java src/share/classes/sun/security/ssl/EphemeralKeyManager.java src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java src/share/classes/sun/security/ssl/ExtensionType.java src/share/classes/sun/security/ssl/HandshakeHash.java src/share/classes/sun/security/ssl/HandshakeInStream.java src/share/classes/sun/security/ssl/HandshakeMessage.java src/share/classes/sun/security/ssl/HandshakeOutStream.java src/share/classes/sun/security/ssl/HandshakeStateManager.java src/share/classes/sun/security/ssl/Handshaker.java src/share/classes/sun/security/ssl/HelloExtension.java src/share/classes/sun/security/ssl/HelloExtensions.java src/share/classes/sun/security/ssl/InputRecord.java src/share/classes/sun/security/ssl/JsseJce.java src/share/classes/sun/security/ssl/KeyManagerFactoryImpl.java src/share/classes/sun/security/ssl/MAC.java src/share/classes/sun/security/ssl/OutputRecord.java src/share/classes/sun/security/ssl/ProtocolList.java src/share/classes/sun/security/ssl/ProtocolVersion.java src/share/classes/sun/security/ssl/RSAClientKeyExchange.java src/share/classes/sun/security/ssl/RSASignature.java src/share/classes/sun/security/ssl/RandomCookie.java src/share/classes/sun/security/ssl/Record.java src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java src/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java src/share/classes/sun/security/ssl/SSLContextImpl.java src/share/classes/sun/security/ssl/SSLEngineImpl.java src/share/classes/sun/security/ssl/SSLServerSocketFactoryImpl.java src/share/classes/sun/security/ssl/SSLServerSocketImpl.java src/share/classes/sun/security/ssl/SSLSessionContextImpl.java src/share/classes/sun/security/ssl/SSLSessionImpl.java src/share/classes/sun/security/ssl/SSLSocketFactoryImpl.java src/share/classes/sun/security/ssl/SSLSocketImpl.java src/share/classes/sun/security/ssl/ServerHandshaker.java src/share/classes/sun/security/ssl/ServerNameExtension.java src/share/classes/sun/security/ssl/SessionId.java src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java src/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java src/share/classes/sun/security/ssl/TrustStoreManager.java src/share/classes/sun/security/ssl/UnknownExtension.java src/share/classes/sun/security/ssl/Utilities.java src/share/classes/sun/security/ssl/X509KeyManagerImpl.java src/share/classes/sun/security/ssl/X509TrustManagerImpl.java |
diffstat | 67 files changed, 0 insertions(+), 32738 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/sun/security/ssl/ALPNExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.nio.charset.*; -import java.util.*; - -import javax.net.ssl.*; - -/* - * [RFC 7301] - * This TLS extension facilitates the negotiation of application-layer protocols - * within the TLS handshake. Clients MAY include an extension of type - * "application_layer_protocol_negotiation" in the (extended) ClientHello - * message. The "extension_data" field of this extension SHALL contain a - * "ProtocolNameList" value: - * - * enum { - * application_layer_protocol_negotiation(16), (65535) - * } ExtensionType; - * - * opaque ProtocolName<1..2^8-1>; - * - * struct { - * ProtocolName protocol_name_list<2..2^16-1> - * } ProtocolNameList; - */ -final class ALPNExtension extends HelloExtension { - - final static int ALPN_HEADER_LENGTH = 1; - final static int MAX_APPLICATION_PROTOCOL_LENGTH = 255; - final static int MAX_APPLICATION_PROTOCOL_LIST_LENGTH = 65535; - private int listLength = 0; // ProtocolNameList length - private List<String> protocolNames = null; - - // constructor for ServerHello - ALPNExtension(String protocolName) throws SSLException { - this(new String[]{ protocolName }); - } - - // constructor for ClientHello - ALPNExtension(String[] protocolNames) throws SSLException { - super(ExtensionType.EXT_ALPN); - if (protocolNames.length == 0) { // never null, never empty - throw new IllegalArgumentException( - "The list of application protocols cannot be empty"); - } - this.protocolNames = Arrays.asList(protocolNames); - for (String p : protocolNames) { - int length = p.getBytes(StandardCharsets.UTF_8).length; - if (length == 0) { - throw new SSLProtocolException( - "Application protocol name is empty"); - } - if (length <= MAX_APPLICATION_PROTOCOL_LENGTH) { - listLength += length + ALPN_HEADER_LENGTH; - } else { - throw new SSLProtocolException( - "Application protocol name is too long: " + p); - } - if (listLength > MAX_APPLICATION_PROTOCOL_LIST_LENGTH) { - throw new SSLProtocolException( - "Application protocol name list is too long"); - } - } - } - - // constructor for ServerHello for parsing ALPN extension - ALPNExtension(HandshakeInStream s, int len) throws IOException { - super(ExtensionType.EXT_ALPN); - - if (len >= 2) { - listLength = s.getInt16(); // list length - if (listLength < 2 || listLength + 2 != len) { - throw new SSLProtocolException( - "Invalid " + type + " extension: incorrect list length " + - "(length=" + listLength + ")"); - } - } else { - throw new SSLProtocolException( - "Invalid " + type + " extension: insufficient data " + - "(length=" + len + ")"); - } - - int remaining = listLength; - this.protocolNames = new ArrayList<>(); - while (remaining > 0) { - // opaque ProtocolName<1..2^8-1>; // RFC 7301 - byte[] bytes = s.getBytes8(); - if (bytes.length == 0) { - throw new SSLProtocolException("Invalid " + type + - " extension: empty application protocol name"); - } - String p = - new String(bytes, StandardCharsets.UTF_8); // app protocol - protocolNames.add(p); - remaining -= bytes.length + ALPN_HEADER_LENGTH; - } - - if (remaining != 0) { - throw new SSLProtocolException( - "Invalid " + type + " extension: extra data " + - "(length=" + remaining + ")"); - } - } - - List<String> getPeerAPs() { - return protocolNames; - } - - /* - * Return the length in bytes, including extension type and length fields. - */ - @Override - int length() { - return 6 + listLength; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(listLength + 2); // length of extension_data - s.putInt16(listLength); // length of ProtocolNameList - - for (String p : protocolNames) { - s.putBytes8(p.getBytes(StandardCharsets.UTF_8)); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (protocolNames == null || protocolNames.isEmpty()) { - sb.append("<empty>"); - } else { - for (String protocolName : protocolNames) { - sb.append("[" + protocolName + "]"); - } - } - - return "Extension " + type + - ", protocol names: " + sb; - } -}
--- a/src/share/classes/sun/security/ssl/Alerts.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.net.ssl.*; - -/* - * A simple class to congregate alerts, their definitions, and common - * support methods. - */ - -final class Alerts { - - /* - * Alerts are always a fixed two byte format (level/description). - */ - - // warnings and fatal errors are package private facilities/constants - - // Alert levels (enum AlertLevel) - static final byte alert_warning = 1; - static final byte alert_fatal = 2; - - /* - * Alert descriptions (enum AlertDescription) - * - * We may not use them all in our processing, but if someone - * sends us one, we can at least convert it to a string for the - * user. - */ - static final byte alert_close_notify = 0; - static final byte alert_unexpected_message = 10; - static final byte alert_bad_record_mac = 20; - static final byte alert_decryption_failed = 21; - static final byte alert_record_overflow = 22; - static final byte alert_decompression_failure = 30; - static final byte alert_handshake_failure = 40; - static final byte alert_no_certificate = 41; - static final byte alert_bad_certificate = 42; - static final byte alert_unsupported_certificate = 43; - static final byte alert_certificate_revoked = 44; - static final byte alert_certificate_expired = 45; - static final byte alert_certificate_unknown = 46; - static final byte alert_illegal_parameter = 47; - static final byte alert_unknown_ca = 48; - static final byte alert_access_denied = 49; - static final byte alert_decode_error = 50; - static final byte alert_decrypt_error = 51; - static final byte alert_export_restriction = 60; - static final byte alert_protocol_version = 70; - static final byte alert_insufficient_security = 71; - static final byte alert_internal_error = 80; - static final byte alert_user_canceled = 90; - static final byte alert_no_renegotiation = 100; - - // from RFC 3546 (TLS Extensions) - static final byte alert_unsupported_extension = 110; - static final byte alert_certificate_unobtainable = 111; - static final byte alert_unrecognized_name = 112; - static final byte alert_bad_certificate_status_response = 113; - static final byte alert_bad_certificate_hash_value = 114; - - // from RFC 7301 (TLS ALPN Extension) - static final byte alert_no_application_protocol = 120; - - static String alertDescription(byte code) { - switch (code) { - - case alert_close_notify: - return "close_notify"; - case alert_unexpected_message: - return "unexpected_message"; - case alert_bad_record_mac: - return "bad_record_mac"; - case alert_decryption_failed: - return "decryption_failed"; - case alert_record_overflow: - return "record_overflow"; - case alert_decompression_failure: - return "decompression_failure"; - case alert_handshake_failure: - return "handshake_failure"; - case alert_no_certificate: - return "no_certificate"; - case alert_bad_certificate: - return "bad_certificate"; - case alert_unsupported_certificate: - return "unsupported_certificate"; - case alert_certificate_revoked: - return "certificate_revoked"; - case alert_certificate_expired: - return "certificate_expired"; - case alert_certificate_unknown: - return "certificate_unknown"; - case alert_illegal_parameter: - return "illegal_parameter"; - case alert_unknown_ca: - return "unknown_ca"; - case alert_access_denied: - return "access_denied"; - case alert_decode_error: - return "decode_error"; - case alert_decrypt_error: - return "decrypt_error"; - case alert_export_restriction: - return "export_restriction"; - case alert_protocol_version: - return "protocol_version"; - case alert_insufficient_security: - return "insufficient_security"; - case alert_internal_error: - return "internal_error"; - case alert_user_canceled: - return "user_canceled"; - case alert_no_renegotiation: - return "no_renegotiation"; - case alert_unsupported_extension: - return "unsupported_extension"; - case alert_certificate_unobtainable: - return "certificate_unobtainable"; - case alert_unrecognized_name: - return "unrecognized_name"; - case alert_bad_certificate_status_response: - return "bad_certificate_status_response"; - case alert_bad_certificate_hash_value: - return "bad_certificate_hash_value"; - case alert_no_application_protocol: - return "no_application_protocol"; - - default: - return "<UNKNOWN ALERT: " + (code & 0x0ff) + ">"; - } - } - - static SSLException getSSLException(byte description, String reason) { - return getSSLException(description, null, reason); - } - - /* - * Try to be a little more specific in our choice of - * exceptions to throw. - */ - static SSLException getSSLException(byte description, Throwable cause, - String reason) { - - SSLException e; - // the SSLException classes do not have a no-args constructor - // make up a message if there is none - if (reason == null) { - if (cause != null) { - reason = cause.toString(); - } else { - reason = ""; - } - } - switch (description) { - case alert_handshake_failure: - case alert_no_certificate: - case alert_bad_certificate: - case alert_unsupported_certificate: - case alert_certificate_revoked: - case alert_certificate_expired: - case alert_certificate_unknown: - case alert_unknown_ca: - case alert_access_denied: - case alert_decrypt_error: - case alert_export_restriction: - case alert_insufficient_security: - case alert_unsupported_extension: - case alert_certificate_unobtainable: - case alert_unrecognized_name: - case alert_bad_certificate_status_response: - case alert_bad_certificate_hash_value: - case alert_no_application_protocol: - e = new SSLHandshakeException(reason); - break; - - case alert_close_notify: - case alert_unexpected_message: - case alert_bad_record_mac: - case alert_decryption_failed: - case alert_record_overflow: - case alert_decompression_failure: - case alert_illegal_parameter: - case alert_decode_error: - case alert_protocol_version: - case alert_internal_error: - case alert_user_canceled: - case alert_no_renegotiation: - default: - e = new SSLException(reason); - break; - } - - if (cause != null) { - e.initCause(cause); - } - return e; - } -}
--- a/src/share/classes/sun/security/ssl/AppInputStream.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,155 +0,0 @@ -/* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; - -/** - * InputStream for application data as returned by SSLSocket.getInputStream(). - * It uses an InputRecord as internal buffer that is refilled on demand - * whenever it runs out of data. - * - * @author David Brownell - */ -class AppInputStream extends InputStream { - - // static dummy array we use to implement skip() - private final static byte[] SKIP_ARRAY = new byte[1024]; - - private SSLSocketImpl c; - InputRecord r; - - // One element array used to implement the single byte read() method - private final byte[] oneByte = new byte[1]; - - AppInputStream(SSLSocketImpl conn) { - r = new InputRecord(); - c = conn; - } - - /** - * Return the minimum number of bytes that can be read without blocking. - * Currently not synchronized. - */ - @Override - public int available() throws IOException { - if (c.checkEOF() || (r.isAppDataValid() == false)) { - return 0; - } - return r.available(); - } - - /** - * Read a single byte, returning -1 on non-fault EOF status. - */ - @Override - public synchronized int read() throws IOException { - int n = read(oneByte, 0, 1); - if (n <= 0) { // EOF - return -1; - } - return oneByte[0] & 0xff; - } - - /** - * Read up to "len" bytes into this buffer, starting at "off". - * If the layer above needs more data, it asks for more, so we - * are responsible only for blocking to fill at most one buffer, - * and returning "-1" on non-fault EOF status. - */ - @Override - public synchronized int read(byte b[], int off, int len) - throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - - if (c.checkEOF()) { - return -1; - } - try { - /* - * Read data if needed ... notice that the connection guarantees - * that handshake, alert, and change cipher spec data streams are - * handled as they arrive, so we never see them here. - */ - while (r.available() == 0) { - c.readDataRecord(r); - if (c.checkEOF()) { - return -1; - } - } - - int howmany = Math.min(len, r.available()); - howmany = r.read(b, off, howmany); - return howmany; - } catch (Exception e) { - // shutdown and rethrow (wrapped) exception as appropriate - c.handleException(e); - // dummy for compiler - return -1; - } - } - - - /** - * Skip n bytes. This implementation is somewhat less efficient - * than possible, but not badly so (redundant copy). We reuse - * the read() code to keep things simpler. Note that SKIP_ARRAY - * is static and may garbled by concurrent use, but we are not interested - * in the data anyway. - */ - @Override - public synchronized long skip(long n) throws IOException { - long skipped = 0; - while (n > 0) { - int len = (int)Math.min(n, SKIP_ARRAY.length); - int r = read(SKIP_ARRAY, 0, len); - if (r <= 0) { - break; - } - n -= r; - skipped += r; - } - return skipped; - } - - /* - * Socket close is already synchronized, no need to block here. - */ - @Override - public void close() throws IOException { - c.close(); - } - - // inherit default mark/reset behavior (throw Exceptions) from InputStream - -}
--- a/src/share/classes/sun/security/ssl/AppOutputStream.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.OutputStream; -import java.io.IOException; - -/* - * Output stream for application data. This is the kind of stream - * that's handed out via SSLSocket.getOutputStream(). It's all the application - * ever sees. - * - * Once the initial handshake has completed, application data may be - * interleaved with handshake data. That is handled internally and remains - * transparent to the application. - * - * @author David Brownell - */ -class AppOutputStream extends OutputStream { - - private SSLSocketImpl c; - OutputRecord r; - - // One element array used to implement the write(byte) method - private final byte[] oneByte = new byte[1]; - - AppOutputStream(SSLSocketImpl conn) { - r = new OutputRecord(Record.ct_application_data); - c = conn; - } - - /** - * Write the data out, NOW. - */ - @Override - synchronized public void write(byte b[], int off, int len) - throws IOException { - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - // check if the Socket is invalid (error or closed) - c.checkWrite(); - - /* - * By default, we counter chosen plaintext issues on CBC mode - * ciphersuites in SSLv3/TLS1.0 by sending one byte of application - * data in the first record of every payload, and the rest in - * subsequent record(s). Note that the issues have been solved in - * TLS 1.1 or later. - * - * It is not necessary to split the very first application record of - * a freshly negotiated TLS session, as there is no previous - * application data to guess. To improve compatibility, we will not - * split such records. - * - * This avoids issues in the outbound direction. For a full fix, - * the peer must have similar protections. - */ - boolean isFirstRecordOfThePayload = true; - - // Always flush at the end of each application level record. - // This lets application synchronize read and write streams - // however they like; if we buffered here, they couldn't. - try { - do { - boolean holdRecord = false; - int howmuch; - if (isFirstRecordOfThePayload && c.needToSplitPayload()) { - howmuch = Math.min(0x01, r.availableDataBytes()); - /* - * Nagle's algorithm (TCP_NODELAY) was coming into - * play here when writing short (split) packets. - * Signal to the OutputRecord code to internally - * buffer this small packet until the next outbound - * packet (of any type) is written. - */ - if ((len != 1) && (howmuch == 1)) { - holdRecord = true; - } - } else { - howmuch = Math.min(len, r.availableDataBytes()); - } - - if (isFirstRecordOfThePayload && howmuch != 0) { - isFirstRecordOfThePayload = false; - } - - // NOTE: *must* call c.writeRecord() even for howmuch == 0 - if (howmuch > 0) { - r.write(b, off, howmuch); - off += howmuch; - len -= howmuch; - } - c.writeRecord(r, holdRecord); - c.checkWrite(); - } while (len > 0); - } catch (Exception e) { - // shutdown and rethrow (wrapped) exception as appropriate - c.handleException(e); - } - } - - /** - * Write one byte now. - */ - @Override - synchronized public void write(int i) throws IOException { - oneByte[0] = (byte)i; - write(oneByte, 0, 1); - } - - /* - * Socket close is already synchronized, no need to block here. - */ - @Override - public void close() throws IOException { - c.close(); - } - - // inherit no-op flush() -}
--- a/src/share/classes/sun/security/ssl/Authenticator.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.Arrays; - -/** - * This class represents an SSL/TLS message authentication token, - * which encapsulates a sequence number and ensures that attempts to - * delete or reorder messages can be detected. - * - * Each SSL/TLS connection state contains a sequence number, which - * is maintained separately for read and write states. The sequence - * number MUST be set to zero whenever a connection state is made the - * active state. Sequence numbers are of type uint64 and may not - * exceed 2^64-1. Sequence numbers do not wrap. If a SSL/TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. A sequence number is incremented after each - * record: specifically, the first record transmitted under a - * particular connection state MUST use sequence number 0. - */ -class Authenticator { - - // byte array containing the additional authentication information for - // each record - private final byte[] block; - - // the block size of SSL v3.0: - // sequence number + record type + + record length - private static final int BLOCK_SIZE_SSL = 8 + 1 + 2; - - // the block size of TLS v1.0 and later: - // sequence number + record type + protocol version + record length - private static final int BLOCK_SIZE_TLS = 8 + 1 + 2 + 2; - - /** - * Default construct, no message authentication token is initialized. - * - * Note that this construct can only be called for null MAC - */ - Authenticator() { - block = new byte[0]; - } - - /** - * Constructs the message authentication token for the specified - * SSL/TLS protocol. - */ - Authenticator(ProtocolVersion protocolVersion) { - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - block = new byte[BLOCK_SIZE_TLS]; - block[9] = protocolVersion.major; - block[10] = protocolVersion.minor; - } else { - block = new byte[BLOCK_SIZE_SSL]; - } - } - - /** - * Checks whether the sequence number is close to wrap. - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. When the sequence number is near - * to wrap, we need to close the connection immediately. - * - * @return true if the sequence number is close to wrap - */ - final boolean seqNumOverflow() { - /* - * Conservatively, we don't allow more records to be generated - * when there are only 2^8 sequence numbers left. - */ - return (block.length != 0 && - block[0] == (byte)0xFF && block[1] == (byte)0xFF && - block[2] == (byte)0xFF && block[3] == (byte)0xFF && - block[4] == (byte)0xFF && block[5] == (byte)0xFF && - block[6] == (byte)0xFF); - } - - /** - * Checks whether the sequence number close to renew. - * - * Sequence numbers are of type uint64 and may not exceed 2^64-1. - * Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead. - * - * @return true if the sequence number is huge enough to renew - */ - final boolean seqNumIsHuge() { - /* - * Conservatively, we should ask for renegotiation when there are - * only 2^48 sequence numbers left. - */ - return (block.length != 0 && - block[0] == (byte)0xFF && block[1] == (byte)0xFF); - } - - /** - * Gets the current sequence number. - * - * @return the byte array of the current sequence number - */ - final byte[] sequenceNumber() { - return Arrays.copyOf(block, 8); - } - - /** - * Acquires the current message authentication information with the - * specified record type and fragment length, and then increases the - * sequence number. - * - * @param type the record type - * @param length the fragment of the record - * @return the byte array of the current message authentication information - */ - final byte[] acquireAuthenticationBytes(byte type, int length) { - byte[] copy = block.clone(); - - if (block.length != 0) { - copy[8] = type; - copy[copy.length - 2] = (byte)(length >> 8); - copy[copy.length - 1] = (byte)(length); - - /* - * Increase the sequence number in the block array - * it is a 64-bit number stored in big-endian format - */ - int k = 7; - while ((k >= 0) && (++block[k] == 0)) { - k--; - } - } - - return copy; - } - -}
--- a/src/share/classes/sun/security/ssl/BaseSSLSocketImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,640 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.channels.SocketChannel; -import java.net.*; - -import javax.net.ssl.*; - -/** - * Abstract base class for SSLSocketImpl. Its purpose is to house code with - * no SSL related logic (or no logic at all). This makes SSLSocketImpl shorter - * and easier to read. It contains a few constants and static methods plus - * overridden java.net.Socket methods. - * - * Methods are defined final to ensure that they are not accidentally - * overridden in SSLSocketImpl. - * - * @see javax.net.ssl.SSLSocket - * @see SSLSocketImpl - * - */ -abstract class BaseSSLSocketImpl extends SSLSocket { - - /* - * Normally "self" is "this" ... but not when this connection is - * layered over a preexisting socket. If we're using an existing - * socket, we delegate some actions to it. Else, we delegate - * instead to "super". This is important to ensure that we don't - * recurse infinitely ... e.g. close() calling itself, or doing - * I/O in terms of our own streams. - */ - final private Socket self; - final private InputStream consumedInput; - - BaseSSLSocketImpl() { - super(); - this.self = this; - this.consumedInput = null; - } - - BaseSSLSocketImpl(Socket socket) { - super(); - this.self = socket; - this.consumedInput = null; - } - - BaseSSLSocketImpl(Socket socket, InputStream consumed) { - super(); - this.self = socket; - this.consumedInput = consumed; - } - - // - // CONSTANTS AND STATIC METHODS - // - - /** - * TLS requires that a close_notify warning alert is sent before the - * connection is closed in order to avoid truncation attacks. Some - * implementations (MS IIS and others) don't do that. The property - * below controls whether we accept that or treat it as an error. - * - * The default is "false", i.e. tolerate the broken behavior. - */ - private final static String PROP_NAME = - "com.sun.net.ssl.requireCloseNotify"; - - final static boolean requireCloseNotify = - Debug.getBooleanProperty(PROP_NAME, false); - - // - // MISC SOCKET METHODS - // - - /** - * Returns the unique {@link java.nio.SocketChannel SocketChannel} object - * associated with this socket, if any. - * @see java.net.Socket#getChannel - */ - @Override - public final SocketChannel getChannel() { - if (self == this) { - return super.getChannel(); - } else { - return self.getChannel(); - } - } - - /** - * Binds the address to the socket. - * @see java.net.Socket#bind - */ - @Override - public void bind(SocketAddress bindpoint) throws IOException { - /* - * Bind to this socket - */ - if (self == this) { - super.bind(bindpoint); - } else { - // If we're binding on a layered socket... - throw new IOException( - "Underlying socket should already be connected"); - } - } - - /** - * Returns the address of the endpoint this socket is connected to - * @see java.net.Socket#getLocalSocketAddress - */ - @Override - public SocketAddress getLocalSocketAddress() { - if (self == this) { - return super.getLocalSocketAddress(); - } else { - return self.getLocalSocketAddress(); - } - } - - /** - * Returns the address of the endpoint this socket is connected to - * @see java.net.Socket#getRemoteSocketAddress - */ - @Override - public SocketAddress getRemoteSocketAddress() { - if (self == this) { - return super.getRemoteSocketAddress(); - } else { - return self.getRemoteSocketAddress(); - } - } - - /** - * Connects this socket to the server. - * - * This method is either called on an unconnected SSLSocketImpl by the - * application, or it is called in the constructor of a regular - * SSLSocketImpl. If we are layering on top on another socket, then - * this method should not be called, because we assume that the - * underlying socket is already connected by the time it is passed to - * us. - * - * @param endpoint the <code>SocketAddress</code> - * @throws IOException if an error occurs during the connection - */ - @Override - public final void connect(SocketAddress endpoint) throws IOException { - connect(endpoint, 0); - } - - /** - * Returns the connection state of the socket. - * @see java.net.Socket#isConnected - */ - @Override - public final boolean isConnected() { - if (self == this) { - return super.isConnected(); - } else { - return self.isConnected(); - } - } - - /** - * Returns the binding state of the socket. - * @see java.net.Socket#isBound - */ - @Override - public final boolean isBound() { - if (self == this) { - return super.isBound(); - } else { - return self.isBound(); - } - } - - // - // CLOSE RELATED METHODS - // - - /** - * The semantics of shutdownInput is not supported in TLS 1.0 - * spec. Thus when the method is called on an SSL socket, an - * UnsupportedOperationException will be thrown. - * - * @throws UnsupportedOperationException - */ - @Override - public final void shutdownInput() throws IOException { - throw new UnsupportedOperationException("The method shutdownInput()" + - " is not supported in SSLSocket"); - } - - /** - * The semantics of shutdownOutput is not supported in TLS 1.0 - * spec. Thus when the method is called on an SSL socket, an - * UnsupportedOperationException will be thrown. - * - * @throws UnsupportedOperationException - */ - @Override - public final void shutdownOutput() throws IOException { - throw new UnsupportedOperationException("The method shutdownOutput()" + - " is not supported in SSLSocket"); - - } - - /** - * Returns the input state of the socket - * @see java.net.Socket#isInputShutdown - */ - @Override - public final boolean isInputShutdown() { - if (self == this) { - return super.isInputShutdown(); - } else { - return self.isInputShutdown(); - } - } - - /** - * Returns the output state of the socket - * @see java.net.Socket#isOutputShutdown - */ - @Override - public final boolean isOutputShutdown() { - if (self == this) { - return super.isOutputShutdown(); - } else { - return self.isOutputShutdown(); - } - } - - /** - * Ensures that the SSL connection is closed down as cleanly - * as possible, in case the application forgets to do so. - * This allows SSL connections to be implicitly reclaimed, - * rather than forcing them to be explicitly reclaimed at - * the penalty of prematurly killing SSL sessions. - */ - @Override - protected final void finalize() throws Throwable { - try { - close(); - } catch (IOException e1) { - try { - if (self == this) { - super.close(); - } - } catch (IOException e2) { - // ignore - } - } finally { - // We called close on the underlying socket above to - // make doubly sure all resources got released. We - // don't finalize self in the case of overlain sockets, - // that's a different object which the GC will finalize - // separately. - - super.finalize(); - } - } - - // - // GET ADDRESS METHODS - // - - /** - * Returns the address of the remote peer for this connection. - */ - @Override - public final InetAddress getInetAddress() { - if (self == this) { - return super.getInetAddress(); - } else { - return self.getInetAddress(); - } - } - - /** - * Gets the local address to which the socket is bound. - * - * @return the local address to which the socket is bound. - * @since JDK1.1 - */ - @Override - public final InetAddress getLocalAddress() { - if (self == this) { - return super.getLocalAddress(); - } else { - return self.getLocalAddress(); - } - } - - /** - * Returns the number of the remote port that this connection uses. - */ - @Override - public final int getPort() { - if (self == this) { - return super.getPort(); - } else { - return self.getPort(); - } - } - - /** - * Returns the number of the local port that this connection uses. - */ - @Override - public final int getLocalPort() { - if (self == this) { - return super.getLocalPort(); - } else { - return self.getLocalPort(); - } - } - - // - // SOCKET OPTION METHODS - // - - /** - * Enables or disables the Nagle optimization. - * @see java.net.Socket#setTcpNoDelay - */ - @Override - public final void setTcpNoDelay(boolean value) throws SocketException { - if (self == this) { - super.setTcpNoDelay(value); - } else { - self.setTcpNoDelay(value); - } - } - - /** - * Returns true if the Nagle optimization is disabled. This - * relates to low-level buffering of TCP traffic, delaying the - * traffic to promote better throughput. - * - * @see java.net.Socket#getTcpNoDelay - */ - @Override - public final boolean getTcpNoDelay() throws SocketException { - if (self == this) { - return super.getTcpNoDelay(); - } else { - return self.getTcpNoDelay(); - } - } - - /** - * Assigns the socket's linger timeout. - * @see java.net.Socket#setSoLinger - */ - @Override - public final void setSoLinger(boolean flag, int linger) - throws SocketException { - if (self == this) { - super.setSoLinger(flag, linger); - } else { - self.setSoLinger(flag, linger); - } - } - - /** - * Returns the socket's linger timeout. - * @see java.net.Socket#getSoLinger - */ - @Override - public final int getSoLinger() throws SocketException { - if (self == this) { - return super.getSoLinger(); - } else { - return self.getSoLinger(); - } - } - - /** - * Send one byte of urgent data on the socket. - * @see java.net.Socket#sendUrgentData - * At this point, there seems to be no specific requirement to support - * this for an SSLSocket. An implementation can be provided if a need - * arises in future. - */ - @Override - public final void sendUrgentData(int data) throws SocketException { - throw new SocketException("This method is not supported " - + "by SSLSockets"); - } - - /** - * Enable/disable OOBINLINE (receipt of TCP urgent data) By default, this - * option is disabled and TCP urgent data received on a socket is silently - * discarded. - * @see java.net.Socket#setOOBInline - * Setting OOBInline does not have any effect on SSLSocket, - * since currently we don't support sending urgent data. - */ - @Override - public final void setOOBInline(boolean on) throws SocketException { - throw new SocketException("This method is ineffective, since" - + " sending urgent data is not supported by SSLSockets"); - } - - /** - * Tests if OOBINLINE is enabled. - * @see java.net.Socket#getOOBInline - */ - @Override - public final boolean getOOBInline() throws SocketException { - throw new SocketException("This method is ineffective, since" - + " sending urgent data is not supported by SSLSockets"); - } - - /** - * Returns the socket timeout. - * @see java.net.Socket#getSoTimeout - */ - @Override - public final int getSoTimeout() throws SocketException { - if (self == this) { - return super.getSoTimeout(); - } else { - return self.getSoTimeout(); - } - } - - @Override - public final void setSendBufferSize(int size) throws SocketException { - if (self == this) { - super.setSendBufferSize(size); - } else { - self.setSendBufferSize(size); - } - } - - @Override - public final int getSendBufferSize() throws SocketException { - if (self == this) { - return super.getSendBufferSize(); - } else { - return self.getSendBufferSize(); - } - } - - @Override - public final void setReceiveBufferSize(int size) throws SocketException { - if (self == this) { - super.setReceiveBufferSize(size); - } else { - self.setReceiveBufferSize(size); - } - } - - @Override - public final int getReceiveBufferSize() throws SocketException { - if (self == this) { - return super.getReceiveBufferSize(); - } else { - return self.getReceiveBufferSize(); - } - } - - /** - * Enable/disable SO_KEEPALIVE. - * @see java.net.Socket#setKeepAlive - */ - @Override - public final void setKeepAlive(boolean on) throws SocketException { - if (self == this) { - super.setKeepAlive(on); - } else { - self.setKeepAlive(on); - } - } - - /** - * Tests if SO_KEEPALIVE is enabled. - * @see java.net.Socket#getKeepAlive - */ - @Override - public final boolean getKeepAlive() throws SocketException { - if (self == this) { - return super.getKeepAlive(); - } else { - return self.getKeepAlive(); - } - } - - /** - * Sets traffic class or type-of-service octet in the IP header for - * packets sent from this Socket. - * @see java.net.Socket#setTrafficClass - */ - @Override - public final void setTrafficClass(int tc) throws SocketException { - if (self == this) { - super.setTrafficClass(tc); - } else { - self.setTrafficClass(tc); - } - } - - /** - * Gets traffic class or type-of-service in the IP header for packets - * sent from this Socket. - * @see java.net.Socket#getTrafficClass - */ - @Override - public final int getTrafficClass() throws SocketException { - if (self == this) { - return super.getTrafficClass(); - } else { - return self.getTrafficClass(); - } - } - - /** - * Enable/disable SO_REUSEADDR. - * @see java.net.Socket#setReuseAddress - */ - @Override - public final void setReuseAddress(boolean on) throws SocketException { - if (self == this) { - super.setReuseAddress(on); - } else { - self.setReuseAddress(on); - } - } - - /** - * Tests if SO_REUSEADDR is enabled. - * @see java.net.Socket#getReuseAddress - */ - @Override - public final boolean getReuseAddress() throws SocketException { - if (self == this) { - return super.getReuseAddress(); - } else { - return self.getReuseAddress(); - } - } - - /** - * Sets performance preferences for this socket. - * - * @see java.net.Socket#setPerformancePreferences(int, int, int) - */ - @Override - public void setPerformancePreferences(int connectionTime, - int latency, int bandwidth) { - if (self == this) { - super.setPerformancePreferences( - connectionTime, latency, bandwidth); - } else { - self.setPerformancePreferences( - connectionTime, latency, bandwidth); - } - } - - @Override - public String toString() { - if (self == this) { - return super.toString(); - } - - return self.toString(); - } - - @Override - public InputStream getInputStream() throws IOException { - if (self == this) { - return super.getInputStream(); - } - - if (consumedInput != null) { - return new SequenceInputStream(consumedInput, - self.getInputStream()); - } - - return self.getInputStream(); - } - - @Override - public OutputStream getOutputStream() throws IOException { - if (self == this) { - return super.getOutputStream(); - } - - return self.getOutputStream(); - } - - @Override - public synchronized void close() throws IOException { - if (self == this) { - super.close(); - } else { - self.close(); - } - } - - @Override - public synchronized void setSoTimeout(int timeout) throws SocketException { - if (self == this) { - super.setSoTimeout(timeout); - } else { - self.setSoTimeout(timeout); - } - } - - boolean isLayered() { - return (self != this); - } -}
--- a/src/share/classes/sun/security/ssl/ByteBufferInputStream.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; - -/** - * A simple InputStream which uses ByteBuffers as it's backing store. - * <P> - * The only IOException should come if the InputStream has been closed. - * All other IOException should not occur because all the data is local. - * Data reads on an exhausted ByteBuffer returns a -1. - * - * @author Brad Wetmore - */ -class ByteBufferInputStream extends InputStream { - - ByteBuffer bb; - - ByteBufferInputStream(ByteBuffer bb) { - this.bb = bb; - } - - /** - * Returns a byte from the ByteBuffer. - * - * Increments position(). - */ - @Override - public int read() throws IOException { - - if (bb == null) { - throw new IOException("read on a closed InputStream"); - } - - if (bb.remaining() == 0) { - return -1; - } - - return (bb.get() & 0xFF); // need to be in the range 0 to 255 - } - - /** - * Returns a byte array from the ByteBuffer. - * - * Increments position(). - */ - @Override - public int read(byte b[]) throws IOException { - - if (bb == null) { - throw new IOException("read on a closed InputStream"); - } - - return read(b, 0, b.length); - } - - /** - * Returns a byte array from the ByteBuffer. - * - * Increments position(). - */ - @Override - public int read(byte b[], int off, int len) throws IOException { - - if (bb == null) { - throw new IOException("read on a closed InputStream"); - } - - if (b == null) { - throw new NullPointerException(); - } else if (off < 0 || len < 0 || len > b.length - off) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return 0; - } - - int length = Math.min(bb.remaining(), len); - if (length == 0) { - return -1; - } - - bb.get(b, off, length); - return length; - } - - /** - * Skips over and discards <code>n</code> bytes of data from this input - * stream. - */ - @Override - public long skip(long n) throws IOException { - - if (bb == null) { - throw new IOException("skip on a closed InputStream"); - } - - if (n <= 0) { - return 0; - } - - /* - * ByteBuffers have at most an int, so lose the upper bits. - * The contract allows this. - */ - int nInt = (int) n; - int skip = Math.min(bb.remaining(), nInt); - - bb.position(bb.position() + skip); - - return nInt; - } - - /** - * Returns the number of bytes that can be read (or skipped over) - * from this input stream without blocking by the next caller of a - * method for this input stream. - */ - @Override - public int available() throws IOException { - - if (bb == null) { - throw new IOException("available on a closed InputStream"); - } - - return bb.remaining(); - } - - /** - * Closes this input stream and releases any system resources associated - * with the stream. - * - * @exception IOException if an I/O error occurs. - */ - @Override - public void close() throws IOException { - bb = null; - } - - /** - * Marks the current position in this input stream. - */ - @Override - public synchronized void mark(int readlimit) {} - - /** - * Repositions this stream to the position at the time the - * <code>mark</code> method was last called on this input stream. - */ - @Override - public synchronized void reset() throws IOException { - throw new IOException("mark/reset not supported"); - } - - /** - * Tests if this input stream supports the <code>mark</code> and - * <code>reset</code> methods. - */ - @Override - public boolean markSupported() { - return false; - } -}
--- a/src/share/classes/sun/security/ssl/CipherBox.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1089 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.ByteArrayInputStream; -import java.io.IOException; -import java.util.Hashtable; -import java.util.Arrays; - -import java.security.*; -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.GCMParameterSpec; - -import java.nio.*; - -import sun.security.ssl.CipherSuite.*; -import static sun.security.ssl.CipherSuite.*; -import static sun.security.ssl.CipherSuite.CipherType.*; - -import sun.misc.HexDumpEncoder; - - -/** - * This class handles bulk data enciphering/deciphering for each SSLv3 - * message. This provides data confidentiality. Stream ciphers (such - * as RC4) don't need to do padding; block ciphers (e.g. DES) need it. - * - * Individual instances are obtained by calling the static method - * newCipherBox(), which should only be invoked by BulkCipher.newCipher(). - * - * In RFC 2246, with bock ciphers in CBC mode, the Initialization - * Vector (IV) for the first record is generated with the other keys - * and secrets when the security parameters are set. The IV for - * subsequent records is the last ciphertext block from the previous - * record. - * - * In RFC 4346, the implicit Initialization Vector (IV) is replaced - * with an explicit IV to protect against CBC attacks. RFC 4346 - * recommends two algorithms used to generated the per-record IV. - * The implementation uses the algorithm (2)(b), as described at - * section 6.2.3.2 of RFC 4346. - * - * The usage of IV in CBC block cipher can be illustrated in - * the following diagrams. - * - * (random) - * R P1 IV C1 - * | | | | - * SIV---+ |-----+ |-... |----- |------ - * | | | | | | | | - * +----+ | +----+ | +----+ | +----+ | - * | Ek | | + Ek + | | Dk | | | Dk | | - * +----+ | +----+ | +----+ | +----+ | - * | | | | | | | | - * |----| |----| SIV--+ |----| |-... - * | | | | - * IV C1 R P1 - * (discard) - * - * CBC Encryption CBC Decryption - * - * NOTE that any ciphering involved in key exchange (e.g. with RSA) is - * handled separately. - * - * @author David Brownell - * @author Andreas Sterbenz - */ -final class CipherBox { - - // A CipherBox that implements the identity operation - final static CipherBox NULL = new CipherBox(); - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - // the protocol version this cipher conforms to - private final ProtocolVersion protocolVersion; - - // cipher object - private final Cipher cipher; - - /** - * secure random - */ - private SecureRandom random; - - /** - * fixed IV, the implicit nonce of AEAD cipher suite, only apply to - * AEAD cipher suites - */ - private final byte[] fixedIv; - - /** - * the key, reserved only for AEAD cipher initialization - */ - private final Key key; - - /** - * the operation mode, reserved for AEAD cipher initialization - */ - private final int mode; - - /** - * the authentication tag size, only apply to AEAD cipher suites - */ - private final int tagSize; - - /** - * the record IV length, only apply to AEAD cipher suites - */ - private final int recordIvSize; - - /** - * cipher type - */ - private final CipherType cipherType; - - /** - * Fixed masks of various block size, as the initial decryption IVs - * for TLS 1.1 or later. - * - * For performance, we do not use random IVs. As the initial decryption - * IVs will be discarded by TLS decryption processes, so the fixed masks - * do not hurt cryptographic strength. - */ - private static Hashtable<Integer, IvParameterSpec> masks; - - /** - * NULL cipherbox. Identity operation, no encryption. - */ - private CipherBox() { - this.protocolVersion = ProtocolVersion.DEFAULT; - this.cipher = null; - this.cipherType = STREAM_CIPHER; - this.fixedIv = new byte[0]; - this.key = null; - this.mode = Cipher.ENCRYPT_MODE; // choose at random - this.random = null; - this.tagSize = 0; - this.recordIvSize = 0; - } - - /** - * Construct a new CipherBox using the cipher transformation. - * - * @exception NoSuchAlgorithmException if no appropriate JCE Cipher - * implementation could be found. - */ - private CipherBox(ProtocolVersion protocolVersion, BulkCipher bulkCipher, - SecretKey key, IvParameterSpec iv, SecureRandom random, - boolean encrypt) throws NoSuchAlgorithmException { - try { - this.protocolVersion = protocolVersion; - this.cipher = JsseJce.getCipher(bulkCipher.transformation); - this.mode = encrypt ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE; - - if (random == null) { - random = JsseJce.getSecureRandom(); - } - this.random = random; - this.cipherType = bulkCipher.cipherType; - - /* - * RFC 4346 recommends two algorithms used to generated the - * per-record IV. The implementation uses the algorithm (2)(b), - * as described at section 6.2.3.2 of RFC 4346. - * - * As we don't care about the initial IV value for TLS 1.1 or - * later, so if the "iv" parameter is null, we use the default - * value generated by Cipher.init() for encryption, and a fixed - * mask for decryption. - */ - if (iv == null && bulkCipher.ivSize != 0 && - mode == Cipher.DECRYPT_MODE && - protocolVersion.v >= ProtocolVersion.TLS11.v) { - iv = getFixedMask(bulkCipher.ivSize); - } - - if (cipherType == AEAD_CIPHER) { - // AEAD must completely initialize the cipher for each packet, - // and so we save initialization parameters for packet - // processing time. - - // Set the tag size for AEAD cipher - tagSize = bulkCipher.tagSize; - - // Reserve the key for AEAD cipher initialization - this.key = key; - - fixedIv = iv.getIV(); - if (fixedIv == null || - fixedIv.length != bulkCipher.fixedIvSize) { - throw new RuntimeException("Improper fixed IV for AEAD"); - } - - // Set the record IV length for AEAD cipher - recordIvSize = bulkCipher.ivSize - bulkCipher.fixedIvSize; - - // DON'T initialize the cipher for AEAD! - } else { - // CBC only requires one initialization during its lifetime - // (future packets/IVs set the proper CBC state), so we can - // initialize now. - - // Zeroize the variables that only apply to AEAD cipher - this.tagSize = 0; - this.fixedIv = new byte[0]; - this.recordIvSize = 0; - this.key = null; - - // Initialize the cipher - cipher.init(mode, key, iv, random); - } - } catch (NoSuchAlgorithmException e) { - throw e; - } catch (Exception e) { - throw new NoSuchAlgorithmException - ("Could not create cipher " + bulkCipher, e); - } catch (ExceptionInInitializerError e) { - throw new NoSuchAlgorithmException - ("Could not create cipher " + bulkCipher, e); - } - } - - /* - * Factory method to obtain a new CipherBox object. - */ - static CipherBox newCipherBox(ProtocolVersion version, BulkCipher cipher, - SecretKey key, IvParameterSpec iv, SecureRandom random, - boolean encrypt) throws NoSuchAlgorithmException { - if (cipher.allowed == false) { - throw new NoSuchAlgorithmException("Unsupported cipher " + cipher); - } - - if (cipher == B_NULL) { - return NULL; - } else { - return new CipherBox(version, cipher, key, iv, random, encrypt); - } - } - - /* - * Get a fixed mask, as the initial decryption IVs for TLS 1.1 or later. - */ - private static IvParameterSpec getFixedMask(int ivSize) { - if (masks == null) { - masks = new Hashtable<Integer, IvParameterSpec>(5); - } - - IvParameterSpec iv = masks.get(ivSize); - if (iv == null) { - iv = new IvParameterSpec(new byte[ivSize]); - masks.put(ivSize, iv); - } - - return iv; - } - - /* - * Encrypts a block of data, returning the size of the - * resulting block. - */ - int encrypt(byte[] buf, int offset, int len) { - if (cipher == null) { - return len; - } - - try { - int blockSize = cipher.getBlockSize(); - if (cipherType == BLOCK_CIPHER) { - len = addPadding(buf, offset, len, blockSize); - } - - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext before ENCRYPTION: len = " - + len); - hd.encodeBuffer( - new ByteArrayInputStream(buf, offset, len), - System.out); - } catch (IOException e) { } - } - - - if (cipherType == AEAD_CIPHER) { - try { - return cipher.doFinal(buf, offset, len, buf, offset); - } catch (IllegalBlockSizeException | BadPaddingException ibe) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibe); - } - } else { - int newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - return newLen; - } - } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here - throw new ArrayIndexOutOfBoundsException(e.toString()); - } - } - - /* - * Encrypts a ByteBuffer block of data, returning the size of the - * resulting block. - * - * The byte buffers position and limit initially define the amount - * to encrypt. On return, the position and limit are - * set to last position padded/encrypted. The limit may have changed - * because of the added padding bytes. - */ - int encrypt(ByteBuffer bb, int outLimit) { - - int len = bb.remaining(); - - if (cipher == null) { - bb.position(bb.limit()); - return len; - } - - int pos = bb.position(); - - int blockSize = cipher.getBlockSize(); - if (cipherType == BLOCK_CIPHER) { - // addPadding adjusts pos/limit - len = addPadding(bb, blockSize); - bb.position(pos); - } - - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext before ENCRYPTION: len = " - + len); - hd.encodeBuffer(bb.duplicate(), System.out); - - } catch (IOException e) { } - } - - /* - * Encrypt "in-place". This does not add its own padding. - */ - ByteBuffer dup = bb.duplicate(); - if (cipherType == AEAD_CIPHER) { - try { - int outputSize = cipher.getOutputSize(dup.remaining()); - if (outputSize > bb.remaining()) { - // need to expand the limit of the output buffer for - // the authentication tag. - // - // DON'T worry about the buffer's capacity, we have - // reserved space for the authentication tag. - if (outLimit < pos + outputSize) { - // unlikely to happen - throw new ShortBufferException( - "need more space in output buffer"); - } - bb.limit(pos + outputSize); - } - int newLen = cipher.doFinal(dup, bb); - if (newLen != outputSize) { - throw new RuntimeException( - "Cipher buffering error in JCE provider " + - cipher.getProvider().getName()); - } - return newLen; - } catch (IllegalBlockSizeException | - BadPaddingException | ShortBufferException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibse); - } - } else { - int newLen; - try { - newLen = cipher.update(dup, bb); - } catch (ShortBufferException sbe) { - // unlikely to happen - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - - if (bb.position() != dup.position()) { - throw new RuntimeException("bytebuffer padding error"); - } - - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - return newLen; - } - } - - - /* - * Decrypts a block of data, returning the size of the - * resulting block if padding was required. - * - * For SSLv3 and TLSv1.0, with block ciphers in CBC mode the - * Initialization Vector (IV) for the first record is generated by - * the handshake protocol, the IV for subsequent records is the - * last ciphertext block from the previous record. - * - * From TLSv1.1, the implicit IV is replaced with an explicit IV to - * protect against CBC attacks. - * - * Differentiating between bad_record_mac and decryption_failed alerts - * may permit certain attacks against CBC mode. It is preferable to - * uniformly use the bad_record_mac alert to hide the specific type of - * the error. - */ - int decrypt(byte[] buf, int offset, int len, - int tagLen) throws BadPaddingException { - if (cipher == null) { - return len; - } - - try { - int newLen; - if (cipherType == AEAD_CIPHER) { - try { - newLen = cipher.doFinal(buf, offset, len, buf, offset); - } catch (IllegalBlockSizeException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode in JCE provider " + - cipher.getProvider().getName(), ibse); - } - } else { - newLen = cipher.update(buf, offset, len, buf, offset); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - } - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext after DECRYPTION: len = " - + newLen); - hd.encodeBuffer( - new ByteArrayInputStream(buf, offset, newLen), - System.out); - } catch (IOException e) { } - } - - if (cipherType == BLOCK_CIPHER) { - int blockSize = cipher.getBlockSize(); - newLen = removePadding( - buf, offset, newLen, tagLen, blockSize, protocolVersion); - - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - if (newLen < blockSize) { - throw new BadPaddingException("The length after " + - "padding removal (" + newLen + ") should be larger " + - "than <" + blockSize + "> since explicit IV used"); - } - } - } - return newLen; - } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here - throw new ArrayIndexOutOfBoundsException(e.toString()); - } - } - - /* - * Decrypts a block of data, returning the size of the - * resulting block if padding was required. position and limit - * point to the end of the decrypted/depadded data. The initial - * limit and new limit may be different, given we may - * have stripped off some padding bytes. - * - * @see decrypt(byte[], int, int) - */ - int decrypt(ByteBuffer bb, int tagLen) throws BadPaddingException { - - int len = bb.remaining(); - - if (cipher == null) { - bb.position(bb.limit()); - return len; - } - - try { - /* - * Decrypt "in-place". - */ - int pos = bb.position(); - ByteBuffer dup = bb.duplicate(); - int newLen; - if (cipherType == AEAD_CIPHER) { - try { - newLen = cipher.doFinal(dup, bb); - } catch (IllegalBlockSizeException ibse) { - // unlikely to happen - throw new RuntimeException( - "Cipher error in AEAD mode \"" + ibse.getMessage() + - " \"in JCE provider " + cipher.getProvider().getName()); - } - } else { - newLen = cipher.update(dup, bb); - if (newLen != len) { - // catch BouncyCastle buffering error - throw new RuntimeException("Cipher buffering error " + - "in JCE provider " + cipher.getProvider().getName()); - } - } - - // reset the limit to the end of the decryted data - bb.limit(pos + newLen); - - if (debug != null && Debug.isOn("plaintext")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println( - "Padded plaintext after DECRYPTION: len = " - + newLen); - - hd.encodeBuffer( - (ByteBuffer)bb.duplicate().position(pos), System.out); - } catch (IOException e) { } - } - - /* - * Remove the block padding. - */ - if (cipherType == BLOCK_CIPHER) { - int blockSize = cipher.getBlockSize(); - bb.position(pos); - newLen = removePadding(bb, tagLen, blockSize, protocolVersion); - - // check the explicit IV of TLS v1.1 or later - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - if (newLen < blockSize) { - throw new BadPaddingException("The length after " + - "padding removal (" + newLen + ") should be larger " + - "than <" + blockSize + "> since explicit IV used"); - } - - // reset the position to the end of the decrypted data - bb.position(bb.limit()); - } - } - return newLen; - } catch (ShortBufferException e) { - // unlikely to happen, we should have enough buffer space here - throw new ArrayIndexOutOfBoundsException(e.toString()); - } - } - - private static int addPadding(byte[] buf, int offset, int len, - int blockSize) { - int newlen = len + 1; - byte pad; - int i; - - if ((newlen % blockSize) != 0) { - newlen += blockSize - 1; - newlen -= newlen % blockSize; - } - pad = (byte) (newlen - len); - - if (buf.length < (newlen + offset)) { - throw new IllegalArgumentException("no space to pad buffer"); - } - - /* - * TLS version of the padding works for both SSLv3 and TLSv1 - */ - for (i = 0, offset += len; i < pad; i++) { - buf [offset++] = (byte) (pad - 1); - } - return newlen; - } - - /* - * Apply the padding to the buffer. - * - * Limit is advanced to the new buffer length. - * Position is equal to limit. - */ - private static int addPadding(ByteBuffer bb, int blockSize) { - - int len = bb.remaining(); - int offset = bb.position(); - - int newlen = len + 1; - byte pad; - int i; - - if ((newlen % blockSize) != 0) { - newlen += blockSize - 1; - newlen -= newlen % blockSize; - } - pad = (byte) (newlen - len); - - /* - * Update the limit to what will be padded. - */ - bb.limit(newlen + offset); - - /* - * TLS version of the padding works for both SSLv3 and TLSv1 - */ - for (i = 0, offset += len; i < pad; i++) { - bb.put(offset++, (byte) (pad - 1)); - } - - bb.position(offset); - bb.limit(offset); - - return newlen; - } - - /* - * A constant-time check of the padding. - * - * NOTE that we are checking both the padding and the padLen bytes here. - * - * The caller MUST ensure that the len parameter is a positive number. - */ - private static int[] checkPadding( - byte[] buf, int offset, int len, byte pad) { - - if (len <= 0) { - throw new RuntimeException("padding len must be positive"); - } - - // An array of hits is used to prevent Hotspot optimization for - // the purpose of a constant-time check. - int[] results = {0, 0}; // {missed #, matched #} - for (int i = 0; i <= 256;) { - for (int j = 0; j < len && i <= 256; j++, i++) { // j <= i - if (buf[offset + j] != pad) { - results[0]++; // mismatched padding data - } else { - results[1]++; // matched padding data - } - } - } - - return results; - } - - /* - * A constant-time check of the padding. - * - * NOTE that we are checking both the padding and the padLen bytes here. - * - * The caller MUST ensure that the bb parameter has remaining. - */ - private static int[] checkPadding(ByteBuffer bb, byte pad) { - - if (!bb.hasRemaining()) { - throw new RuntimeException("hasRemaining() must be positive"); - } - - // An array of hits is used to prevent Hotspot optimization for - // the purpose of a constant-time check. - int[] results = {0, 0}; // {missed #, matched #} - bb.mark(); - for (int i = 0; i <= 256; bb.reset()) { - for (; bb.hasRemaining() && i <= 256; i++) { - if (bb.get() != pad) { - results[0]++; // mismatched padding data - } else { - results[1]++; // matched padding data - } - } - } - - return results; - } - - /* - * Typical TLS padding format for a 64 bit block cipher is as follows: - * xx xx xx xx xx xx xx 00 - * xx xx xx xx xx xx 01 01 - * ... - * xx 06 06 06 06 06 06 06 - * 07 07 07 07 07 07 07 07 - * TLS also allows any amount of padding from 1 and 256 bytes as long - * as it makes the data a multiple of the block size - */ - private static int removePadding(byte[] buf, int offset, int len, - int tagLen, int blockSize, - ProtocolVersion protocolVersion) throws BadPaddingException { - - // last byte is length byte (i.e. actual padding length - 1) - int padOffset = offset + len - 1; - int padLen = buf[padOffset] & 0xFF; - - int newLen = len - (padLen + 1); - if ((newLen - tagLen) < 0) { - // If the buffer is not long enough to contain the padding plus - // a MAC tag, do a dummy constant-time padding check. - // - // Note that it is a dummy check, so we won't care about what is - // the actual padding data. - checkPadding(buf, offset, len, (byte)(padLen & 0xFF)); - - throw new BadPaddingException("Invalid Padding length: " + padLen); - } - - // The padding data should be filled with the padding length value. - int[] results = checkPadding(buf, offset + newLen, - padLen + 1, (byte)(padLen & 0xFF)); - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - if (results[0] != 0) { // padding data has invalid bytes - throw new BadPaddingException("Invalid TLS padding data"); - } - } else { // SSLv3 - // SSLv3 requires 0 <= length byte < block size - // some implementations do 1 <= length byte <= block size, - // so accept that as well - // v3 does not require any particular value for the other bytes - if (padLen > blockSize) { - throw new BadPaddingException("Padding length (" + - padLen + ") of SSLv3 message should not be bigger " + - "than the block size (" + blockSize + ")"); - } - } - return newLen; - } - - /* - * Position/limit is equal the removed padding. - */ - private static int removePadding(ByteBuffer bb, - int tagLen, int blockSize, - ProtocolVersion protocolVersion) throws BadPaddingException { - - int len = bb.remaining(); - int offset = bb.position(); - - // last byte is length byte (i.e. actual padding length - 1) - int padOffset = offset + len - 1; - int padLen = bb.get(padOffset) & 0xFF; - - int newLen = len - (padLen + 1); - if ((newLen - tagLen) < 0) { - // If the buffer is not long enough to contain the padding plus - // a MAC tag, do a dummy constant-time padding check. - // - // Note that it is a dummy check, so we won't care about what is - // the actual padding data. - checkPadding(bb.duplicate(), (byte)(padLen & 0xFF)); - - throw new BadPaddingException("Invalid Padding length: " + padLen); - } - - // The padding data should be filled with the padding length value. - int[] results = checkPadding( - (ByteBuffer)bb.duplicate().position(offset + newLen), - (byte)(padLen & 0xFF)); - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - if (results[0] != 0) { // padding data has invalid bytes - throw new BadPaddingException("Invalid TLS padding data"); - } - } else { // SSLv3 - // SSLv3 requires 0 <= length byte < block size - // some implementations do 1 <= length byte <= block size, - // so accept that as well - // v3 does not require any particular value for the other bytes - if (padLen > blockSize) { - throw new BadPaddingException("Padding length (" + - padLen + ") of SSLv3 message should not be bigger " + - "than the block size (" + blockSize + ")"); - } - } - - /* - * Reset buffer limit to remove padding. - */ - bb.position(offset + newLen); - bb.limit(offset + newLen); - - return newLen; - } - - /* - * Dispose of any intermediate state in the underlying cipher. - * For PKCS11 ciphers, this will release any attached sessions, and - * thus make finalization faster. - */ - void dispose() { - try { - if (cipher != null) { - // ignore return value. - cipher.doFinal(); - } - } catch (Exception e) { - // swallow all types of exceptions. - } - } - - /* - * Does the cipher use CBC mode? - * - * @return true if the cipher use CBC mode, false otherwise. - */ - boolean isCBCMode() { - return cipherType == BLOCK_CIPHER; - } - - /* - * Does the cipher use AEAD mode? - * - * @return true if the cipher use AEAD mode, false otherwise. - */ - boolean isAEADMode() { - return cipherType == AEAD_CIPHER; - } - - /* - * Is the cipher null? - * - * @return true if the cipher is null, false otherwise. - */ - boolean isNullCipher() { - return cipher == null; - } - - /* - * Gets the explicit nonce/IV size of the cipher. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @return the explicit nonce size of the cipher. - */ - int getExplicitNonceSize() { - switch (cipherType) { - case BLOCK_CIPHER: - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - return cipher.getBlockSize(); - } - break; - case AEAD_CIPHER: - return recordIvSize; - // It is also the length of sequence number, which is - // used as the nonce_explicit for AEAD cipher suites. - } - - return 0; - } - - /* - * Applies the explicit nonce/IV to this cipher. This method is used to - * decrypt an SSL/TLS input record. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param bb the byte buffer to get the explicit nonce from - * - * @return the explicit nonce size of the cipher. - */ - int applyExplicitNonce(Authenticator authenticator, byte contentType, - ByteBuffer bb) throws BadPaddingException { - switch (cipherType) { - case BLOCK_CIPHER: - // sanity check length of the ciphertext - int tagLen = (authenticator instanceof MAC) ? - ((MAC)authenticator).MAClen() : 0; - if (tagLen != 0) { - if (!sanityCheck(tagLen, bb.remaining())) { - throw new BadPaddingException( - "ciphertext sanity check failed"); - } - } - - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - return cipher.getBlockSize(); - } - break; - case AEAD_CIPHER: - if (bb.remaining() < (recordIvSize + tagSize)) { - throw new BadPaddingException( - "Insufficient buffer remaining for AEAD cipher " + - "fragment (" + bb.remaining() + "). Needs to be " + - "more than or equal to IV size (" + recordIvSize + - ") + tag size (" + tagSize + ")"); - } - - // initialize the AEAD cipher for the unique IV - byte[] iv = Arrays.copyOf(fixedIv, - fixedIv.length + recordIvSize); - bb.get(iv, fixedIv.length, recordIvSize); - bb.position(bb.position() - recordIvSize); - GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); - try { - cipher.init(mode, key, spec, random); - } catch (InvalidKeyException | - InvalidAlgorithmParameterException ikae) { - // unlikely to happen - throw new RuntimeException( - "invalid key or spec in GCM mode", ikae); - } - - // update the additional authentication data - byte[] aad = authenticator.acquireAuthenticationBytes( - contentType, bb.remaining() - recordIvSize - tagSize); - cipher.updateAAD(aad); - - return recordIvSize; - // It is also the length of sequence number, which is - // used as the nonce_explicit for AEAD cipher suites. - } - - return 0; - } - - /* - * Applies the explicit nonce/IV to this cipher. This method is used to - * decrypt an SSL/TLS input record. - * - * The returned value is the SecurityParameters.record_iv_length in - * RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param buf the byte array to get the explicit nonce from - * @param offset the offset of the byte buffer - * @param cipheredLength the ciphered fragment length of the output - * record, it is the TLSCiphertext.length in RFC 4346/5246. - * - * @return the explicit nonce size of the cipher. - */ - int applyExplicitNonce(Authenticator authenticator, - byte contentType, byte[] buf, int offset, - int cipheredLength) throws BadPaddingException { - - ByteBuffer bb = ByteBuffer.wrap(buf, offset, cipheredLength); - - return applyExplicitNonce(authenticator, contentType, bb); - } - - /* - * Creates the explicit nonce/IV to this cipher. This method is used to - * encrypt an SSL/TLS output record. - * - * The size of the returned array is the SecurityParameters.record_iv_length - * in RFC 4346/5246. It is the size of explicit IV for CBC mode, and the - * size of explicit nonce for AEAD mode. - * - * @param authenticator the authenticator to get the additional - * authentication data - * @param contentType the content type of the input record - * @param fragmentLength the fragment length of the output record, it is - * the TLSCompressed.length in RFC 4346/5246. - * - * @return the explicit nonce of the cipher. - */ - byte[] createExplicitNonce(Authenticator authenticator, - byte contentType, int fragmentLength) { - - byte[] nonce = new byte[0]; - switch (cipherType) { - case BLOCK_CIPHER: - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - // For block ciphers, the explicit IV length is of length - // SecurityParameters.record_iv_length, which is equal to - // the SecurityParameters.block_size. - // - // Generate a random number as the explicit IV parameter. - nonce = new byte[cipher.getBlockSize()]; - random.nextBytes(nonce); - } - break; - case AEAD_CIPHER: - // To be unique and aware of overflow-wrap, sequence number - // is used as the nonce_explicit of AEAD cipher suites. - nonce = authenticator.sequenceNumber(); - - // initialize the AEAD cipher for the unique IV - byte[] iv = Arrays.copyOf(fixedIv, - fixedIv.length + nonce.length); - System.arraycopy(nonce, 0, iv, fixedIv.length, nonce.length); - GCMParameterSpec spec = new GCMParameterSpec(tagSize * 8, iv); - try { - cipher.init(mode, key, spec, random); - } catch (InvalidKeyException | - InvalidAlgorithmParameterException ikae) { - // unlikely to happen - throw new RuntimeException( - "invalid key or spec in GCM mode", ikae); - } - - // update the additional authentication data - byte[] aad = authenticator.acquireAuthenticationBytes( - contentType, fragmentLength); - cipher.updateAAD(aad); - break; - } - - return nonce; - } - - /** - * Sanity check the length of a fragment before decryption. - * - * In CBC mode, check that the fragment length is one or multiple times - * of the block size of the cipher suite, and is at least one (one is the - * smallest size of padding in CBC mode) bigger than the tag size of the - * MAC algorithm except the explicit IV size for TLS 1.1 or later. - * - * In non-CBC mode, check that the fragment length is not less than the - * tag size of the MAC algorithm. - * - * @return true if the length of a fragment matches above requirements - */ - private boolean sanityCheck(int tagLen, int fragmentLen) { - if (!isCBCMode()) { - return fragmentLen >= tagLen; - } - - int blockSize = cipher.getBlockSize(); - if ((fragmentLen % blockSize) == 0) { - int minimal = tagLen + 1; - minimal = (minimal >= blockSize) ? minimal : blockSize; - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - minimal += blockSize; // plus the size of the explicit IV - } - - return (fragmentLen >= minimal); - } - - return false; - } - -}
--- a/src/share/classes/sun/security/ssl/CipherSuite.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1618 +0,0 @@ -/* - * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.*; - -import java.security.NoSuchAlgorithmException; -import java.security.InvalidKeyException; -import java.security.SecureRandom; -import java.security.KeyManagementException; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import static sun.security.ssl.CipherSuite.KeyExchange.*; -import static sun.security.ssl.CipherSuite.PRF.*; -import static sun.security.ssl.CipherSuite.CipherType.*; -import static sun.security.ssl.JsseJce.*; - -/** - * An SSL/TLS CipherSuite. Constants for the standard key exchange, cipher, - * and mac algorithms are also defined in this class. - * - * The CipherSuite class and the inner classes defined in this file roughly - * follow the type safe enum pattern described in Effective Java. This means: - * - * . instances are immutable, classes are final - * - * . there is a unique instance of every value, i.e. there are never two - * instances representing the same CipherSuite, etc. This means equality - * tests can be performed using == instead of equals() (although that works - * as well). [A minor exception are *unsupported* CipherSuites read from a - * handshake message, but this is usually irrelevant] - * - * . instances are obtained using the static valueOf() factory methods. - * - * . properties are defined as final variables and made available as - * package private variables without method accessors - * - * . if the member variable allowed is false, the given algorithm is either - * unavailable or disabled at compile time - * - */ -final class CipherSuite implements Comparable<CipherSuite> { - - // minimum priority for supported CipherSuites - final static int SUPPORTED_SUITES_PRIORITY = 1; - - // minimum priority for default enabled CipherSuites - final static int DEFAULT_SUITES_PRIORITY = 300; - - private final static boolean ALLOW_ECC = Debug.getBooleanProperty - ("com.sun.net.ssl.enableECC", true); - - // Map Integer(id) -> CipherSuite - // contains all known CipherSuites - private final static Map<Integer,CipherSuite> idMap; - - // Map String(name) -> CipherSuite - // contains only supported CipherSuites (i.e. allowed == true) - private final static Map<String,CipherSuite> nameMap; - - // Protocol defined CipherSuite name, e.g. SSL_RSA_WITH_RC4_128_MD5 - // we use TLS_* only for new CipherSuites, still SSL_* for old ones - final String name; - - // id in 16 bit MSB format, i.e. 0x0004 for SSL_RSA_WITH_RC4_128_MD5 - final int id; - - // priority for the internal default preference order. the higher the - // better. Each supported CipherSuite *must* have a unique priority. - // Ciphersuites with priority >= DEFAULT_SUITES_PRIORITY are enabled - // by default - final int priority; - - // key exchange, bulk cipher, mac and prf algorithms. See those - // classes below. - final KeyExchange keyExchange; - final BulkCipher cipher; - final MacAlg macAlg; - final PRF prfAlg; - - // whether a CipherSuite qualifies as exportable under 512/40 bit rules. - // TLS 1.1+ (RFC 4346) must not negotiate to these suites. - final boolean exportable; - - // true iff implemented and enabled at compile time - final boolean allowed; - - // obsoleted since protocol version - final int obsoleted; - - // supported since protocol version - final int supported; - - /** - * Constructor for implemented CipherSuites. - */ - private CipherSuite(String name, int id, int priority, - KeyExchange keyExchange, BulkCipher cipher, - boolean allowed, int obsoleted, int supported, PRF prfAlg) { - this.name = name; - this.id = id; - this.priority = priority; - this.keyExchange = keyExchange; - this.cipher = cipher; - this.exportable = cipher.exportable; - if (cipher.cipherType == CipherType.AEAD_CIPHER) { - macAlg = M_NULL; - } else if (name.endsWith("_MD5")) { - macAlg = M_MD5; - } else if (name.endsWith("_SHA")) { - macAlg = M_SHA; - } else if (name.endsWith("_SHA256")) { - macAlg = M_SHA256; - } else if (name.endsWith("_SHA384")) { - macAlg = M_SHA384; - } else if (name.endsWith("_NULL")) { - macAlg = M_NULL; - } else if (name.endsWith("_SCSV")) { - macAlg = M_NULL; - } else { - throw new IllegalArgumentException - ("Unknown MAC algorithm for ciphersuite " + name); - } - - allowed &= keyExchange.allowed; - allowed &= cipher.allowed; - this.allowed = allowed; - this.obsoleted = obsoleted; - this.supported = supported; - this.prfAlg = prfAlg; - } - - /** - * Constructor for unimplemented CipherSuites. - */ - private CipherSuite(String name, int id) { - this.name = name; - this.id = id; - this.allowed = false; - - this.priority = 0; - this.keyExchange = null; - this.cipher = null; - this.macAlg = null; - this.exportable = false; - this.obsoleted = ProtocolVersion.LIMIT_MAX_VALUE; - this.supported = ProtocolVersion.LIMIT_MIN_VALUE; - this.prfAlg = P_NONE; - } - - /** - * Return whether this CipherSuite is available for use. A - * CipherSuite may be unavailable even if it is supported - * (i.e. allowed == true) if the required JCE cipher is not installed. - */ - boolean isAvailable() { - return allowed && keyExchange.isAvailable() && cipher.isAvailable(); - } - - boolean isNegotiable() { - return this != C_SCSV && isAvailable(); - } - - /** - * Compares CipherSuites based on their priority. Has the effect of - * sorting CipherSuites when put in a sorted collection, which is - * used by CipherSuiteList. Follows standard Comparable contract. - * - * Note that for unsupported CipherSuites parsed from a handshake - * message we violate the equals() contract. - */ - @Override - public int compareTo(CipherSuite o) { - return o.priority - priority; - } - - /** - * Returns this.name. - */ - @Override - public String toString() { - return name; - } - - /** - * Return a CipherSuite for the given name. The returned CipherSuite - * is supported by this implementation but may not actually be - * currently useable. See isAvailable(). - * - * @exception IllegalArgumentException if the CipherSuite is unknown or - * unsupported. - */ - static CipherSuite valueOf(String s) { - if (s == null) { - throw new IllegalArgumentException("Name must not be null"); - } - - CipherSuite c = nameMap.get(s); - if ((c == null) || (c.allowed == false)) { - throw new IllegalArgumentException("Unsupported ciphersuite " + s); - } - - return c; - } - - /** - * Return a CipherSuite with the given ID. A temporary object is - * constructed if the ID is unknown. Use isAvailable() to verify that - * the CipherSuite can actually be used. - */ - static CipherSuite valueOf(int id1, int id2) { - id1 &= 0xff; - id2 &= 0xff; - int id = (id1 << 8) | id2; - CipherSuite c = idMap.get(id); - if (c == null) { - String h1 = Integer.toString(id1, 16); - String h2 = Integer.toString(id2, 16); - c = new CipherSuite("Unknown 0x" + h1 + ":0x" + h2, id); - } - return c; - } - - // for use by CipherSuiteList only - static Collection<CipherSuite> allowedCipherSuites() { - return nameMap.values(); - } - - /* - * Use this method when all of the values need to be specified. - * This is primarily used when defining a new ciphersuite for - * TLS 1.2+ that doesn't use the "default" PRF. - */ - private static void add(String name, int id, int priority, - KeyExchange keyExchange, BulkCipher cipher, - boolean allowed, int obsoleted, int supported, PRF prf) { - - CipherSuite c = new CipherSuite(name, id, priority, keyExchange, - cipher, allowed, obsoleted, supported, prf); - if (idMap.put(id, c) != null) { - throw new RuntimeException("Duplicate ciphersuite definition: " - + id + ", " + name); - } - if (c.allowed) { - if (nameMap.put(name, c) != null) { - throw new RuntimeException("Duplicate ciphersuite definition: " - + id + ", " + name); - } - } - } - - /* - * Use this method when there is no lower protocol limit where this - * suite can be used, and the PRF is P_SHA256. That is, the - * existing ciphersuites. From RFC 5246: - * - * All cipher suites in this document use P_SHA256. - */ - private static void add(String name, int id, int priority, - KeyExchange keyExchange, BulkCipher cipher, - boolean allowed, int obsoleted) { - // If this is an obsoleted suite, then don't let the TLS 1.2 - // protocol have a valid PRF value. - PRF prf = P_SHA256; - if (obsoleted < ProtocolVersion.TLS12.v) { - prf = P_NONE; - } - - add(name, id, priority, keyExchange, cipher, allowed, obsoleted, - ProtocolVersion.LIMIT_MIN_VALUE, prf); - } - - /* - * Use this method when there is no upper protocol limit. That is, - * suites which have not been obsoleted. - */ - private static void add(String name, int id, int priority, - KeyExchange keyExchange, BulkCipher cipher, boolean allowed) { - add(name, id, priority, keyExchange, - cipher, allowed, ProtocolVersion.LIMIT_MAX_VALUE); - } - - /* - * Use this method to define an unimplemented suite. This provides - * a number<->name mapping that can be used for debugging. - */ - private static void add(String name, int id) { - CipherSuite c = new CipherSuite(name, id); - if (idMap.put(id, c) != null) { - throw new RuntimeException("Duplicate ciphersuite definition: " - + id + ", " + name); - } - } - - /** - * An SSL/TLS key exchange algorithm. - */ - static enum KeyExchange { - - // key exchange algorithms - K_NULL ("NULL", false, false), - K_RSA ("RSA", true, false), - K_RSA_EXPORT ("RSA_EXPORT", true, false), - K_DH_RSA ("DH_RSA", false, false), - K_DH_DSS ("DH_DSS", false, false), - K_DHE_DSS ("DHE_DSS", true, false), - K_DHE_RSA ("DHE_RSA", true, false), - K_DH_ANON ("DH_anon", true, false), - - K_ECDH_ECDSA ("ECDH_ECDSA", ALLOW_ECC, true), - K_ECDH_RSA ("ECDH_RSA", ALLOW_ECC, true), - K_ECDHE_ECDSA("ECDHE_ECDSA", ALLOW_ECC, true), - K_ECDHE_RSA ("ECDHE_RSA", ALLOW_ECC, true), - K_ECDH_ANON ("ECDH_anon", ALLOW_ECC, true), - - // Kerberos cipher suites - K_KRB5 ("KRB5", true, false), - K_KRB5_EXPORT("KRB5_EXPORT", true, false), - - // renegotiation protection request signaling cipher suite - K_SCSV ("SCSV", true, false); - - // name of the key exchange algorithm, e.g. DHE_DSS - final String name; - final boolean allowed; - final boolean isEC; - private final boolean alwaysAvailable; - - KeyExchange(String name, boolean allowed, boolean isEC) { - this.name = name; - this.allowed = allowed; - this.isEC = isEC; - this.alwaysAvailable = allowed && - (!name.startsWith("EC")) && (!name.startsWith("KRB")); - } - - boolean isAvailable() { - if (alwaysAvailable) { - return true; - } - - if (isEC) { - return (allowed && JsseJce.isEcAvailable()); - } else if (name.startsWith("KRB")) { - return (allowed && JsseJce.isKerberosAvailable()); - } else { - return allowed; - } - } - - @Override - public String toString() { - return name; - } - } - - static enum CipherType { - STREAM_CIPHER, // null or stream cipher - BLOCK_CIPHER, // block cipher in CBC mode - AEAD_CIPHER // AEAD cipher - } - - /** - * An SSL/TLS bulk cipher algorithm. One instance per combination of - * cipher and key length. - * - * Also contains a factory method to obtain in initialized CipherBox - * for this algorithm. - */ - final static class BulkCipher { - - // descriptive name including key size, e.g. AES/128 - final String description; - - // JCE cipher transformation string, e.g. AES/CBC/NoPadding - final String transformation; - - // algorithm name, e.g. AES - final String algorithm; - - // supported and compile time enabled. Also see isAvailable() - final boolean allowed; - - // number of bytes of entropy in the key - final int keySize; - - // length of the actual cipher key in bytes. - // for non-exportable ciphers, this is the same as keySize - final int expandedKeySize; - - // size of the IV - final int ivSize; - - // size of fixed IV - // - // record_iv_length = ivSize - fixedIvSize - final int fixedIvSize; - - // exportable under 512/40 bit rules - final boolean exportable; - - // Is the cipher algorithm of Cipher Block Chaining (CBC) mode? - final CipherType cipherType; - - // size of the authentication tag, only applicable to cipher suites in - // Galois Counter Mode (GCM) - // - // As far as we know, all supported GCM cipher suites use 128-bits - // authentication tags. - final int tagSize = 16; - - // The secure random used to detect the cipher availability. - private final static SecureRandom secureRandom; - - // runtime availability - private final boolean isAvailable; - - static { - try { - secureRandom = JsseJce.getSecureRandom(); - } catch (KeyManagementException kme) { - throw new RuntimeException(kme); - } - } - - BulkCipher(String transformation, CipherType cipherType, int keySize, - int expandedKeySize, int ivSize, - int fixedIvSize, boolean allowed) { - - this.transformation = transformation; - String[] splits = transformation.split("/"); - this.algorithm = splits[0]; - this.cipherType = cipherType; - this.description = this.algorithm + "/" + (keySize << 3); - this.keySize = keySize; - this.ivSize = ivSize; - this.fixedIvSize = fixedIvSize; - this.allowed = allowed; - - this.expandedKeySize = expandedKeySize; - this.exportable = true; - - // availability of this bulk cipher - // - // Currently all supported ciphers except AES are always available - // via the JSSE internal implementations. We also assume AES/128 of - // CBC mode is always available since it is shipped with the SunJCE - // provider. However, AES/256 is unavailable when the default JCE - // policy jurisdiction files are installed because of key length - // restrictions. - this.isAvailable = - allowed ? isUnlimited(keySize, transformation) : false; - } - - BulkCipher(String transformation, CipherType cipherType, int keySize, - int ivSize, int fixedIvSize, boolean allowed) { - this.transformation = transformation; - String[] splits = transformation.split("/"); - this.algorithm = splits[0]; - this.cipherType = cipherType; - this.description = this.algorithm + "/" + (keySize << 3); - this.keySize = keySize; - this.ivSize = ivSize; - this.fixedIvSize = fixedIvSize; - this.allowed = allowed; - - this.expandedKeySize = keySize; - this.exportable = false; - - // availability of this bulk cipher - // - // Currently all supported ciphers except AES are always available - // via the JSSE internal implementations. We also assume AES/128 of - // CBC mode is always available since it is shipped with the SunJCE - // provider. However, AES/256 is unavailable when the default JCE - // policy jurisdiction files are installed because of key length - // restrictions. - this.isAvailable = - allowed ? isUnlimited(keySize, transformation) : false; - } - - /** - * Return an initialized CipherBox for this BulkCipher. - * IV must be null for stream ciphers. - * - * @exception NoSuchAlgorithmException if anything goes wrong - */ - CipherBox newCipher(ProtocolVersion version, SecretKey key, - IvParameterSpec iv, SecureRandom random, - boolean encrypt) throws NoSuchAlgorithmException { - return CipherBox.newCipherBox(version, this, - key, iv, random, encrypt); - } - - /** - * Test if this bulk cipher is available. For use by CipherSuite. - */ - boolean isAvailable() { - return this.isAvailable; - } - - private static boolean isUnlimited(int keySize, String transformation) { - int keySizeInBits = keySize * 8; - if (keySizeInBits > 128) { // need the JCE unlimited - // strength jurisdiction policy - try { - if (Cipher.getMaxAllowedKeyLength( - transformation) < keySizeInBits) { - - return false; - } - } catch (Exception e) { - return false; - } - } - - return true; - } - - @Override - public String toString() { - return description; - } - } - - /** - * An SSL/TLS key MAC algorithm. - * - * Also contains a factory method to obtain an initialized MAC - * for this algorithm. - */ - final static class MacAlg { - - // descriptive name, e.g. MD5 - final String name; - - // size of the MAC value (and MAC key) in bytes - final int size; - - // block size of the underlying hash algorithm - final int hashBlockSize; - - // minimal padding size of the underlying hash algorithm - final int minimalPaddingSize; - - MacAlg(String name, int size, - int hashBlockSize, int minimalPaddingSize) { - this.name = name; - this.size = size; - this.hashBlockSize = hashBlockSize; - this.minimalPaddingSize = minimalPaddingSize; - } - - /** - * Return an initialized MAC for this MacAlg. ProtocolVersion - * must either be SSL30 (SSLv3 custom MAC) or TLS10 (std. HMAC). - * - * @exception NoSuchAlgorithmException if anything goes wrong - */ - MAC newMac(ProtocolVersion protocolVersion, SecretKey secret) - throws NoSuchAlgorithmException, InvalidKeyException { - return new MAC(this, protocolVersion, secret); - } - - @Override - public String toString() { - return name; - } - } - - // export strength ciphers - final static BulkCipher B_NULL = - new BulkCipher("NULL", STREAM_CIPHER, 0, 0, 0, 0, true); - final static BulkCipher B_RC4_40 = - new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 5, 16, 0, 0, true); - final static BulkCipher B_RC2_40 = - new BulkCipher("RC2", BLOCK_CIPHER, 5, 16, 8, 0, false); - final static BulkCipher B_DES_40 = - new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 5, 8, 8, 0, true); - - // domestic strength ciphers - final static BulkCipher B_RC4_128 = - new BulkCipher(CIPHER_RC4, STREAM_CIPHER, 16, 0, 0, true); - final static BulkCipher B_DES = - new BulkCipher(CIPHER_DES, BLOCK_CIPHER, 8, 8, 0, true); - final static BulkCipher B_3DES = - new BulkCipher(CIPHER_3DES, BLOCK_CIPHER, 24, 8, 0, true); - final static BulkCipher B_IDEA = - new BulkCipher("IDEA", BLOCK_CIPHER, 16, 8, 0, false); - final static BulkCipher B_AES_128 = - new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 16, 16, 0, true); - final static BulkCipher B_AES_256 = - new BulkCipher(CIPHER_AES, BLOCK_CIPHER, 32, 16, 0, true); - final static BulkCipher B_AES_128_GCM = - new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 16, 12, 4, true); - final static BulkCipher B_AES_256_GCM = - new BulkCipher(CIPHER_AES_GCM, AEAD_CIPHER, 32, 12, 4, true); - - // MACs - final static MacAlg M_NULL = new MacAlg("NULL", 0, 0, 0); - final static MacAlg M_MD5 = new MacAlg("MD5", 16, 64, 9); - final static MacAlg M_SHA = new MacAlg("SHA", 20, 64, 9); - final static MacAlg M_SHA256 = new MacAlg("SHA256", 32, 64, 9); - final static MacAlg M_SHA384 = new MacAlg("SHA384", 48, 128, 17); - - /** - * PRFs (PseudoRandom Function) from TLS specifications. - * - * TLS 1.1- uses a single MD5/SHA1-based PRF algorithm for generating - * the necessary material. - * - * In TLS 1.2+, all existing/known CipherSuites use SHA256, however - * new Ciphersuites (e.g. RFC 5288) can define specific PRF hash - * algorithms. - */ - static enum PRF { - - // PRF algorithms - P_NONE( "NONE", 0, 0), - P_SHA256("SHA-256", 32, 64), - P_SHA384("SHA-384", 48, 128), - P_SHA512("SHA-512", 64, 128); // not currently used. - - // PRF characteristics - private final String prfHashAlg; - private final int prfHashLength; - private final int prfBlockSize; - - PRF(String prfHashAlg, int prfHashLength, int prfBlockSize) { - this.prfHashAlg = prfHashAlg; - this.prfHashLength = prfHashLength; - this.prfBlockSize = prfBlockSize; - } - - String getPRFHashAlg() { - return prfHashAlg; - } - - int getPRFHashLength() { - return prfHashLength; - } - - int getPRFBlockSize() { - return prfBlockSize; - } - } - - static { - idMap = new HashMap<Integer,CipherSuite>(); - nameMap = new HashMap<String,CipherSuite>(); - - final boolean F = false; - final boolean T = true; - // N: ciphersuites only allowed if we are not in FIPS mode - final boolean N = (SunJSSE.isFIPS() == false); - - /* - * TLS Cipher Suite Registry, as of November 2015. - * - * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml - * - * Range Registration Procedures Notes - * 000-191 Standards Action Refers to value of first byte - * 192-254 Specification Required Refers to value of first byte - * 255 Reserved for Private Use Refers to value of first byte - * - * Value Description Reference - * 0x00,0x00 TLS_NULL_WITH_NULL_NULL [RFC5246] - * 0x00,0x01 TLS_RSA_WITH_NULL_MD5 [RFC5246] - * 0x00,0x02 TLS_RSA_WITH_NULL_SHA [RFC5246] - * 0x00,0x03 TLS_RSA_EXPORT_WITH_RC4_40_MD5 [RFC4346] - * 0x00,0x04 TLS_RSA_WITH_RC4_128_MD5 [RFC5246] - * 0x00,0x05 TLS_RSA_WITH_RC4_128_SHA [RFC5246] - * 0x00,0x06 TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 [RFC4346] - * 0x00,0x07 TLS_RSA_WITH_IDEA_CBC_SHA [RFC5469] - * 0x00,0x08 TLS_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x09 TLS_RSA_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x0A TLS_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x0B TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x0C TLS_DH_DSS_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x0D TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x0E TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x0F TLS_DH_RSA_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x10 TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x11 TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x12 TLS_DHE_DSS_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x13 TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x14 TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x15 TLS_DHE_RSA_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x16 TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x17 TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 [RFC4346] - * 0x00,0x18 TLS_DH_anon_WITH_RC4_128_MD5 [RFC5246] - * 0x00,0x19 TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA [RFC4346] - * 0x00,0x1A TLS_DH_anon_WITH_DES_CBC_SHA [RFC5469] - * 0x00,0x1B TLS_DH_anon_WITH_3DES_EDE_CBC_SHA [RFC5246] - * 0x00,0x1C-1D Reserved to avoid conflicts with SSLv3 [RFC5246] - * 0x00,0x1E TLS_KRB5_WITH_DES_CBC_SHA [RFC2712] - * 0x00,0x1F TLS_KRB5_WITH_3DES_EDE_CBC_SHA [RFC2712] - * 0x00,0x20 TLS_KRB5_WITH_RC4_128_SHA [RFC2712] - * 0x00,0x21 TLS_KRB5_WITH_IDEA_CBC_SHA [RFC2712] - * 0x00,0x22 TLS_KRB5_WITH_DES_CBC_MD5 [RFC2712] - * 0x00,0x23 TLS_KRB5_WITH_3DES_EDE_CBC_MD5 [RFC2712] - * 0x00,0x24 TLS_KRB5_WITH_RC4_128_MD5 [RFC2712] - * 0x00,0x25 TLS_KRB5_WITH_IDEA_CBC_MD5 [RFC2712] - * 0x00,0x26 TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA [RFC2712] - * 0x00,0x27 TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA [RFC2712] - * 0x00,0x28 TLS_KRB5_EXPORT_WITH_RC4_40_SHA [RFC2712] - * 0x00,0x29 TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 [RFC2712] - * 0x00,0x2A TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5 [RFC2712] - * 0x00,0x2B TLS_KRB5_EXPORT_WITH_RC4_40_MD5 [RFC2712] - * 0x00,0x2C TLS_PSK_WITH_NULL_SHA [RFC4785] - * 0x00,0x2D TLS_DHE_PSK_WITH_NULL_SHA [RFC4785] - * 0x00,0x2E TLS_RSA_PSK_WITH_NULL_SHA [RFC4785] - * 0x00,0x2F TLS_RSA_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x30 TLS_DH_DSS_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x31 TLS_DH_RSA_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x32 TLS_DHE_DSS_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x33 TLS_DHE_RSA_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x34 TLS_DH_anon_WITH_AES_128_CBC_SHA [RFC5246] - * 0x00,0x35 TLS_RSA_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x36 TLS_DH_DSS_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x37 TLS_DH_RSA_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x38 TLS_DHE_DSS_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x39 TLS_DHE_RSA_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x3A TLS_DH_anon_WITH_AES_256_CBC_SHA [RFC5246] - * 0x00,0x3B TLS_RSA_WITH_NULL_SHA256 [RFC5246] - * 0x00,0x3C TLS_RSA_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x3D TLS_RSA_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x3E TLS_DH_DSS_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x3F TLS_DH_RSA_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x40 TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x41 TLS_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x42 TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x43 TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x44 TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x45 TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x46 TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA [RFC5932] - * 0x00,0x47-4F Reserved to avoid conflicts with - * deployed implementations [Pasi_Eronen] - * 0x00,0x50-58 Reserved to avoid conflicts [Pasi Eronen] - * 0x00,0x59-5C Reserved to avoid conflicts with - * deployed implementations [Pasi_Eronen] - * 0x00,0x5D-5F Unassigned - * 0x00,0x60-66 Reserved to avoid conflicts with widely - * deployed implementations [Pasi_Eronen] - * 0x00,0x67 TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x68 TLS_DH_DSS_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x69 TLS_DH_RSA_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x6A TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x6B TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x6C TLS_DH_anon_WITH_AES_128_CBC_SHA256 [RFC5246] - * 0x00,0x6D TLS_DH_anon_WITH_AES_256_CBC_SHA256 [RFC5246] - * 0x00,0x6E-83 Unassigned - * 0x00,0x84 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x85 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x86 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x87 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x88 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x89 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA [RFC5932] - * 0x00,0x8A TLS_PSK_WITH_RC4_128_SHA [RFC4279] - * 0x00,0x8B TLS_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279] - * 0x00,0x8C TLS_PSK_WITH_AES_128_CBC_SHA [RFC4279] - * 0x00,0x8D TLS_PSK_WITH_AES_256_CBC_SHA [RFC4279] - * 0x00,0x8E TLS_DHE_PSK_WITH_RC4_128_SHA [RFC4279] - * 0x00,0x8F TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279] - * 0x00,0x90 TLS_DHE_PSK_WITH_AES_128_CBC_SHA [RFC4279] - * 0x00,0x91 TLS_DHE_PSK_WITH_AES_256_CBC_SHA [RFC4279] - * 0x00,0x92 TLS_RSA_PSK_WITH_RC4_128_SHA [RFC4279] - * 0x00,0x93 TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA [RFC4279] - * 0x00,0x94 TLS_RSA_PSK_WITH_AES_128_CBC_SHA [RFC4279] - * 0x00,0x95 TLS_RSA_PSK_WITH_AES_256_CBC_SHA [RFC4279] - * 0x00,0x96 TLS_RSA_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x97 TLS_DH_DSS_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x98 TLS_DH_RSA_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x99 TLS_DHE_DSS_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x9A TLS_DHE_RSA_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x9B TLS_DH_anon_WITH_SEED_CBC_SHA [RFC4162] - * 0x00,0x9C TLS_RSA_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0x9D TLS_RSA_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0x9E TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0x9F TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0xA0 TLS_DH_RSA_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0xA1 TLS_DH_RSA_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0xA2 TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0xA3 TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0xA4 TLS_DH_DSS_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0xA5 TLS_DH_DSS_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0xA6 TLS_DH_anon_WITH_AES_128_GCM_SHA256 [RFC5288] - * 0x00,0xA7 TLS_DH_anon_WITH_AES_256_GCM_SHA384 [RFC5288] - * 0x00,0xA8 TLS_PSK_WITH_AES_128_GCM_SHA256 [RFC5487] - * 0x00,0xA9 TLS_PSK_WITH_AES_256_GCM_SHA384 [RFC5487] - * 0x00,0xAA TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 [RFC5487] - * 0x00,0xAB TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 [RFC5487] - * 0x00,0xAC TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 [RFC5487] - * 0x00,0xAD TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 [RFC5487] - * 0x00,0xAE TLS_PSK_WITH_AES_128_CBC_SHA256 [RFC5487] - * 0x00,0xAF TLS_PSK_WITH_AES_256_CBC_SHA384 [RFC5487] - * 0x00,0xB0 TLS_PSK_WITH_NULL_SHA256 [RFC5487] - * 0x00,0xB1 TLS_PSK_WITH_NULL_SHA384 [RFC5487] - * 0x00,0xB2 TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5487] - * 0x00,0xB3 TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5487] - * 0x00,0xB4 TLS_DHE_PSK_WITH_NULL_SHA256 [RFC5487] - * 0x00,0xB5 TLS_DHE_PSK_WITH_NULL_SHA384 [RFC5487] - * 0x00,0xB6 TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 [RFC5487] - * 0x00,0xB7 TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 [RFC5487] - * 0x00,0xB8 TLS_RSA_PSK_WITH_NULL_SHA256 [RFC5487] - * 0x00,0xB9 TLS_RSA_PSK_WITH_NULL_SHA384 [RFC5487] - * 0x00,0xBA TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xBB TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xBC TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xBD TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xBE TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xBF TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 [RFC5932] - * 0x00,0xC0 TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC1 TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC2 TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC3 TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC4 TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC5 TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 [RFC5932] - * 0x00,0xC6-FE Unassigned - * 0x00,0xFF TLS_EMPTY_RENEGOTIATION_INFO_SCSV [RFC5746] - * 0x01-55,* Unassigned - * 0x56,0x00 TLS_FALLBACK_SCSV [RFC7507] - * 0x56,0x01-0xC0,0x00 Unassigned - * 0xC0,0x01 TLS_ECDH_ECDSA_WITH_NULL_SHA [RFC4492] - * 0xC0,0x02 TLS_ECDH_ECDSA_WITH_RC4_128_SHA [RFC4492] - * 0xC0,0x03 TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492] - * 0xC0,0x04 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA [RFC4492] - * 0xC0,0x05 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA [RFC4492] - * 0xC0,0x06 TLS_ECDHE_ECDSA_WITH_NULL_SHA [RFC4492] - * 0xC0,0x07 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA [RFC4492] - * 0xC0,0x08 TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA [RFC4492] - * 0xC0,0x09 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA [RFC4492] - * 0xC0,0x0A TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA [RFC4492] - * 0xC0,0x0B TLS_ECDH_RSA_WITH_NULL_SHA [RFC4492] - * 0xC0,0x0C TLS_ECDH_RSA_WITH_RC4_128_SHA [RFC4492] - * 0xC0,0x0D TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492] - * 0xC0,0x0E TLS_ECDH_RSA_WITH_AES_128_CBC_SHA [RFC4492] - * 0xC0,0x0F TLS_ECDH_RSA_WITH_AES_256_CBC_SHA [RFC4492] - * 0xC0,0x10 TLS_ECDHE_RSA_WITH_NULL_SHA [RFC4492] - * 0xC0,0x11 TLS_ECDHE_RSA_WITH_RC4_128_SHA [RFC4492] - * 0xC0,0x12 TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA [RFC4492] - * 0xC0,0x13 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA [RFC4492] - * 0xC0,0x14 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA [RFC4492] - * 0xC0,0x15 TLS_ECDH_anon_WITH_NULL_SHA [RFC4492] - * 0xC0,0x16 TLS_ECDH_anon_WITH_RC4_128_SHA [RFC4492] - * 0xC0,0x17 TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA [RFC4492] - * 0xC0,0x18 TLS_ECDH_anon_WITH_AES_128_CBC_SHA [RFC4492] - * 0xC0,0x19 TLS_ECDH_anon_WITH_AES_256_CBC_SHA [RFC4492] - * 0xC0,0x1A TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA [RFC5054] - * 0xC0,0x1B TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA [RFC5054] - * 0xC0,0x1C TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA [RFC5054] - * 0xC0,0x1D TLS_SRP_SHA_WITH_AES_128_CBC_SHA [RFC5054] - * 0xC0,0x1E TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA [RFC5054] - * 0xC0,0x1F TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA [RFC5054] - * 0xC0,0x20 TLS_SRP_SHA_WITH_AES_256_CBC_SHA [RFC5054] - * 0xC0,0x21 TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA [RFC5054] - * 0xC0,0x22 TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA [RFC5054] - * 0xC0,0x23 TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289] - * 0xC0,0x24 TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289] - * 0xC0,0x25 TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 [RFC5289] - * 0xC0,0x26 TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 [RFC5289] - * 0xC0,0x27 TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 [RFC5289] - * 0xC0,0x28 TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 [RFC5289] - * 0xC0,0x29 TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 [RFC5289] - * 0xC0,0x2A TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 [RFC5289] - * 0xC0,0x2B TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289] - * 0xC0,0x2C TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289] - * 0xC0,0x2D TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 [RFC5289] - * 0xC0,0x2E TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 [RFC5289] - * 0xC0,0x2F TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 [RFC5289] - * 0xC0,0x30 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 [RFC5289] - * 0xC0,0x31 TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 [RFC5289] - * 0xC0,0x32 TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 [RFC5289] - * 0xC0,0x33 TLS_ECDHE_PSK_WITH_RC4_128_SHA [RFC5489] - * 0xC0,0x34 TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA [RFC5489] - * 0xC0,0x35 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA [RFC5489] - * 0xC0,0x36 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA [RFC5489] - * 0xC0,0x37 TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 [RFC5489] - * 0xC0,0x38 TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 [RFC5489] - * 0xC0,0x39 TLS_ECDHE_PSK_WITH_NULL_SHA [RFC5489] - * 0xC0,0x3A TLS_ECDHE_PSK_WITH_NULL_SHA256 [RFC5489] - * 0xC0,0x3B TLS_ECDHE_PSK_WITH_NULL_SHA384 [RFC5489] - * 0xC0,0x3C TLS_RSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x3D TLS_RSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x3E TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x3F TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x40 TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x41 TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x42 TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x43 TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x44 TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x45 TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x46 TLS_DH_anon_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x47 TLS_DH_anon_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x48 TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x49 TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x4A TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x4B TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x4C TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x4D TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x4E TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x4F TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x50 TLS_RSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x51 TLS_RSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x52 TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x53 TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x54 TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x55 TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x56 TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x57 TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x58 TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x59 TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x5A TLS_DH_anon_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x5B TLS_DH_anon_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x5C TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x5D TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x5E TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x5F TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x60 TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x61 TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x62 TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x63 TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x64 TLS_PSK_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x65 TLS_PSK_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x66 TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x67 TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x68 TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x69 TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x6A TLS_PSK_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x6B TLS_PSK_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x6C TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x6D TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x6E TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256 [RFC6209] - * 0xC0,0x6F TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384 [RFC6209] - * 0xC0,0x70 TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256 [RFC6209] - * 0xC0,0x71 TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384 [RFC6209] - * 0xC0,0x72 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x73 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x74 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x75 TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x76 TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x77 TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x78 TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x79 TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x7A TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x7B TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x7C TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x7D TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x7E TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x7F TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x80 TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x81 TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x82 TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x83 TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x84 TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x85 TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x86 TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x87 TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x88 TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x89 TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x8A TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x8B TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x8C TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x8D TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x8E TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x8F TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x90 TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x91 TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x92 TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 [RFC6367] - * 0xC0,0x93 TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 [RFC6367] - * 0xC0,0x94 TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x95 TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x96 TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x97 TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x98 TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x99 TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x9A TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 [RFC6367] - * 0xC0,0x9B TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 [RFC6367] - * 0xC0,0x9C TLS_RSA_WITH_AES_128_CCM [RFC6655] - * 0xC0,0x9D TLS_RSA_WITH_AES_256_CCM [RFC6655] - * 0xC0,0x9E TLS_DHE_RSA_WITH_AES_128_CCM [RFC6655] - * 0xC0,0x9F TLS_DHE_RSA_WITH_AES_256_CCM [RFC6655] - * 0xC0,0xA0 TLS_RSA_WITH_AES_128_CCM_8 [RFC6655] - * 0xC0,0xA1 TLS_RSA_WITH_AES_256_CCM_8 [RFC6655] - * 0xC0,0xA2 TLS_DHE_RSA_WITH_AES_128_CCM_8 [RFC6655] - * 0xC0,0xA3 TLS_DHE_RSA_WITH_AES_256_CCM_8 [RFC6655] - * 0xC0,0xA4 TLS_PSK_WITH_AES_128_CCM [RFC6655] - * 0xC0,0xA5 TLS_PSK_WITH_AES_256_CCM [RFC6655] - * 0xC0,0xA6 TLS_DHE_PSK_WITH_AES_128_CCM [RFC6655] - * 0xC0,0xA7 TLS_DHE_PSK_WITH_AES_256_CCM [RFC6655] - * 0xC0,0xA8 TLS_PSK_WITH_AES_128_CCM_8 [RFC6655] - * 0xC0,0xA9 TLS_PSK_WITH_AES_256_CCM_8 [RFC6655] - * 0xC0,0xAA TLS_PSK_DHE_WITH_AES_128_CCM_8 [RFC6655] - * 0xC0,0xAB TLS_PSK_DHE_WITH_AES_256_CCM_8 [RFC6655] - * 0xC0,0xAC TLS_ECDHE_ECDSA_WITH_AES_128_CCM [RFC7251] - * 0xC0,0xAD TLS_ECDHE_ECDSA_WITH_AES_256_CCM [RFC7251] - * 0xC0,0xAE TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 [RFC7251] - * 0xC0,0xAF TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 [RFC7251] - * 0xC0,0xB0-FF Unassigned - * 0xC1-FD,* Unassigned - * 0xFE,0x00-FD Unassigned - * 0xFE,0xFE-FF Reserved to avoid conflicts with widely - * deployed implementations [Pasi_Eronen] - * 0xFF,0x00-FF Reserved for Private Use [RFC5246] - */ - - add("SSL_NULL_WITH_NULL_NULL", - 0x0000, 1, K_NULL, B_NULL, F); - - /* - * Definition of the CipherSuites that are enabled by default. - * They are listed in preference order, most preferred first, using - * the following criteria: - * 1. Prefer Suite B compliant cipher suites, see RFC6460 (To be - * changed later, see below). - * 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), - * AES_128(GCM), AES_256, AES_128, 3DES-EDE. - * 3. Prefer the stronger MAC algorithm, in the order of SHA384, - * SHA256, SHA, MD5. - * 4. Prefer the better performance of key exchange and digital - * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, - * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. - */ - int p = DEFAULT_SUITES_PRIORITY * 2; - - // shorten names to fit the following table cleanly. - int max = ProtocolVersion.LIMIT_MAX_VALUE; - int tls11 = ProtocolVersion.TLS11.v; - int tls12 = ProtocolVersion.TLS12.v; - - // ID Key Exchange Cipher A obs suprt PRF - // ====== ============ ========= = === ===== ======== - - - // Placeholder for cipher suites in GCM mode. - // - // For better compatibility and interoperability, we decrease the - // priority of cipher suites in GCM mode for a while as GCM - // technologies mature in the industry. Eventually we'll move - // the GCM suites here. - - // AES_256(CBC) - add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", - 0xc024, --p, K_ECDHE_ECDSA, B_AES_256, T, max, tls12, P_SHA384); - add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", - 0xc028, --p, K_ECDHE_RSA, B_AES_256, T, max, tls12, P_SHA384); - add("TLS_RSA_WITH_AES_256_CBC_SHA256", - 0x003d, --p, K_RSA, B_AES_256, T, max, tls12, P_SHA256); - add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", - 0xc026, --p, K_ECDH_ECDSA, B_AES_256, T, max, tls12, P_SHA384); - add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", - 0xc02a, --p, K_ECDH_RSA, B_AES_256, T, max, tls12, P_SHA384); - add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", - 0x006b, --p, K_DHE_RSA, B_AES_256, T, max, tls12, P_SHA256); - add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", - 0x006a, --p, K_DHE_DSS, B_AES_256, T, max, tls12, P_SHA256); - - add("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", - 0xC00A, --p, K_ECDHE_ECDSA, B_AES_256, T); - add("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", - 0xC014, --p, K_ECDHE_RSA, B_AES_256, T); - add("TLS_RSA_WITH_AES_256_CBC_SHA", - 0x0035, --p, K_RSA, B_AES_256, T); - add("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", - 0xC005, --p, K_ECDH_ECDSA, B_AES_256, T); - add("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", - 0xC00F, --p, K_ECDH_RSA, B_AES_256, T); - add("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", - 0x0039, --p, K_DHE_RSA, B_AES_256, T); - add("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", - 0x0038, --p, K_DHE_DSS, B_AES_256, T); - - // AES_128(CBC) - add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", - 0xc023, --p, K_ECDHE_ECDSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", - 0xc027, --p, K_ECDHE_RSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_RSA_WITH_AES_128_CBC_SHA256", - 0x003c, --p, K_RSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", - 0xc025, --p, K_ECDH_ECDSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", - 0xc029, --p, K_ECDH_RSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", - 0x0067, --p, K_DHE_RSA, B_AES_128, T, max, tls12, P_SHA256); - add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", - 0x0040, --p, K_DHE_DSS, B_AES_128, T, max, tls12, P_SHA256); - - add("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", - 0xC009, --p, K_ECDHE_ECDSA, B_AES_128, T); - add("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", - 0xC013, --p, K_ECDHE_RSA, B_AES_128, T); - add("TLS_RSA_WITH_AES_128_CBC_SHA", - 0x002f, --p, K_RSA, B_AES_128, T); - add("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", - 0xC004, --p, K_ECDH_ECDSA, B_AES_128, T); - add("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", - 0xC00E, --p, K_ECDH_RSA, B_AES_128, T); - add("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", - 0x0033, --p, K_DHE_RSA, B_AES_128, T); - add("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", - 0x0032, --p, K_DHE_DSS, B_AES_128, T); - - // Cipher suites in GCM mode, see RFC 5288/5289. - // - // We may increase the priority of cipher suites in GCM mode when - // GCM technologies become mature in the industry. - - // Suite B compliant cipher suites, see RFC 6460. - // - // Note that, at present this provider is not Suite B compliant. The - // preference order of the GCM cipher suites does not follow the spec - // of RFC 6460. - add("TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", - 0xc02c, --p, K_ECDHE_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", - 0xc02b, --p, K_ECDHE_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - - // AES_256(GCM) - add("TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", - 0xc030, --p, K_ECDHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_RSA_WITH_AES_256_GCM_SHA384", - 0x009d, --p, K_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", - 0xc02e, --p, K_ECDH_ECDSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", - 0xc032, --p, K_ECDH_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", - 0x009f, --p, K_DHE_RSA, B_AES_256_GCM, T, max, tls12, P_SHA384); - add("TLS_DHE_DSS_WITH_AES_256_GCM_SHA384", - 0x00a3, --p, K_DHE_DSS, B_AES_256_GCM, T, max, tls12, P_SHA384); - - // AES_128(GCM) - add("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", - 0xc02f, --p, K_ECDHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_RSA_WITH_AES_128_GCM_SHA256", - 0x009c, --p, K_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", - 0xc02d, --p, K_ECDH_ECDSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", - 0xc031, --p, K_ECDH_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", - 0x009e, --p, K_DHE_RSA, B_AES_128_GCM, T, max, tls12, P_SHA256); - add("TLS_DHE_DSS_WITH_AES_128_GCM_SHA256", - 0x00a2, --p, K_DHE_DSS, B_AES_128_GCM, T, max, tls12, P_SHA256); - // End of cipher suites in GCM mode. - - // 3DES_EDE - add("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", - 0xC008, --p, K_ECDHE_ECDSA, B_3DES, T); - add("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", - 0xC012, --p, K_ECDHE_RSA, B_3DES, T); - add("SSL_RSA_WITH_3DES_EDE_CBC_SHA", - 0x000a, --p, K_RSA, B_3DES, T); - add("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", - 0xC003, --p, K_ECDH_ECDSA, B_3DES, T); - add("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", - 0xC00D, --p, K_ECDH_RSA, B_3DES, T); - add("SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - 0x0016, --p, K_DHE_RSA, B_3DES, T); - add("SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - 0x0013, --p, K_DHE_DSS, B_3DES, N); - - // Renegotiation protection request Signalling Cipher Suite Value (SCSV) - add("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", - 0x00ff, --p, K_SCSV, B_NULL, T); - - /* - * Definition of the CipherSuites that are supported but not enabled - * by default. - * They are listed in preference order, preferred first, using the - * following criteria: - * 1. CipherSuites for KRB5 need additional KRB5 service - * configuration, and these suites are not common in practice, - * so we put KRB5 based cipher suites at the end of the supported - * list. - * 2. If a cipher suite has been obsoleted, we put it at the end of - * the list. - * 3. Prefer the stronger bulk cipher, in the order of AES_256, - * AES_128, 3DES-EDE, RC-4, DES, DES40, RC4_40, NULL. - * 4. Prefer the stronger MAC algorithm, in the order of SHA384, - * SHA256, SHA, MD5. - * 5. Prefer the better performance of key exchange and digital - * signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, - * RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS, anonymous. - */ - p = DEFAULT_SUITES_PRIORITY; - - add("TLS_DH_anon_WITH_AES_256_GCM_SHA384", - 0x00a7, --p, K_DH_ANON, B_AES_256_GCM, N, max, tls12, P_SHA384); - add("TLS_DH_anon_WITH_AES_128_GCM_SHA256", - 0x00a6, --p, K_DH_ANON, B_AES_128_GCM, N, max, tls12, P_SHA256); - - add("TLS_DH_anon_WITH_AES_256_CBC_SHA256", - 0x006d, --p, K_DH_ANON, B_AES_256, N, max, tls12, P_SHA256); - add("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", - 0xC019, --p, K_ECDH_ANON, B_AES_256, N); - add("TLS_DH_anon_WITH_AES_256_CBC_SHA", - 0x003a, --p, K_DH_ANON, B_AES_256, N); - - add("TLS_DH_anon_WITH_AES_128_CBC_SHA256", - 0x006c, --p, K_DH_ANON, B_AES_128, N, max, tls12, P_SHA256); - add("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", - 0xC018, --p, K_ECDH_ANON, B_AES_128, N); - add("TLS_DH_anon_WITH_AES_128_CBC_SHA", - 0x0034, --p, K_DH_ANON, B_AES_128, N); - - add("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", - 0xC017, --p, K_ECDH_ANON, B_3DES, N); - add("SSL_DH_anon_WITH_3DES_EDE_CBC_SHA", - 0x001b, --p, K_DH_ANON, B_3DES, N); - - // RC-4 - add("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", - 0xC007, --p, K_ECDHE_ECDSA, B_RC4_128, N); - add("TLS_ECDHE_RSA_WITH_RC4_128_SHA", - 0xC011, --p, K_ECDHE_RSA, B_RC4_128, N); - add("SSL_RSA_WITH_RC4_128_SHA", - 0x0005, --p, K_RSA, B_RC4_128, N); - add("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", - 0xC002, --p, K_ECDH_ECDSA, B_RC4_128, N); - add("TLS_ECDH_RSA_WITH_RC4_128_SHA", - 0xC00C, --p, K_ECDH_RSA, B_RC4_128, N); - add("SSL_RSA_WITH_RC4_128_MD5", - 0x0004, --p, K_RSA, B_RC4_128, N); - - add("TLS_ECDH_anon_WITH_RC4_128_SHA", - 0xC016, --p, K_ECDH_ANON, B_RC4_128, N); - add("SSL_DH_anon_WITH_RC4_128_MD5", - 0x0018, --p, K_DH_ANON, B_RC4_128, N); - - // weak cipher suites obsoleted in TLS 1.2 - add("SSL_RSA_WITH_DES_CBC_SHA", - 0x0009, --p, K_RSA, B_DES, N, tls12); - add("SSL_DHE_RSA_WITH_DES_CBC_SHA", - 0x0015, --p, K_DHE_RSA, B_DES, N, tls12); - add("SSL_DHE_DSS_WITH_DES_CBC_SHA", - 0x0012, --p, K_DHE_DSS, B_DES, N, tls12); - add("SSL_DH_anon_WITH_DES_CBC_SHA", - 0x001a, --p, K_DH_ANON, B_DES, N, tls12); - - // weak cipher suites obsoleted in TLS 1.1 - add("SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", - 0x0008, --p, K_RSA_EXPORT, B_DES_40, N, tls11); - add("SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", - 0x0014, --p, K_DHE_RSA, B_DES_40, N, tls11); - add("SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", - 0x0011, --p, K_DHE_DSS, B_DES_40, N, tls11); - add("SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA", - 0x0019, --p, K_DH_ANON, B_DES_40, N, tls11); - - add("SSL_RSA_EXPORT_WITH_RC4_40_MD5", - 0x0003, --p, K_RSA_EXPORT, B_RC4_40, N, tls11); - add("SSL_DH_anon_EXPORT_WITH_RC4_40_MD5", - 0x0017, --p, K_DH_ANON, B_RC4_40, N, tls11); - - add("TLS_RSA_WITH_NULL_SHA256", - 0x003b, --p, K_RSA, B_NULL, N, max, tls12, P_SHA256); - add("TLS_ECDHE_ECDSA_WITH_NULL_SHA", - 0xC006, --p, K_ECDHE_ECDSA, B_NULL, N); - add("TLS_ECDHE_RSA_WITH_NULL_SHA", - 0xC010, --p, K_ECDHE_RSA, B_NULL, N); - add("SSL_RSA_WITH_NULL_SHA", - 0x0002, --p, K_RSA, B_NULL, N); - add("TLS_ECDH_ECDSA_WITH_NULL_SHA", - 0xC001, --p, K_ECDH_ECDSA, B_NULL, N); - add("TLS_ECDH_RSA_WITH_NULL_SHA", - 0xC00B, --p, K_ECDH_RSA, B_NULL, N); - add("TLS_ECDH_anon_WITH_NULL_SHA", - 0xC015, --p, K_ECDH_ANON, B_NULL, N); - add("SSL_RSA_WITH_NULL_MD5", - 0x0001, --p, K_RSA, B_NULL, N); - - // Supported Kerberos ciphersuites from RFC2712 - add("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", - 0x001f, --p, K_KRB5, B_3DES, N); - add("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", - 0x0023, --p, K_KRB5, B_3DES, N); - add("TLS_KRB5_WITH_RC4_128_SHA", - 0x0020, --p, K_KRB5, B_RC4_128, N); - add("TLS_KRB5_WITH_RC4_128_MD5", - 0x0024, --p, K_KRB5, B_RC4_128, N); - add("TLS_KRB5_WITH_DES_CBC_SHA", - 0x001e, --p, K_KRB5, B_DES, N, tls12); - add("TLS_KRB5_WITH_DES_CBC_MD5", - 0x0022, --p, K_KRB5, B_DES, N, tls12); - add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", - 0x0026, --p, K_KRB5_EXPORT, B_DES_40, N, tls11); - add("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", - 0x0029, --p, K_KRB5_EXPORT, B_DES_40, N, tls11); - add("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", - 0x0028, --p, K_KRB5_EXPORT, B_RC4_40, N, tls11); - add("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", - 0x002b, --p, K_KRB5_EXPORT, B_RC4_40, N, tls11); - - /* - * Other values from the TLS Cipher Suite Registry, as of August 2010. - * - * http://www.iana.org/assignments/tls-parameters/tls-parameters.xml - * - * Range Registration Procedures Notes - * 000-191 Standards Action Refers to value of first byte - * 192-254 Specification Required Refers to value of first byte - * 255 Reserved for Private Use Refers to value of first byte - */ - - // Register the names of a few additional CipherSuites. - // Makes them show up as names instead of numbers in - // the debug output. - - // remaining unsupported ciphersuites defined in RFC2246. - add("SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5", 0x0006); - add("SSL_RSA_WITH_IDEA_CBC_SHA", 0x0007); - add("SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", 0x000b); - add("SSL_DH_DSS_WITH_DES_CBC_SHA", 0x000c); - add("SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", 0x000d); - add("SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", 0x000e); - add("SSL_DH_RSA_WITH_DES_CBC_SHA", 0x000f); - add("SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", 0x0010); - - // SSL 3.0 Fortezza ciphersuites - add("SSL_FORTEZZA_DMS_WITH_NULL_SHA", 0x001c); - add("SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA", 0x001d); - - // 1024/56 bit exportable ciphersuites from expired internet draft - add("SSL_RSA_EXPORT1024_WITH_DES_CBC_SHA", 0x0062); - add("SSL_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA", 0x0063); - add("SSL_RSA_EXPORT1024_WITH_RC4_56_SHA", 0x0064); - add("SSL_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA", 0x0065); - add("SSL_DHE_DSS_WITH_RC4_128_SHA", 0x0066); - - // Netscape old and new SSL 3.0 FIPS ciphersuites - // see http://www.mozilla.org/projects/security/pki/nss/ssl/fips-ssl-ciphersuites.html - add("NETSCAPE_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", 0xffe0); - add("NETSCAPE_RSA_FIPS_WITH_DES_CBC_SHA", 0xffe1); - add("SSL_RSA_FIPS_WITH_DES_CBC_SHA", 0xfefe); - add("SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA", 0xfeff); - - // Unsupported Kerberos cipher suites from RFC 2712 - add("TLS_KRB5_WITH_IDEA_CBC_SHA", 0x0021); - add("TLS_KRB5_WITH_IDEA_CBC_MD5", 0x0025); - add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", 0x0027); - add("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", 0x002a); - - // Unsupported cipher suites from RFC 4162 - add("TLS_RSA_WITH_SEED_CBC_SHA", 0x0096); - add("TLS_DH_DSS_WITH_SEED_CBC_SHA", 0x0097); - add("TLS_DH_RSA_WITH_SEED_CBC_SHA", 0x0098); - add("TLS_DHE_DSS_WITH_SEED_CBC_SHA", 0x0099); - add("TLS_DHE_RSA_WITH_SEED_CBC_SHA", 0x009a); - add("TLS_DH_anon_WITH_SEED_CBC_SHA", 0x009b); - - // Unsupported cipher suites from RFC 4279 - add("TLS_PSK_WITH_RC4_128_SHA", 0x008a); - add("TLS_PSK_WITH_3DES_EDE_CBC_SHA", 0x008b); - add("TLS_PSK_WITH_AES_128_CBC_SHA", 0x008c); - add("TLS_PSK_WITH_AES_256_CBC_SHA", 0x008d); - add("TLS_DHE_PSK_WITH_RC4_128_SHA", 0x008e); - add("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", 0x008f); - add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", 0x0090); - add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", 0x0091); - add("TLS_RSA_PSK_WITH_RC4_128_SHA", 0x0092); - add("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", 0x0093); - add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", 0x0094); - add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", 0x0095); - - // Unsupported cipher suites from RFC 4785 - add("TLS_PSK_WITH_NULL_SHA", 0x002c); - add("TLS_DHE_PSK_WITH_NULL_SHA", 0x002d); - add("TLS_RSA_PSK_WITH_NULL_SHA", 0x002e); - - // Unsupported cipher suites from RFC 5246 - add("TLS_DH_DSS_WITH_AES_128_CBC_SHA", 0x0030); - add("TLS_DH_RSA_WITH_AES_128_CBC_SHA", 0x0031); - add("TLS_DH_DSS_WITH_AES_256_CBC_SHA", 0x0036); - add("TLS_DH_RSA_WITH_AES_256_CBC_SHA", 0x0037); - add("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", 0x003e); - add("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", 0x003f); - add("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", 0x0068); - add("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", 0x0069); - - // Unsupported cipher suites from RFC 5288 - add("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", 0x00a0); - add("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", 0x00a1); - add("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", 0x00a4); - add("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", 0x00a5); - - // Unsupported cipher suites from RFC 5487 - add("TLS_PSK_WITH_AES_128_GCM_SHA256", 0x00a8); - add("TLS_PSK_WITH_AES_256_GCM_SHA384", 0x00a9); - add("TLS_DHE_PSK_WITH_AES_128_GCM_SHA256", 0x00aa); - add("TLS_DHE_PSK_WITH_AES_256_GCM_SHA384", 0x00ab); - add("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", 0x00ac); - add("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", 0x00ad); - add("TLS_PSK_WITH_AES_128_CBC_SHA256", 0x00ae); - add("TLS_PSK_WITH_AES_256_CBC_SHA384", 0x00af); - add("TLS_PSK_WITH_NULL_SHA256", 0x00b0); - add("TLS_PSK_WITH_NULL_SHA384", 0x00b1); - add("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", 0x00b2); - add("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", 0x00b3); - add("TLS_DHE_PSK_WITH_NULL_SHA256", 0x00b4); - add("TLS_DHE_PSK_WITH_NULL_SHA384", 0x00b5); - add("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", 0x00b6); - add("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", 0x00b7); - add("TLS_RSA_PSK_WITH_NULL_SHA256", 0x00b8); - add("TLS_RSA_PSK_WITH_NULL_SHA384", 0x00b9); - - // Unsupported cipher suites from RFC 5932 - add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0041); - add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0042); - add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0043); - add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", 0x0044); - add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", 0x0045); - add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", 0x0046); - add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0084); - add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0085); - add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0086); - add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", 0x0087); - add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", 0x0088); - add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", 0x0089); - add("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00ba); - add("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bb); - add("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00bc); - add("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", 0x00bd); - add("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0x00be); - add("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", 0x00bf); - add("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c0); - add("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c1); - add("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c2); - add("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", 0x00c3); - add("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", 0x00c4); - add("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", 0x00c5); - - // TLS Fallback Signaling Cipher Suite Value (SCSV) RFC 7507 - add("TLS_FALLBACK_SCSV", 0x5600); - - // Unsupported cipher suites from RFC 5054 - add("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", 0xc01a); - add("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", 0xc01b); - add("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", 0xc01c); - add("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", 0xc01d); - add("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", 0xc01e); - add("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", 0xc01f); - add("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", 0xc020); - add("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", 0xc021); - add("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", 0xc022); - - // Unsupported cipher suites from RFC 5489 - add("TLS_ECDHE_PSK_WITH_RC4_128_SHA", 0xc033); - add("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", 0xc034); - add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", 0xc035); - add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", 0xc036); - add("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", 0xc037); - add("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", 0xc038); - add("TLS_ECDHE_PSK_WITH_NULL_SHA", 0xc039); - add("TLS_ECDHE_PSK_WITH_NULL_SHA256", 0xc03a); - add("TLS_ECDHE_PSK_WITH_NULL_SHA384", 0xc03b); - - // Unsupported cipher suites from RFC 6209 - add("TLS_RSA_WITH_ARIA_128_CBC_SHA256", 0xc03c); - add("TLS_RSA_WITH_ARIA_256_CBC_SHA384", 0xc03d); - add("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", 0xc03e); - add("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", 0xc03f); - add("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc040); - add("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc041); - add("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", 0xc042); - add("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", 0xc043); - add("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc044); - add("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc045); - add("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", 0xc046); - add("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", 0xc047); - add("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc048); - add("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc049); - add("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", 0xc04a); - add("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", 0xc04b); - add("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04c); - add("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04d); - add("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", 0xc04e); - add("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", 0xc04f); - add("TLS_RSA_WITH_ARIA_128_GCM_SHA256", 0xc050); - add("TLS_RSA_WITH_ARIA_256_GCM_SHA384", 0xc051); - add("TLS_DHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc052); - add("TLS_DHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc053); - add("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc054); - add("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc055); - add("TLS_DHE_DSS_WITH_ARIA_128_GCM_SHA256", 0xc056); - add("TLS_DHE_DSS_WITH_ARIA_256_GCM_SHA384", 0xc057); - add("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", 0xc058); - add("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", 0xc059); - add("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", 0xc05a); - add("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", 0xc05b); - add("TLS_ECDHE_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05c); - add("TLS_ECDHE_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05d); - add("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", 0xc05e); - add("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", 0xc05f); - add("TLS_ECDHE_RSA_WITH_ARIA_128_GCM_SHA256", 0xc060); - add("TLS_ECDHE_RSA_WITH_ARIA_256_GCM_SHA384", 0xc061); - add("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", 0xc062); - add("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", 0xc063); - add("TLS_PSK_WITH_ARIA_128_CBC_SHA256", 0xc064); - add("TLS_PSK_WITH_ARIA_256_CBC_SHA384", 0xc065); - add("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc066); - add("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc067); - add("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", 0xc068); - add("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", 0xc069); - add("TLS_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06a); - add("TLS_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06b); - add("TLS_DHE_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06c); - add("TLS_DHE_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06d); - add("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", 0xc06e); - add("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", 0xc06f); - add("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", 0xc070); - add("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", 0xc071); - - // Unsupported cipher suites from RFC 6367 - add("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc072); - add("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc073); - add("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc074); - add("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc075); - add("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc076); - add("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc077); - add("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", 0xc078); - add("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", 0xc079); - add("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07a); - add("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07b); - add("TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07c); - add("TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07d); - add("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc07e); - add("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc07f); - add("TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc080); - add("TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc081); - add("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", 0xc082); - add("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", 0xc083); - add("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", 0xc084); - add("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", 0xc085); - add("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc086); - add("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc087); - add("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc088); - add("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc089); - add("TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08a); - add("TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08b); - add("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", 0xc08c); - add("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", 0xc08d); - add("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc08e); - add("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc08f); - add("TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc090); - add("TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc091); - add("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", 0xc092); - add("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", 0xc093); - add("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc094); - add("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc095); - add("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc096); - add("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc097); - add("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc098); - add("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc099); - add("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", 0xc09a); - add("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", 0xc09b); - - // Unsupported cipher suites from RFC 6655 - add("TLS_RSA_WITH_AES_128_CCM", 0xc09c); - add("TLS_RSA_WITH_AES_256_CCM", 0xc09d); - add("TLS_DHE_RSA_WITH_AES_128_CCM", 0xc09e); - add("TLS_DHE_RSA_WITH_AES_256_CCM", 0xc09f); - add("TLS_RSA_WITH_AES_128_CCM_8", 0xc0A0); - add("TLS_RSA_WITH_AES_256_CCM_8", 0xc0A1); - add("TLS_DHE_RSA_WITH_AES_128_CCM_8", 0xc0A2); - add("TLS_DHE_RSA_WITH_AES_256_CCM_8", 0xc0A3); - add("TLS_PSK_WITH_AES_128_CCM", 0xc0A4); - add("TLS_PSK_WITH_AES_256_CCM", 0xc0A5); - add("TLS_DHE_PSK_WITH_AES_128_CCM", 0xc0A6); - add("TLS_DHE_PSK_WITH_AES_256_CCM", 0xc0A7); - add("TLS_PSK_WITH_AES_128_CCM_8", 0xc0A8); - add("TLS_PSK_WITH_AES_256_CCM_8", 0xc0A9); - add("TLS_PSK_DHE_WITH_AES_128_CCM_8", 0xc0Aa); - add("TLS_PSK_DHE_WITH_AES_256_CCM_8", 0xc0Ab); - - // Unsupported cipher suites from RFC 7251 - add("TLS_ECDHE_ECDSA_WITH_AES_128_CCM", 0xc0Ac); - add("TLS_ECDHE_ECDSA_WITH_AES_256_CCM", 0xc0Ad); - add("TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8", 0xc0Ae); - add("TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8", 0xc0Af); - } - - // ciphersuite SSL_NULL_WITH_NULL_NULL - final static CipherSuite C_NULL = CipherSuite.valueOf(0, 0); - - // ciphersuite TLS_EMPTY_RENEGOTIATION_INFO_SCSV - final static CipherSuite C_SCSV = CipherSuite.valueOf(0x00, 0xff); -}
--- a/src/share/classes/sun/security/ssl/CipherSuiteList.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.util.*; - -import javax.net.ssl.SSLException; - -/** - * A list of CipherSuites. Also maintains the lists of supported and - * default ciphersuites and supports I/O from handshake streams. - * - * Instances of this class are immutable. - * - */ -final class CipherSuiteList { - - private final Collection<CipherSuite> cipherSuites; - private String[] suiteNames; - - // flag indicating whether this list contains any ECC ciphersuites. - // null if not yet checked. - private volatile Boolean containsEC; - - // for use by buildAvailableCache() and - // Handshaker.getKickstartMessage() only - CipherSuiteList(Collection<CipherSuite> cipherSuites) { - this.cipherSuites = cipherSuites; - } - - /** - * Create a CipherSuiteList with a single element. - */ - CipherSuiteList(CipherSuite suite) { - cipherSuites = new ArrayList<CipherSuite>(1); - cipherSuites.add(suite); - } - - /** - * Construct a CipherSuiteList from a array of names. We don't bother - * to eliminate duplicates. - * - * @exception IllegalArgumentException if the array or any of its elements - * is null or if the ciphersuite name is unrecognized or unsupported - * using currently installed providers. - */ - CipherSuiteList(String[] names) { - if (names == null) { - throw new IllegalArgumentException("CipherSuites may not be null"); - } - cipherSuites = new ArrayList<CipherSuite>(names.length); - for (int i = 0; i < names.length; i++) { - String suiteName = names[i]; - CipherSuite suite = CipherSuite.valueOf(suiteName); - if (suite.isAvailable() == false) { - throw new IllegalArgumentException("Cannot support " - + suiteName + " with currently installed providers"); - } - cipherSuites.add(suite); - } - } - - /** - * Read a CipherSuiteList from a HandshakeInStream in V3 ClientHello - * format. Does not check if the listed ciphersuites are known or - * supported. - */ - CipherSuiteList(HandshakeInStream in) throws IOException { - byte[] bytes = in.getBytes16(); - if ((bytes.length & 1) != 0) { - throw new SSLException("Invalid ClientHello message"); - } - cipherSuites = new ArrayList<CipherSuite>(bytes.length >> 1); - for (int i = 0; i < bytes.length; i += 2) { - cipherSuites.add(CipherSuite.valueOf(bytes[i], bytes[i+1])); - } - } - - /** - * Return whether this list contains the given CipherSuite. - */ - boolean contains(CipherSuite suite) { - return cipherSuites.contains(suite); - } - - // Return whether this list contains any ECC ciphersuites - boolean containsEC() { - if (containsEC == null) { - for (CipherSuite c : cipherSuites) { - if (c.keyExchange.isEC) { - containsEC = true; - return true; - } - } - - containsEC = false; - } - - return containsEC; - } - - /** - * Return an Iterator for the CipherSuites in this list. - */ - Iterator<CipherSuite> iterator() { - return cipherSuites.iterator(); - } - - /** - * Return a reference to the internal Collection of CipherSuites. - * The Collection MUST NOT be modified. - */ - Collection<CipherSuite> collection() { - return cipherSuites; - } - - /** - * Return the number of CipherSuites in this list. - */ - int size() { - return cipherSuites.size(); - } - - /** - * Return an array with the names of the CipherSuites in this list. - */ - synchronized String[] toStringArray() { - if (suiteNames == null) { - suiteNames = new String[cipherSuites.size()]; - int i = 0; - for (CipherSuite c : cipherSuites) { - suiteNames[i++] = c.name; - } - } - return suiteNames.clone(); - } - - @Override - public String toString() { - return cipherSuites.toString(); - } - - /** - * Write this list to an HandshakeOutStream in V3 ClientHello format. - */ - void send(HandshakeOutStream s) throws IOException { - byte[] suiteBytes = new byte[cipherSuites.size() * 2]; - int i = 0; - for (CipherSuite c : cipherSuites) { - suiteBytes[i] = (byte)(c.id >> 8); - suiteBytes[i+1] = (byte)c.id; - i += 2; - } - s.putBytes16(suiteBytes); - } -}
--- a/src/share/classes/sun/security/ssl/ClientHandshaker.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1812 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.math.BigInteger; -import java.security.*; -import java.util.*; - -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.ECParameterSpec; - -import java.security.cert.X509Certificate; -import java.security.cert.CertificateException; -import java.security.cert.CertificateParsingException; -import javax.security.auth.x500.X500Principal; - -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import javax.net.ssl.*; - -import javax.security.auth.Subject; - -import sun.security.ssl.HandshakeMessage.*; -import static sun.security.ssl.CipherSuite.KeyExchange.*; - -/** - * ClientHandshaker does the protocol handshaking from the point - * of view of a client. It is driven asychronously by handshake messages - * as delivered by the parent Handshaker class, and also uses - * common functionality (e.g. key generation) that is provided there. - * - * @author David Brownell - */ -final class ClientHandshaker extends Handshaker { - - // constants for subject alt names of type DNS and IP - private final static int ALTNAME_DNS = 2; - private final static int ALTNAME_IP = 7; - - // the server's public key from its certificate. - private PublicKey serverKey; - - // the server's ephemeral public key from the server key exchange message - // for ECDHE/ECDH_anon and RSA_EXPORT. - private PublicKey ephemeralServerKey; - - // server's ephemeral public value for DHE/DH_anon key exchanges - private BigInteger serverDH; - - private DHCrypt dh; - - private ECDHCrypt ecdh; - - private CertificateRequest certRequest; - - private boolean serverKeyExchangeReceived; - - /* - * The RSA PreMasterSecret needs to know the version of - * ClientHello that was used on this handshake. This represents - * the "max version" this client is supporting. In the - * case of an initial handshake, it's the max version enabled, - * but in the case of a resumption attempt, it's the version - * of the session we're trying to resume. - */ - private ProtocolVersion maxProtocolVersion; - - // To switch off the SNI extension. - private final static boolean enableSNIExtension = - Debug.getBooleanProperty("jsse.enableSNIExtension", true); - - /* - * Allow unsafe server certificate change? - * - * Server certificate change during SSL/TLS renegotiation may be considered - * unsafe, as described in the Triple Handshake attacks: - * - * https://secure-resumption.com/tlsauth.pdf - * - * Endpoint identification (See - * SSLParameters.getEndpointIdentificationAlgorithm()) is a pretty nice - * guarantee that the server certificate change in renegotiation is legal. - * However, endpoing identification is only enabled for HTTPS and LDAP - * over SSL/TLS by default. It is not enough to protect SSL/TLS - * connections other than HTTPS and LDAP. - * - * The renegotiation indication extension (See RFC 5764) is a pretty - * strong guarantee that the endpoints on both client and server sides - * are identical on the same connection. However, the Triple Handshake - * attacks can bypass this guarantee if there is a session-resumption - * handshake between the initial full handshake and the renegotiation - * full handshake. - * - * Server certificate change may be unsafe and should be restricted if - * endpoint identification is not enabled and the previous handshake is - * a session-resumption abbreviated initial handshake, unless the - * identities represented by both certificates can be regraded as the - * same (See isIdentityEquivalent()). - * - * Considering the compatibility impact and the actual requirements to - * support server certificate change in practice, the system property, - * jdk.tls.allowUnsafeServerCertChange, is used to define whether unsafe - * server certificate change in renegotiation is allowed or not. The - * default value of the system property is "false". To mitigate the - * compactibility impact, applications may want to set the system - * property to "true" at their own risk. - * - * If the value of the system property is "false", server certificate - * change in renegotiation after a session-resumption abbreviated initial - * handshake is restricted (See isIdentityEquivalent()). - * - * If the system property is set to "true" explicitly, the restriction on - * server certificate change in renegotiation is disabled. - */ - private final static boolean allowUnsafeServerCertChange = - Debug.getBooleanProperty("jdk.tls.allowUnsafeServerCertChange", false); - - // Whether an ALPN extension was sent in the ClientHello - private boolean alpnActive = false; - - private List<SNIServerName> requestedServerNames = - Collections.<SNIServerName>emptyList(); - - private boolean serverNamesAccepted = false; - - /* - * the reserved server certificate chain in previous handshaking - * - * The server certificate chain is only reserved if the previous - * handshake is a session-resumption abbreviated initial handshake. - */ - private X509Certificate[] reservedServerCerts = null; - - /* - * Constructors - */ - ClientHandshaker(SSLSocketImpl socket, SSLContextImpl context, - ProtocolList enabledProtocols, - ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - super(socket, context, enabledProtocols, true, true, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - } - - ClientHandshaker(SSLEngineImpl engine, SSLContextImpl context, - ProtocolList enabledProtocols, - ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - super(engine, context, enabledProtocols, true, true, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - } - - /* - * This routine handles all the client side handshake messages, one at - * a time. Given the message type (and in some cases the pending cipher - * spec) it parses the type-specific message. Then it calls a function - * that handles that specific message. - * - * It updates the state machine (need to verify it) as each message - * is processed, and writes responses as needed using the connection - * in the constructor. - */ - @Override - void processMessage(byte type, int messageLen) throws IOException { - - // check the handshake state - List<Byte> ignoredOptStates = handshakeState.check(type); - - switch (type) { - case HandshakeMessage.ht_hello_request: - HelloRequest helloRequest = new HelloRequest(input); - handshakeState.update(helloRequest, resumingSession); - this.serverHelloRequest(helloRequest); - break; - - case HandshakeMessage.ht_server_hello: - ServerHello serverHello = new ServerHello(input, messageLen); - this.serverHello(serverHello); - - // This handshake state update needs the resumingSession value - // set by serverHello(). - handshakeState.update(serverHello, resumingSession); - break; - - case HandshakeMessage.ht_certificate: - if (keyExchange == K_DH_ANON || keyExchange == K_ECDH_ANON - || keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { - fatalSE(Alerts.alert_unexpected_message, - "unexpected server cert chain"); - // NOTREACHED - } - CertificateMsg certificateMsg = new CertificateMsg(input); - handshakeState.update(certificateMsg, resumingSession); - this.serverCertificate(certificateMsg); - serverKey = - session.getPeerCertificates()[0].getPublicKey(); - break; - - case HandshakeMessage.ht_server_key_exchange: - serverKeyExchangeReceived = true; - switch (keyExchange) { - case K_RSA_EXPORT: - /** - * The server key exchange message is sent by the server only - * when the server certificate message does not contain the - * proper amount of data to allow the client to exchange a - * premaster secret, such as when RSA_EXPORT is used and the - * public key in the server certificate is longer than 512 bits. - */ - if (serverKey == null) { - throw new SSLProtocolException - ("Server did not send certificate message"); - } - - if (!(serverKey instanceof RSAPublicKey)) { - throw new SSLProtocolException("Protocol violation:" + - " the certificate type must be appropriate for the" + - " selected cipher suite's key exchange algorithm"); - } - - if (JsseJce.getRSAKeyLength(serverKey) <= 512) { - throw new SSLProtocolException("Protocol violation:" + - " server sent a server key exchange message for" + - " key exchange " + keyExchange + - " when the public key in the server certificate" + - " is less than or equal to 512 bits in length"); - } - - try { - RSA_ServerKeyExchange rsaSrvKeyExchange = - new RSA_ServerKeyExchange(input); - handshakeState.update(rsaSrvKeyExchange, resumingSession); - this.serverKeyExchange(rsaSrvKeyExchange); - } catch (GeneralSecurityException e) { - throwSSLException("Server key", e); - } - break; - case K_DH_ANON: - try { - DH_ServerKeyExchange dhSrvKeyExchange = - new DH_ServerKeyExchange(input, protocolVersion); - handshakeState.update(dhSrvKeyExchange, resumingSession); - this.serverKeyExchange(dhSrvKeyExchange); - } catch (GeneralSecurityException e) { - throwSSLException("Server key", e); - } - break; - case K_DHE_DSS: - case K_DHE_RSA: - try { - DH_ServerKeyExchange dhSrvKeyExchange = - new DH_ServerKeyExchange( - input, serverKey, - clnt_random.random_bytes, svr_random.random_bytes, - messageLen, - getLocalSupportedSignAlgs(), protocolVersion); - handshakeState.update(dhSrvKeyExchange, resumingSession); - this.serverKeyExchange(dhSrvKeyExchange); - } catch (GeneralSecurityException e) { - throwSSLException("Server key", e); - } - break; - case K_ECDHE_ECDSA: - case K_ECDHE_RSA: - case K_ECDH_ANON: - try { - ECDH_ServerKeyExchange ecdhSrvKeyExchange = - new ECDH_ServerKeyExchange - (input, serverKey, clnt_random.random_bytes, - svr_random.random_bytes, - getLocalSupportedSignAlgs(), protocolVersion); - handshakeState.update(ecdhSrvKeyExchange, resumingSession); - this.serverKeyExchange(ecdhSrvKeyExchange); - } catch (GeneralSecurityException e) { - throwSSLException("Server key", e); - } - break; - case K_RSA: - case K_DH_RSA: - case K_DH_DSS: - case K_ECDH_ECDSA: - case K_ECDH_RSA: - throw new SSLProtocolException( - "Protocol violation: server sent a server key exchange" - + " message for key exchange " + keyExchange); - case K_KRB5: - case K_KRB5_EXPORT: - throw new SSLProtocolException( - "unexpected receipt of server key exchange algorithm"); - default: - throw new SSLProtocolException( - "unsupported key exchange algorithm = " - + keyExchange); - } - break; - - case HandshakeMessage.ht_certificate_request: - // save for later, it's handled by serverHelloDone - if ((keyExchange == K_DH_ANON) || (keyExchange == K_ECDH_ANON)) { - throw new SSLHandshakeException( - "Client authentication requested for "+ - "anonymous cipher suite."); - } else if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { - throw new SSLHandshakeException( - "Client certificate requested for "+ - "kerberos cipher suite."); - } - certRequest = new CertificateRequest(input, protocolVersion); - if (debug != null && Debug.isOn("handshake")) { - certRequest.print(System.out); - } - handshakeState.update(certRequest, resumingSession); - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - Collection<SignatureAndHashAlgorithm> peerSignAlgs = - certRequest.getSignAlgorithms(); - if (peerSignAlgs == null || peerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No peer supported signature algorithms"); - } - - Collection<SignatureAndHashAlgorithm> supportedPeerSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints, peerSignAlgs); - if (supportedPeerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature and hash algorithm in common"); - } - - setPeerSupportedSignAlgs(supportedPeerSignAlgs); - session.setPeerSupportedSignatureAlgorithms( - supportedPeerSignAlgs); - } - - break; - - case HandshakeMessage.ht_server_hello_done: - ServerHelloDone serverHelloDone = new ServerHelloDone(input); - handshakeState.update(serverHelloDone, resumingSession); - this.serverHelloDone(serverHelloDone); - break; - - case HandshakeMessage.ht_finished: - Finished serverFinished = - new Finished(protocolVersion, input, cipherSuite); - handshakeState.update(serverFinished, resumingSession); - this.serverFinished(serverFinished); - - break; - - default: - throw new SSLProtocolException( - "Illegal client handshake msg, " + type); - } - } - - /* - * Used by the server to kickstart negotiations -- this requests a - * "client hello" to renegotiate current cipher specs (e.g. maybe lots - * of data has been encrypted with the same keys, or the server needs - * the client to present a certificate). - */ - private void serverHelloRequest(HelloRequest mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - // - // Could be (e.g. at connection setup) that we already - // sent the "client hello" but the server's not seen it. - // - if (!clientHelloDelivered) { - if (!secureRenegotiation && !allowUnsafeRenegotiation) { - // renegotiation is not allowed. - if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { - // response with a no_renegotiation warning, - warningSE(Alerts.alert_no_renegotiation); - - // invalidate the handshake so that the caller can - // dispose this object. - invalidated = true; - - // If there is still unread block in the handshake - // input stream, it would be truncated with the disposal - // and the next handshake message will become incomplete. - // - // However, according to SSL/TLS specifications, no more - // handshake message should immediately follow ClientHello - // or HelloRequest. So just let it be. - } else { - // For SSLv3, send the handshake_failure fatal error. - // Note that SSLv3 does not define a no_renegotiation - // alert like TLSv1. However we cannot ignore the message - // simply, otherwise the other side was waiting for a - // response that would never come. - fatalSE(Alerts.alert_handshake_failure, - "Renegotiation is not allowed"); - } - } else { - if (!secureRenegotiation) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning: continue with insecure renegotiation"); - } - } - kickstart(); - } - } - } - - - /* - * Server chooses session parameters given options created by the - * client -- basically, cipher options, session id, and someday a - * set of compression options. - * - * There are two branches of the state machine, decided by the - * details of this message. One is the "fast" handshake, where we - * can resume the pre-existing session we asked resume. The other - * is a more expensive "full" handshake, with key exchange and - * probably authentication getting done. - */ - private void serverHello(ServerHello mesg) throws IOException { - serverKeyExchangeReceived = false; - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - // check if the server selected protocol version is OK for us - ProtocolVersion mesgVersion = mesg.protocolVersion; - if (!isNegotiable(mesgVersion)) { - throw new SSLHandshakeException( - "Server chose " + mesgVersion + - ", but that protocol version is not enabled or not supported " + - "by the client."); - } - - handshakeHash.protocolDetermined(mesgVersion); - - // Set protocolVersion and propagate to SSLSocket and the - // Handshake streams - setVersion(mesgVersion); - - // check the "renegotiation_info" extension - RenegotiationInfoExtension serverHelloRI = (RenegotiationInfoExtension) - mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); - if (serverHelloRI != null) { - if (isInitialHandshake) { - // verify the length of the "renegotiated_connection" field - if (!serverHelloRI.isEmpty()) { - // abort the handshake with a fatal handshake_failure alert - fatalSE(Alerts.alert_handshake_failure, - "The renegotiation_info field is not empty"); - } - - secureRenegotiation = true; - } else { - // For a legacy renegotiation, the client MUST verify that - // it does not contain the "renegotiation_info" extension. - if (!secureRenegotiation) { - fatalSE(Alerts.alert_handshake_failure, - "Unexpected renegotiation indication extension"); - } - - // verify the client_verify_data and server_verify_data values - byte[] verifyData = - new byte[clientVerifyData.length + serverVerifyData.length]; - System.arraycopy(clientVerifyData, 0, verifyData, - 0, clientVerifyData.length); - System.arraycopy(serverVerifyData, 0, verifyData, - clientVerifyData.length, serverVerifyData.length); - if (!MessageDigest.isEqual(verifyData, - serverHelloRI.getRenegotiatedConnection())) { - fatalSE(Alerts.alert_handshake_failure, - "Incorrect verify data in ServerHello " + - "renegotiation_info message"); - } - } - } else { - // no renegotiation indication extension - if (isInitialHandshake) { - if (!allowLegacyHelloMessages) { - // abort the handshake with a fatal handshake_failure alert - fatalSE(Alerts.alert_handshake_failure, - "Failed to negotiate the use of secure renegotiation"); - } - - secureRenegotiation = false; - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Warning: No renegotiation " + - "indication extension in ServerHello"); - } - } else { - // For a secure renegotiation, the client must abort the - // handshake if no "renegotiation_info" extension is present. - if (secureRenegotiation) { - fatalSE(Alerts.alert_handshake_failure, - "No renegotiation indication extension"); - } - - // we have already allowed unsafe renegotation before request - // the renegotiation. - } - } - - // - // Save server nonce, we always use it to compute connection - // keys and it's also used to create the master secret if we're - // creating a new session (i.e. in the full handshake). - // - svr_random = mesg.svr_random; - - if (isNegotiable(mesg.cipherSuite) == false) { - fatalSE(Alerts.alert_illegal_parameter, - "Server selected improper ciphersuite " + mesg.cipherSuite); - } - - setCipherSuite(mesg.cipherSuite); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg()); - } - - if (mesg.compression_method != 0) { - fatalSE(Alerts.alert_illegal_parameter, - "compression type not supported, " - + mesg.compression_method); - // NOTREACHED - } - - // so far so good, let's look at the session - if (session != null) { - // we tried to resume, let's see what the server decided - if (session.getSessionId().equals(mesg.sessionId)) { - // server resumed the session, let's make sure everything - // checks out - - // Verify that the session ciphers are unchanged. - CipherSuite sessionSuite = session.getSuite(); - if (cipherSuite != sessionSuite) { - throw new SSLProtocolException - ("Server returned wrong cipher suite for session"); - } - - // verify protocol version match - ProtocolVersion sessionVersion = session.getProtocolVersion(); - if (protocolVersion != sessionVersion) { - throw new SSLProtocolException - ("Server resumed session with wrong protocol version"); - } - - // validate subject identity - if (sessionSuite.keyExchange == K_KRB5 || - sessionSuite.keyExchange == K_KRB5_EXPORT) { - Principal localPrincipal = session.getLocalPrincipal(); - - Subject subject = null; - try { - subject = AccessController.doPrivileged( - new PrivilegedExceptionAction<Subject>() { - @Override - public Subject run() throws Exception { - return Krb5Helper.getClientSubject(getAccSE()); - }}); - } catch (PrivilegedActionException e) { - subject = null; - if (debug != null && Debug.isOn("session")) { - System.out.println("Attempt to obtain" + - " subject failed!"); - } - } - - if (subject != null) { - // Eliminate dependency on KerberosPrincipal - Set<Principal> principals = - subject.getPrincipals(Principal.class); - if (!principals.contains(localPrincipal)) { - throw new SSLProtocolException("Server resumed" + - " session with wrong subject identity"); - } else { - if (debug != null && Debug.isOn("session")) - System.out.println("Subject identity is same"); - } - } else { - if (debug != null && Debug.isOn("session")) - System.out.println("Kerberos credentials are not" + - " present in the current Subject; check if " + - " javax.security.auth.useSubjectAsCreds" + - " system property has been set to false"); - throw new SSLProtocolException - ("Server resumed session with no subject"); - } - } - - // looks fine; resume it, and update the state machine. - resumingSession = true; - calculateConnectionKeys(session.getMasterSecret()); - if (debug != null && Debug.isOn("session")) { - System.out.println("%% Server resumed " + session); - } - } else { - // we wanted to resume, but the server refused - // - // Invalidate the session for initial handshake in case - // of reusing next time. - if (isInitialHandshake) { - session.invalidate(); - } - session = null; - if (!enableNewSession) { - throw new SSLException("New session creation is disabled"); - } - } - } - - // check the "extended_master_secret" extension - ExtendedMasterSecretExtension extendedMasterSecretExt = - (ExtendedMasterSecretExtension)mesg.extensions.get( - ExtensionType.EXT_EXTENDED_MASTER_SECRET); - if (extendedMasterSecretExt != null) { - // Is it the expected server extension? - if (!useExtendedMasterSecret || - !(mesgVersion.v >= ProtocolVersion.TLS10.v) || !requestedToUseEMS) { - fatalSE(Alerts.alert_unsupported_extension, - "Server sent the extended_master_secret " + - "extension improperly"); - } - - // For abbreviated handshake, if the original session did not use - // the "extended_master_secret" extension but the new ServerHello - // contains the extension, the client MUST abort the handshake. - if (resumingSession && (session != null) && - !session.getUseExtendedMasterSecret()) { - fatalSE(Alerts.alert_unsupported_extension, - "Server sent an unexpected extended_master_secret " + - "extension on session resumption"); - } - } else { - if (useExtendedMasterSecret && !allowLegacyMasterSecret) { - // For full handshake, if a client receives a ServerHello - // without the extension, it SHOULD abort the handshake if - // it does not wish to interoperate with legacy servers. - fatalSE(Alerts.alert_handshake_failure, - "Extended Master Secret extension is required"); - } - - if (resumingSession && (session != null)) { - if (session.getUseExtendedMasterSecret()) { - // For abbreviated handshake, if the original session used - // the "extended_master_secret" extension but the new - // ServerHello does not contain the extension, the client - // MUST abort the handshake. - fatalSE(Alerts.alert_handshake_failure, - "Missing Extended Master Secret extension " + - "on session resumption"); - } else if (useExtendedMasterSecret && !allowLegacyResumption) { - // Unlikely, abbreviated handshake should be discarded. - fatalSE(Alerts.alert_handshake_failure, - "Extended Master Secret extension is required"); - } - } - } - - // check the ALPN extension - ALPNExtension serverHelloALPN = - (ALPNExtension) mesg.extensions.get(ExtensionType.EXT_ALPN); - - if (serverHelloALPN != null) { - // Check whether an ALPN extension was sent in ClientHello message - if (!alpnActive) { - fatalSE(Alerts.alert_unsupported_extension, - "Server sent " + ExtensionType.EXT_ALPN + - " extension when not requested by client"); - } - - List<String> protocols = serverHelloALPN.getPeerAPs(); - // Only one application protocol name should be present - String p; - if ((protocols.size() == 1) && - !((p = protocols.get(0)).isEmpty())) { - int i; - for (i = 0; i < localApl.length; i++) { - if (localApl[i].equals(p)) { - break; - } - } - if (i == localApl.length) { - fatalSE(Alerts.alert_handshake_failure, - "Server has selected an application protocol name " + - "which was not offered by the client: " + p); - - } - applicationProtocol = p; - } else { - fatalSE(Alerts.alert_handshake_failure, - "Incorrect data in ServerHello " + ExtensionType.EXT_ALPN + - " message"); - } - } else { - applicationProtocol = ""; - } - - if (resumingSession && session != null) { - setHandshakeSessionSE(session); - // Reserve the handshake state if this is a session-resumption - // abbreviated initial handshake. - if (isInitialHandshake) { - session.setAsSessionResumption(true); - } - - return; - } - - // check extensions - for (HelloExtension ext : mesg.extensions.list()) { - ExtensionType type = ext.type; - if (type == ExtensionType.EXT_SERVER_NAME) { - serverNamesAccepted = true; - } else if ((type != ExtensionType.EXT_ELLIPTIC_CURVES) - && (type != ExtensionType.EXT_EC_POINT_FORMATS) - && (type != ExtensionType.EXT_SERVER_NAME) - && (type != ExtensionType.EXT_ALPN) - && (type != ExtensionType.EXT_RENEGOTIATION_INFO) - && (type != ExtensionType.EXT_EXTENDED_MASTER_SECRET)){ - fatalSE(Alerts.alert_unsupported_extension, - "Server sent an unsupported extension: " + type); - } - } - - // Create a new session, we need to do the full handshake - session = new SSLSessionImpl(protocolVersion, cipherSuite, - getLocalSupportedSignAlgs(), - mesg.sessionId, getHostSE(), getPortSE(), - (extendedMasterSecretExt != null), - getEndpointIdentificationAlgorithmSE()); - session.setRequestedServerNames(requestedServerNames); - setHandshakeSessionSE(session); - if (debug != null && Debug.isOn("handshake")) { - System.out.println("** " + cipherSuite); - } - } - - /* - * Server's own key was either a signing-only key, or was too - * large for export rules ... this message holds an ephemeral - * RSA key to use for key exchange. - */ - private void serverKeyExchange(RSA_ServerKeyExchange mesg) - throws IOException, GeneralSecurityException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - if (!mesg.verify(serverKey, clnt_random, svr_random)) { - fatalSE(Alerts.alert_handshake_failure, - "server key exchange invalid"); - // NOTREACHED - } - ephemeralServerKey = mesg.getPublicKey(); - - // check constraints of RSA PublicKey - if (!algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), ephemeralServerKey)) { - - throw new SSLHandshakeException("RSA ServerKeyExchange " + - "does not comply to algorithm constraints"); - } - } - - - /* - * Diffie-Hellman key exchange. We save the server public key and - * our own D-H algorithm object so we can defer key calculations - * until after we've sent the client key exchange message (which - * gives client and server some useful parallelism). - */ - private void serverKeyExchange(DH_ServerKeyExchange mesg) - throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - dh = new DHCrypt(mesg.getModulus(), mesg.getBase(), - sslContext.getSecureRandom()); - serverDH = mesg.getServerPublicKey(); - - // check algorithm constraints - dh.checkConstraints(algorithmConstraints, serverDH); - } - - private void serverKeyExchange(ECDH_ServerKeyExchange mesg) - throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - ECPublicKey key = mesg.getPublicKey(); - ecdh = new ECDHCrypt(key.getParams(), sslContext.getSecureRandom()); - ephemeralServerKey = key; - - // check constraints of EC PublicKey - if (!algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), ephemeralServerKey)) { - - throw new SSLHandshakeException("ECDH ServerKeyExchange " + - "does not comply to algorithm constraints"); - } - } - - /* - * The server's "Hello Done" message is the client's sign that - * it's time to do all the hard work. - */ - private void serverHelloDone(ServerHelloDone mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - /* - * Always make sure the input has been digested before we - * start emitting data, to ensure the hashes are correctly - * computed for the Finished and CertificateVerify messages - * which we send (here). - */ - input.digestNow(); - - /* - * FIRST ... if requested, send an appropriate Certificate chain - * to authenticate the client, and remember the associated private - * key to sign the CertificateVerify message. - */ - PrivateKey signingKey = null; - - if (certRequest != null) { - X509ExtendedKeyManager km = sslContext.getX509KeyManager(); - - ArrayList<String> keytypesTmp = new ArrayList<>(4); - - for (int i = 0; i < certRequest.types.length; i++) { - String typeName; - - switch (certRequest.types[i]) { - case CertificateRequest.cct_rsa_sign: - typeName = "RSA"; - break; - - case CertificateRequest.cct_dss_sign: - typeName = "DSA"; - break; - - case CertificateRequest.cct_ecdsa_sign: - // ignore if we do not have EC crypto available - typeName = JsseJce.isEcAvailable() ? "EC" : null; - break; - - // Fixed DH/ECDH client authentication not supported - // - // case CertificateRequest.cct_rsa_fixed_dh: - // case CertificateRequest.cct_dss_fixed_dh: - // case CertificateRequest.cct_rsa_fixed_ecdh: - // case CertificateRequest.cct_ecdsa_fixed_ecdh: - // - // Any other values (currently not used in TLS) - // - // case CertificateRequest.cct_rsa_ephemeral_dh: - // case CertificateRequest.cct_dss_ephemeral_dh: - default: - typeName = null; - break; - } - - if ((typeName != null) && (!keytypesTmp.contains(typeName))) { - keytypesTmp.add(typeName); - } - } - - String alias = null; - int keytypesTmpSize = keytypesTmp.size(); - if (keytypesTmpSize != 0) { - String keytypes[] = - keytypesTmp.toArray(new String[keytypesTmpSize]); - - if (conn != null) { - alias = km.chooseClientAlias(keytypes, - certRequest.getAuthorities(), conn); - } else { - alias = km.chooseEngineClientAlias(keytypes, - certRequest.getAuthorities(), engine); - } - } - - CertificateMsg m1 = null; - if (alias != null) { - X509Certificate[] certs = km.getCertificateChain(alias); - if ((certs != null) && (certs.length != 0)) { - PublicKey publicKey = certs[0].getPublicKey(); - if (publicKey != null) { - m1 = new CertificateMsg(certs); - signingKey = km.getPrivateKey(alias); - session.setLocalPrivateKey(signingKey); - session.setLocalCertificates(certs); - } - } - } - if (m1 == null) { - // - // No appropriate cert was found ... report this to the - // server. For SSLv3, send the no_certificate alert; - // TLS uses an empty cert chain instead. - // - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - m1 = new CertificateMsg(new X509Certificate [0]); - } else { - warningSE(Alerts.alert_no_certificate); - } - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning: no suitable certificate found - " + - "continuing without client authentication"); - } - } - - // - // At last ... send any client certificate chain. - // - if (m1 != null) { - if (debug != null && Debug.isOn("handshake")) { - m1.print(System.out); - } - m1.write(output); - handshakeState.update(m1, resumingSession); - } - } - - /* - * SECOND ... send the client key exchange message. The - * procedure used is a function of the cipher suite selected; - * one is always needed. - */ - HandshakeMessage m2; - - switch (keyExchange) { - - case K_RSA: - case K_RSA_EXPORT: - if (serverKey == null) { - throw new SSLProtocolException - ("Server did not send certificate message"); - } - - if (!(serverKey instanceof RSAPublicKey)) { - throw new SSLProtocolException - ("Server certificate does not include an RSA key"); - } - - /* - * For RSA key exchange, we randomly generate a new - * pre-master secret and encrypt it with the server's - * public key. Then we save that pre-master secret - * so that we can calculate the keying data later; - * it's a performance speedup not to do that until - * the client's waiting for the server response, but - * more of a speedup for the D-H case. - * - * If the RSA_EXPORT scheme is active, when the public - * key in the server certificate is less than or equal - * to 512 bits in length, use the cert's public key, - * otherwise, the ephemeral one. - */ - PublicKey key; - if (keyExchange == K_RSA) { - key = serverKey; - } else { // K_RSA_EXPORT - if (JsseJce.getRSAKeyLength(serverKey) <= 512) { - // extraneous ephemeralServerKey check done - // above in processMessage() - key = serverKey; - } else { - if (ephemeralServerKey == null) { - throw new SSLProtocolException("Server did not send" + - " a RSA_EXPORT Server Key Exchange message"); - } - key = ephemeralServerKey; - } - } - - m2 = new RSAClientKeyExchange(protocolVersion, maxProtocolVersion, - sslContext.getSecureRandom(), key); - break; - case K_DH_RSA: - case K_DH_DSS: - /* - * For DH Key exchange, we only need to make sure the server - * knows our public key, so we calculate the same pre-master - * secret. - * - * For certs that had DH keys in them, we send an empty - * handshake message (no key) ... we flag this case by - * passing a null "dhPublic" value. - * - * Otherwise we send ephemeral DH keys, unsigned. - */ - // if (useDH_RSA || useDH_DSS) - m2 = new DHClientKeyExchange(); - break; - case K_DHE_RSA: - case K_DHE_DSS: - case K_DH_ANON: - if (dh == null) { - throw new SSLProtocolException - ("Server did not send a DH Server Key Exchange message"); - } - m2 = new DHClientKeyExchange(dh.getPublicKey()); - break; - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - if (ecdh == null) { - throw new SSLProtocolException - ("Server did not send a ECDH Server Key Exchange message"); - } - m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - if (serverKey == null) { - throw new SSLProtocolException - ("Server did not send certificate message"); - } - if (serverKey instanceof ECPublicKey == false) { - throw new SSLProtocolException - ("Server certificate does not include an EC key"); - } - ECParameterSpec params = ((ECPublicKey)serverKey).getParams(); - ecdh = new ECDHCrypt(params, sslContext.getSecureRandom()); - m2 = new ECDHClientKeyExchange(ecdh.getPublicKey()); - break; - case K_KRB5: - case K_KRB5_EXPORT: - String sniHostname = null; - for (SNIServerName serverName : requestedServerNames) { - if (serverName instanceof SNIHostName) { - sniHostname = ((SNIHostName) serverName).getAsciiName(); - break; - } - } - - KerberosClientKeyExchange kerberosMsg = null; - if (sniHostname != null) { - // use first requested SNI hostname - try { - kerberosMsg = new KerberosClientKeyExchange( - sniHostname, getAccSE(), protocolVersion, - sslContext.getSecureRandom()); - } catch(IOException e) { - if (serverNamesAccepted) { - // server accepted requested SNI hostname, - // so it must be used - throw e; - } - // fallback to using hostname - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning, cannot use Server Name Indication: " - + e.getMessage()); - } - } - } - - if (kerberosMsg == null) { - String hostname = getHostSE(); - if (hostname == null) { - throw new IOException("Hostname is required" + - " to use Kerberos cipher suites"); - } - kerberosMsg = new KerberosClientKeyExchange( - hostname, getAccSE(), protocolVersion, - sslContext.getSecureRandom()); - } - - // Record the principals involved in exchange - session.setPeerPrincipal(kerberosMsg.getPeerPrincipal()); - session.setLocalPrincipal(kerberosMsg.getLocalPrincipal()); - m2 = kerberosMsg; - break; - default: - // somethings very wrong - throw new RuntimeException - ("Unsupported key exchange: " + keyExchange); - } - if (debug != null && Debug.isOn("handshake")) { - m2.print(System.out); - } - m2.write(output); - - handshakeState.update(m2, resumingSession); - - /* - * THIRD, send a "change_cipher_spec" record followed by the - * "Finished" message. We flush the messages we've queued up, to - * get concurrency between client and server. The concurrency is - * useful as we calculate the master secret, which is needed both - * to compute the "Finished" message, and to compute the keys used - * to protect all records following the change_cipher_spec. - */ - - output.doHashes(); - output.flush(); - - /* - * We deferred calculating the master secret and this connection's - * keying data; we do it now. Deferring this calculation is good - * from a performance point of view, since it lets us do it during - * some time that network delays and the server's own calculations - * would otherwise cause to be "dead" in the critical path. - */ - SecretKey preMasterSecret; - switch (keyExchange) { - case K_RSA: - case K_RSA_EXPORT: - preMasterSecret = ((RSAClientKeyExchange)m2).preMaster; - break; - case K_KRB5: - case K_KRB5_EXPORT: - byte[] secretBytes = - ((KerberosClientKeyExchange)m2).getUnencryptedPreMasterSecret(); - preMasterSecret = new SecretKeySpec(secretBytes, - "TlsPremasterSecret"); - break; - case K_DHE_RSA: - case K_DHE_DSS: - case K_DH_ANON: - preMasterSecret = dh.getAgreedSecret(serverDH, true); - break; - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - preMasterSecret = ecdh.getAgreedSecret(ephemeralServerKey); - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - preMasterSecret = ecdh.getAgreedSecret(serverKey); - break; - default: - throw new IOException("Internal error: unknown key exchange " - + keyExchange); - } - - calculateKeys(preMasterSecret, null); - - /* - * FOURTH, if we sent a Certificate, we need to send a signed - * CertificateVerify (unless the key in the client's certificate - * was a Diffie-Hellman key).). - * - * This uses a hash of the previous handshake messages ... either - * a nonfinal one (if the particular implementation supports it) - * or else using the third element in the arrays of hashes being - * computed. - */ - if (signingKey != null) { - CertificateVerify m3; - try { - SignatureAndHashAlgorithm preferableSignatureAlgorithm = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - getPeerSupportedSignAlgs(), - signingKey.getAlgorithm(), signingKey); - - if (preferableSignatureAlgorithm == null) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - - String hashAlg = - SignatureAndHashAlgorithm.getHashAlgorithmName( - preferableSignatureAlgorithm); - if (hashAlg == null || hashAlg.length() == 0) { - throw new SSLHandshakeException( - "No supported hash algorithm"); - } - } - - m3 = new CertificateVerify(protocolVersion, handshakeHash, - signingKey, session.getMasterSecret(), - sslContext.getSecureRandom(), - preferableSignatureAlgorithm); - } catch (GeneralSecurityException e) { - fatalSE(Alerts.alert_handshake_failure, - "Error signing certificate verify", e); - // NOTREACHED, make compiler happy - m3 = null; - } - if (debug != null && Debug.isOn("handshake")) { - m3.print(System.out); - } - m3.write(output); - handshakeState.update(m3, resumingSession); - output.doHashes(); - } - - /* - * OK, that's that! - */ - sendChangeCipherAndFinish(false); - } - - - /* - * "Finished" is the last handshake message sent. If we got this - * far, the MAC has been validated post-decryption. We validate - * the two hashes here as an additional sanity check, protecting - * the handshake against various active attacks. - */ - private void serverFinished(Finished mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - boolean verified = mesg.verify(handshakeHash, Finished.SERVER, - session.getMasterSecret()); - - if (!verified) { - fatalSE(Alerts.alert_illegal_parameter, - "server 'finished' message doesn't verify"); - // NOTREACHED - } - - /* - * save server verify data for secure renegotiation - */ - if (secureRenegotiation) { - serverVerifyData = mesg.getVerifyData(); - } - - /* - * Reset the handshake state if this is not an initial handshake. - */ - if (!isInitialHandshake) { - session.setAsSessionResumption(false); - } - - /* - * OK, it verified. If we're doing the fast handshake, add that - * "Finished" message to the hash of handshake messages, then send - * our own change_cipher_spec and Finished message for the server - * to verify in turn. These are the last handshake messages. - * - * In any case, update the session cache. We're done handshaking, - * so there are no threats any more associated with partially - * completed handshakes. - */ - if (resumingSession) { - input.digestNow(); - sendChangeCipherAndFinish(true); - } else { - handshakeFinished = true; - } - session.setLastAccessedTime(System.currentTimeMillis()); - - if (!resumingSession) { - if (session.isRejoinable()) { - ((SSLSessionContextImpl) sslContext - .engineGetClientSessionContext()) - .put(session); - if (debug != null && Debug.isOn("session")) { - System.out.println("%% Cached client session: " + session); - } - } else if (debug != null && Debug.isOn("session")) { - System.out.println( - "%% Didn't cache non-resumable client session: " - + session); - } - } - } - - - /* - * Send my change-cipher-spec and Finished message ... done as the - * last handshake act in either the short or long sequences. In - * the short one, we've already seen the server's Finished; in the - * long one, we wait for it now. - */ - private void sendChangeCipherAndFinish(boolean finishedTag) - throws IOException { - Finished mesg = new Finished(protocolVersion, handshakeHash, - Finished.CLIENT, session.getMasterSecret(), cipherSuite); - - /* - * Send the change_cipher_spec message, then the Finished message - * which we just calculated (and protected using the keys we just - * calculated). Server responds with its Finished message, except - * in the "fast handshake" (resume session) case. - */ - sendChangeCipherSpec(mesg, finishedTag); - - /* - * save client verify data for secure renegotiation - */ - if (secureRenegotiation) { - clientVerifyData = mesg.getVerifyData(); - } - } - - - /* - * Returns a ClientHello message to kickstart renegotiations - */ - @Override - HandshakeMessage getKickstartMessage() throws SSLException { - // session ID of the ClientHello message - SessionId sessionId = new SessionId(new byte[0]); - - // a list of cipher suites sent by the client - CipherSuiteList cipherSuites = getActiveCipherSuites(); - - // set the max protocol version this client is supporting. - maxProtocolVersion = protocolVersion; - - // - // Try to resume an existing session. This might be mandatory, - // given certain API options. - // - session = ((SSLSessionContextImpl)sslContext - .engineGetClientSessionContext()) - .get(getHostSE(), getPortSE()); - if (debug != null && Debug.isOn("session")) { - if (session != null) { - System.out.println("%% Client cached " - + session - + (session.isRejoinable() ? "" : " (not rejoinable)")); - } else { - System.out.println("%% No cached client session"); - } - } - if (session != null) { - // If unsafe server certificate change is not allowed, reserve - // current server certificates if the previous handshake is a - // session-resumption abbreviated initial handshake. - if (!allowUnsafeServerCertChange && session.isSessionResumption()) { - try { - // If existing, peer certificate chain cannot be null. - reservedServerCerts = - (X509Certificate[])session.getPeerCertificates(); - } catch (SSLPeerUnverifiedException puve) { - // Maybe not certificate-based, ignore the exception. - } - } - - if (!session.isRejoinable()) { - session = null; - } - } - - if (session != null) { - CipherSuite sessionSuite = session.getSuite(); - ProtocolVersion sessionVersion = session.getProtocolVersion(); - if (isNegotiable(sessionSuite) == false) { - if (debug != null && Debug.isOn("session")) { - System.out.println("%% can't resume, unavailable cipher"); - } - session = null; - } - - if ((session != null) && !isNegotiable(sessionVersion)) { - if (debug != null && Debug.isOn("session")) { - System.out.println("%% can't resume, protocol disabled"); - } - session = null; - } - - if ((session != null) && useExtendedMasterSecret) { - boolean isTLS10Plus = sessionVersion.v >= ProtocolVersion.TLS10.v; - if (isTLS10Plus && !session.getUseExtendedMasterSecret()) { - if (!allowLegacyResumption) { - // perform full handshake instead - // - // The client SHOULD NOT offer an abbreviated handshake - // to resume a session that does not use an extended - // master secret. Instead, it SHOULD offer a full - // handshake. - session = null; - } - } - - if ((session != null) && !allowUnsafeServerCertChange) { - // It is fine to move on with abbreviate handshake if - // endpoint identification is enabled. - String identityAlg = getEndpointIdentificationAlgorithmSE(); - if ((identityAlg == null || identityAlg.length() == 0)) { - if (isTLS10Plus) { - if (!session.getUseExtendedMasterSecret()) { - // perform full handshake instead - session = null; - } // Otherwise, use extended master secret. - } else { - // The extended master secret extension does not - // apply to SSL 3.0. Perform a full handshake - // instead. - // - // Note that the useExtendedMasterSecret is - // extended to protect SSL 3.0 connections, - // by discarding abbreviate handshake. - session = null; - } - } - } - } - - // ensure that the endpoint identification algorithm matches the - // one in the session - String identityAlg = getEndpointIdentificationAlgorithmSE(); - if (session != null && identityAlg != null) { - - String sessionIdentityAlg = - session.getEndpointIdentificationAlgorithm(); - if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { - - if (debug != null && Debug.isOn("session")) { - System.out.println("%% can't resume, endpoint id" + - " algorithm does not match, requested: " + - identityAlg + ", cached: " + sessionIdentityAlg); - } - session = null; - } - } - - if (session != null) { - if (debug != null) { - if (Debug.isOn("handshake") || Debug.isOn("session")) { - System.out.println("%% Try resuming " + session - + " from port " + getLocalPortSE()); - } - } - - sessionId = session.getSessionId(); - maxProtocolVersion = sessionVersion; - - // Update SSL version number in underlying SSL socket and - // handshake output stream, so that the output records (at the - // record layer) have the correct version - setVersion(sessionVersion); - } - - /* - * Force use of the previous session ciphersuite, and - * add the SCSV if enabled. - */ - if (!enableNewSession) { - if (session == null) { - throw new SSLHandshakeException( - "Can't reuse existing SSL client session"); - } - - Collection<CipherSuite> cipherList = new ArrayList<>(2); - cipherList.add(sessionSuite); - if (!secureRenegotiation && - cipherSuites.contains(CipherSuite.C_SCSV)) { - cipherList.add(CipherSuite.C_SCSV); - } // otherwise, renegotiation_info extension will be used - - cipherSuites = new CipherSuiteList(cipherList); - } - } - - if (session == null && !enableNewSession) { - throw new SSLHandshakeException("No existing session to resume"); - } - - // exclude SCSV for secure renegotiation - if (secureRenegotiation && cipherSuites.contains(CipherSuite.C_SCSV)) { - Collection<CipherSuite> cipherList = - new ArrayList<>(cipherSuites.size() - 1); - for (CipherSuite suite : cipherSuites.collection()) { - if (suite != CipherSuite.C_SCSV) { - cipherList.add(suite); - } - } - - cipherSuites = new CipherSuiteList(cipherList); - } - - // make sure there is a negotiable cipher suite. - boolean negotiable = false; - for (CipherSuite suite : cipherSuites.collection()) { - if (isNegotiable(suite)) { - negotiable = true; - break; - } - } - - if (!negotiable) { - throw new SSLHandshakeException("No negotiable cipher suite"); - } - - // Not a TLS1.2+ handshake - // For SSLv2Hello, HandshakeHash.reset() will be called, so we - // cannot call HandshakeHash.protocolDetermined() here. As it does - // not follow the spec that HandshakeHash.reset() can be only be - // called before protocolDetermined. - // if (maxProtocolVersion.v < ProtocolVersion.TLS12.v) { - // handshakeHash.protocolDetermined(maxProtocolVersion); - // } - - // create the ClientHello message - ClientHello clientHelloMessage = new ClientHello( - sslContext.getSecureRandom(), maxProtocolVersion, - sessionId, cipherSuites); - - // add elliptic curves and point format extensions - if (cipherSuites.containsEC()) { - EllipticCurvesExtension ece = - EllipticCurvesExtension.createExtension(algorithmConstraints); - if (ece != null) { - clientHelloMessage.extensions.add(ece); - clientHelloMessage.extensions.add( - EllipticPointFormatsExtension.DEFAULT); - } - } - - // add signature_algorithm extension - if (maxProtocolVersion.v >= ProtocolVersion.TLS12.v) { - // we will always send the signature_algorithm extension - Collection<SignatureAndHashAlgorithm> localSignAlgs = - getLocalSupportedSignAlgs(); - if (localSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - - clientHelloMessage.addSignatureAlgorithmsExtension(localSignAlgs); - } - - // add Extended Master Secret extension - if (useExtendedMasterSecret && (maxProtocolVersion.v >= ProtocolVersion.TLS10.v)) { - if ((session == null) || session.getUseExtendedMasterSecret()) { - clientHelloMessage.addExtendedMasterSecretExtension(); - requestedToUseEMS = true; - } - } - - // add server_name extension - if (enableSNIExtension) { - if (session != null) { - requestedServerNames = session.getRequestedServerNames(); - } else { - requestedServerNames = serverNames; - } - - if (!requestedServerNames.isEmpty()) { - clientHelloMessage.addSNIExtension(requestedServerNames); - } - } - - // Add ALPN extension - if (localApl != null && localApl.length > 0) { - clientHelloMessage.addALPNExtension(localApl); - alpnActive = true; - } - - // reset the client random cookie - clnt_random = clientHelloMessage.clnt_random; - - /* - * need to set the renegotiation_info extension for: - * 1: secure renegotiation - * 2: initial handshake and no SCSV in the ClientHello - * 3: insecure renegotiation and no SCSV in the ClientHello - */ - if (secureRenegotiation || - !cipherSuites.contains(CipherSuite.C_SCSV)) { - clientHelloMessage.addRenegotiationInfoExtension(clientVerifyData); - } - - return clientHelloMessage; - } - - /* - * Fault detected during handshake. - */ - @Override - void handshakeAlert(byte description) throws SSLProtocolException { - String message = Alerts.alertDescription(description); - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("SSL - handshake alert: " + message); - } - throw new SSLProtocolException("handshake alert: " + message); - } - - /* - * Unless we are using an anonymous ciphersuite, the server always - * sends a certificate message (for the CipherSuites we currently - * support). The trust manager verifies the chain for us. - */ - private void serverCertificate(CertificateMsg mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - X509Certificate[] peerCerts = mesg.getCertificateChain(); - if (peerCerts.length == 0) { - fatalSE(Alerts.alert_bad_certificate, "empty certificate chain"); - } - - // Allow server certificate change in client side during renegotiation - // after a session-resumption abbreviated initial handshake? - // - // DO NOT need to check allowUnsafeServerCertChange here. We only - // reserve server certificates when allowUnsafeServerCertChange is - // flase. - // - // Allow server certificate change if it is negotiated to use the - // extended master secret. - if ((reservedServerCerts != null) && - !session.getUseExtendedMasterSecret()) { - // It is not necessary to check the certificate update if endpoint - // identification is enabled. - String identityAlg = getEndpointIdentificationAlgorithmSE(); - if ((identityAlg == null || identityAlg.length() == 0) && - !isIdentityEquivalent(peerCerts[0], reservedServerCerts[0])) { - - fatalSE(Alerts.alert_bad_certificate, - "server certificate change is restricted " + - "during renegotiation"); - } - } - - // ask the trust manager to verify the chain - X509TrustManager tm = sslContext.getX509TrustManager(); - try { - // find out the key exchange algorithm used - // use "RSA" for non-ephemeral "RSA_EXPORT" - String keyExchangeString; - if (keyExchange == K_RSA_EXPORT && !serverKeyExchangeReceived) { - keyExchangeString = K_RSA.name; - } else { - keyExchangeString = keyExchange.name; - } - - if (tm instanceof X509ExtendedTrustManager) { - if (conn != null) { - ((X509ExtendedTrustManager)tm).checkServerTrusted( - peerCerts.clone(), - keyExchangeString, - conn); - } else { - ((X509ExtendedTrustManager)tm).checkServerTrusted( - peerCerts.clone(), - keyExchangeString, - engine); - } - } else { - // Unlikely to happen, because we have wrapped the old - // X509TrustManager with the new X509ExtendedTrustManager. - throw new CertificateException( - "Improper X509TrustManager implementation"); - } - } catch (CertificateException e) { - // This will throw an exception, so include the original error. - fatalSE(Alerts.alert_certificate_unknown, e); - } - session.setPeerCertificates(peerCerts); - } - - /* - * Whether the certificates can represent the same identity? - * - * The certificates can be used to represent the same identity: - * 1. If the subject alternative names of IP address are present in - * both certificates, they should be identical; otherwise, - * 2. if the subject alternative names of DNS name are present in - * both certificates, they should be identical; otherwise, - * 3. if the subject fields are present in both certificates, the - * certificate subjects and issuers should be identical. - */ - private static boolean isIdentityEquivalent(X509Certificate thisCert, - X509Certificate prevCert) { - if (thisCert.equals(prevCert)) { - return true; - } - - // check subject alternative names - Collection<List<?>> thisSubjectAltNames = null; - try { - thisSubjectAltNames = thisCert.getSubjectAlternativeNames(); - } catch (CertificateParsingException cpe) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Attempt to obtain subjectAltNames extension failed!"); - } - } - - Collection<List<?>> prevSubjectAltNames = null; - try { - prevSubjectAltNames = prevCert.getSubjectAlternativeNames(); - } catch (CertificateParsingException cpe) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Attempt to obtain subjectAltNames extension failed!"); - } - } - - if ((thisSubjectAltNames != null) && (prevSubjectAltNames != null)) { - // check the iPAddress field in subjectAltName extension - Collection<String> thisSubAltIPAddrs = - getSubjectAltNames(thisSubjectAltNames, ALTNAME_IP); - Collection<String> prevSubAltIPAddrs = - getSubjectAltNames(prevSubjectAltNames, ALTNAME_IP); - if ((thisSubAltIPAddrs != null) && (prevSubAltIPAddrs != null) && - (isEquivalent(thisSubAltIPAddrs, prevSubAltIPAddrs))) { - - return true; - } - - // check the dNSName field in subjectAltName extension - Collection<String> thisSubAltDnsNames = - getSubjectAltNames(thisSubjectAltNames, ALTNAME_DNS); - Collection<String> prevSubAltDnsNames = - getSubjectAltNames(prevSubjectAltNames, ALTNAME_DNS); - if ((thisSubAltDnsNames != null) && (prevSubAltDnsNames != null) && - (isEquivalent(thisSubAltDnsNames, prevSubAltDnsNames))) { - - return true; - } - } - - // check the certificate subject and issuer - X500Principal thisSubject = thisCert.getSubjectX500Principal(); - X500Principal prevSubject = prevCert.getSubjectX500Principal(); - X500Principal thisIssuer = thisCert.getIssuerX500Principal(); - X500Principal prevIssuer = prevCert.getIssuerX500Principal(); - if (!thisSubject.getName().isEmpty() && - !prevSubject.getName().isEmpty() && - thisSubject.equals(prevSubject) && - thisIssuer.equals(prevIssuer)) { - return true; - } - - return false; - } - - /* - * Returns the subject alternative name of the specified type in the - * subjectAltNames extension of a certificate. - * - * Note that only those subjectAltName types that use String data - * should be passed into this function. - */ - private static Collection<String> getSubjectAltNames( - Collection<List<?>> subjectAltNames, int type) { - - HashSet<String> subAltDnsNames = null; - for (List<?> subjectAltName : subjectAltNames) { - int subjectAltNameType = (Integer)subjectAltName.get(0); - if (subjectAltNameType == type) { - String subAltDnsName = (String)subjectAltName.get(1); - if ((subAltDnsName != null) && !subAltDnsName.isEmpty()) { - if (subAltDnsNames == null) { - subAltDnsNames = - new HashSet<>(subjectAltNames.size()); - } - subAltDnsNames.add(subAltDnsName); - } - } - } - - return subAltDnsNames; - } - - private static boolean isEquivalent(Collection<String> thisSubAltNames, - Collection<String> prevSubAltNames) { - - for (String thisSubAltName : thisSubAltNames) { - for (String prevSubAltName : prevSubAltNames) { - // Only allow the exactly match. Check no wildcard character. - if (thisSubAltName.equalsIgnoreCase(prevSubAltName)) { - return true; - } - } - } - - return false; - } -}
--- a/src/share/classes/sun/security/ssl/DHClientKeyExchange.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.io.PrintStream; -import java.math.BigInteger; -import javax.net.ssl.SSLHandshakeException; - -/* - * Message used by clients to send their Diffie-Hellman public - * keys to servers. - * - * @author David Brownell - */ -final class DHClientKeyExchange extends HandshakeMessage { - - @Override - int messageType() { - return ht_client_key_exchange; - } - - /* - * This value may be empty if it was included in the - * client's certificate ... - */ - private byte dh_Yc[]; // 1 to 2^16 -1 bytes - - BigInteger getClientPublicKey() { - return dh_Yc == null ? null : new BigInteger(1, dh_Yc); - } - - /* - * Either pass the client's public key explicitly (because it's - * using DHE or DH_anon), or implicitly (the public key was in the - * certificate). - */ - DHClientKeyExchange(BigInteger publicKey) { - dh_Yc = toByteArray(publicKey); - } - - DHClientKeyExchange() { - dh_Yc = null; - } - - /* - * Get the client's public key either explicitly or implicitly. - * (It's ugly to have an empty record be sent in the latter case, - * but that's what the protocol spec requires.) - */ - DHClientKeyExchange(HandshakeInStream input) throws IOException { - if (input.available() >= 2) { - dh_Yc = input.getBytes16(); - } else { - // currently, we don't support cipher suites that requires - // implicit public key of client. - throw new SSLHandshakeException( - "Unsupported implicit client DiffieHellman public key"); - } - } - - @Override - int messageLength() { - if (dh_Yc == null) { - return 0; - } else { - return dh_Yc.length + 2; - } - } - - @Override - void send(HandshakeOutStream s) throws IOException { - if (dh_Yc != null && dh_Yc.length != 0) { - s.putBytes16(dh_Yc); - } - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** ClientKeyExchange, DH"); - - if (debug != null && Debug.isOn("verbose")) { - Debug.println(s, "DH Public key", dh_Yc); - } - } -}
--- a/src/share/classes/sun/security/ssl/DHCrypt.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,538 +0,0 @@ -/* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.Map; -import java.util.HashMap; -import java.util.Collections; -import java.util.regex.Pattern; -import java.util.regex.Matcher; -import java.math.BigInteger; -import java.security.*; -import java.io.IOException; -import javax.net.ssl.SSLHandshakeException; -import javax.crypto.SecretKey; -import javax.crypto.KeyAgreement; -import javax.crypto.interfaces.DHPublicKey; -import javax.crypto.spec.*; -import java.util.EnumSet; - -import sun.security.util.KeyUtil; - -/** - * This class implements the Diffie-Hellman key exchange algorithm. - * D-H means combining your private key with your partners public key to - * generate a number. The peer does the same with its private key and our - * public key. Through the magic of Diffie-Hellman we both come up with the - * same number. This number is secret (discounting MITM attacks) and hence - * called the shared secret. It has the same length as the modulus, e.g. 512 - * or 1024 bit. Man-in-the-middle attacks are typically countered by an - * independent authentication step using certificates (RSA, DSA, etc.). - * - * The thing to note is that the shared secret is constant for two partners - * with constant private keys. This is often not what we want, which is why - * it is generally a good idea to create a new private key for each session. - * Generating a private key involves one modular exponentiation assuming - * suitable D-H parameters are available. - * - * General usage of this class (TLS DHE case): - * . if we are server, call DHCrypt(keyLength,random). This generates - * an ephemeral keypair of the request length. - * . if we are client, call DHCrypt(modulus, base, random). This - * generates an ephemeral keypair using the parameters specified by - * the server. - * . send parameters and public value to remote peer - * . receive peers ephemeral public key - * . call getAgreedSecret() to calculate the shared secret - * - * In TLS the server chooses the parameter values itself, the client must use - * those sent to it by the server. - * - * The use of ephemeral keys as described above also achieves what is called - * "forward secrecy". This means that even if the authentication keys are - * broken at a later date, the shared secret remains secure. The session is - * compromised only if the authentication keys are already broken at the - * time the key exchange takes place and an active MITM attack is used. - * This is in contrast to straightforward encrypting RSA key exchanges. - * - * @author David Brownell - */ -final class DHCrypt { - - // group parameters (prime modulus and generator) - private BigInteger modulus; // P (aka N) - private BigInteger base; // G (aka alpha) - - // our private key (including private component x) - private PrivateKey privateKey; - - // public component of our key, X = (g ^ x) mod p - private BigInteger publicValue; // X (aka y) - - // the times to recove from failure if public key validation - private static int MAX_FAILOVER_TIMES = 2; - - /** - * Generate a Diffie-Hellman keypair of the specified size. - */ - DHCrypt(int keyLength, SecureRandom random) { - this(keyLength, - ParametersHolder.definedParams.get(keyLength), random); - } - - /** - * Generate a Diffie-Hellman keypair using the specified parameters. - * - * @param modulus the Diffie-Hellman modulus P - * @param base the Diffie-Hellman base G - */ - DHCrypt(BigInteger modulus, BigInteger base, SecureRandom random) { - this(modulus.bitLength(), - new DHParameterSpec(modulus, base), random); - } - - /** - * Generate a Diffie-Hellman keypair using the specified size and - * parameters. - */ - private DHCrypt(int keyLength, - DHParameterSpec params, SecureRandom random) { - - try { - KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("DiffieHellman"); - if (params != null) { - kpg.initialize(params, random); - } else { - kpg.initialize(keyLength, random); - } - - DHPublicKeySpec spec = generateDHPublicKeySpec(kpg); - if (spec == null) { - throw new RuntimeException("Could not generate DH keypair"); - } - - publicValue = spec.getY(); - modulus = spec.getP(); - base = spec.getG(); - } catch (GeneralSecurityException e) { - throw new RuntimeException("Could not generate DH keypair", e); - } - } - - static DHPublicKeySpec getDHPublicKeySpec(PublicKey key) { - if (key instanceof DHPublicKey) { - DHPublicKey dhKey = (DHPublicKey)key; - DHParameterSpec params = dhKey.getParams(); - return new DHPublicKeySpec(dhKey.getY(), - params.getP(), params.getG()); - } - try { - KeyFactory factory = JsseJce.getKeyFactory("DiffieHellman"); - return factory.getKeySpec(key, DHPublicKeySpec.class); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - - /** Returns the Diffie-Hellman modulus. */ - BigInteger getModulus() { - return modulus; - } - - /** Returns the Diffie-Hellman base (generator). */ - BigInteger getBase() { - return base; - } - - /** - * Gets the public key of this end of the key exchange. - */ - BigInteger getPublicKey() { - return publicValue; - } - - /** - * Get the secret data that has been agreed on through Diffie-Hellman - * key agreement protocol. Note that in the two party protocol, if - * the peer keys are already known, no other data needs to be sent in - * order to agree on a secret. That is, a secured message may be - * sent without any mandatory round-trip overheads. - * - * <P>It is illegal to call this member function if the private key - * has not been set (or generated). - * - * @param peerPublicKey the peer's public key. - * @param keyIsValidated whether the {@code peerPublicKey} has beed - * validated - * @return the secret, which is an unsigned big-endian integer - * the same size as the Diffie-Hellman modulus. - */ - SecretKey getAgreedSecret(BigInteger peerPublicValue, - boolean keyIsValidated) throws SSLHandshakeException { - try { - KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); - DHPublicKeySpec spec = - new DHPublicKeySpec(peerPublicValue, modulus, base); - PublicKey publicKey = kf.generatePublic(spec); - KeyAgreement ka = JsseJce.getKeyAgreement("DiffieHellman"); - - // validate the Diffie-Hellman public key - if (!keyIsValidated && - !KeyUtil.isOracleJCEProvider(ka.getProvider().getName())) { - try { - KeyUtil.validate(spec); - } catch (InvalidKeyException ike) { - // prefer handshake_failure alert to internal_error alert - throw new SSLHandshakeException(ike.getMessage()); - } - } - - ka.init(privateKey); - ka.doPhase(publicKey, true); - return ka.generateSecret("TlsPremasterSecret"); - } catch (GeneralSecurityException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); - } - } - - // Check constraints of the specified DH public key. - void checkConstraints(AlgorithmConstraints constraints, - BigInteger peerPublicValue) throws SSLHandshakeException { - - try { - KeyFactory kf = JsseJce.getKeyFactory("DiffieHellman"); - DHPublicKeySpec spec = - new DHPublicKeySpec(peerPublicValue, modulus, base); - DHPublicKey publicKey = (DHPublicKey)kf.generatePublic(spec); - - // check constraints of DHPublicKey - if (!constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) { - throw new SSLHandshakeException( - "DHPublicKey does not comply to algorithm constraints"); - } - } catch (GeneralSecurityException gse) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate DHPublicKey").initCause(gse); - } - } - - // Generate and validate DHPublicKeySpec - private DHPublicKeySpec generateDHPublicKeySpec(KeyPairGenerator kpg) - throws GeneralSecurityException { - - boolean doExtraValiadtion = - (!KeyUtil.isOracleJCEProvider(kpg.getProvider().getName())); - for (int i = 0; i <= MAX_FAILOVER_TIMES; i++) { - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - DHPublicKeySpec spec = getDHPublicKeySpec(kp.getPublic()); - - // validate the Diffie-Hellman public key - if (doExtraValiadtion) { - try { - KeyUtil.validate(spec); - } catch (InvalidKeyException ivke) { - if (i == MAX_FAILOVER_TIMES) { - throw ivke; - } - // otherwise, ignore the exception and try the next one - continue; - } - } - - return spec; - } - - return null; - } - - // lazy initialization holder class idiom for static default parameters - // - // See Effective Java Second Edition: Item 71. - private static class ParametersHolder { - private final static boolean debugIsOn = - (Debug.getInstance("ssl") != null) && Debug.isOn("sslctx"); - - // - // Default DH ephemeral parameters - // - private static final BigInteger g2 = BigInteger.valueOf(2); - - private static final BigInteger p512 = new BigInteger( // generated - "D87780E15FF50B4ABBE89870188B049406B5BEA98AB23A02" + - "41D88EA75B7755E669C08093D3F0CA7FC3A5A25CF067DCB9" + - "A43DD89D1D90921C6328884461E0B6D3", 16); - private static final BigInteger p768 = new BigInteger( // RFC 2409 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16); - - private static final BigInteger p1024 = new BigInteger( // RFC 2409 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + - "FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p1536 = new BigInteger( // RFC 3526 - "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + - "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + - "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + - "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + - "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" + - "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" + - "83655D23DCA3AD961C62F356208552BB9ED529077096966D" + - "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p2048 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B423861285C97FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p3072 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B66C62E37FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p4096 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E655F6A" + - "FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p6144 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + - "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + - "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + - "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + - "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + - "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + - "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + - "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + - "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + - "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + - "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + - "A41D570D7938DAD4A40E329CD0E40E65FFFFFFFFFFFFFFFF", 16); - private static final BigInteger p8192 = new BigInteger( // TLS FFDHE - "FFFFFFFFFFFFFFFFADF85458A2BB4A9AAFDC5620273D3CF1" + - "D8B9C583CE2D3695A9E13641146433FBCC939DCE249B3EF9" + - "7D2FE363630C75D8F681B202AEC4617AD3DF1ED5D5FD6561" + - "2433F51F5F066ED0856365553DED1AF3B557135E7F57C935" + - "984F0C70E0E68B77E2A689DAF3EFE8721DF158A136ADE735" + - "30ACCA4F483A797ABC0AB182B324FB61D108A94BB2C8E3FB" + - "B96ADAB760D7F4681D4F42A3DE394DF4AE56EDE76372BB19" + - "0B07A7C8EE0A6D709E02FCE1CDF7E2ECC03404CD28342F61" + - "9172FE9CE98583FF8E4F1232EEF28183C3FE3B1B4C6FAD73" + - "3BB5FCBC2EC22005C58EF1837D1683B2C6F34A26C1B2EFFA" + - "886B4238611FCFDCDE355B3B6519035BBC34F4DEF99C0238" + - "61B46FC9D6E6C9077AD91D2691F7F7EE598CB0FAC186D91C" + - "AEFE130985139270B4130C93BC437944F4FD4452E2D74DD3" + - "64F2E21E71F54BFF5CAE82AB9C9DF69EE86D2BC522363A0D" + - "ABC521979B0DEADA1DBF9A42D5C4484E0ABCD06BFA53DDEF" + - "3C1B20EE3FD59D7C25E41D2B669E1EF16E6F52C3164DF4FB" + - "7930E9E4E58857B6AC7D5F42D69F6D187763CF1D55034004" + - "87F55BA57E31CC7A7135C886EFB4318AED6A1E012D9E6832" + - "A907600A918130C46DC778F971AD0038092999A333CB8B7A" + - "1A1DB93D7140003C2A4ECEA9F98D0ACC0A8291CDCEC97DCF" + - "8EC9B55A7F88A46B4DB5A851F44182E1C68A007E5E0DD902" + - "0BFD64B645036C7A4E677D2C38532A3A23BA4442CAF53EA6" + - "3BB454329B7624C8917BDD64B1C0FD4CB38E8C334C701C3A" + - "CDAD0657FCCFEC719B1F5C3E4E46041F388147FB4CFDB477" + - "A52471F7A9A96910B855322EDB6340D8A00EF092350511E3" + - "0ABEC1FFF9E3A26E7FB29F8C183023C3587E38DA0077D9B4" + - "763E4E4B94B2BBC194C6651E77CAF992EEAAC0232A281BF6" + - "B3A739C1226116820AE8DB5847A67CBEF9C9091B462D538C" + - "D72B03746AE77F5E62292C311562A846505DC82DB854338A" + - "E49F5235C95B91178CCF2DD5CACEF403EC9D1810C6272B04" + - "5B3B71F9DC6B80D63FDD4A8E9ADB1E6962A69526D43161C1" + - "A41D570D7938DAD4A40E329CCFF46AAA36AD004CF600C838" + - "1E425A31D951AE64FDB23FCEC9509D43687FEB69EDD1CC5E" + - "0B8CC3BDF64B10EF86B63142A3AB8829555B2F747C932665" + - "CB2C0F1CC01BD70229388839D2AF05E454504AC78B758282" + - "2846C0BA35C35F5C59160CC046FD8251541FC68C9C86B022" + - "BB7099876A460E7451A8A93109703FEE1C217E6C3826E52C" + - "51AA691E0E423CFC99E9E31650C1217B624816CDAD9A95F9" + - "D5B8019488D9C0A0A1FE3075A577E23183F81D4A3F2FA457" + - "1EFC8CE0BA8A4FE8B6855DFE72B0A66EDED2FBABFBE58A30" + - "FAFABE1C5D71A87E2F741EF8C1FE86FEA6BBFDE530677F0D" + - "97D11D49F7A8443D0822E506A9F4614E011E2A94838FF88C" + - "D68C8BB7C5C6424CFFFFFFFFFFFFFFFF", 16); - - private static final BigInteger[] supportedPrimes = { - p512, p768, p1024, p1536, p2048, p3072, p4096, p6144, p8192}; - - // a measure of the uncertainty that prime modulus p is not a prime - // - // see BigInteger.isProbablePrime(int certainty) - private final static int PRIME_CERTAINTY = 120; - - // the known security property, jdk.tls.server.defaultDHEParameters - private final static String PROPERTY_NAME = - "jdk.tls.server.defaultDHEParameters"; - - private static final Pattern spacesPattern = Pattern.compile("\\s+"); - - private final static Pattern syntaxPattern = Pattern.compile( - "(\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})" + - "(,\\{[0-9A-Fa-f]+,[0-9A-Fa-f]+\\})*"); - - private static final Pattern paramsPattern = Pattern.compile( - "\\{([0-9A-Fa-f]+),([0-9A-Fa-f]+)\\}"); - - // cache of predefined default DH ephemeral parameters - private final static Map<Integer,DHParameterSpec> definedParams; - - static { - String property = AccessController.doPrivileged( - new PrivilegedAction<String>() { - public String run() { - return Security.getProperty(PROPERTY_NAME); - } - }); - - if (property != null && !property.isEmpty()) { - // remove double quote marks from beginning/end of the property - if (property.length() >= 2 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - - property = property.trim(); - } - - if (property != null && !property.isEmpty()) { - Matcher spacesMatcher = spacesPattern.matcher(property); - property = spacesMatcher.replaceAll(""); - - if (debugIsOn) { - System.out.println("The Security Property " + - PROPERTY_NAME + ": " + property); - } - } - - Map<Integer,DHParameterSpec> defaultParams = new HashMap<>(); - if (property != null && !property.isEmpty()) { - Matcher syntaxMatcher = syntaxPattern.matcher(property); - if (syntaxMatcher.matches()) { - Matcher paramsFinder = paramsPattern.matcher(property); - while(paramsFinder.find()) { - String primeModulus = paramsFinder.group(1); - BigInteger p = new BigInteger(primeModulus, 16); - if (!p.isProbablePrime(PRIME_CERTAINTY)) { - if (debugIsOn) { - System.out.println( - "Prime modulus p in Security Property, " + - PROPERTY_NAME + ", is not a prime: " + - primeModulus); - } - - continue; - } - - String baseGenerator = paramsFinder.group(2); - BigInteger g = new BigInteger(baseGenerator, 16); - - DHParameterSpec spec = new DHParameterSpec(p, g); - int primeLen = p.bitLength(); - defaultParams.put(primeLen, spec); - } - } else if (debugIsOn) { - System.out.println("Invalid Security Property, " + - PROPERTY_NAME + ", definition"); - } - } - - for (BigInteger p : supportedPrimes) { - int primeLen = p.bitLength(); - defaultParams.putIfAbsent(primeLen, new DHParameterSpec(p, g2)); - } - - definedParams = - Collections.<Integer,DHParameterSpec>unmodifiableMap( - defaultParams); - } - } -}
--- a/src/share/classes/sun/security/ssl/Debug.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/* - * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.PrintStream; -import java.security.AccessController; -import java.util.Locale; - -import sun.security.action.GetPropertyAction; - -/** - * This class has be shamefully lifted from sun.security.util.Debug - * - * @author Gary Ellison - */ -public class Debug { - - private String prefix; - - private static String args; - - static { - args = java.security.AccessController.doPrivileged( - new GetPropertyAction("javax.net.debug", "")); - args = args.toLowerCase(Locale.ENGLISH); - if (args.equals("help")) { - Help(); - } - } - - public static void Help() - { - System.err.println(); - System.err.println("all turn on all debugging"); - System.err.println("ssl turn on ssl debugging"); - System.err.println(); - System.err.println("The following can be used with ssl:"); - System.err.println("\trecord enable per-record tracing"); - System.err.println("\thandshake print each handshake message"); - System.err.println("\tkeygen print key generation data"); - System.err.println("\tsession print session activity"); - System.err.println("\tdefaultctx print default SSL initialization"); - System.err.println("\tsslctx print SSLContext tracing"); - System.err.println("\tsessioncache print session cache tracing"); - System.err.println("\tkeymanager print key manager tracing"); - System.err.println("\ttrustmanager print trust manager tracing"); - System.err.println("\tpluggability print pluggability tracing"); - System.err.println(); - System.err.println("\thandshake debugging can be widened with:"); - System.err.println("\tdata hex dump of each handshake message"); - System.err.println("\tverbose verbose handshake message printing"); - System.err.println(); - System.err.println("\trecord debugging can be widened with:"); - System.err.println("\tplaintext hex dump of record plaintext"); - System.err.println("\tpacket print raw SSL/TLS packets"); - System.err.println(); - System.exit(0); - } - - /** - * Get a Debug object corresponding to whether or not the given - * option is set. Set the prefix to be the same as option. - */ - - public static Debug getInstance(String option) - { - return getInstance(option, option); - } - - /** - * Get a Debug object corresponding to whether or not the given - * option is set. Set the prefix to be prefix. - */ - public static Debug getInstance(String option, String prefix) - { - if (isOn(option)) { - Debug d = new Debug(); - d.prefix = prefix; - return d; - } else { - return null; - } - } - - /** - * True if the property "javax.net.debug" contains the - * string "option". - */ - public static boolean isOn(String option) - { - if (args == null) { - return false; - } else { - int n = 0; - option = option.toLowerCase(Locale.ENGLISH); - - if (args.indexOf("all") != -1) { - return true; - } else if ((n = args.indexOf("ssl")) != -1) { - if (args.indexOf("sslctx", n) == -1) { - // don't enable data and plaintext options by default - if (!(option.equals("data") - || option.equals("packet") - || option.equals("plaintext"))) { - return true; - } - } - } - return (args.indexOf(option) != -1); - } - } - - /** - * print a message to stderr that is prefixed with the prefix - * created from the call to getInstance. - */ - - public void println(String message) - { - System.err.println(prefix + ": "+message); - } - - /** - * print a blank line to stderr that is prefixed with the prefix. - */ - - public void println() - { - System.err.println(prefix + ":"); - } - - /** - * print a message to stderr that is prefixed with the prefix. - */ - - public static void println(String prefix, String message) - { - System.err.println(prefix + ": "+message); - } - - public static void println(PrintStream s, String name, byte[] data) { - s.print(name + ": { "); - if (data == null) { - s.print("null"); - } else { - for (int i = 0; i < data.length; i++) { - if (i != 0) s.print(", "); - s.print(data[i] & 0x0ff); - } - } - s.println(" }"); - } - - /** - * Return the value of the boolean System property propName. - * - * Note use of doPrivileged(). Do make accessible to applications. - */ - static boolean getBooleanProperty(String propName, boolean defaultValue) { - // if set, require value of either true or false - String b = AccessController.doPrivileged( - new GetPropertyAction(propName)); - if (b == null) { - return defaultValue; - } else if (b.equalsIgnoreCase("false")) { - return false; - } else if (b.equalsIgnoreCase("true")) { - return true; - } else { - throw new RuntimeException("Value of " + propName - + " must either be 'true' or 'false'"); - } - } - - static String toString(byte[] b) { - return sun.security.util.Debug.toString(b); - } -}
--- a/src/share/classes/sun/security/ssl/ECDHClientKeyExchange.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.io.PrintStream; - -import java.security.PublicKey; -import java.security.interfaces.ECPublicKey; -import java.security.spec.*; - -/** - * ClientKeyExchange message for all ECDH based key exchange methods. It - * contains the client's ephemeral public value. - * - * @since 1.6 - * @author Andreas Sterbenz - */ -final class ECDHClientKeyExchange extends HandshakeMessage { - - @Override - int messageType() { - return ht_client_key_exchange; - } - - private byte[] encodedPoint; - - byte[] getEncodedPoint() { - return encodedPoint; - } - - // Called by the client with its ephemeral public key. - ECDHClientKeyExchange(PublicKey publicKey) { - ECPublicKey ecKey = (ECPublicKey)publicKey; - ECPoint point = ecKey.getW(); - ECParameterSpec params = ecKey.getParams(); - encodedPoint = JsseJce.encodePoint(point, params.getCurve()); - } - - ECDHClientKeyExchange(HandshakeInStream input) throws IOException { - encodedPoint = input.getBytes8(); - } - - @Override - int messageLength() { - return encodedPoint.length + 1; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putBytes8(encodedPoint); - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** ECDHClientKeyExchange"); - - if (debug != null && Debug.isOn("verbose")) { - Debug.println(s, "ECDH Public value", encodedPoint); - } - } -}
--- a/src/share/classes/sun/security/ssl/ECDHCrypt.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +0,0 @@ -/* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.*; -import java.security.interfaces.ECPublicKey; -import java.security.spec.*; - -import java.util.EnumSet; -import javax.crypto.SecretKey; -import javax.crypto.KeyAgreement; -import javax.net.ssl.SSLHandshakeException; - -/** - * Helper class for the ECDH key exchange. It generates the appropriate - * ephemeral keys as necessary and performs the actual shared secret derivation. - * - * @since 1.6 - * @author Andreas Sterbenz - */ -final class ECDHCrypt { - - // our private key - private PrivateKey privateKey; - - // our public key - private ECPublicKey publicKey; - - // Called by ServerHandshaker for static ECDH - ECDHCrypt(PrivateKey privateKey, PublicKey publicKey) { - this.privateKey = privateKey; - this.publicKey = (ECPublicKey)publicKey; - } - - // Called by ServerHandshaker for ephemeral ECDH - ECDHCrypt(int curveId, SecureRandom random) { - try { - KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC"); - ECGenParameterSpec params = - EllipticCurvesExtension.getECGenParamSpec(curveId); - kpg.initialize(params, random); - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - publicKey = (ECPublicKey)kp.getPublic(); - } catch (GeneralSecurityException e) { - throw new RuntimeException("Could not generate DH keypair", e); - } - } - - // Called by ClientHandshaker with params it received from the server - ECDHCrypt(ECParameterSpec params, SecureRandom random) { - try { - KeyPairGenerator kpg = JsseJce.getKeyPairGenerator("EC"); - kpg.initialize(params, random); - KeyPair kp = kpg.generateKeyPair(); - privateKey = kp.getPrivate(); - publicKey = (ECPublicKey)kp.getPublic(); - } catch (GeneralSecurityException e) { - throw new RuntimeException("Could not generate DH keypair", e); - } - } - - /** - * Gets the public key of this end of the key exchange. - */ - PublicKey getPublicKey() { - return publicKey; - } - - // called by ClientHandshaker with either the server's static or - // ephemeral public key - SecretKey getAgreedSecret( - PublicKey peerPublicKey) throws SSLHandshakeException { - - try { - KeyAgreement ka = JsseJce.getKeyAgreement("ECDH"); - ka.init(privateKey); - ka.doPhase(peerPublicKey, true); - return ka.generateSecret("TlsPremasterSecret"); - } catch (GeneralSecurityException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); - } - } - - // called by ServerHandshaker - SecretKey getAgreedSecret( - byte[] encodedPoint) throws SSLHandshakeException { - - try { - ECParameterSpec params = publicKey.getParams(); - ECPoint point = - JsseJce.decodePoint(encodedPoint, params.getCurve()); - KeyFactory kf = JsseJce.getKeyFactory("EC"); - ECPublicKeySpec spec = new ECPublicKeySpec(point, params); - PublicKey peerPublicKey = kf.generatePublic(spec); - return getAgreedSecret(peerPublicKey); - } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate secret").initCause(e); - } - } - - // Check constraints of the specified EC public key. - void checkConstraints(AlgorithmConstraints constraints, - byte[] encodedPoint) throws SSLHandshakeException { - - try { - - ECParameterSpec params = publicKey.getParams(); - ECPoint point = - JsseJce.decodePoint(encodedPoint, params.getCurve()); - ECPublicKeySpec spec = new ECPublicKeySpec(point, params); - - KeyFactory kf = JsseJce.getKeyFactory("EC"); - ECPublicKey publicKey = (ECPublicKey)kf.generatePublic(spec); - - // check constraints of ECPublicKey - if (!constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), publicKey)) { - throw new SSLHandshakeException( - "ECPublicKey does not comply to algorithm constraints"); - } - } catch (GeneralSecurityException | java.io.IOException e) { - throw (SSLHandshakeException) new SSLHandshakeException( - "Could not generate ECPublicKey").initCause(e); - } - } - -}
--- a/src/share/classes/sun/security/ssl/EllipticCurvesExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,388 +0,0 @@ -/* - * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.spec.ECParameterSpec; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.InvalidParameterSpecException; -import java.security.AlgorithmParameters; -import java.security.AlgorithmConstraints; -import java.security.CryptoPrimitive; -import java.security.AccessController; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.Map; -import java.util.ArrayList; -import javax.net.ssl.SSLProtocolException; - -import sun.security.action.GetPropertyAction; - -final class EllipticCurvesExtension extends HelloExtension { - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - private static final int ARBITRARY_PRIME = 0xff01; - private static final int ARBITRARY_CHAR2 = 0xff02; - - // speed up the searching - private static final Map<String, Integer> oidToIdMap = new HashMap<>(); - private static final Map<Integer, String> idToOidMap = new HashMap<>(); - - // speed up the parameters construction - private static final Map<Integer, - AlgorithmParameters> idToParams = new HashMap<>(); - - // the supported elliptic curves - private static final int[] supportedCurveIds; - - // the curves of the extension - private final int[] curveIds; - - // See sun.security.util.CurveDB for the OIDs - private static enum NamedEllipticCurve { - T163_K1(1, "sect163k1", "1.3.132.0.1", true), // NIST K-163 - T163_R1(2, "sect163r1", "1.3.132.0.2", false), - T163_R2(3, "sect163r2", "1.3.132.0.15", true), // NIST B-163 - T193_R1(4, "sect193r1", "1.3.132.0.24", false), - T193_R2(5, "sect193r2", "1.3.132.0.25", false), - T233_K1(6, "sect233k1", "1.3.132.0.26", true), // NIST K-233 - T233_R1(7, "sect233r1", "1.3.132.0.27", true), // NIST B-233 - T239_K1(8, "sect239k1", "1.3.132.0.3", false), - T283_K1(9, "sect283k1", "1.3.132.0.16", true), // NIST K-283 - T283_R1(10, "sect283r1", "1.3.132.0.17", true), // NIST B-283 - T409_K1(11, "sect409k1", "1.3.132.0.36", true), // NIST K-409 - T409_R1(12, "sect409r1", "1.3.132.0.37", true), // NIST B-409 - T571_K1(13, "sect571k1", "1.3.132.0.38", true), // NIST K-571 - T571_R1(14, "sect571r1", "1.3.132.0.39", true), // NIST B-571 - - P160_K1(15, "secp160k1", "1.3.132.0.9", false), - P160_R1(16, "secp160r1", "1.3.132.0.8", false), - P160_R2(17, "secp160r2", "1.3.132.0.30", false), - P192_K1(18, "secp192k1", "1.3.132.0.31", false), - P192_R1(19, "secp192r1", "1.2.840.10045.3.1.1", true), // NIST P-192 - P224_K1(20, "secp224k1", "1.3.132.0.32", false), - P224_R1(21, "secp224r1", "1.3.132.0.33", true), // NIST P-224 - P256_K1(22, "secp256k1", "1.3.132.0.10", false), - P256_R1(23, "secp256r1", "1.2.840.10045.3.1.7", true), // NIST P-256 - P384_R1(24, "secp384r1", "1.3.132.0.34", true), // NIST P-384 - P521_R1(25, "secp521r1", "1.3.132.0.35", true); // NIST P-521 - - int id; - String name; - String oid; - boolean isFips; - - NamedEllipticCurve(int id, String name, String oid, boolean isFips) { - this.id = id; - this.name = name; - this.oid = oid; - this.isFips = isFips; - - if (oidToIdMap.put(oid, id) != null || - idToOidMap.put(id, oid) != null) { - - throw new RuntimeException( - "Duplicate named elliptic curve definition: " + name); - } - } - - static NamedEllipticCurve getCurve(String name, boolean requireFips) { - for (NamedEllipticCurve curve : NamedEllipticCurve.values()) { - if (curve.name.equals(name) && (!requireFips || curve.isFips)) { - return curve; - } - } - - return null; - } - } - - static { - boolean requireFips = SunJSSE.isFIPS(); - - // hack code to initialize NamedEllipticCurve - NamedEllipticCurve nec = - NamedEllipticCurve.getCurve("secp256r1", false); - - // The value of the System Property defines a list of enabled named - // curves in preference order, separated with comma. For example: - // - // jdk.tls.namedGroups="secp521r1, secp256r1, secp384r1" - // - // If the System Property is not defined or the value is empty, the - // default curves and preferences will be used. - String property = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.namedGroups")); - if (property != null && property.length() != 0) { - // remove double quote marks from beginning/end of the property - if (property.length() > 1 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - } - - ArrayList<Integer> idList; - if (property != null && property.length() != 0) { // customized curves - String[] curves = property.split(","); - idList = new ArrayList<>(curves.length); - for (String curve : curves) { - curve = curve.trim(); - if (!curve.isEmpty()) { - NamedEllipticCurve namedCurve = - NamedEllipticCurve.getCurve(curve, requireFips); - if (namedCurve != null) { - if (isAvailableCurve(namedCurve.id)) { - idList.add(namedCurve.id); - } - } // ignore unknown curves - } - } - if (idList.isEmpty() && JsseJce.isEcAvailable()) { - throw new IllegalArgumentException( - "System property jdk.tls.namedGroups(" + property + ") " + - "contains no supported elliptic curves"); - } - } else { // default curves - int[] ids = new int[] { - // The three widely-used NIST curves: - // secp256r1, secp384r1 & secp521r1 - 23, 24, 25 - }; - - idList = new ArrayList<>(ids.length); - for (int curveId : ids) { - if (isAvailableCurve(curveId)) { - idList.add(curveId); - } - } - } - - if (debug != null && idList.isEmpty()) { - debug.println( - "Initialized [jdk.tls.namedGroups|default] list contains " + - "no available elliptic curves. " + - (property != null ? "(" + property + ")" : "[Default]")); - } - - supportedCurveIds = new int[idList.size()]; - int i = 0; - for (Integer id : idList) { - supportedCurveIds[i++] = id; - } - } - - // check whether the curve is supported by the underlying providers - private static boolean isAvailableCurve(int curveId) { - String oid = idToOidMap.get(curveId); - if (oid != null) { - AlgorithmParameters params = null; - try { - params = JsseJce.getAlgorithmParameters("EC"); - params.init(new ECGenParameterSpec(oid)); - } catch (Exception e) { - return false; - } - - // cache the parameters - idToParams.put(curveId, params); - - return true; - } - - return false; - } - - private EllipticCurvesExtension(int[] curveIds) { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - this.curveIds = curveIds; - } - - EllipticCurvesExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_ELLIPTIC_CURVES); - int k = s.getInt16(); - if (((len & 1) != 0) || (k + 2 != len)) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - // Note: unknown curves will be ignored later. - curveIds = new int[k >> 1]; - for (int i = 0; i < curveIds.length; i++) { - curveIds[i] = s.getInt16(); - } - } - - // get the preferred active curve - static int getActiveCurves(AlgorithmConstraints constraints) { - return getPreferredCurve(supportedCurveIds, constraints); - } - - static boolean hasActiveCurves(AlgorithmConstraints constraints) { - return getActiveCurves(constraints) >= 0; - } - - static EllipticCurvesExtension createExtension( - AlgorithmConstraints constraints) { - - ArrayList<Integer> idList = new ArrayList<>(supportedCurveIds.length); - for (int curveId : supportedCurveIds) { - if (constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - "EC", idToParams.get(curveId))) { - idList.add(curveId); - } - } - - if (!idList.isEmpty()) { - int[] ids = new int[idList.size()]; - int i = 0; - for (Integer id : idList) { - ids[i++] = id; - } - - return new EllipticCurvesExtension(ids); - } - - return null; - } - - // get the preferred activated curve - int getPreferredCurve(AlgorithmConstraints constraints) { - return getPreferredCurve(curveIds, constraints); - } - - // get a preferred activated curve - private static int getPreferredCurve(int[] curves, - AlgorithmConstraints constraints) { - for (int curveId : curves) { - if (isSupported(curveId) && constraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - "EC", idToParams.get(curveId))) { - return curveId; - } - } - - return -1; - } - - boolean contains(int index) { - for (int curveId : curveIds) { - if (index == curveId) { - return true; - } - } - return false; - } - - @Override - int length() { - return 6 + (curveIds.length << 1); - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - int k = curveIds.length << 1; - s.putInt16(k + 2); - s.putInt16(k); - for (int curveId : curveIds) { - s.putInt16(curveId); - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("Extension " + type + ", curve names: {"); - boolean first = true; - for (int curveId : curveIds) { - if (first) { - first = false; - } else { - sb.append(", "); - } - String curveName = getCurveName(curveId); - if (curveName != null) { - sb.append(curveName); - } else if (curveId == ARBITRARY_PRIME) { - sb.append("arbitrary_explicit_prime_curves"); - } else if (curveId == ARBITRARY_CHAR2) { - sb.append("arbitrary_explicit_char2_curves"); - } else { - sb.append("unknown curve " + curveId); - } - } - sb.append("}"); - return sb.toString(); - } - - // Test whether the given curve is supported. - static boolean isSupported(int index) { - for (int curveId : supportedCurveIds) { - if (index == curveId) { - return true; - } - } - - return false; - } - - static int getCurveIndex(ECParameterSpec params) { - String oid = JsseJce.getNamedCurveOid(params); - if (oid == null) { - return -1; - } - Integer n = oidToIdMap.get(oid); - return (n == null) ? -1 : n; - } - - static String getCurveOid(int index) { - return idToOidMap.get(index); - } - - static ECGenParameterSpec getECGenParamSpec(int index) { - AlgorithmParameters params = idToParams.get(index); - try { - return params.getParameterSpec(ECGenParameterSpec.class); - } catch (InvalidParameterSpecException ipse) { - // should be unlikely - String curveOid = getCurveOid(index); - return new ECGenParameterSpec(curveOid); - } - } - - private static String getCurveName(int index) { - for (NamedEllipticCurve namedCurve : NamedEllipticCurve.values()) { - if (namedCurve.id == index) { - return namedCurve.name; - } - } - - return null; - } -}
--- a/src/share/classes/sun/security/ssl/EllipticPointFormatsExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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; - -final class EllipticPointFormatsExtension extends HelloExtension { - - final static int FMT_UNCOMPRESSED = 0; - final static int FMT_ANSIX962_COMPRESSED_PRIME = 1; - final static int FMT_ANSIX962_COMPRESSED_CHAR2 = 2; - - static final HelloExtension DEFAULT = - new EllipticPointFormatsExtension( - new byte[] {FMT_UNCOMPRESSED}); - - private final byte[] formats; - - private EllipticPointFormatsExtension(byte[] formats) { - super(ExtensionType.EXT_EC_POINT_FORMATS); - this.formats = formats; - } - - EllipticPointFormatsExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_EC_POINT_FORMATS); - formats = s.getBytes8(); - // RFC 4492 says uncompressed points must always be supported. - // Check just to make sure. - boolean uncompressed = false; - for (int format : formats) { - if (format == FMT_UNCOMPRESSED) { - uncompressed = true; - break; - } - } - if (uncompressed == false) { - throw new SSLProtocolException - ("Peer does not support uncompressed points"); - } - } - - @Override - int length() { - return 5 + formats.length; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(formats.length + 1); - s.putBytes8(formats); - } - - private static String toString(byte format) { - int f = format & 0xff; - switch (f) { - case FMT_UNCOMPRESSED: - return "uncompressed"; - case FMT_ANSIX962_COMPRESSED_PRIME: - return "ansiX962_compressed_prime"; - case FMT_ANSIX962_COMPRESSED_CHAR2: - return "ansiX962_compressed_char2"; - default: - return "unknown-" + f; - } - } - - @Override - public String toString() { - List<String> list = new ArrayList<String>(); - for (byte format : formats) { - list.add(toString(format)); - } - return "Extension " + type + ", formats: " + list; - } -}
--- a/src/share/classes/sun/security/ssl/EngineArgs.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - * Copyright (c) 2004, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.nio.*; - -/* - * A multi-purpose class which handles all of the SSLEngine arguments. - * It validates arguments, checks for RO conditions, does space - * calculations, performs scatter/gather, etc. - * - * @author Brad R. Wetmore - */ -class EngineArgs { - - /* - * Keep track of the input parameters. - */ - ByteBuffer netData; - ByteBuffer [] appData; - - private int offset; // offset/len for the appData array. - private int len; - - /* - * The initial pos/limit conditions. This is useful because we can - * quickly calculate the amount consumed/produced in successful - * operations, or easily return the buffers to their pre-error - * conditions. - */ - private int netPos; - private int netLim; - - private int [] appPoss; - private int [] appLims; - - /* - * Sum total of the space remaining in all of the appData buffers - */ - private int appRemaining = 0; - - private boolean wrapMethod; - - /* - * Called by the SSLEngine.wrap() method. - */ - EngineArgs(ByteBuffer [] appData, int offset, int len, - ByteBuffer netData) { - this.wrapMethod = true; - init(netData, appData, offset, len); - } - - /* - * Called by the SSLEngine.unwrap() method. - */ - EngineArgs(ByteBuffer netData, ByteBuffer [] appData, int offset, - int len) { - this.wrapMethod = false; - init(netData, appData, offset, len); - } - - /* - * The main initialization method for the arguments. Most - * of them are pretty obvious as to what they do. - * - * Since we're already iterating over appData array for validity - * checking, we also keep track of how much remainging space is - * available. Info is used in both unwrap (to see if there is - * enough space available in the destination), and in wrap (to - * determine how much more we can copy into the outgoing data - * buffer. - */ - private void init(ByteBuffer netData, ByteBuffer [] appData, - int offset, int len) { - - if ((netData == null) || (appData == null)) { - throw new IllegalArgumentException("src/dst is null"); - } - - if ((offset < 0) || (len < 0) || (offset > appData.length - len)) { - throw new IndexOutOfBoundsException(); - } - - if (wrapMethod && netData.isReadOnly()) { - throw new ReadOnlyBufferException(); - } - - netPos = netData.position(); - netLim = netData.limit(); - - appPoss = new int [appData.length]; - appLims = new int [appData.length]; - - for (int i = offset; i < offset + len; i++) { - if (appData[i] == null) { - throw new IllegalArgumentException( - "appData[" + i + "] == null"); - } - - /* - * If we're unwrapping, then check to make sure our - * destination bufffers are writable. - */ - if (!wrapMethod && appData[i].isReadOnly()) { - throw new ReadOnlyBufferException(); - } - - appRemaining += appData[i].remaining(); - - appPoss[i] = appData[i].position(); - appLims[i] = appData[i].limit(); - } - - /* - * Ok, looks like we have a good set of args, let's - * store the rest of this stuff. - */ - this.netData = netData; - this.appData = appData; - this.offset = offset; - this.len = len; - } - - /* - * Given spaceLeft bytes to transfer, gather up that much data - * from the appData buffers (starting at offset in the array), - * and transfer it into the netData buffer. - * - * The user has already ensured there is enough room. - */ - void gather(int spaceLeft) { - for (int i = offset; (i < (offset + len)) && (spaceLeft > 0); i++) { - int amount = Math.min(appData[i].remaining(), spaceLeft); - appData[i].limit(appData[i].position() + amount); - netData.put(appData[i]); - appRemaining -= amount; - spaceLeft -= amount; - } - } - - /* - * Using the supplied buffer, scatter the data into the appData buffers - * (starting at offset in the array). - * - * The user has already ensured there is enough room. - */ - void scatter(ByteBuffer readyData) { - int amountLeft = readyData.remaining(); - - for (int i = offset; (i < (offset + len)) && (amountLeft > 0); - i++) { - int amount = Math.min(appData[i].remaining(), amountLeft); - readyData.limit(readyData.position() + amount); - appData[i].put(readyData); - amountLeft -= amount; - } - assert(readyData.remaining() == 0); - } - - int getAppRemaining() { - return appRemaining; - } - - /* - * Calculate the bytesConsumed/byteProduced. Aren't you glad - * we saved this off earlier? - */ - int deltaNet() { - return (netData.position() - netPos); - } - - /* - * Calculate the bytesConsumed/byteProduced. Aren't you glad - * we saved this off earlier? - */ - int deltaApp() { - int sum = 0; // Only calculating 2^14 here, don't need a long. - - for (int i = offset; i < offset + len; i++) { - sum += appData[i].position() - appPoss[i]; - } - - return sum; - } - - /* - * In the case of Exception, we want to reset the positions - * to appear as though no data has been consumed or produced. - * - * Currently, this method is only called as we are preparing to - * fail out, and thus we don't need to actually recalculate - * appRemaining. If that assumption changes, that variable should - * be updated here. - */ - void resetPos() { - netData.position(netPos); - for (int i = offset; i < offset + len; i++) { - // See comment above about recalculating appRemaining. - appData[i].position(appPoss[i]); - } - } - - /* - * We are doing lots of ByteBuffer manipulations, in which case - * we need to make sure that the limits get set back correctly. - * This is one of the last things to get done before returning to - * the user. - */ - void resetLim() { - netData.limit(netLim); - for (int i = offset; i < offset + len; i++) { - appData[i].limit(appLims[i]); - } - } -}
--- a/src/share/classes/sun/security/ssl/EngineInputRecord.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; -import javax.net.ssl.*; -import javax.crypto.BadPaddingException; -import sun.misc.HexDumpEncoder; - - -/** - * Wrapper class around InputRecord. - * - * Application data is kept external to the InputRecord, - * but handshake data (alert/change_cipher_spec/handshake) will - * be kept internally in the ByteArrayInputStream. - * - * @author Brad Wetmore - */ -final class EngineInputRecord extends InputRecord { - - private SSLEngineImpl engine; - - /* - * A dummy ByteBuffer we'll pass back even when the data - * is stored internally. It'll never actually be used. - */ - static private ByteBuffer tmpBB = ByteBuffer.allocate(0); - - /* - * Flag to tell whether the last read/parsed data resides - * internal in the ByteArrayInputStream, or in the external - * buffers. - */ - private boolean internalData; - - EngineInputRecord(SSLEngineImpl engine) { - super(); - this.engine = engine; - } - - @Override - byte contentType() { - if (internalData) { - return super.contentType(); - } else { - return ct_application_data; - } - } - - /* - * Check if there is enough inbound data in the ByteBuffer - * to make a inbound packet. Look for both SSLv2 and SSLv3. - * - * @return -1 if there are not enough bytes to tell (small header), - */ - int bytesInCompletePacket(ByteBuffer buf) throws SSLException { - - /* - * SSLv2 length field is in bytes 0/1 - * SSLv3/TLS length field is in bytes 3/4 - */ - if (buf.remaining() < 5) { - return -1; - } - - int pos = buf.position(); - byte byteZero = buf.get(pos); - - int len = 0; - - /* - * If we have already verified previous packets, we can - * ignore the verifications steps, and jump right to the - * determination. Otherwise, try one last hueristic to - * see if it's SSL/TLS. - */ - if (formatVerified || - (byteZero == ct_handshake) || - (byteZero == ct_alert)) { - /* - * Last sanity check that it's not a wild record - */ - ProtocolVersion recordVersion = - ProtocolVersion.valueOf(buf.get(pos + 1), buf.get(pos + 2)); - - // check the record version - checkRecordVersion(recordVersion, false); - - /* - * Reasonably sure this is a V3, disable further checks. - * We can't do the same in the v2 check below, because - * read still needs to parse/handle the v2 clientHello. - */ - formatVerified = true; - - /* - * One of the SSLv3/TLS message types. - */ - len = ((buf.get(pos + 3) & 0xff) << 8) + - (buf.get(pos + 4) & 0xff) + headerSize; - - } else { - /* - * Must be SSLv2 or something unknown. - * Check if it's short (2 bytes) or - * long (3) header. - * - * Internals can warn about unsupported SSLv2 - */ - boolean isShort = ((byteZero & 0x80) != 0); - - if (isShort && - ((buf.get(pos + 2) == 1) || buf.get(pos + 2) == 4)) { - - ProtocolVersion recordVersion = - ProtocolVersion.valueOf(buf.get(pos + 3), buf.get(pos + 4)); - - // check the record version - checkRecordVersion(recordVersion, true); - - /* - * Client or Server Hello - */ - int mask = (isShort ? 0x7f : 0x3f); - len = ((byteZero & mask) << 8) + (buf.get(pos + 1) & 0xff) + - (isShort ? 2 : 3); - - } else { - // Gobblygook! - throw new SSLException( - "Unrecognized SSL message, plaintext connection?"); - } - } - - return len; - } - - /* - * Pass the data down if it's internally cached, otherwise - * do it here. - * - * If internal data, data is decrypted internally. - * - * If external data(app), return a new ByteBuffer with data to - * process. - */ - ByteBuffer decrypt(Authenticator authenticator, - CipherBox box, ByteBuffer bb) throws BadPaddingException { - - if (internalData) { - decrypt(authenticator, box); // MAC is checked during decryption - return tmpBB; - } - - BadPaddingException reservedBPE = null; - int tagLen = - (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; - int cipheredLength = bb.remaining(); - - if (!box.isNullCipher()) { - try { - // apply explicit nonce for AEAD/CBC cipher suites if needed - int nonceSize = - box.applyExplicitNonce(authenticator, contentType(), bb); - - // decrypt the content - if (box.isAEADMode()) { - // DON'T encrypt the nonce_explicit for AEAD mode - bb.position(bb.position() + nonceSize); - } // The explicit IV for CBC mode can be decrypted. - - // Note that the CipherBox.decrypt() does not change - // the capacity of the buffer. - box.decrypt(bb, tagLen); - bb.position(nonceSize); // We don't actually remove the nonce. - } catch (BadPaddingException bpe) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al and the - // update in RFC 4346/5246. - // - // Failover to message authentication code checking. - reservedBPE = bpe; - } - } - - // Requires message authentication code for null, stream and block - // cipher suites. - if ((authenticator instanceof MAC) && (tagLen != 0)) { - MAC signer = (MAC)authenticator; - int macOffset = bb.limit() - tagLen; - - // Note that although it is not necessary, we run the same MAC - // computation and comparison on the payload for both stream - // cipher and CBC block cipher. - if (bb.remaining() < tagLen) { - // negative data length, something is wrong - if (reservedBPE == null) { - reservedBPE = new BadPaddingException("bad record"); - } - - // set offset of the dummy MAC - macOffset = cipheredLength - tagLen; - bb.limit(cipheredLength); - } - - // Run MAC computation and comparison on the payload. - if (checkMacTags(contentType(), bb, signer, false)) { - if (reservedBPE == null) { - reservedBPE = new BadPaddingException("bad record MAC"); - } - } - - // Run MAC computation and comparison on the remainder. - // - // It is only necessary for CBC block cipher. It is used to get a - // constant time of MAC computation and comparison on each record. - if (box.isCBCMode()) { - int remainingLen = calculateRemainingLen( - signer, cipheredLength, macOffset); - - // NOTE: here we use the InputRecord.buf because I did not find - // an effective way to work on ByteBuffer when its capacity is - // less than remainingLen. - - // NOTE: remainingLen may be bigger (less than 1 block of the - // hash algorithm of the MAC) than the cipheredLength. However, - // We won't need to worry about it because we always use a - // maximum buffer for every record. We need a change here if - // we use small buffer size in the future. - if (remainingLen > buf.length) { - // unlikely to happen, just a placehold - throw new RuntimeException( - "Internal buffer capacity error"); - } - - // Won't need to worry about the result on the remainder. And - // then we won't need to worry about what's actual data to - // check MAC tag on. We start the check from the header of the - // buffer so that we don't need to construct a new byte buffer. - checkMacTags(contentType(), buf, 0, remainingLen, signer, true); - } - - bb.limit(macOffset); - } - - // Is it a failover? - if (reservedBPE != null) { - throw reservedBPE; - } - - return bb.slice(); - } - - /* - * Run MAC computation and comparison - * - * Please DON'T change the content of the ByteBuffer parameter! - */ - private static boolean checkMacTags(byte contentType, ByteBuffer bb, - MAC signer, boolean isSimulated) { - - int position = bb.position(); - int tagLen = signer.MAClen(); - int lim = bb.limit(); - int macData = lim - tagLen; - - bb.limit(macData); - byte[] hash = signer.compute(contentType, bb, isSimulated); - if (hash == null || tagLen != hash.length) { - // Something is wrong with MAC implementation. - throw new RuntimeException("Internal MAC error"); - } - - bb.position(macData); - bb.limit(lim); - try { - int[] results = compareMacTags(bb, hash); - return (results[0] != 0); - } finally { - // reset to the data - bb.position(position); - bb.limit(macData); - } - } - - /* - * A constant-time comparison of the MAC tags. - * - * Please DON'T change the content of the ByteBuffer parameter! - */ - private static int[] compareMacTags(ByteBuffer bb, byte[] tag) { - - // An array of hits is used to prevent Hotspot optimization for - // the purpose of a constant-time check. - int[] results = {0, 0}; // {missed #, matched #} - - // The caller ensures there are enough bytes available in the buffer. - // So we won't need to check the remaining of the buffer. - for (int i = 0; i < tag.length; i++) { - if (bb.get() != tag[i]) { - results[0]++; // mismatched bytes - } else { - results[1]++; // matched bytes - } - } - - return results; - } - - /* - * Override the actual write below. We do things this way to be - * consistent with InputRecord. InputRecord may try to write out - * data to the peer, and *then* throw an Exception. This forces - * data to be generated/output before the exception is ever - * generated. - */ - @Override - void writeBuffer(OutputStream s, byte [] buf, int off, int len) - throws IOException { - /* - * Copy data out of buffer, it's ready to go. - */ - ByteBuffer netBB = (ByteBuffer) - (ByteBuffer.allocate(len).put(buf, 0, len).flip()); - engine.writer.putOutboundDataSync(netBB); - } - - /* - * Delineate or read a complete packet from src. - * - * If internal data (hs, alert, ccs), the data is read and - * stored internally. - * - * If external data (app), return a new ByteBuffer which points - * to the data to process. - */ - ByteBuffer read(ByteBuffer srcBB) throws IOException { - /* - * Could have a src == null/dst == null check here, - * but that was already checked by SSLEngine.unwrap before - * ever attempting to read. - */ - - /* - * If we have anything besides application data, - * or if we haven't even done the initial v2 verification, - * we send this down to be processed by the underlying - * internal cache. - */ - if (!formatVerified || - (srcBB.get(srcBB.position()) != ct_application_data)) { - internalData = true; - read(new ByteBufferInputStream(srcBB), (OutputStream) null); - return tmpBB; - } - - internalData = false; - - int srcPos = srcBB.position(); - int srcLim = srcBB.limit(); - - ProtocolVersion recordVersion = ProtocolVersion.valueOf( - srcBB.get(srcPos + 1), srcBB.get(srcPos + 2)); - - // check the record version - checkRecordVersion(recordVersion, false); - - /* - * It's really application data. How much to consume? - * Jump over the header. - */ - int len = bytesInCompletePacket(srcBB); - assert(len > 0); - - if (debug != null && Debug.isOn("packet")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - ByteBuffer bb = srcBB.duplicate(); // Use copy of BB - bb.limit(srcPos + len); - - System.out.println("[Raw read (bb)]: length = " + len); - hd.encodeBuffer(bb, System.out); - } catch (IOException e) { } - } - - // Demarcate past header to end of packet. - srcBB.position(srcPos + headerSize); - srcBB.limit(srcPos + len); - - // Protect remainder of buffer, create slice to actually - // operate on. - ByteBuffer bb = srcBB.slice(); - - srcBB.position(srcBB.limit()); - srcBB.limit(srcLim); - - return bb; - } -}
--- a/src/share/classes/sun/security/ssl/EngineOutputRecord.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,331 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; - -/** - * A OutputRecord class extension which uses external ByteBuffers - * or the internal ByteArrayOutputStream for data manipulations. - * <P> - * Instead of rewriting this entire class - * to use ByteBuffers, we leave things intact, so handshake, CCS, - * and alerts will continue to use the internal buffers, but application - * data will use external buffers. - * - * @author Brad Wetmore - */ -final class EngineOutputRecord extends OutputRecord { - - private SSLEngineImpl engine; - private EngineWriter writer; - - private boolean finishedMsg = false; - - /* - * All handshake hashing is done by the superclass - */ - - /* - * Default constructor makes a record supporting the maximum - * SSL record size. It allocates the header bytes directly. - * - * @param type the content type for the record - */ - EngineOutputRecord(byte type, SSLEngineImpl engine) { - super(type, recordSize(type)); - this.engine = engine; - writer = engine.writer; - } - - /** - * Get the size of the buffer we need for records of the specified - * type. - * <P> - * Application data buffers will provide their own byte buffers, - * and will not use the internal byte caching. - */ - private static int recordSize(byte type) { - switch (type) { - - case ct_change_cipher_spec: - case ct_alert: - return maxAlertRecordSize; - - case ct_handshake: - return maxRecordSize; - - case ct_application_data: - return 0; - } - - throw new RuntimeException("Unknown record type: " + type); - } - - void setFinishedMsg() { - finishedMsg = true; - } - - @Override - public void flush() throws IOException { - finishedMsg = false; - } - - boolean isFinishedMsg() { - return finishedMsg; - } - - /* - * Override the actual write below. We do things this way to be - * consistent with InputRecord. InputRecord may try to write out - * data to the peer, and *then* throw an Exception. This forces - * data to be generated/output before the exception is ever - * generated. - */ - @Override - void writeBuffer(OutputStream s, byte [] buf, int off, int len, - int debugOffset) throws IOException { - /* - * Copy data out of buffer, it's ready to go. - */ - ByteBuffer netBB = (ByteBuffer) - ByteBuffer.allocate(len).put(buf, off, len).flip(); - - writer.putOutboundData(netBB); - } - - /* - * Main method for writing non-application data. - * We MAC/encrypt, then send down for processing. - */ - void write(Authenticator authenticator, CipherBox writeCipher) - throws IOException { - - /* - * Sanity check. - */ - switch (contentType()) { - case ct_change_cipher_spec: - case ct_alert: - case ct_handshake: - break; - default: - throw new RuntimeException("unexpected byte buffers"); - } - - /* - * Don't bother to really write empty records. We went this - * far to drive the handshake machinery, for correctness; not - * writing empty records improves performance by cutting CPU - * time and network resource usage. Also, some protocol - * implementations are fragile and don't like to see empty - * records, so this increases robustness. - * - * (Even change cipher spec messages have a byte of data!) - */ - if (!isEmpty()) { - // compress(); // eventually - encrypt(authenticator, writeCipher); - - // send down for processing - write((OutputStream)null, false, (ByteArrayOutputStream)null); - } - return; - } - - /** - * Main wrap/write driver. - */ - void write(EngineArgs ea, Authenticator authenticator, - CipherBox writeCipher) throws IOException { - /* - * sanity check to make sure someone didn't inadvertantly - * send us an impossible combination we don't know how - * to process. - */ - assert(contentType() == ct_application_data); - - /* - * Have we set the MAC's yet? If not, we're not ready - * to process application data yet. - */ - if (authenticator == MAC.NULL) { - return; - } - - /* - * Don't bother to really write empty records. We went this - * far to drive the handshake machinery, for correctness; not - * writing empty records improves performance by cutting CPU - * time and network resource usage. Also, some protocol - * implementations are fragile and don't like to see empty - * records, so this increases robustness. - */ - if (ea.getAppRemaining() == 0) { - return; - } - - /* - * By default, we counter chosen plaintext issues on CBC mode - * ciphersuites in SSLv3/TLS1.0 by sending one byte of application - * data in the first record of every payload, and the rest in - * subsequent record(s). Note that the issues have been solved in - * TLS 1.1 or later. - * - * It is not necessary to split the very first application record of - * a freshly negotiated TLS session, as there is no previous - * application data to guess. To improve compatibility, we will not - * split such records. - * - * Because of the compatibility, we'd better produce no more than - * SSLSession.getPacketBufferSize() net data for each wrap. As we - * need a one-byte record at first, the 2nd record size should be - * equal to or less than Record.maxDataSizeMinusOneByteRecord. - * - * This avoids issues in the outbound direction. For a full fix, - * the peer must have similar protections. - */ - int length; - if (engine.needToSplitPayload(writeCipher, protocolVersion)) { - write(ea, authenticator, writeCipher, 0x01); - ea.resetLim(); // reset application data buffer limit - length = Math.min(ea.getAppRemaining(), - maxDataSizeMinusOneByteRecord); - } else { - length = Math.min(ea.getAppRemaining(), maxDataSize); - } - - // Don't bother to really write empty records. - if (length > 0) { - write(ea, authenticator, writeCipher, length); - } - - return; - } - - void write(EngineArgs ea, Authenticator authenticator, - CipherBox writeCipher, int length) throws IOException { - /* - * Copy out existing buffer values. - */ - ByteBuffer dstBB = ea.netData; - int dstPos = dstBB.position(); - int dstLim = dstBB.limit(); - - /* - * Where to put the data. Jump over the header. - * - * Don't need to worry about SSLv2 rewrites, if we're here, - * that's long since done. - */ - int dstData = dstPos + headerSize + writeCipher.getExplicitNonceSize(); - dstBB.position(dstData); - - /* - * transfer application data into the network data buffer - */ - ea.gather(length); - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - - /* - * "flip" but skip over header again, add MAC & encrypt - */ - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType(), dstBB, false); - - /* - * position was advanced to limit in compute above. - * - * Mark next area as writable (above layers should have - * established that we have plenty of room), then write - * out the hash. - */ - dstBB.limit(dstBB.limit() + hash.length); - dstBB.put(hash); - - // reset the position and limit - dstBB.limit(dstBB.position()); - dstBB.position(dstData); - } - } - - if (!writeCipher.isNullCipher()) { - /* - * Requires explicit IV/nonce for CBC/AEAD cipher suites for TLS 1.1 - * or later. - */ - if (protocolVersion.v >= ProtocolVersion.TLS11.v && - (writeCipher.isCBCMode() || writeCipher.isAEADMode())) { - byte[] nonce = writeCipher.createExplicitNonce( - authenticator, contentType(), dstBB.remaining()); - dstBB.position(dstPos + headerSize); - dstBB.put(nonce); - if (!writeCipher.isAEADMode()) { - // The explicit IV in TLS 1.1 and later can be encrypted. - dstBB.position(dstPos + headerSize); - } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode - } - - /* - * Encrypt may pad, so again the limit may have changed. - */ - writeCipher.encrypt(dstBB, dstLim); - - if ((debug != null) && (Debug.isOn("record") || - (Debug.isOn("handshake") && - (contentType() == ct_change_cipher_spec)))) { - System.out.println(Thread.currentThread().getName() - // v3.0/v3.1 ... - + ", WRITE: " + protocolVersion - + " " + InputRecord.contentName(contentType()) - + ", length = " + length); - } - } else { - dstBB.position(dstBB.limit()); - } - - int packetLength = dstBB.limit() - dstPos - headerSize; - - /* - * Finish out the record header. - */ - dstBB.put(dstPos, contentType()); - dstBB.put(dstPos + 1, protocolVersion.major); - dstBB.put(dstPos + 2, protocolVersion.minor); - dstBB.put(dstPos + 3, (byte)(packetLength >> 8)); - dstBB.put(dstPos + 4, (byte)packetLength); - - /* - * Position was already set by encrypt() above. - */ - dstBB.limit(dstLim); - } -}
--- a/src/share/classes/sun/security/ssl/EngineWriter.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.nio.ByteBuffer; -import java.util.LinkedList; -import javax.net.ssl.SSLEngineResult.HandshakeStatus; -import sun.misc.HexDumpEncoder; - -/** - * A class to help abstract away SSLEngine writing synchronization. - */ -final class EngineWriter { - - /* - * Outgoing handshake Data waiting for a ride is stored here. - * Normal application data is written directly into the outbound - * buffer, but handshake data can be written out at any time, - * so we have buffer it somewhere. - * - * When wrap is called, we first check to see if there is - * any data waiting, then if we're in a data transfer state, - * we try to write app data. - * - * This will contain either ByteBuffers, or the marker - * HandshakeStatus.FINISHED to signify that a handshake just completed. - */ - private LinkedList<Object> outboundList; - - private boolean outboundClosed = false; - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - EngineWriter() { - outboundList = new LinkedList<Object>(); - } - - /* - * Upper levels assured us we had room for at least one packet of data. - * As per the SSLEngine spec, we only return one SSL packets worth of - * data. - */ - private HandshakeStatus getOutboundData(ByteBuffer dstBB) { - - Object msg = outboundList.removeFirst(); - assert(msg instanceof ByteBuffer); - - ByteBuffer bbIn = (ByteBuffer) msg; - assert(dstBB.remaining() >= bbIn.remaining()); - - dstBB.put(bbIn); - - /* - * If we have more data in the queue, it's either - * a finished message, or an indication that we need - * to call wrap again. - */ - if (hasOutboundDataInternal()) { - msg = outboundList.getFirst(); - if (msg == HandshakeStatus.FINISHED) { - outboundList.removeFirst(); // consume the message - return HandshakeStatus.FINISHED; - } else { - return HandshakeStatus.NEED_WRAP; - } - } else { - return null; - } - } - - /* - * Properly orders the output of the data written to the wrap call. - * This is only handshake data, application data goes through the - * other writeRecord. - */ - synchronized void writeRecord(EngineOutputRecord outputRecord, - Authenticator authenticator, - CipherBox writeCipher) throws IOException { - - /* - * Only output if we're still open. - */ - if (outboundClosed) { - throw new IOException("writer side was already closed."); - } - - outputRecord.write(authenticator, writeCipher); - - /* - * Did our handshakers notify that we just sent the - * Finished message? - * - * Add an "I'm finished" message to the queue. - */ - if (outputRecord.isFinishedMsg()) { - outboundList.addLast(HandshakeStatus.FINISHED); - } - } - - /* - * Output the packet info. - */ - private void dumpPacket(EngineArgs ea, boolean hsData) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - ByteBuffer bb = ea.netData.duplicate(); - - int pos = bb.position(); - bb.position(pos - ea.deltaNet()); - bb.limit(pos); - - System.out.println("[Raw write" + - (hsData ? "" : " (bb)") + "]: length = " + - bb.remaining()); - hd.encodeBuffer(bb, System.out); - } catch (IOException e) { } - } - - /* - * Properly orders the output of the data written to the wrap call. - * Only app data goes through here, handshake data goes through - * the other writeRecord. - * - * Shouldn't expect to have an IOException here. - * - * Return any determined status. - */ - synchronized HandshakeStatus writeRecord( - EngineOutputRecord outputRecord, EngineArgs ea, - Authenticator authenticator, - CipherBox writeCipher) throws IOException { - - /* - * If we have data ready to go, output this first before - * trying to consume app data. - */ - if (hasOutboundDataInternal()) { - HandshakeStatus hss = getOutboundData(ea.netData); - - if (debug != null && Debug.isOn("packet")) { - /* - * We could have put the dump in - * OutputRecord.write(OutputStream), but let's actually - * output when it's actually output by the SSLEngine. - */ - dumpPacket(ea, true); - } - - return hss; - } - - /* - * If we are closed, no more app data can be output. - * Only existing handshake data (above) can be obtained. - */ - if (outboundClosed) { - throw new IOException("The write side was already closed"); - } - - outputRecord.write(ea, authenticator, writeCipher); - - if (debug != null && Debug.isOn("packet")) { - dumpPacket(ea, false); - } - - /* - * No way new outbound handshake data got here if we're - * locked properly. - * - * We don't have any status we can return. - */ - return null; - } - - /* - * We already hold "this" lock, this is the callback from the - * outputRecord.write() above. We already know this - * writer can accept more data (outboundClosed == false), - * and the closure is sync'd. - */ - void putOutboundData(ByteBuffer bytes) { - outboundList.addLast(bytes); - } - - /* - * This is for the really rare case that someone is writing from - * the *InputRecord* before we know what to do with it. - */ - synchronized void putOutboundDataSync(ByteBuffer bytes) - throws IOException { - - if (outboundClosed) { - throw new IOException("Write side already closed"); - } - - outboundList.addLast(bytes); - } - - /* - * Non-synch'd version of this method, called by internals - */ - private boolean hasOutboundDataInternal() { - return (outboundList.size() != 0); - } - - synchronized boolean hasOutboundData() { - return hasOutboundDataInternal(); - } - - synchronized boolean isOutboundDone() { - return outboundClosed && !hasOutboundDataInternal(); - } - - synchronized void closeOutbound() { - outboundClosed = true; - } - -}
--- a/src/share/classes/sun/security/ssl/EphemeralKeyManager.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.*; - -/** - * The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys - * are handled by the DHCrypt and ECDHCrypt classes, respectively. - * - * @author Andreas Sterbenz - */ -final class EphemeralKeyManager { - - // indices for the keys array below - private final static int INDEX_RSA512 = 0; - private final static int INDEX_RSA1024 = 1; - - /* - * Current cached RSA KeyPairs. Elements are never null. - * Indexed via the the constants above. - */ - private final EphemeralKeyPair[] keys = new EphemeralKeyPair[] { - new EphemeralKeyPair(null), - new EphemeralKeyPair(null), - }; - - EphemeralKeyManager() { - // empty - } - - /* - * Get a temporary RSA KeyPair. - */ - KeyPair getRSAKeyPair(boolean export, SecureRandom random) { - int length, index; - if (export) { - length = 512; - index = INDEX_RSA512; - } else { - length = 1024; - index = INDEX_RSA1024; - } - - synchronized (keys) { - KeyPair kp = keys[index].getKeyPair(); - if (kp == null) { - try { - KeyPairGenerator kgen = JsseJce.getKeyPairGenerator("RSA"); - kgen.initialize(length, random); - keys[index] = new EphemeralKeyPair(kgen.genKeyPair()); - kp = keys[index].getKeyPair(); - } catch (Exception e) { - // ignore - } - } - return kp; - } - } - - /** - * Inner class to handle storage of ephemeral KeyPairs. - */ - private static class EphemeralKeyPair { - - // maximum number of times a KeyPair is used - private final static int MAX_USE = 200; - - // maximum time interval in which the keypair is used (1 hour in ms) - private final static long USE_INTERVAL = 3600*1000; - - private KeyPair keyPair; - private int uses; - private long expirationTime; - - private EphemeralKeyPair(KeyPair keyPair) { - this.keyPair = keyPair; - expirationTime = System.currentTimeMillis() + USE_INTERVAL; - } - - /* - * Check if the KeyPair can still be used. - */ - private boolean isValid() { - return (keyPair != null) && (uses < MAX_USE) - && (System.currentTimeMillis() < expirationTime); - } - - /* - * Return the KeyPair or null if it is invalid. - */ - private KeyPair getKeyPair() { - if (isValid() == false) { - keyPair = null; - return null; - } - uses++; - return keyPair; - } - } -}
--- a/src/share/classes/sun/security/ssl/ExtendedMasterSecretExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2017, Red Hat, Inc. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.net.ssl.SSLProtocolException; - -/** - * Extended Master Secret TLS extension (TLS 1.0+). This extension - * defines how to calculate the TLS connection master secret and - * mitigates some types of man-in-the-middle attacks. - * - * See further information in - * <a href="https://tools.ietf.org/html/rfc7627">RFC 7627</a>. - * - * @author Martin Balao (mbalao@redhat.com) - */ -final class ExtendedMasterSecretExtension extends HelloExtension { - ExtendedMasterSecretExtension() { - super(ExtensionType.EXT_EXTENDED_MASTER_SECRET); - } - - ExtendedMasterSecretExtension(HandshakeInStream s, - int len) throws IOException { - super(ExtensionType.EXT_EXTENDED_MASTER_SECRET); - - if (len != 0) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - } - - @Override - int length() { - return 4; // 4: extension type and length fields - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); // ExtensionType extension_type; - s.putInt16(0); // extension_data length - } - - @Override - public String toString() { - return "Extension " + type; - } -} -
--- a/src/share/classes/sun/security/ssl/ExtensionType.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.ArrayList; -import java.util.List; - -final class ExtensionType { - - final int id; - final String name; - - private ExtensionType(int id, String name) { - this.id = id; - this.name = name; - } - - @Override - public String toString() { - return name; - } - - static List<ExtensionType> knownExtensions = - new ArrayList<ExtensionType>(15); - - static ExtensionType get(int id) { - for (ExtensionType ext : knownExtensions) { - if (ext.id == id) { - return ext; - } - } - return new ExtensionType(id, "type_" + id); - } - - private static ExtensionType e(int id, String name) { - ExtensionType ext = new ExtensionType(id, name); - knownExtensions.add(ext); - return ext; - } - - // extensions defined in RFC 3546 - final static ExtensionType EXT_SERVER_NAME = - e(0x0000, "server_name"); // IANA registry value: 0 - final static ExtensionType EXT_MAX_FRAGMENT_LENGTH = - e(0x0001, "max_fragment_length"); // IANA registry value: 1 - final static ExtensionType EXT_CLIENT_CERTIFICATE_URL = - e(0x0002, "client_certificate_url"); // IANA registry value: 2 - final static ExtensionType EXT_TRUSTED_CA_KEYS = - e(0x0003, "trusted_ca_keys"); // IANA registry value: 3 - final static ExtensionType EXT_TRUNCATED_HMAC = - e(0x0004, "truncated_hmac"); // IANA registry value: 4 - final static ExtensionType EXT_STATUS_REQUEST = - e(0x0005, "status_request"); // IANA registry value: 5 - - // extensions defined in RFC 4681 - final static ExtensionType EXT_USER_MAPPING = - e(0x0006, "user_mapping"); // IANA registry value: 6 - - // extensions defined in RFC 5081 - final static ExtensionType EXT_CERT_TYPE = - e(0x0009, "cert_type"); // IANA registry value: 9 - - // extensions defined in RFC 4492 (ECC) - final static ExtensionType EXT_ELLIPTIC_CURVES = - e(0x000A, "elliptic_curves"); // IANA registry value: 10 - final static ExtensionType EXT_EC_POINT_FORMATS = - e(0x000B, "ec_point_formats"); // IANA registry value: 11 - - // extensions defined in RFC 5054 - final static ExtensionType EXT_SRP = - e(0x000C, "srp"); // IANA registry value: 12 - - // extensions defined in RFC 5246 - final static ExtensionType EXT_SIGNATURE_ALGORITHMS = - e(0x000D, "signature_algorithms"); // IANA registry value: 13 - - // extension defined in RFC 7301 (ALPN) - static final ExtensionType EXT_ALPN = - e(0x0010, "application_layer_protocol_negotiation"); - // IANA registry value: 16 - - // extensions defined in RFC 7627 - static final ExtensionType EXT_EXTENDED_MASTER_SECRET = - e(0x0017, "extended_master_secret"); // IANA registry value: 23 - - // extensions defined in RFC 5746 - final static ExtensionType EXT_RENEGOTIATION_INFO = - e(0xff01, "renegotiation_info"); // IANA registry value: 65281 -}
--- a/src/share/classes/sun/security/ssl/HandshakeHash.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.ByteArrayOutputStream; -import java.security.*; -import java.util.Locale; - -/** - * Abstraction for the SSL/TLS hash of all handshake messages that is - * maintained to verify the integrity of the negotiation. Internally, - * it consists of an MD5 and an SHA1 digest. They are used in the client - * and server finished messages and in certificate verify messages (if sent). - * - * This class transparently deals with cloneable and non-cloneable digests. - * - * This class now supports TLS 1.2 also. The key difference for TLS 1.2 - * is that you cannot determine the hash algorithms for CertificateVerify - * at a early stage. On the other hand, it's simpler than TLS 1.1 (and earlier) - * that there is no messy MD5+SHA1 digests. - * - * You need to obey these conventions when using this class: - * - * 1. protocolDetermined(version) should be called when the negotiated - * protocol version is determined. - * - * 2. Before protocolDetermined() is called, only update(), and reset() - * and setFinishedAlg() can be called. - * - * 3. After protocolDetermined() is called, reset() cannot be called. - * - * 4. After protocolDetermined() is called, if the version is pre-TLS 1.2, - * getFinishedHash() cannot be called. Otherwise, - * getMD5Clone() and getSHAClone() cannot be called. - * - * 5. getMD5Clone() and getSHAClone() can only be called after - * protocolDetermined() is called and version is pre-TLS 1.2. - * - * 6. getFinishedHash() can only be called after protocolDetermined() - * and setFinishedAlg() have been called and the version is TLS 1.2. - * - * Suggestion: Call protocolDetermined() and setFinishedAlg() - * as early as possible. - * - * Example: - * <pre> - * HandshakeHash hh = new HandshakeHash(...) - * hh.protocolDetermined(ProtocolVersion.TLS12); - * hh.update(clientHelloBytes); - * hh.setFinishedAlg("SHA-256"); - * hh.update(serverHelloBytes); - * ... - * hh.update(CertificateVerifyBytes); - * ... - * hh.update(finished1); - * byte[] finDigest1 = hh.getFinishedHash(); - * hh.update(finished2); - * byte[] finDigest2 = hh.getFinishedHash(); - * </pre> - */ -final class HandshakeHash { - - // Common - - // -1: unknown - // 1: <=TLS 1.1 - // 2: TLS 1.2 - private int version = -1; - private ByteArrayOutputStream data = new ByteArrayOutputStream(); - - // For TLS 1.1 - private MessageDigest md5, sha; - private final int clonesNeeded; // needs to be saved for later use - - // For TLS 1.2 - private MessageDigest finMD; - - /** - * Create a new HandshakeHash. needCertificateVerify indicates whether - * a hash for the certificate verify message is required. - */ - HandshakeHash(boolean needCertificateVerify) { - // We may rework the code later, but for now we use hard-coded number - // of clones if the underlying MessageDigests are not cloneable. - // - // The number used here is based on the current handshake protocols and - // implementation. It may be changed if the handshake processe gets - // changed in the future, for example adding a new extension that - // requires handshake hash. Please be careful about the number of - // clones if additional handshak hash is required in the future. - // - // For the current implementation, the handshake hash is required for - // the following items: - // . CertificateVerify handshake message (optional) - // . client Finished handshake message - // . server Finished Handshake message - // . the extended Master Secret extension [RFC 7627] - // - // Note that a late call to server setNeedClientAuth dose not update - // the number of clones. We may address the issue later. - // - // Note for safe, we allocate one more clone for the current - // implementation. We may consider it more carefully in the future - // for the exactly number or rework the code in a different way. - clonesNeeded = needCertificateVerify ? 5 : 4; - } - - void update(byte[] b, int offset, int len) { - switch (version) { - case 1: - md5.update(b, offset, len); - sha.update(b, offset, len); - break; - default: - if (finMD != null) { - finMD.update(b, offset, len); - } - data.write(b, offset, len); - break; - } - } - - /** - * Reset the remaining digests. Note this does *not* reset the number of - * digest clones that can be obtained. Digests that have already been - * cloned and are gone remain gone. - */ - void reset() { - if (version != -1) { - throw new RuntimeException( - "reset() can be only be called before protocolDetermined"); - } - data.reset(); - } - - - void protocolDetermined(ProtocolVersion pv) { - - // Do not set again, will ignore - if (version != -1) return; - - version = pv.compareTo(ProtocolVersion.TLS12) >= 0 ? 2 : 1; - switch (version) { - case 1: - // initiate md5, sha and call update on saved array - try { - md5 = CloneableDigest.getDigest("MD5", clonesNeeded); - sha = CloneableDigest.getDigest("SHA", clonesNeeded); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException - ("Algorithm MD5 or SHA not available", e); - } - byte[] bytes = data.toByteArray(); - update(bytes, 0, bytes.length); - break; - case 2: - break; - } - } - - ///////////////////////////////////////////////////////////// - // Below are old methods for pre-TLS 1.1 - ///////////////////////////////////////////////////////////// - - /** - * Return a new MD5 digest updated with all data hashed so far. - */ - MessageDigest getMD5Clone() { - if (version != 1) { - throw new RuntimeException( - "getMD5Clone() can be only be called for TLS 1.1"); - } - return cloneDigest(md5); - } - - /** - * Return a new SHA digest updated with all data hashed so far. - */ - MessageDigest getSHAClone() { - if (version != 1) { - throw new RuntimeException( - "getSHAClone() can be only be called for TLS 1.1"); - } - return cloneDigest(sha); - } - - private static MessageDigest cloneDigest(MessageDigest digest) { - try { - return (MessageDigest)digest.clone(); - } catch (CloneNotSupportedException e) { - // cannot occur for digests generated via CloneableDigest - throw new RuntimeException("Could not clone digest", e); - } - } - - ///////////////////////////////////////////////////////////// - // Below are new methods for TLS 1.2 - ///////////////////////////////////////////////////////////// - - private static String normalizeAlgName(String alg) { - alg = alg.toUpperCase(Locale.US); - if (alg.startsWith("SHA")) { - if (alg.length() == 3) { - return "SHA-1"; - } - if (alg.charAt(3) != '-') { - return "SHA-" + alg.substring(3); - } - } - return alg; - } - /** - * Specifies the hash algorithm used in Finished. This should be called - * based in info in ServerHello. - * Can be called multiple times. - */ - void setFinishedAlg(String s) { - if (s == null) { - throw new RuntimeException( - "setFinishedAlg's argument cannot be null"); - } - - // Can be called multiple times, but only set once - if (finMD != null) return; - - try { - // See comment in the contructor. - finMD = CloneableDigest.getDigest(normalizeAlgName(s), 4); - } catch (NoSuchAlgorithmException e) { - throw new Error(e); - } - finMD.update(data.toByteArray()); - } - - byte[] getAllHandshakeMessages() { - return data.toByteArray(); - } - - /** - * Calculates the hash in Finished. Must be called after setFinishedAlg(). - * This method can be called twice, for Finished messages of the server - * side and client side respectively. - */ - byte[] getFinishedHash() { - try { - return cloneDigest(finMD).digest(); - } catch (Exception e) { - throw new Error("Error during hash calculation", e); - } - } -} - -/** - * A wrapper for MessageDigests that simulates cloning of non-cloneable - * digests. It uses the standard MessageDigest API and therefore can be used - * transparently in place of a regular digest. - * - * Note that we extend the MessageDigest class directly rather than - * MessageDigestSpi. This works because MessageDigest was originally designed - * this way in the JDK 1.1 days which allows us to avoid creating an internal - * provider. - * - * It can be "cloned" a limited number of times, which is specified at - * construction time. This is achieved by internally maintaining n digests - * in parallel. Consequently, it is only 1/n-th times as fast as the original - * digest. - * - * Example: - * MessageDigest md = CloneableDigest.getDigest("SHA", 2); - * md.update(data1); - * MessageDigest md2 = (MessageDigest)md.clone(); - * md2.update(data2); - * byte[] d1 = md2.digest(); // digest of data1 || data2 - * md.update(data3); - * byte[] d2 = md.digest(); // digest of data1 || data3 - * - * This class is not thread safe. - * - */ -final class CloneableDigest extends MessageDigest implements Cloneable { - - /** - * The individual MessageDigests. Initially, all elements are non-null. - * When clone() is called, the non-null element with the maximum index is - * returned and the array element set to null. - * - * All non-null element are always in the same state. - */ - private final MessageDigest[] digests; - - private CloneableDigest(MessageDigest digest, int n, String algorithm) - throws NoSuchAlgorithmException { - super(algorithm); - digests = new MessageDigest[n]; - digests[0] = digest; - for (int i = 1; i < n; i++) { - digests[i] = JsseJce.getMessageDigest(algorithm); - } - } - - /** - * Return a MessageDigest for the given algorithm that can be cloned the - * specified number of times. If the default implementation supports - * cloning, it is returned. Otherwise, an instance of this class is - * returned. - */ - static MessageDigest getDigest(String algorithm, int n) - throws NoSuchAlgorithmException { - MessageDigest digest = JsseJce.getMessageDigest(algorithm); - try { - digest.clone(); - // already cloneable, use it - return digest; - } catch (CloneNotSupportedException e) { - return new CloneableDigest(digest, n, algorithm); - } - } - - /** - * Check if this object is still usable. If it has already been cloned the - * maximum number of times, there are no digests left and this object can no - * longer be used. - */ - private void checkState() { - // XXX handshaking currently doesn't stop updating hashes... - // if (digests[0] == null) { - // throw new IllegalStateException("no digests left"); - // } - } - - @Override - protected int engineGetDigestLength() { - checkState(); - return digests[0].getDigestLength(); - } - - @Override - protected void engineUpdate(byte b) { - checkState(); - for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { - digests[i].update(b); - } - } - - @Override - protected void engineUpdate(byte[] b, int offset, int len) { - checkState(); - for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { - digests[i].update(b, offset, len); - } - } - - @Override - protected byte[] engineDigest() { - checkState(); - byte[] digest = digests[0].digest(); - digestReset(); - return digest; - } - - @Override - protected int engineDigest(byte[] buf, int offset, int len) - throws DigestException { - checkState(); - int n = digests[0].digest(buf, offset, len); - digestReset(); - return n; - } - - /** - * Reset all digests after a digest() call. digests[0] has already been - * implicitly reset by the digest() call and does not need to be reset - * again. - */ - private void digestReset() { - for (int i = 1; (i < digests.length) && (digests[i] != null); i++) { - digests[i].reset(); - } - } - - @Override - protected void engineReset() { - checkState(); - for (int i = 0; (i < digests.length) && (digests[i] != null); i++) { - digests[i].reset(); - } - } - - @Override - public Object clone() { - checkState(); - for (int i = digests.length - 1; i >= 0; i--) { - if (digests[i] != null) { - MessageDigest digest = digests[i]; - digests[i] = null; - return digest; - } - } - // cannot occur - throw new InternalError(); - } - -}
--- a/src/share/classes/sun/security/ssl/HandshakeInStream.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.InputStream; -import java.io.IOException; - -import javax.net.ssl.SSLException; - -/** - * InputStream for handshake data, used internally only. Contains the - * handshake message buffer and methods to parse them. - * - * Once a new handshake record arrives, it is buffered in this class until - * processed by the Handshaker. The buffer may also contain incomplete - * handshake messages in case the message is split across multiple records. - * Handshaker.process_record deals with all that. It may also contain - * handshake messages larger than the default buffer size (e.g. large - * certificate messages). The buffer is grown dynamically to handle that - * (see InputRecord.queueHandshake()). - * - * Note that the InputRecord used as a buffer here is separate from the - * AppInStream.r, which is where data from the socket is initially read - * into. This is because once the initial handshake has been completed, - * handshake and application data messages may be interleaved arbitrarily - * and must be processed independently. - * - * @author David Brownell - */ -public class HandshakeInStream extends InputStream { - - InputRecord r; - - /* - * Construct the stream; we'll be accumulating hashes of the - * input records using two sets of digests. - */ - HandshakeInStream(HandshakeHash handshakeHash) { - r = new InputRecord(); - r.setHandshakeHash(handshakeHash); - } - - - // overridden InputStream methods - - /* - * Return the number of bytes available for read(). - * - * Note that this returns the bytes remaining in the buffer, not - * the bytes remaining in the current handshake message. - */ - @Override - public int available() { - return r.available(); - } - - /* - * Get a byte of handshake data. - */ - @Override - public int read() throws IOException { - int n = r.read(); - if (n == -1) { - throw new SSLException("Unexpected end of handshake data"); - } - return n; - } - - /* - * Get a bunch of bytes of handshake data. - */ - @Override - public int read(byte b [], int off, int len) throws IOException { - // we read from a ByteArrayInputStream, it always returns the - // data in a single read if enough is available - int n = r.read(b, off, len); - if (n != len) { - throw new SSLException("Unexpected end of handshake data"); - } - return n; - } - - /* - * Skip some handshake data. - */ - @Override - public long skip(long n) throws IOException { - return r.skip(n); - } - - /* - * Mark/ reset code, implemented using InputRecord mark/ reset. - * - * Note that it currently provides only a limited mark functionality - * and should be used with care (once a new handshake record has been - * read, data that has already been consumed is lost even if marked). - */ - - @Override - public void mark(int readlimit) { - r.mark(readlimit); - } - - @Override - public void reset() throws IOException { - r.reset(); - } - - @Override - public boolean markSupported() { - return true; - } - - - // handshake management functions - - /* - * Here's an incoming record with handshake data. Queue the contents; - * it might be one or more entire messages, complete a message that's - * partly queued, or both. - */ - void incomingRecord(InputRecord in) throws IOException { - r.queueHandshake(in); - } - - /* - * Hash any data we've consumed but not yet hashed. Useful mostly - * for processing client certificate messages (so we can check the - * immediately following cert verify message) and finished messages - * (so we can compute our own finished message). - */ - void digestNow() { - r.doHashes(); - } - - /* - * Do more than skip that handshake data ... totally ignore it. - * The difference is that the data does not get hashed. - */ - void ignore(int n) { - r.ignore(n); - } - - - // Message parsing methods - - /* - * Read 8, 16, 24, and 32 bit SSL integer data types, encoded - * in standard big-endian form. - */ - - int getInt8() throws IOException { - return read(); - } - - int getInt16() throws IOException { - return (getInt8() << 8) | getInt8(); - } - - int getInt24() throws IOException { - return (getInt8() << 16) | (getInt8() << 8) | getInt8(); - } - - int getInt32() throws IOException { - return (getInt8() << 24) | (getInt8() << 16) - | (getInt8() << 8) | getInt8(); - } - - /* - * Read byte vectors with 8, 16, and 24 bit length encodings. - */ - - byte[] getBytes8() throws IOException { - int len = getInt8(); - verifyLength(len); - byte b[] = new byte[len]; - - read(b, 0, len); - return b; - } - - public byte[] getBytes16() throws IOException { - int len = getInt16(); - verifyLength(len); - byte b[] = new byte[len]; - - read(b, 0, len); - return b; - } - - byte[] getBytes24() throws IOException { - int len = getInt24(); - verifyLength(len); - byte b[] = new byte[len]; - - read(b, 0, len); - return b; - } - - // Is a length greater than available bytes in the record? - private void verifyLength(int len) throws SSLException { - if (len > available()) { - throw new SSLException( - "Not enough data to fill declared vector size"); - } - } - -}
--- a/src/share/classes/sun/security/ssl/HandshakeMessage.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2061 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.math.BigInteger; -import java.security.*; -import java.security.interfaces.*; -import java.security.spec.*; -import java.security.cert.*; -import java.security.cert.Certificate; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; - -import java.lang.reflect.*; - -import javax.security.auth.x500.X500Principal; - -import javax.crypto.KeyGenerator; -import javax.crypto.SecretKey; -import javax.crypto.spec.DHPublicKeySpec; - -import javax.net.ssl.*; - -import sun.security.internal.spec.TlsPrfParameterSpec; -import sun.security.ssl.CipherSuite.*; -import static sun.security.ssl.CipherSuite.PRF.*; -import sun.security.util.KeyUtil; - -/** - * Many data structures are involved in the handshake messages. These - * classes are used as structures, with public data members. They are - * not visible outside the SSL package. - * - * Handshake messages all have a common header format, and they are all - * encoded in a "handshake data" SSL record substream. The base class - * here (HandshakeMessage) provides a common framework and records the - * SSL record type of the particular handshake message. - * - * This file contains subclasses for all the basic handshake messages. - * All handshake messages know how to encode and decode themselves on - * SSL streams; this facilitates using the same code on SSL client and - * server sides, although they don't send and receive the same messages. - * - * Messages also know how to print themselves, which is quite handy - * for debugging. They always identify their type, and can optionally - * dump all of their content. - * - * @author David Brownell - */ -public abstract class HandshakeMessage { - - HandshakeMessage() { } - - // enum HandshakeType: - static final byte ht_hello_request = 0; - static final byte ht_client_hello = 1; - static final byte ht_server_hello = 2; - - static final byte ht_certificate = 11; - static final byte ht_server_key_exchange = 12; - static final byte ht_certificate_request = 13; - static final byte ht_server_hello_done = 14; - static final byte ht_certificate_verify = 15; - static final byte ht_client_key_exchange = 16; - - static final byte ht_finished = 20; - - static final byte ht_not_applicable = -1; // N/A - - /* Class and subclass dynamic debugging support */ - public static final Debug debug = Debug.getInstance("ssl"); - - /** - * Utility method to convert a BigInteger to a byte array in unsigned - * format as needed in the handshake messages. BigInteger uses - * 2's complement format, i.e. it prepends an extra zero if the MSB - * is set. We remove that. - */ - static byte[] toByteArray(BigInteger bi) { - byte[] b = bi.toByteArray(); - if ((b.length > 1) && (b[0] == 0)) { - int n = b.length - 1; - byte[] newarray = new byte[n]; - System.arraycopy(b, 1, newarray, 0, n); - b = newarray; - } - return b; - } - - /* - * SSL 3.0 MAC padding constants. - * Also used by CertificateVerify and Finished during the handshake. - */ - static final byte[] MD5_pad1 = genPad(0x36, 48); - static final byte[] MD5_pad2 = genPad(0x5c, 48); - - static final byte[] SHA_pad1 = genPad(0x36, 40); - static final byte[] SHA_pad2 = genPad(0x5c, 40); - - private static byte[] genPad(int b, int count) { - byte[] padding = new byte[count]; - Arrays.fill(padding, (byte)b); - return padding; - } - - /* - * Write a handshake message on the (handshake) output stream. - * This is just a four byte header followed by the data. - * - * NOTE that huge messages -- notably, ones with huge cert - * chains -- are handled correctly. - */ - final void write(HandshakeOutStream s) throws IOException { - int len = messageLength(); - if (len >= Record.OVERFLOW_OF_INT24) { - throw new SSLException("Handshake message too big" - + ", type = " + messageType() + ", len = " + len); - } - s.write(messageType()); - s.putInt24(len); - send(s); - } - - /* - * Subclasses implement these methods so those kinds of - * messages can be emitted. Base class delegates to subclass. - */ - abstract int messageType(); - abstract int messageLength(); - abstract void send(HandshakeOutStream s) throws IOException; - - /* - * Write a descriptive message on the output stream; for debugging. - */ - abstract void print(PrintStream p) throws IOException; - -// -// NOTE: the rest of these classes are nested within this one, and are -// imported by other classes in this package. There are a few other -// handshake message classes, not neatly nested here because of current -// licensing requirement for native (RSA) methods. They belong here, -// but those native methods complicate things a lot! -// - - -/* - * HelloRequest ... SERVER --> CLIENT - * - * Server can ask the client to initiate a new handshake, e.g. to change - * session parameters after a connection has been (re)established. - */ -static final class HelloRequest extends HandshakeMessage { - @Override - int messageType() { return ht_hello_request; } - - HelloRequest() { } - - HelloRequest(HandshakeInStream in) throws IOException - { - // nothing in this message - } - - @Override - int messageLength() { return 0; } - - @Override - void send(HandshakeOutStream out) throws IOException - { - // nothing in this messaage - } - - @Override - void print(PrintStream out) throws IOException - { - out.println("*** HelloRequest (empty)"); - } - -} - - -/* - * ClientHello ... CLIENT --> SERVER - * - * Client initiates handshake by telling server what it wants, and what it - * can support (prioritized by what's first in the ciphe suite list). - * - * By RFC2246:7.4.1.2 it's explicitly anticipated that this message - * will have more data added at the end ... e.g. what CAs the client trusts. - * Until we know how to parse it, we will just read what we know - * about, and let our caller handle the jumps over unknown data. - */ -static final class ClientHello extends HandshakeMessage { - - ProtocolVersion protocolVersion; - RandomCookie clnt_random; - SessionId sessionId; - private CipherSuiteList cipherSuites; - byte[] compression_methods; - - HelloExtensions extensions = new HelloExtensions(); - - private final static byte[] NULL_COMPRESSION = new byte[] {0}; - - ClientHello(SecureRandom generator, ProtocolVersion protocolVersion, - SessionId sessionId, CipherSuiteList cipherSuites) { - - this.protocolVersion = protocolVersion; - this.sessionId = sessionId; - this.cipherSuites = cipherSuites; - - clnt_random = new RandomCookie(generator); - compression_methods = NULL_COMPRESSION; - } - - ClientHello(HandshakeInStream s, int messageLength) throws IOException { - protocolVersion = ProtocolVersion.valueOf(s.getInt8(), s.getInt8()); - clnt_random = new RandomCookie(s); - sessionId = new SessionId(s.getBytes8()); - sessionId.checkLength(protocolVersion); - cipherSuites = new CipherSuiteList(s); - compression_methods = s.getBytes8(); - if (messageLength() != messageLength) { - extensions = new HelloExtensions(s); - } - } - - CipherSuiteList getCipherSuites() { - return cipherSuites; - } - - // add renegotiation_info extension - void addRenegotiationInfoExtension(byte[] clientVerifyData) { - HelloExtension renegotiationInfo = new RenegotiationInfoExtension( - clientVerifyData, new byte[0]); - extensions.add(renegotiationInfo); - } - - // add server_name extension - void addSNIExtension(List<SNIServerName> serverNames) { - try { - extensions.add(new ServerNameExtension(serverNames)); - } catch (IOException ioe) { - // ignore the exception and return - } - } - - // add signature_algorithm extension - void addSignatureAlgorithmsExtension( - Collection<SignatureAndHashAlgorithm> algorithms) { - HelloExtension signatureAlgorithm = - new SignatureAlgorithmsExtension(algorithms); - extensions.add(signatureAlgorithm); - } - - void addExtendedMasterSecretExtension() { - extensions.add(new ExtendedMasterSecretExtension()); - } - - // add application_layer_protocol_negotiation extension - void addALPNExtension(String[] applicationProtocols) throws SSLException { - extensions.add(new ALPNExtension(applicationProtocols)); - } - - @Override - int messageType() { return ht_client_hello; } - - @Override - int messageLength() { - /* - * Add fixed size parts of each field... - * version + random + session + cipher + compress - */ - return (2 + 32 + 1 + 2 + 1 - + sessionId.length() /* ... + variable parts */ - + (cipherSuites.size() * 2) - + compression_methods.length) - + extensions.length(); - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt8(protocolVersion.major); - s.putInt8(protocolVersion.minor); - clnt_random.send(s); - s.putBytes8(sessionId.getId()); - cipherSuites.send(s); - s.putBytes8(compression_methods); - extensions.send(s); - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** ClientHello, " + protocolVersion); - - if (debug != null && Debug.isOn("verbose")) { - s.print("RandomCookie: "); - clnt_random.print(s); - - s.print("Session ID: "); - s.println(sessionId); - - s.println("Cipher Suites: " + cipherSuites); - - Debug.println(s, "Compression Methods", compression_methods); - extensions.print(s); - s.println("***"); - } - } -} - -/* - * ServerHello ... SERVER --> CLIENT - * - * Server chooses protocol options from among those it supports and the - * client supports. Then it sends the basic session descriptive parameters - * back to the client. - */ -static final -class ServerHello extends HandshakeMessage -{ - @Override - int messageType() { return ht_server_hello; } - - ProtocolVersion protocolVersion; - RandomCookie svr_random; - SessionId sessionId; - CipherSuite cipherSuite; - byte compression_method; - HelloExtensions extensions = new HelloExtensions(); - - ServerHello() { - // empty - } - - ServerHello(HandshakeInStream input, int messageLength) - throws IOException { - protocolVersion = ProtocolVersion.valueOf(input.getInt8(), - input.getInt8()); - svr_random = new RandomCookie(input); - sessionId = new SessionId(input.getBytes8()); - sessionId.checkLength(protocolVersion); - cipherSuite = CipherSuite.valueOf(input.getInt8(), input.getInt8()); - compression_method = (byte)input.getInt8(); - if (messageLength() != messageLength) { - extensions = new HelloExtensions(input); - } - } - - @Override - int messageLength() - { - // almost fixed size, except session ID and extensions: - // major + minor = 2 - // random = 32 - // session ID len field = 1 - // cipher suite + compression = 3 - // extensions: if present, 2 + length of extensions - return 38 + sessionId.length() + extensions.length(); - } - - @Override - void send(HandshakeOutStream s) throws IOException - { - s.putInt8(protocolVersion.major); - s.putInt8(protocolVersion.minor); - svr_random.send(s); - s.putBytes8(sessionId.getId()); - s.putInt8(cipherSuite.id >> 8); - s.putInt8(cipherSuite.id & 0xff); - s.putInt8(compression_method); - extensions.send(s); - } - - @Override - void print(PrintStream s) throws IOException - { - s.println("*** ServerHello, " + protocolVersion); - - if (debug != null && Debug.isOn("verbose")) { - s.print("RandomCookie: "); - svr_random.print(s); - - s.print("Session ID: "); - s.println(sessionId); - - s.println("Cipher Suite: " + cipherSuite); - s.println("Compression Method: " + compression_method); - extensions.print(s); - s.println("***"); - } - } -} - - -/* - * CertificateMsg ... send by both CLIENT and SERVER - * - * Each end of a connection may need to pass its certificate chain to - * the other end. Such chains are intended to validate an identity with - * reference to some certifying authority. Examples include companies - * like Verisign, or financial institutions. There's some control over - * the certifying authorities which are sent. - * - * NOTE: that these messages might be huge, taking many handshake records. - * Up to 2^48 bytes of certificate may be sent, in records of at most 2^14 - * bytes each ... up to 2^32 records sent on the output stream. - */ -static final -class CertificateMsg extends HandshakeMessage -{ - @Override - int messageType() { return ht_certificate; } - - private X509Certificate[] chain; - - private List<byte[]> encodedChain; - - private int messageLength; - - CertificateMsg(X509Certificate[] certs) { - chain = certs; - } - - CertificateMsg(HandshakeInStream input) throws IOException { - int chainLen = input.getInt24(); - List<Certificate> v = new ArrayList<>(4); - - CertificateFactory cf = null; - while (chainLen > 0) { - byte[] cert = input.getBytes24(); - chainLen -= (3 + cert.length); - try { - if (cf == null) { - cf = CertificateFactory.getInstance("X.509"); - } - v.add(cf.generateCertificate(new ByteArrayInputStream(cert))); - } catch (CertificateException e) { - throw (SSLProtocolException)new SSLProtocolException( - e.getMessage()).initCause(e); - } - } - - chain = v.toArray(new X509Certificate[v.size()]); - } - - @Override - int messageLength() { - if (encodedChain == null) { - messageLength = 3; - encodedChain = new ArrayList<byte[]>(chain.length); - try { - for (X509Certificate cert : chain) { - byte[] b = cert.getEncoded(); - encodedChain.add(b); - messageLength += b.length + 3; - } - } catch (CertificateEncodingException e) { - encodedChain = null; - throw new RuntimeException("Could not encode certificates", e); - } - } - return messageLength; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt24(messageLength() - 3); - for (byte[] b : encodedChain) { - s.putBytes24(b); - } - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** Certificate chain"); - - if (chain.length == 0) { - s.println("<Empty>"); - } else if (debug != null && Debug.isOn("verbose")) { - for (int i = 0; i < chain.length; i++) { - s.println("chain [" + i + "] = " + chain[i]); - } - } - s.println("***"); - } - - X509Certificate[] getCertificateChain() { - return chain.clone(); - } -} - -/* - * ServerKeyExchange ... SERVER --> CLIENT - * - * The cipher suite selected, when combined with the certificate exchanged, - * implies one of several different kinds of key exchange. Most current - * cipher suites require the server to send more than its certificate. - * - * The primary exceptions are when a server sends an encryption-capable - * RSA public key in its cert, to be used with RSA (or RSA_export) key - * exchange; and when a server sends its Diffie-Hellman cert. Those kinds - * of key exchange do not require a ServerKeyExchange message. - * - * Key exchange can be viewed as having three modes, which are explicit - * for the Diffie-Hellman flavors and poorly specified for RSA ones: - * - * - "Ephemeral" keys. Here, a "temporary" key is allocated by the - * server, and signed. Diffie-Hellman keys signed using RSA or - * DSS are ephemeral (DHE flavor). RSA keys get used to do the same - * thing, to cut the key size down to 512 bits (export restrictions) - * or for signing-only RSA certificates. - * - * - Anonymity. Here no server certificate is sent, only the public - * key of the server. This case is subject to man-in-the-middle - * attacks. This can be done with Diffie-Hellman keys (DH_anon) or - * with RSA keys, but is only used in SSLv3 for DH_anon. - * - * - "Normal" case. Here a server certificate is sent, and the public - * key there is used directly in exchanging the premaster secret. - * For example, Diffie-Hellman "DH" flavor, and any RSA flavor with - * only 512 bit keys. - * - * If a server certificate is sent, there is no anonymity. However, - * when a certificate is sent, ephemeral keys may still be used to - * exchange the premaster secret. That's how RSA_EXPORT often works, - * as well as how the DHE_* flavors work. - */ -static abstract class ServerKeyExchange extends HandshakeMessage -{ - @Override - int messageType() { return ht_server_key_exchange; } -} - - -/* - * Using RSA for Key Exchange: exchange a session key that's not as big - * as the signing-only key. Used for export applications, since exported - * RSA encryption keys can't be bigger than 512 bytes. - * - * This is never used when keys are 512 bits or smaller, and isn't used - * on "US Domestic" ciphers in any case. - */ -static final -class RSA_ServerKeyExchange extends ServerKeyExchange -{ - private byte rsa_modulus[]; // 1 to 2^16 - 1 bytes - private byte rsa_exponent[]; // 1 to 2^16 - 1 bytes - - private Signature signature; - private byte[] signatureBytes; - - /* - * Hash the nonces and the ephemeral RSA public key. - */ - private void updateSignature(byte clntNonce[], byte svrNonce[]) - throws SignatureException { - int tmp; - - signature.update(clntNonce); - signature.update(svrNonce); - - tmp = rsa_modulus.length; - signature.update((byte)(tmp >> 8)); - signature.update((byte)(tmp & 0x0ff)); - signature.update(rsa_modulus); - - tmp = rsa_exponent.length; - signature.update((byte)(tmp >> 8)); - signature.update((byte)(tmp & 0x0ff)); - signature.update(rsa_exponent); - } - - - /* - * Construct an RSA server key exchange message, using data - * known _only_ to the server. - * - * The client knows the public key corresponding to this private - * key, from the Certificate message sent previously. To comply - * with US export regulations we use short RSA keys ... either - * long term ones in the server's X509 cert, or else ephemeral - * ones sent using this message. - */ - RSA_ServerKeyExchange(PublicKey ephemeralKey, PrivateKey privateKey, - RandomCookie clntNonce, RandomCookie svrNonce, SecureRandom sr) - throws GeneralSecurityException { - RSAPublicKeySpec rsaKey = JsseJce.getRSAPublicKeySpec(ephemeralKey); - rsa_modulus = toByteArray(rsaKey.getModulus()); - rsa_exponent = toByteArray(rsaKey.getPublicExponent()); - signature = RSASignature.getInstance(); - signature.initSign(privateKey, sr); - updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); - signatureBytes = signature.sign(); - } - - - /* - * Parse an RSA server key exchange message, using data known - * to the client (and, in some situations, eavesdroppers). - */ - RSA_ServerKeyExchange(HandshakeInStream input) - throws IOException, NoSuchAlgorithmException { - signature = RSASignature.getInstance(); - rsa_modulus = input.getBytes16(); - rsa_exponent = input.getBytes16(); - signatureBytes = input.getBytes16(); - } - - /* - * Get the ephemeral RSA public key that will be used in this - * SSL connection. - */ - PublicKey getPublicKey() { - try { - KeyFactory kfac = JsseJce.getKeyFactory("RSA"); - // modulus and exponent are always positive - RSAPublicKeySpec kspec = new RSAPublicKeySpec( - new BigInteger(1, rsa_modulus), - new BigInteger(1, rsa_exponent)); - return kfac.generatePublic(kspec); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /* - * Verify the signed temporary key using the hashes computed - * from it and the two nonces. This is called by clients - * with "exportable" RSA flavors. - */ - boolean verify(PublicKey certifiedKey, RandomCookie clntNonce, - RandomCookie svrNonce) throws GeneralSecurityException { - signature.initVerify(certifiedKey); - updateSignature(clntNonce.random_bytes, svrNonce.random_bytes); - return signature.verify(signatureBytes); - } - - @Override - int messageLength() { - return 6 + rsa_modulus.length + rsa_exponent.length - + signatureBytes.length; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putBytes16(rsa_modulus); - s.putBytes16(rsa_exponent); - s.putBytes16(signatureBytes); - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** RSA ServerKeyExchange"); - - if (debug != null && Debug.isOn("verbose")) { - Debug.println(s, "RSA Modulus", rsa_modulus); - Debug.println(s, "RSA Public Exponent", rsa_exponent); - } - } -} - - -/* - * Using Diffie-Hellman algorithm for key exchange. All we really need to - * do is securely get Diffie-Hellman keys (using the same P, G parameters) - * to our peer, then we automatically have a shared secret without need - * to exchange any more data. (D-H only solutions, such as SKIP, could - * eliminate key exchange negotiations and get faster connection setup. - * But they still need a signature algorithm like DSS/DSA to support the - * trusted distribution of keys without relying on unscalable physical - * key distribution systems.) - * - * This class supports several DH-based key exchange algorithms, though - * perhaps eventually each deserves its own class. Notably, this has - * basic support for DH_anon and its DHE_DSS and DHE_RSA signed variants. - */ -static final -class DH_ServerKeyExchange extends ServerKeyExchange -{ - // Fix message encoding, see 4348279 - private final static boolean dhKeyExchangeFix = - Debug.getBooleanProperty("com.sun.net.ssl.dhKeyExchangeFix", true); - - private byte dh_p []; // 1 to 2^16 - 1 bytes - private byte dh_g []; // 1 to 2^16 - 1 bytes - private byte dh_Ys []; // 1 to 2^16 - 1 bytes - - private byte signature []; - - // protocol version being established using this ServerKeyExchange message - ProtocolVersion protocolVersion; - - // the preferable signature algorithm used by this ServerKeyExchange message - private SignatureAndHashAlgorithm preferableSignatureAlgorithm; - - /* - * Construct from initialized DH key object, for DH_anon - * key exchange. - */ - DH_ServerKeyExchange(DHCrypt obj, ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; - this.preferableSignatureAlgorithm = null; - - // The DH key has been validated in the constructor of DHCrypt. - setValues(obj); - signature = null; - } - - /* - * Construct from initialized DH key object and the key associated - * with the cert chain which was sent ... for DHE_DSS and DHE_RSA - * key exchange. (Constructor called by server.) - */ - DH_ServerKeyExchange(DHCrypt obj, PrivateKey key, byte clntNonce[], - byte svrNonce[], SecureRandom sr, - SignatureAndHashAlgorithm signAlgorithm, - ProtocolVersion protocolVersion) throws GeneralSecurityException { - - this.protocolVersion = protocolVersion; - - // The DH key has been validated in the constructor of DHCrypt. - setValues(obj); - - Signature sig; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - this.preferableSignatureAlgorithm = signAlgorithm; - sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); - } else { - this.preferableSignatureAlgorithm = null; - if (key.getAlgorithm().equals("DSA")) { - sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); - } else { - sig = RSASignature.getInstance(); - } - } - - sig.initSign(key, sr); - updateSignature(sig, clntNonce, svrNonce); - signature = sig.sign(); - } - - /* - * Construct a DH_ServerKeyExchange message from an input - * stream, as if sent from server to client for use with - * DH_anon key exchange - */ - DH_ServerKeyExchange(HandshakeInStream input, - ProtocolVersion protocolVersion) - throws IOException, GeneralSecurityException { - - this.protocolVersion = protocolVersion; - this.preferableSignatureAlgorithm = null; - - dh_p = input.getBytes16(); - dh_g = input.getBytes16(); - dh_Ys = input.getBytes16(); - KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys), - new BigInteger(1, dh_p), - new BigInteger(1, dh_g))); - - signature = null; - } - - /* - * Construct a DH_ServerKeyExchange message from an input stream - * and a certificate, as if sent from server to client for use with - * DHE_DSS or DHE_RSA key exchange. (Called by client.) - */ - DH_ServerKeyExchange(HandshakeInStream input, PublicKey publicKey, - byte clntNonce[], byte svrNonce[], int messageSize, - Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, - ProtocolVersion protocolVersion) - throws IOException, GeneralSecurityException { - - this.protocolVersion = protocolVersion; - - // read params: ServerDHParams - dh_p = input.getBytes16(); - dh_g = input.getBytes16(); - dh_Ys = input.getBytes16(); - KeyUtil.validate(new DHPublicKeySpec(new BigInteger(1, dh_Ys), - new BigInteger(1, dh_p), - new BigInteger(1, dh_g))); - - // read the signature and hash algorithm - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - int hash = input.getInt8(); // hash algorithm - int signature = input.getInt8(); // signature algorithm - - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.valueOf(hash, signature, 0); - - // Is it a local supported signature algorithm? - if (!localSupportedSignAlgs.contains( - preferableSignatureAlgorithm)) { - throw new SSLHandshakeException( - "Unsupported SignatureAndHashAlgorithm in " + - "ServerKeyExchange message: " + - preferableSignatureAlgorithm); - } - } else { - this.preferableSignatureAlgorithm = null; - } - - // read the signature - byte signature[]; - if (dhKeyExchangeFix) { - signature = input.getBytes16(); - } else { - messageSize -= (dh_p.length + 2); - messageSize -= (dh_g.length + 2); - messageSize -= (dh_Ys.length + 2); - - signature = new byte[messageSize]; - input.read(signature); - } - - Signature sig; - String algorithm = publicKey.getAlgorithm(); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - sig = JsseJce.getSignature( - preferableSignatureAlgorithm.getAlgorithmName()); - } else { - switch (algorithm) { - case "DSA": - sig = JsseJce.getSignature(JsseJce.SIGNATURE_DSA); - break; - case "RSA": - sig = RSASignature.getInstance(); - break; - default: - throw new SSLKeyException( - "neither an RSA or a DSA key: " + algorithm); - } - } - - sig.initVerify(publicKey); - updateSignature(sig, clntNonce, svrNonce); - - if (sig.verify(signature) == false ) { - throw new SSLKeyException("Server D-H key verification failed"); - } - } - - /* Return the Diffie-Hellman modulus */ - BigInteger getModulus() { - return new BigInteger(1, dh_p); - } - - /* Return the Diffie-Hellman base/generator */ - BigInteger getBase() { - return new BigInteger(1, dh_g); - } - - /* Return the server's Diffie-Hellman public key */ - BigInteger getServerPublicKey() { - return new BigInteger(1, dh_Ys); - } - - /* - * Update sig with nonces and Diffie-Hellman public key. - */ - private void updateSignature(Signature sig, byte clntNonce[], - byte svrNonce[]) throws SignatureException { - int tmp; - - sig.update(clntNonce); - sig.update(svrNonce); - - tmp = dh_p.length; - sig.update((byte)(tmp >> 8)); - sig.update((byte)(tmp & 0x0ff)); - sig.update(dh_p); - - tmp = dh_g.length; - sig.update((byte)(tmp >> 8)); - sig.update((byte)(tmp & 0x0ff)); - sig.update(dh_g); - - tmp = dh_Ys.length; - sig.update((byte)(tmp >> 8)); - sig.update((byte)(tmp & 0x0ff)); - sig.update(dh_Ys); - } - - private void setValues(DHCrypt obj) { - dh_p = toByteArray(obj.getModulus()); - dh_g = toByteArray(obj.getBase()); - dh_Ys = toByteArray(obj.getPublicKey()); - } - - @Override - int messageLength() { - int temp = 6; // overhead for p, g, y(s) values. - - temp += dh_p.length; - temp += dh_g.length; - temp += dh_Ys.length; - - if (signature != null) { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - temp += SignatureAndHashAlgorithm.sizeInRecord(); - } - - temp += signature.length; - if (dhKeyExchangeFix) { - temp += 2; - } - } - - return temp; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putBytes16(dh_p); - s.putBytes16(dh_g); - s.putBytes16(dh_Ys); - - if (signature != null) { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.putInt8(preferableSignatureAlgorithm.getHashValue()); - s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); - } - - if (dhKeyExchangeFix) { - s.putBytes16(signature); - } else { - s.write(signature); - } - } - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** Diffie-Hellman ServerKeyExchange"); - - if (debug != null && Debug.isOn("verbose")) { - Debug.println(s, "DH Modulus", dh_p); - Debug.println(s, "DH Base", dh_g); - Debug.println(s, "Server DH Public Key", dh_Ys); - - if (signature == null) { - s.println("Anonymous"); - } else { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.println("Signature Algorithm " + - preferableSignatureAlgorithm.getAlgorithmName()); - } - - s.println("Signed with a DSA or RSA public key"); - } - } - } -} - -/* - * ECDH server key exchange message. Sent by the server for ECDHE and ECDH_anon - * ciphersuites to communicate its ephemeral public key (including the - * EC domain parameters). - * - * We support named curves only, no explicitly encoded curves. - */ -static final -class ECDH_ServerKeyExchange extends ServerKeyExchange { - - // constants for ECCurveType - private final static int CURVE_EXPLICIT_PRIME = 1; - private final static int CURVE_EXPLICIT_CHAR2 = 2; - private final static int CURVE_NAMED_CURVE = 3; - - // id of the curve we are using - private int curveId; - // encoded public point - private byte[] pointBytes; - - // signature bytes (or null if anonymous) - private byte[] signatureBytes; - - // public key object encapsulated in this message - private ECPublicKey publicKey; - - // protocol version being established using this ServerKeyExchange message - ProtocolVersion protocolVersion; - - // the preferable signature algorithm used by this ServerKeyExchange message - private SignatureAndHashAlgorithm preferableSignatureAlgorithm; - - ECDH_ServerKeyExchange(ECDHCrypt obj, PrivateKey privateKey, - byte[] clntNonce, byte[] svrNonce, SecureRandom sr, - SignatureAndHashAlgorithm signAlgorithm, - ProtocolVersion protocolVersion) throws GeneralSecurityException { - - this.protocolVersion = protocolVersion; - - publicKey = (ECPublicKey)obj.getPublicKey(); - ECParameterSpec params = publicKey.getParams(); - ECPoint point = publicKey.getW(); - pointBytes = JsseJce.encodePoint(point, params.getCurve()); - curveId = EllipticCurvesExtension.getCurveIndex(params); - - if (privateKey == null) { - // ECDH_anon - return; - } - - Signature sig; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - this.preferableSignatureAlgorithm = signAlgorithm; - sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); - } else { - sig = getSignature(privateKey.getAlgorithm()); - } - sig.initSign(privateKey, sr); - - updateSignature(sig, clntNonce, svrNonce); - signatureBytes = sig.sign(); - } - - /* - * Parse an ECDH server key exchange message. - */ - ECDH_ServerKeyExchange(HandshakeInStream input, PublicKey signingKey, - byte[] clntNonce, byte[] svrNonce, - Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, - ProtocolVersion protocolVersion) - throws IOException, GeneralSecurityException { - - this.protocolVersion = protocolVersion; - - // read params: ServerECDHParams - int curveType = input.getInt8(); - ECParameterSpec parameters; - // These parsing errors should never occur as we negotiated - // the supported curves during the exchange of the Hello messages. - if (curveType == CURVE_NAMED_CURVE) { - curveId = input.getInt16(); - if (!EllipticCurvesExtension.isSupported(curveId)) { - throw new SSLHandshakeException( - "Unsupported curveId: " + curveId); - } - String curveOid = EllipticCurvesExtension.getCurveOid(curveId); - if (curveOid == null) { - throw new SSLHandshakeException( - "Unknown named curve: " + curveId); - } - parameters = JsseJce.getECParameterSpec(curveOid); - if (parameters == null) { - throw new SSLHandshakeException( - "Unsupported curve: " + curveOid); - } - } else { - throw new SSLHandshakeException( - "Unsupported ECCurveType: " + curveType); - } - pointBytes = input.getBytes8(); - - ECPoint point = JsseJce.decodePoint(pointBytes, parameters.getCurve()); - KeyFactory factory = JsseJce.getKeyFactory("EC"); - publicKey = (ECPublicKey)factory.generatePublic( - new ECPublicKeySpec(point, parameters)); - - if (signingKey == null) { - // ECDH_anon - return; - } - - // read the signature and hash algorithm - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - int hash = input.getInt8(); // hash algorithm - int signature = input.getInt8(); // signature algorithm - - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.valueOf(hash, signature, 0); - - // Is it a local supported signature algorithm? - if (!localSupportedSignAlgs.contains( - preferableSignatureAlgorithm)) { - throw new SSLHandshakeException( - "Unsupported SignatureAndHashAlgorithm in " + - "ServerKeyExchange message: " + - preferableSignatureAlgorithm); - } - } - - // read the signature - signatureBytes = input.getBytes16(); - - // verify the signature - Signature sig; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - sig = JsseJce.getSignature( - preferableSignatureAlgorithm.getAlgorithmName()); - } else { - sig = getSignature(signingKey.getAlgorithm()); - } - sig.initVerify(signingKey); - - updateSignature(sig, clntNonce, svrNonce); - - if (sig.verify(signatureBytes) == false ) { - throw new SSLKeyException( - "Invalid signature on ECDH server key exchange message"); - } - } - - /* - * Get the ephemeral EC public key encapsulated in this message. - */ - ECPublicKey getPublicKey() { - return publicKey; - } - - private static Signature getSignature(String keyAlgorithm) - throws NoSuchAlgorithmException { - switch (keyAlgorithm) { - case "EC": - return JsseJce.getSignature(JsseJce.SIGNATURE_ECDSA); - case "RSA": - return RSASignature.getInstance(); - default: - throw new NoSuchAlgorithmException( - "neither an RSA or a EC key : " + keyAlgorithm); - } - } - - private void updateSignature(Signature sig, byte clntNonce[], - byte svrNonce[]) throws SignatureException { - sig.update(clntNonce); - sig.update(svrNonce); - - sig.update((byte)CURVE_NAMED_CURVE); - sig.update((byte)(curveId >> 8)); - sig.update((byte)curveId); - sig.update((byte)pointBytes.length); - sig.update(pointBytes); - } - - @Override - int messageLength() { - int sigLen = 0; - if (signatureBytes != null) { - sigLen = 2 + signatureBytes.length; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - sigLen += SignatureAndHashAlgorithm.sizeInRecord(); - } - } - - return 4 + pointBytes.length + sigLen; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt8(CURVE_NAMED_CURVE); - s.putInt16(curveId); - s.putBytes8(pointBytes); - - if (signatureBytes != null) { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.putInt8(preferableSignatureAlgorithm.getHashValue()); - s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); - } - - s.putBytes16(signatureBytes); - } - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** ECDH ServerKeyExchange"); - - if (debug != null && Debug.isOn("verbose")) { - if (signatureBytes == null) { - s.println("Anonymous"); - } else { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.println("Signature Algorithm " + - preferableSignatureAlgorithm.getAlgorithmName()); - } - } - - s.println("Server key: " + publicKey); - } - } -} - -static final class DistinguishedName { - - /* - * DER encoded distinguished name. - * TLS requires that its not longer than 65535 bytes. - */ - byte name[]; - - DistinguishedName(HandshakeInStream input) throws IOException { - name = input.getBytes16(); - } - - DistinguishedName(X500Principal dn) { - name = dn.getEncoded(); - } - - X500Principal getX500Principal() throws IOException { - try { - return new X500Principal(name); - } catch (IllegalArgumentException e) { - throw (SSLProtocolException)new SSLProtocolException( - e.getMessage()).initCause(e); - } - } - - int length() { - return 2 + name.length; - } - - void send(HandshakeOutStream output) throws IOException { - output.putBytes16(name); - } - - void print(PrintStream output) throws IOException { - X500Principal principal = new X500Principal(name); - output.println("<" + principal.toString() + ">"); - } -} - -/* - * CertificateRequest ... SERVER --> CLIENT - * - * Authenticated servers may ask clients to authenticate themselves - * in turn, using this message. - * - * Prior to TLS 1.2, the structure of the message is defined as: - * struct { - * ClientCertificateType certificate_types<1..2^8-1>; - * DistinguishedName certificate_authorities<0..2^16-1>; - * } CertificateRequest; - * - * In TLS 1.2, the structure is changed to: - * struct { - * ClientCertificateType certificate_types<1..2^8-1>; - * SignatureAndHashAlgorithm - * supported_signature_algorithms<2^16-1>; - * DistinguishedName certificate_authorities<0..2^16-1>; - * } CertificateRequest; - * - */ -static final -class CertificateRequest extends HandshakeMessage -{ - // enum ClientCertificateType - static final int cct_rsa_sign = 1; - static final int cct_dss_sign = 2; - static final int cct_rsa_fixed_dh = 3; - static final int cct_dss_fixed_dh = 4; - - // The existance of these two values is a bug in the SSL specification. - // They are never used in the protocol. - static final int cct_rsa_ephemeral_dh = 5; - static final int cct_dss_ephemeral_dh = 6; - - // From RFC 4492 (ECC) - static final int cct_ecdsa_sign = 64; - static final int cct_rsa_fixed_ecdh = 65; - static final int cct_ecdsa_fixed_ecdh = 66; - - private final static byte[] TYPES_NO_ECC = { cct_rsa_sign, cct_dss_sign }; - private final static byte[] TYPES_ECC = - { cct_rsa_sign, cct_dss_sign, cct_ecdsa_sign }; - - byte types []; // 1 to 255 types - DistinguishedName authorities []; // 3 to 2^16 - 1 - // ... "3" because that's the smallest DER-encoded X500 DN - - // protocol version being established using this CertificateRequest message - ProtocolVersion protocolVersion; - - // supported_signature_algorithms for TLS 1.2 or later - private Collection<SignatureAndHashAlgorithm> algorithms; - - // length of supported_signature_algorithms - private int algorithmsLen; - - CertificateRequest(X509Certificate ca[], KeyExchange keyExchange, - Collection<SignatureAndHashAlgorithm> signAlgs, - ProtocolVersion protocolVersion) throws IOException { - - this.protocolVersion = protocolVersion; - - // always use X500Principal - authorities = new DistinguishedName[ca.length]; - for (int i = 0; i < ca.length; i++) { - X500Principal x500Principal = ca[i].getSubjectX500Principal(); - authorities[i] = new DistinguishedName(x500Principal); - } - // we support RSA, DSS, and ECDSA client authentication and they - // can be used with all ciphersuites. If this changes, the code - // needs to be adapted to take keyExchange into account. - // We only request ECDSA client auth if we have ECC crypto available. - this.types = JsseJce.isEcAvailable() ? TYPES_ECC : TYPES_NO_ECC; - - // Use supported_signature_algorithms for TLS 1.2 or later. - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (signAlgs == null || signAlgs.isEmpty()) { - throw new SSLProtocolException( - "No supported signature algorithms"); - } - - algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); - algorithmsLen = - SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); - } else { - algorithms = new ArrayList<SignatureAndHashAlgorithm>(); - algorithmsLen = 0; - } - } - - CertificateRequest(HandshakeInStream input, - ProtocolVersion protocolVersion) throws IOException { - - this.protocolVersion = protocolVersion; - - // Read the certificate_types. - types = input.getBytes8(); - - // Read the supported_signature_algorithms for TLS 1.2 or later. - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - algorithmsLen = input.getInt16(); - if (algorithmsLen < 2) { - throw new SSLProtocolException( - "Invalid supported_signature_algorithms field: " + - algorithmsLen); - } - - algorithms = new ArrayList<SignatureAndHashAlgorithm>(); - int remains = algorithmsLen; - int sequence = 0; - while (remains > 1) { // needs at least two bytes - int hash = input.getInt8(); // hash algorithm - int signature = input.getInt8(); // signature algorithm - - SignatureAndHashAlgorithm algorithm = - SignatureAndHashAlgorithm.valueOf(hash, signature, - ++sequence); - algorithms.add(algorithm); - remains -= 2; // one byte for hash, one byte for signature - } - - if (remains != 0) { - throw new SSLProtocolException( - "Invalid supported_signature_algorithms field. remains: " + - remains); - } - } else { - algorithms = new ArrayList<SignatureAndHashAlgorithm>(); - algorithmsLen = 0; - } - - // read the certificate_authorities - int len = input.getInt16(); - ArrayList<DistinguishedName> v = new ArrayList<>(); - while (len >= 3) { - DistinguishedName dn = new DistinguishedName(input); - v.add(dn); - len -= dn.length(); - } - - if (len != 0) { - throw new SSLProtocolException( - "Bad CertificateRequest DN length: " + len); - } - - authorities = v.toArray(new DistinguishedName[v.size()]); - } - - X500Principal[] getAuthorities() throws IOException { - X500Principal[] ret = new X500Principal[authorities.length]; - for (int i = 0; i < authorities.length; i++) { - ret[i] = authorities[i].getX500Principal(); - } - return ret; - } - - Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { - return algorithms; - } - - @Override - int messageType() { - return ht_certificate_request; - } - - @Override - int messageLength() { - int len = 1 + types.length + 2; - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - len += algorithmsLen + 2; - } - - for (int i = 0; i < authorities.length; i++) { - len += authorities[i].length(); - } - - return len; - } - - @Override - void send(HandshakeOutStream output) throws IOException { - // put certificate_types - output.putBytes8(types); - - // put supported_signature_algorithms - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - output.putInt16(algorithmsLen); - for (SignatureAndHashAlgorithm algorithm : algorithms) { - output.putInt8(algorithm.getHashValue()); // hash - output.putInt8(algorithm.getSignatureValue()); // signature - } - } - - // put certificate_authorities - int len = 0; - for (int i = 0; i < authorities.length; i++) { - len += authorities[i].length(); - } - - output.putInt16(len); - for (int i = 0; i < authorities.length; i++) { - authorities[i].send(output); - } - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** CertificateRequest"); - - if (debug != null && Debug.isOn("verbose")) { - s.print("Cert Types: "); - for (int i = 0; i < types.length; i++) { - switch (types[i]) { - case cct_rsa_sign: - s.print("RSA"); break; - case cct_dss_sign: - s.print("DSS"); break; - case cct_rsa_fixed_dh: - s.print("Fixed DH (RSA sig)"); break; - case cct_dss_fixed_dh: - s.print("Fixed DH (DSS sig)"); break; - case cct_rsa_ephemeral_dh: - s.print("Ephemeral DH (RSA sig)"); break; - case cct_dss_ephemeral_dh: - s.print("Ephemeral DH (DSS sig)"); break; - case cct_ecdsa_sign: - s.print("ECDSA"); break; - case cct_rsa_fixed_ecdh: - s.print("Fixed ECDH (RSA sig)"); break; - case cct_ecdsa_fixed_ecdh: - s.print("Fixed ECDH (ECDSA sig)"); break; - default: - s.print("Type-" + (types[i] & 0xff)); break; - } - if (i != types.length - 1) { - s.print(", "); - } - } - s.println(); - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - StringBuffer buffer = new StringBuffer(); - boolean opened = false; - for (SignatureAndHashAlgorithm signAlg : algorithms) { - if (opened) { - buffer.append(", " + signAlg.getAlgorithmName()); - } else { - buffer.append(signAlg.getAlgorithmName()); - opened = true; - } - } - s.println("Supported Signature Algorithms: " + buffer); - } - - s.println("Cert Authorities:"); - if (authorities.length == 0) { - s.println("<Empty>"); - } else { - for (int i = 0; i < authorities.length; i++) { - authorities[i].print(s); - } - } - } - } -} - - -/* - * ServerHelloDone ... SERVER --> CLIENT - * - * When server's done sending its messages in response to the client's - * "hello" (e.g. its own hello, certificate, key exchange message, perhaps - * client certificate request) it sends this message to flag that it's - * done that part of the handshake. - */ -static final -class ServerHelloDone extends HandshakeMessage -{ - @Override - int messageType() { return ht_server_hello_done; } - - ServerHelloDone() { } - - ServerHelloDone(HandshakeInStream input) - { - // nothing to do - } - - @Override - int messageLength() - { - return 0; - } - - @Override - void send(HandshakeOutStream s) throws IOException - { - // nothing to send - } - - @Override - void print(PrintStream s) throws IOException - { - s.println("*** ServerHelloDone"); - } -} - - -/* - * CertificateVerify ... CLIENT --> SERVER - * - * Sent after client sends signature-capable certificates (e.g. not - * Diffie-Hellman) to verify. - */ -static final class CertificateVerify extends HandshakeMessage { - - // the signature bytes - private byte[] signature; - - // protocol version being established using this CertificateVerify message - ProtocolVersion protocolVersion; - - // the preferable signature algorithm used by this CertificateVerify message - private SignatureAndHashAlgorithm preferableSignatureAlgorithm = null; - - /* - * Create an RSA or DSA signed certificate verify message. - */ - CertificateVerify(ProtocolVersion protocolVersion, - HandshakeHash handshakeHash, PrivateKey privateKey, - SecretKey masterSecret, SecureRandom sr, - SignatureAndHashAlgorithm signAlgorithm) - throws GeneralSecurityException { - - this.protocolVersion = protocolVersion; - - String algorithm = privateKey.getAlgorithm(); - Signature sig = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - this.preferableSignatureAlgorithm = signAlgorithm; - sig = JsseJce.getSignature(signAlgorithm.getAlgorithmName()); - } else { - sig = getSignature(protocolVersion, algorithm); - } - sig.initSign(privateKey, sr); - updateSignature(sig, protocolVersion, handshakeHash, algorithm, - masterSecret); - signature = sig.sign(); - } - - // - // Unmarshal the signed data from the input stream. - // - CertificateVerify(HandshakeInStream input, - Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs, - ProtocolVersion protocolVersion) throws IOException { - - this.protocolVersion = protocolVersion; - - // read the signature and hash algorithm - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - int hashAlg = input.getInt8(); // hash algorithm - int signAlg = input.getInt8(); // signature algorithm - - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.valueOf(hashAlg, signAlg, 0); - - // Is it a local supported signature algorithm? - if (!localSupportedSignAlgs.contains( - preferableSignatureAlgorithm)) { - throw new SSLHandshakeException( - "Unsupported SignatureAndHashAlgorithm in " + - "CertificateVerify message: " + preferableSignatureAlgorithm); - } - } - - // read the signature - signature = input.getBytes16(); - } - - /* - * Get the preferable signature algorithm used by this message - */ - SignatureAndHashAlgorithm getPreferableSignatureAlgorithm() { - return preferableSignatureAlgorithm; - } - - /* - * Verify a certificate verify message. Return the result of verification, - * if there is a problem throw a GeneralSecurityException. - */ - boolean verify(ProtocolVersion protocolVersion, - HandshakeHash handshakeHash, PublicKey publicKey, - SecretKey masterSecret) throws GeneralSecurityException { - String algorithm = publicKey.getAlgorithm(); - Signature sig = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - sig = JsseJce.getSignature( - preferableSignatureAlgorithm.getAlgorithmName()); - } else { - sig = getSignature(protocolVersion, algorithm); - } - sig.initVerify(publicKey); - updateSignature(sig, protocolVersion, handshakeHash, algorithm, - masterSecret); - return sig.verify(signature); - } - - /* - * Get the Signature object appropriate for verification using the - * given signature algorithm and protocol version. - */ - private static Signature getSignature(ProtocolVersion protocolVersion, - String algorithm) throws GeneralSecurityException { - switch (algorithm) { - case "RSA": - return RSASignature.getInternalInstance(); - case "DSA": - return JsseJce.getSignature(JsseJce.SIGNATURE_RAWDSA); - case "EC": - return JsseJce.getSignature(JsseJce.SIGNATURE_RAWECDSA); - default: - throw new SignatureException("Unrecognized algorithm: " - + algorithm); - } - } - - /* - * Update the Signature with the data appropriate for the given - * signature algorithm and protocol version so that the object is - * ready for signing or verifying. - */ - private static void updateSignature(Signature sig, - ProtocolVersion protocolVersion, - HandshakeHash handshakeHash, String algorithm, SecretKey masterKey) - throws SignatureException { - - if (algorithm.equals("RSA")) { - if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1- - MessageDigest md5Clone = handshakeHash.getMD5Clone(); - MessageDigest shaClone = handshakeHash.getSHAClone(); - - if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3 - updateDigest(md5Clone, MD5_pad1, MD5_pad2, masterKey); - updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey); - } - - // The signature must be an instance of RSASignature, need - // to use these hashes directly. - RSASignature.setHashes(sig, md5Clone, shaClone); - } else { // TLS1.2+ - sig.update(handshakeHash.getAllHandshakeMessages()); - } - } else { // DSA, ECDSA - if (protocolVersion.v < ProtocolVersion.TLS12.v) { // TLS1.1- - MessageDigest shaClone = handshakeHash.getSHAClone(); - - if (protocolVersion.v < ProtocolVersion.TLS10.v) { // SSLv3 - updateDigest(shaClone, SHA_pad1, SHA_pad2, masterKey); - } - - sig.update(shaClone.digest()); - } else { // TLS1.2+ - sig.update(handshakeHash.getAllHandshakeMessages()); - } - } - } - - /* - * Update the MessageDigest for SSLv3 certificate verify or finished - * message calculation. The digest must already have been updated with - * all preceding handshake messages. - * Used by the Finished class as well. - */ - private static void updateDigest(MessageDigest md, - byte[] pad1, byte[] pad2, - SecretKey masterSecret) { - // Digest the key bytes if available. - // Otherwise (sensitive key), try digesting the key directly. - // That is currently only implemented in SunPKCS11 using a private - // reflection API, so we avoid that if possible. - byte[] keyBytes = "RAW".equals(masterSecret.getFormat()) - ? masterSecret.getEncoded() : null; - if (keyBytes != null) { - md.update(keyBytes); - } else { - digestKey(md, masterSecret); - } - md.update(pad1); - byte[] temp = md.digest(); - - if (keyBytes != null) { - md.update(keyBytes); - } else { - digestKey(md, masterSecret); - } - md.update(pad2); - md.update(temp); - } - - private final static Class<?> delegate; - private final static Field spiField; - - static { - try { - delegate = Class.forName("java.security.MessageDigest$Delegate"); - spiField = delegate.getDeclaredField("digestSpi"); - } catch (Exception e) { - throw new RuntimeException("Reflection failed", e); - } - makeAccessible(spiField); - } - - private static void makeAccessible(final AccessibleObject o) { - AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - o.setAccessible(true); - return null; - } - }); - } - - // ConcurrentHashMap does not allow null values, use this marker object - private final static Object NULL_OBJECT = new Object(); - - // cache Method objects per Spi class - // Note that this will prevent the Spi classes from being GC'd. We assume - // that is not a problem. - private final static Map<Class<?>,Object> methodCache = - new ConcurrentHashMap<>(); - - private static void digestKey(MessageDigest md, SecretKey key) { - try { - // Verify that md is implemented via MessageDigestSpi, not - // via JDK 1.1 style MessageDigest subclassing. - if (md.getClass() != delegate) { - throw new Exception("Digest is not a MessageDigestSpi"); - } - MessageDigestSpi spi = (MessageDigestSpi)spiField.get(md); - Class<?> clazz = spi.getClass(); - Object r = methodCache.get(clazz); - if (r == null) { - try { - r = clazz.getDeclaredMethod("implUpdate", SecretKey.class); - makeAccessible((Method)r); - } catch (NoSuchMethodException e) { - r = NULL_OBJECT; - } - methodCache.put(clazz, r); - } - if (r == NULL_OBJECT) { - throw new Exception( - "Digest does not support implUpdate(SecretKey)"); - } - Method update = (Method)r; - update.invoke(spi, key); - } catch (Exception e) { - throw new RuntimeException( - "Could not obtain encoded key and " - + "MessageDigest cannot digest key", e); - } - } - - @Override - int messageType() { - return ht_certificate_verify; - } - - @Override - int messageLength() { - int temp = 2; - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - temp += SignatureAndHashAlgorithm.sizeInRecord(); - } - - return temp + signature.length; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.putInt8(preferableSignatureAlgorithm.getHashValue()); - s.putInt8(preferableSignatureAlgorithm.getSignatureValue()); - } - - s.putBytes16(signature); - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** CertificateVerify"); - - if (debug != null && Debug.isOn("verbose")) { - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - s.println("Signature Algorithm " + - preferableSignatureAlgorithm.getAlgorithmName()); - } - } - } -} - - -/* - * FINISHED ... sent by both CLIENT and SERVER - * - * This is the FINISHED message as defined in the SSL and TLS protocols. - * Both protocols define this handshake message slightly differently. - * This class supports both formats. - * - * When handshaking is finished, each side sends a "change_cipher_spec" - * record, then immediately sends a "finished" handshake message prepared - * according to the newly adopted cipher spec. - * - * NOTE that until this is sent, no application data may be passed, unless - * some non-default cipher suite has already been set up on this connection - * connection (e.g. a previous handshake arranged one). - */ -static final class Finished extends HandshakeMessage { - - // constant for a Finished message sent by the client - final static int CLIENT = 1; - - // constant for a Finished message sent by the server - final static int SERVER = 2; - - // enum Sender: "CLNT" and "SRVR" - private static final byte[] SSL_CLIENT = { 0x43, 0x4C, 0x4E, 0x54 }; - private static final byte[] SSL_SERVER = { 0x53, 0x52, 0x56, 0x52 }; - - /* - * Contents of the finished message ("checksum"). For TLS, it - * is 12 bytes long, for SSLv3 36 bytes. - */ - private byte[] verifyData; - - /* - * Current cipher suite we are negotiating. TLS 1.2 has - * ciphersuite-defined PRF algorithms. - */ - private ProtocolVersion protocolVersion; - private CipherSuite cipherSuite; - - /* - * Create a finished message to send to the remote peer. - */ - Finished(ProtocolVersion protocolVersion, HandshakeHash handshakeHash, - int sender, SecretKey master, CipherSuite cipherSuite) { - this.protocolVersion = protocolVersion; - this.cipherSuite = cipherSuite; - verifyData = getFinished(handshakeHash, sender, master); - } - - /* - * Constructor that reads FINISHED message from stream. - */ - Finished(ProtocolVersion protocolVersion, HandshakeInStream input, - CipherSuite cipherSuite) throws IOException { - this.protocolVersion = protocolVersion; - this.cipherSuite = cipherSuite; - int msgLen = (protocolVersion.v >= ProtocolVersion.TLS10.v) ? 12 : 36; - verifyData = new byte[msgLen]; - input.read(verifyData); - } - - /* - * Verify that the hashes here are what would have been produced - * according to a given set of inputs. This is used to ensure that - * both client and server are fully in sync, and that the handshake - * computations have been successful. - */ - boolean verify(HandshakeHash handshakeHash, int sender, SecretKey master) { - byte[] myFinished = getFinished(handshakeHash, sender, master); - return MessageDigest.isEqual(myFinished, verifyData); - } - - /* - * Perform the actual finished message calculation. - */ - private byte[] getFinished(HandshakeHash handshakeHash, - int sender, SecretKey masterKey) { - byte[] sslLabel; - String tlsLabel; - if (sender == CLIENT) { - sslLabel = SSL_CLIENT; - tlsLabel = "client finished"; - } else if (sender == SERVER) { - sslLabel = SSL_SERVER; - tlsLabel = "server finished"; - } else { - throw new RuntimeException("Invalid sender: " + sender); - } - - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - // TLS 1.0+ - try { - byte [] seed; - String prfAlg; - PRF prf; - - // Get the KeyGenerator alg and calculate the seed. - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - // TLS 1.2 - seed = handshakeHash.getFinishedHash(); - - prfAlg = "SunTls12Prf"; - prf = cipherSuite.prfAlg; - } else { - // TLS 1.0/1.1 - MessageDigest md5Clone = handshakeHash.getMD5Clone(); - MessageDigest shaClone = handshakeHash.getSHAClone(); - seed = new byte[36]; - md5Clone.digest(seed, 0, 16); - shaClone.digest(seed, 16, 20); - - prfAlg = "SunTlsPrf"; - prf = P_NONE; - } - - String prfHashAlg = prf.getPRFHashAlg(); - int prfHashLength = prf.getPRFHashLength(); - int prfBlockSize = prf.getPRFBlockSize(); - - /* - * RFC 5246/7.4.9 says that finished messages can - * be ciphersuite-specific in both length/PRF hash - * algorithm. If we ever run across a different - * length, this call will need to be updated. - */ - TlsPrfParameterSpec spec = new TlsPrfParameterSpec( - masterKey, tlsLabel, seed, 12, - prfHashAlg, prfHashLength, prfBlockSize); - - KeyGenerator kg = JsseJce.getKeyGenerator(prfAlg); - kg.init(spec); - SecretKey prfKey = kg.generateKey(); - if ("RAW".equals(prfKey.getFormat()) == false) { - throw new ProviderException( - "Invalid PRF output, format must be RAW. " + - "Format received: " + prfKey.getFormat()); - } - byte[] finished = prfKey.getEncoded(); - return finished; - } catch (GeneralSecurityException e) { - throw new RuntimeException("PRF failed", e); - } - } else { - // SSLv3 - MessageDigest md5Clone = handshakeHash.getMD5Clone(); - MessageDigest shaClone = handshakeHash.getSHAClone(); - updateDigest(md5Clone, sslLabel, MD5_pad1, MD5_pad2, masterKey); - updateDigest(shaClone, sslLabel, SHA_pad1, SHA_pad2, masterKey); - byte[] finished = new byte[36]; - try { - md5Clone.digest(finished, 0, 16); - shaClone.digest(finished, 16, 20); - } catch (DigestException e) { - // cannot occur - throw new RuntimeException("Digest failed", e); - } - return finished; - } - } - - /* - * Update the MessageDigest for SSLv3 finished message calculation. - * The digest must already have been updated with all preceding handshake - * messages. This operation is almost identical to the certificate verify - * hash, reuse that code. - */ - private static void updateDigest(MessageDigest md, byte[] sender, - byte[] pad1, byte[] pad2, SecretKey masterSecret) { - md.update(sender); - CertificateVerify.updateDigest(md, pad1, pad2, masterSecret); - } - - // get the verify_data of the finished message - byte[] getVerifyData() { - return verifyData; - } - - @Override - int messageType() { return ht_finished; } - - @Override - int messageLength() { - return verifyData.length; - } - - @Override - void send(HandshakeOutStream out) throws IOException { - out.write(verifyData); - } - - @Override - void print(PrintStream s) throws IOException { - s.println("*** Finished"); - if (debug != null && Debug.isOn("verbose")) { - Debug.println(s, "verify_data", verifyData); - s.println("***"); - } - } -} - -// -// END of nested classes -// - -}
--- a/src/share/classes/sun/security/ssl/HandshakeOutStream.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,236 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.OutputStream; -import java.io.IOException; - -/** - * Output stream for handshake data. This is used only internally - * to the SSL classes. - * - * MT note: one thread at a time is presumed be writing handshake - * messages, but (after initial connection setup) it's possible to - * have other threads reading/writing application data. It's the - * SSLSocketImpl class that synchronizes record writes. - * - * @author David Brownell - */ -public class HandshakeOutStream extends OutputStream { - - private SSLSocketImpl socket; - private SSLEngineImpl engine; - - OutputRecord r; - - HandshakeOutStream(ProtocolVersion protocolVersion, - ProtocolVersion helloVersion, HandshakeHash handshakeHash, - SSLSocketImpl socket) { - this.socket = socket; - r = new OutputRecord(Record.ct_handshake); - init(protocolVersion, helloVersion, handshakeHash); - } - - HandshakeOutStream(ProtocolVersion protocolVersion, - ProtocolVersion helloVersion, HandshakeHash handshakeHash, - SSLEngineImpl engine) { - this.engine = engine; - r = new EngineOutputRecord(Record.ct_handshake, engine); - init(protocolVersion, helloVersion, handshakeHash); - } - - private void init(ProtocolVersion protocolVersion, - ProtocolVersion helloVersion, HandshakeHash handshakeHash) { - r.setVersion(protocolVersion); - r.setHelloVersion(helloVersion); - r.setHandshakeHash(handshakeHash); - } - - - /* - * Update the handshake data hashes ... mostly for use after a - * client cert has been sent, so the cert verify message can be - * constructed correctly yet without forcing extra I/O. In all - * other cases, automatic hash calculation suffices. - */ - void doHashes() { - r.doHashes(); - } - - /* - * Write some data out onto the stream ... buffers as much as possible. - * Hashes are updated automatically if something gets flushed to the - * network (e.g. a big cert message etc). - */ - @Override - public void write(byte buf[], int off, int len) throws IOException { - while (len > 0) { - int howmuch = Math.min(len, r.availableDataBytes()); - - if (howmuch == 0) { - flush(); - } else { - r.write(buf, off, howmuch); - off += howmuch; - len -= howmuch; - } - } - } - - /* - * write-a-byte - */ - @Override - public void write(int i) throws IOException { - if (r.availableDataBytes() < 1) { - flush(); - } - r.write(i); - } - - @Override - public void flush() throws IOException { - if (socket != null) { - try { - socket.writeRecord(r); - } catch (IOException e) { - // Had problems writing; check if there was an - // alert from peer. If alert received, waitForClose - // will throw an exception for the alert - socket.waitForClose(true); - - // No alert was received, just rethrow exception - throw e; - } - } else { // engine != null - /* - * Even if record might be empty, flush anyway in case - * there is a finished handshake message that we need - * to queue. - */ - engine.writeRecord((EngineOutputRecord)r); - } - } - - /* - * Tell the OutputRecord that a finished message was - * contained either in this record or the one immeiately - * preceding it. We need to reliably pass back notifications - * that a finish message occurred. - */ - void setFinishedMsg() { - assert(socket == null); - - ((EngineOutputRecord)r).setFinishedMsg(); - } - - /* - * Put integers encoded in standard 8, 16, 24, and 32 bit - * big endian formats. Note that OutputStream.write(int) only - * writes the least significant 8 bits and ignores the rest. - */ - - void putInt8(int i) throws IOException { - checkOverflow(i, Record.OVERFLOW_OF_INT08); - r.write(i); - } - - void putInt16(int i) throws IOException { - checkOverflow(i, Record.OVERFLOW_OF_INT16); - if (r.availableDataBytes() < 2) { - flush(); - } - r.write(i >> 8); - r.write(i); - } - - void putInt24(int i) throws IOException { - checkOverflow(i, Record.OVERFLOW_OF_INT24); - if (r.availableDataBytes() < 3) { - flush(); - } - r.write(i >> 16); - r.write(i >> 8); - r.write(i); - } - - void putInt32(int i) throws IOException { - if (r.availableDataBytes() < 4) { - flush(); - } - r.write(i >> 24); - r.write(i >> 16); - r.write(i >> 8); - r.write(i); - } - - /* - * Put byte arrays with length encoded as 8, 16, 24 bit - * integers in big-endian format. - */ - void putBytes8(byte b[]) throws IOException { - if (b == null) { - putInt8(0); - return; - } else { - checkOverflow(b.length, Record.OVERFLOW_OF_INT08); - } - putInt8(b.length); - write(b, 0, b.length); - } - - public void putBytes16(byte b[]) throws IOException { - if (b == null) { - putInt16(0); - return; - } else { - checkOverflow(b.length, Record.OVERFLOW_OF_INT16); - } - putInt16(b.length); - write(b, 0, b.length); - } - - void putBytes24(byte b[]) throws IOException { - if (b == null) { - putInt24(0); - return; - } else { - checkOverflow(b.length, Record.OVERFLOW_OF_INT24); - } - putInt24(b.length); - write(b, 0, b.length); - } - - private void checkOverflow(int length, int overflow) { - if (length >= overflow) { - // internal_error alert will be triggered - throw new RuntimeException( - "Field length overflow, the field length (" + - length + ") should be less than " + overflow); - } - } -}
--- a/src/share/classes/sun/security/ssl/HandshakeStateManager.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,765 +0,0 @@ -/* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.Collections; -import java.util.List; -import java.util.LinkedList; -import java.util.HashMap; -import javax.net.ssl.SSLProtocolException; - -import static sun.security.ssl.CipherSuite.KeyExchange; -import static sun.security.ssl.CipherSuite.KeyExchange.*; -import static sun.security.ssl.HandshakeStateManager.HandshakeState.*; -import static sun.security.ssl.HandshakeMessage.*; - -/* - * Handshake state manager. - * - * Messages flow for a full handshake: - * - * - - - * | HelloRequest (No.0, RFC 5246) [*] | - * | <-------------------------------------------- | - * | | - * | ClientHello (No.1, RFC 5246) | - * | --------------------------------------------> | - * | | - * C | ServerHello (No.2, RFC 5246) | S - * L | SupplementalData (No.23, RFC4680) [*] | E - * I | Certificate (No.11, RFC 5246) [*] | R - * E | CertificateStatus (No.22, RFC 6066) [*] | V - * N | ServerKeyExchange (No.12, RFC 5246) [*] | E - * T | CertificateRequest (No.13, RFC 5246) [*] | R - * | ServerHelloDone (No.14, RFC 5246) | - * | <-------------------------------------------- | - * | | - * | SupplementalData (No.23, RFC4680) [*] | - * | Certificate (No.11, RFC 5246) [*] Or | - * | CertificateURL (No.21, RFC6066) [*] | - * | ClientKeyExchange (No.16, RFC 5246) | - * | CertificateVerify (No.15, RFC 5246) [*] | - * | [ChangeCipherSpec] (RFC 5246) | - * | Finished (No.20, RFC 5246) | - * | --------------------------------------------> | - * | | - * | NewSessionTicket (No.4, RFC4507) [*] | - * | [ChangeCipherSpec] (RFC 5246) | - * | Finished (No.20, RFC 5246) | - * | <-------------------------------------------- | - * - - - * [*] Indicates optional or situation-dependent messages that are not - * always sent. - * - * Message flow for an abbreviated handshake: - * - - - * | ClientHello (No.1, RFC 5246) | - * | --------------------------------------------> | - * | | - * C | ServerHello (No.2, RFC 5246) | S - * L | NewSessionTicket (No.4, RFC4507) [*] | E - * I | [ChangeCipherSpec] (RFC 5246) | R - * E | Finished (No.20, RFC 5246) | V - * N | <-------------------------------------------- | E - * T | | R - * | [ChangeCipherSpec] (RFC 5246) | - * | Finished (No.20, RFC 5246) | - * | --------------------------------------------> | - * - - - * - * - * State machine of handshake states: - * - * +--------------+ - * START -----> | HelloRequest | - * | +--------------+ - * | | - * v v - * +---------------------+ --> +---------------------+ - * | ClientHello | | HelloVerifyRequest | - * +---------------------+ <-- +---------------------+ - * | - * | - * ========================================================================= - * | - * v - * +---------------------+ - * | ServerHello | ----------------------------------+------+ - * +---------------------+ --> +-------------------------+ | | - * | | Server SupplementalData | | | - * | +-------------------------+ | | - * | | | | - * v v | | - * +---------------------+ | | - * +---- | Server Certificate | | | - * | +---------------------+ | | - * | | | | - * | | +--------------------+ | | - * | +-> | CertificateStatus | | | - * | | +--------------------+ v | - * | | | | +--------------------+ | - * | v v +--> | ServerKeyExchange | | - * | +---------------------+ | +--------------------+ | - * | | CertificateRequest | | | | - * | +---------------------+ <-+---------+ | - * | | | | | - * v v | | | - * +---------------------+ <-------+ | | - * | ServerHelloDone | <-----------------+ | - * +---------------------+ | - * | | | - * | | | - * | | | - * ========================================================================= - * | | | - * | v | - * | +-------------------------+ | - * | | Client SupplementalData | --------------+ | - * | +-------------------------+ | | - * | | | | - * | v | | - * | +--------------------+ | | - * +-> | Client Certificate | ALT. | | - * | +--------------------+----------------+ | | - * | | CertificateURL | | | - * | +----------------+ | | - * v | | - * +-------------------+ <------------------------+ | - * | ClientKeyExchange | | - * +-------------------+ | - * | | | - * | v | - * | +-------------------+ | - * | | CertificateVerify | | - * | +-------------------+ | - * | | | - * v v | - * +-------------------------+ | - * | Client ChangeCipherSpec | <---------------+ | - * +-------------------------+ | | - * | | | - * v | | - * +-----------------+ (abbreviated) | | - * | Client Finished | -------------> END | | - * +-----------------+ (Abbreviated handshake) | | - * | | | - * | (full) | | - * | | | - * ================================ | | - * | | | - * | ================================ - * | | | - * v | | - * +------------------+ | (abbreviated) | - * | NewSessionTicket | <--------------------------------+ - * +------------------+ | | - * | | | - * v | | - * +-------------------------+ | (abbreviated) | - * | Server ChangeCipherSpec | <-------------------------------------+ - * +-------------------------+ | - * | | - * v | - * +-----------------+ (abbreviated) | - * | Server Finished | -------------------------+ - * +-----------------+ - * | (full) - * v - * END (Full handshake) - * - * - * The scenarios of the use of this class: - * 1. Create an instance of HandshakeStateManager during the initializtion - * handshake. - * 2. If receiving a handshake message, call HandshakeStateManager.check() - * to make sure that the message is of the expected handshake type. And - * then call HandshakeStateManager.update() in case handshake states may - * be impacted by this new incoming handshake message. - * 3. On delivering a handshake message, call HandshakeStateManager.update() - * in case handshake states may by thie new outgoing handshake message. - * 4. On receiving and delivering ChangeCipherSpec message, call - * HandshakeStateManager.changeCipherSpec() to check the present sequence - * of this message, and update the states if necessary. - */ -final class HandshakeStateManager { - // upcoming handshake states. - private LinkedList<HandshakeState> upcomingStates; - private LinkedList<HandshakeState> alternatives; - - private static final boolean debugIsOn; - - private static final HashMap<Byte, String> handshakeTypes; - - static { - debugIsOn = (Handshaker.debug != null) && - Debug.isOn("handshake") && Debug.isOn("verbose"); - handshakeTypes = new HashMap<>(8); - - handshakeTypes.put(ht_hello_request, "hello_request"); - handshakeTypes.put(ht_client_hello, "client_hello"); - handshakeTypes.put(ht_server_hello, "server_hello"); - handshakeTypes.put(ht_certificate, "certificate"); - handshakeTypes.put(ht_server_key_exchange, "server_key_exchange"); - handshakeTypes.put(ht_server_hello_done, "server_hello_done"); - handshakeTypes.put(ht_certificate_verify, "certificate_verify"); - handshakeTypes.put(ht_client_key_exchange, "client_key_exchange"); - handshakeTypes.put(ht_finished, "finished"); - } - - HandshakeStateManager() { - this.upcomingStates = new LinkedList<>(); - this.alternatives = new LinkedList<>(); - } - - // - // enumation of handshake type - // - static enum HandshakeState { - HS_HELLO_REQUEST( - "hello_request", - HandshakeMessage.ht_hello_request), - HS_CLIENT_HELLO( - "client_hello", - HandshakeMessage.ht_client_hello), - HS_SERVER_HELLO( - "server_hello", - HandshakeMessage.ht_server_hello), - HS_SERVER_CERTIFICATE( - "server certificate", - HandshakeMessage.ht_certificate), - HS_SERVER_KEY_EXCHANGE( - "server_key_exchange", - HandshakeMessage.ht_server_key_exchange, true), - HS_CERTIFICATE_REQUEST( - "certificate_request", - HandshakeMessage.ht_certificate_request, true), - HS_SERVER_HELLO_DONE( - "server_hello_done", - HandshakeMessage.ht_server_hello_done), - HS_CLIENT_CERTIFICATE( - "client certificate", - HandshakeMessage.ht_certificate, true), - HS_CLIENT_KEY_EXCHANGE( - "client_key_exchange", - HandshakeMessage.ht_client_key_exchange), - HS_CERTIFICATE_VERIFY( - "certificate_verify", - HandshakeMessage.ht_certificate_verify, true), - HS_CLIENT_CHANGE_CIPHER_SPEC( - "client change_cipher_spec", - HandshakeMessage.ht_not_applicable), - HS_CLIENT_FINISHED( - "client finished", - HandshakeMessage.ht_finished), - HS_SERVER_CHANGE_CIPHER_SPEC( - "server change_cipher_spec", - HandshakeMessage.ht_not_applicable), - HS_SERVER_FINISHED( - "server finished", - HandshakeMessage.ht_finished); - - final String description; - final byte handshakeType; - final boolean isOptional; - - HandshakeState(String description, byte handshakeType) { - this.description = description; - this.handshakeType = handshakeType; - this.isOptional = false; - } - - HandshakeState(String description, - byte handshakeType, boolean isOptional) { - - this.description = description; - this.handshakeType = handshakeType; - this.isOptional = isOptional; - } - - public String toString() { - return description + "[" + handshakeType + "]" + - (isOptional ? "(optional)" : ""); - } - } - - boolean isEmpty() { - return upcomingStates.isEmpty(); - } - - List<Byte> check(byte handshakeType) throws SSLProtocolException { - List<Byte> ignoredOptional = new LinkedList<>(); - String exceptionMsg = - "Handshake message sequence violation, " + handshakeType; - - if (debugIsOn) { - System.out.println( - "check handshake state: " + toString(handshakeType)); - } - - if (upcomingStates.isEmpty()) { - // Is it a kickstart message? - if ((handshakeType != HandshakeMessage.ht_hello_request) && - (handshakeType != HandshakeMessage.ht_client_hello)) { - throw new SSLProtocolException( - "Handshake message sequence violation, " + handshakeType); - } - - // It is a kickstart message. - return Collections.emptyList(); - } - - // Ignore the checking for HelloRequest messages as they - // may be sent by the server at any time. - if (handshakeType == HandshakeMessage.ht_hello_request) { - return Collections.emptyList(); - } - - for (HandshakeState handshakeState : upcomingStates) { - if (handshakeState.handshakeType == handshakeType) { - // It's the expected next handshake type. - return ignoredOptional; - } - - if (handshakeState.isOptional) { - ignoredOptional.add(handshakeState.handshakeType); - continue; - } else { - for (HandshakeState alternative : alternatives) { - if (alternative.handshakeType == handshakeType) { - return ignoredOptional; - } - - if (alternative.isOptional) { - continue; - } else { - throw new SSLProtocolException(exceptionMsg); - } - } - } - throw new SSLProtocolException(exceptionMsg); - } - - // Not an expected Handshake message. - throw new SSLProtocolException( - "Handshake message sequence violation, " + handshakeType); - } - - void update(HandshakeMessage handshakeMessage, - boolean isAbbreviated) throws SSLProtocolException { - - byte handshakeType = (byte)handshakeMessage.messageType(); - String exceptionMsg = - "Handshake message sequence violation, " + handshakeType; - - if (debugIsOn) { - System.out.println( - "update handshake state: " + toString(handshakeType)); - } - - boolean hasPresentState = false; - switch (handshakeType) { - case HandshakeMessage.ht_hello_request: - // - // State machine: - // PRESENT: START - // TO : ClientHello - // - - // No old state to update. - - // Add the upcoming states. - if (!upcomingStates.isEmpty()) { - // A ClientHello message should be followed. - upcomingStates.add(HS_CLIENT_HELLO); - - } // Otherwise, ignore this HelloRequest message. - - break; - - case HandshakeMessage.ht_client_hello: - // - // State machine: - // PRESENT: START - // HS_CLIENT_HELLO - // TO : HS_SERVER_HELLO - // - - // Check and update the present state. - if (!upcomingStates.isEmpty()) { - // The current state should be HS_CLIENT_HELLO. - HandshakeState handshakeState = upcomingStates.pop(); - if (handshakeState != HS_CLIENT_HELLO) { - throw new SSLProtocolException(exceptionMsg); - } - } - - // Add the upcoming states. - ClientHello clientHello = (ClientHello)handshakeMessage; - upcomingStates.add(HS_SERVER_HELLO); - - break; - - case HandshakeMessage.ht_server_hello: - // - // State machine: - // PRESENT: HS_SERVER_HELLO - // TO : - // Full handshake state stacks - // (ServerHello Flight) - // HS_SERVER_SUPPLEMENTAL_DATA [optional] - // --> HS_SERVER_CERTIFICATE [optional] - // --> HS_CERTIFICATE_STATUS [optional] - // --> HS_SERVER_KEY_EXCHANGE [optional] - // --> HS_CERTIFICATE_REQUEST [optional] - // --> HS_SERVER_HELLO_DONE - // (Client ClientKeyExchange Flight) - // --> HS_CLIENT_SUPPLEMENTAL_DATA [optional] - // --> HS_CLIENT_CERTIFICATE or - // HS_CERTIFICATE_URL - // --> HS_CLIENT_KEY_EXCHANGE - // --> HS_CERTIFICATE_VERIFY [optional] - // --> HS_CLIENT_CHANGE_CIPHER_SPEC - // --> HS_CLIENT_FINISHED - // (Server Finished Flight) - // --> HS_CLIENT_SUPPLEMENTAL_DATA [optional] - // - // Abbreviated handshake state stacks - // (Server Finished Flight) - // HS_NEW_SESSION_TICKET - // --> HS_SERVER_CHANGE_CIPHER_SPEC - // --> HS_SERVER_FINISHED - // (Client Finished Flight) - // --> HS_CLIENT_CHANGE_CIPHER_SPEC - // --> HS_CLIENT_FINISHED - // - // Note that this state may have an alternative option. - - // Check and update the present state. - if (!upcomingStates.isEmpty()) { - // The current state should be HS_SERVER_HELLO - HandshakeState handshakeState = upcomingStates.pop(); - HandshakeState alternative = null; - if (!alternatives.isEmpty()) { - alternative = alternatives.pop(); - } - - if ((handshakeState != HS_SERVER_HELLO) && - (alternative != HS_SERVER_HELLO)) { - throw new SSLProtocolException(exceptionMsg); - } - } else { - // No present state. - throw new SSLProtocolException(exceptionMsg); - } - - // Add the upcoming states. - ServerHello serverHello = (ServerHello)handshakeMessage; - HelloExtensions hes = serverHello.extensions; - - - // Not support SessionTicket extension yet. - // - // boolean hasSessionTicketExt = - // (hes.get(HandshakeMessage.ht_new_session_ticket) != null); - - if (isAbbreviated) { - // Not support SessionTicket extension yet. - // - // // Mandatory NewSessionTicket message - // if (hasSessionTicketExt) { - // upcomingStates.add(HS_NEW_SESSION_TICKET); - // } - - // Mandatory server ChangeCipherSpec and Finished messages - upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC); - upcomingStates.add(HS_SERVER_FINISHED); - - // Mandatory client ChangeCipherSpec and Finished messages - upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC); - upcomingStates.add(HS_CLIENT_FINISHED); - } else { - // Not support SupplementalData extension yet. - // - // boolean hasSupplementalDataExt = - // (hes.get(HandshakeMessage.ht_supplemental_data) != null); - - // Not support CertificateURL extension yet. - // - // boolean hasCertificateUrlExt = - // (hes.get(ExtensionType EXT_CLIENT_CERTIFICATE_URL) - // != null); - - // Not support SupplementalData extension yet. - // - // // Optional SupplementalData message - // if (hasSupplementalDataExt) { - // upcomingStates.add(HS_SERVER_SUPPLEMENTAL_DATA); - // } - - // Need server Certificate message or not? - KeyExchange keyExchange = serverHello.cipherSuite.keyExchange; - if ((keyExchange != K_KRB5) && - (keyExchange != K_KRB5_EXPORT) && - (keyExchange != K_DH_ANON) && - (keyExchange != K_ECDH_ANON)) { - // Mandatory Certificate message - upcomingStates.add(HS_SERVER_CERTIFICATE); - } - - // Need ServerKeyExchange message or not? - if ((keyExchange == K_RSA_EXPORT) || - (keyExchange == K_DHE_RSA) || - (keyExchange == K_DHE_DSS) || - (keyExchange == K_DH_ANON) || - (keyExchange == K_ECDHE_RSA) || - (keyExchange == K_ECDHE_ECDSA) || - (keyExchange == K_ECDH_ANON)) { - // Optional ServerKeyExchange message - upcomingStates.add(HS_SERVER_KEY_EXCHANGE); - } - - // Optional CertificateRequest message - upcomingStates.add(HS_CERTIFICATE_REQUEST); - - // Mandatory ServerHelloDone message - upcomingStates.add(HS_SERVER_HELLO_DONE); - - // Not support SupplementalData extension yet. - // - // // Optional SupplementalData message - // if (hasSupplementalDataExt) { - // upcomingStates.add(HS_CLIENT_SUPPLEMENTAL_DATA); - // } - - // Optional client Certificate message - upcomingStates.add(HS_CLIENT_CERTIFICATE); - - // Not support CertificateURL extension yet. - // - // // Alternative CertificateURL message, optional too. - // // - // // Please put CertificateURL rather than Certificate - // // message in the alternatives list. So that we can - // // simplify the process of this alternative pair later. - // if (hasCertificateUrlExt) { - // alternatives.add(HS_CERTIFICATE_URL); - // } - - // Mandatory ClientKeyExchange message - upcomingStates.add(HS_CLIENT_KEY_EXCHANGE); - - // Optional CertificateVerify message - upcomingStates.add(HS_CERTIFICATE_VERIFY); - - // Mandatory client ChangeCipherSpec and Finished messages - upcomingStates.add(HS_CLIENT_CHANGE_CIPHER_SPEC); - upcomingStates.add(HS_CLIENT_FINISHED); - - // Not support SessionTicket extension yet. - // - // // Mandatory NewSessionTicket message - // if (hasSessionTicketExt) { - // upcomingStates.add(HS_NEW_SESSION_TICKET); - // } - - // Mandatory server ChangeCipherSpec and Finished messages - upcomingStates.add(HS_SERVER_CHANGE_CIPHER_SPEC); - upcomingStates.add(HS_SERVER_FINISHED); - } - - break; - - case HandshakeMessage.ht_certificate: - // - // State machine: - // PRESENT: HS_CERTIFICATE_URL or - // HS_CLIENT_CERTIFICATE - // TO : HS_CLIENT_KEY_EXCHANGE - // - // Or - // - // PRESENT: HS_SERVER_CERTIFICATE - // TO : HS_CERTIFICATE_STATUS [optional] - // HS_SERVER_KEY_EXCHANGE [optional] - // HS_CERTIFICATE_REQUEST [optional] - // HS_SERVER_HELLO_DONE - // - // Note that this state may have an alternative option. - - // Check and update the present state. - while (!upcomingStates.isEmpty()) { - HandshakeState handshakeState = upcomingStates.pop(); - if (handshakeState.handshakeType == handshakeType) { - hasPresentState = true; - - // The current state should be HS_CLIENT_CERTIFICATE or - // HS_SERVER_CERTIFICATE. - // - // Note that we won't put HS_CLIENT_CERTIFICATE into - // the alternative list. - if ((handshakeState != HS_CLIENT_CERTIFICATE) && - (handshakeState != HS_SERVER_CERTIFICATE)) { - throw new SSLProtocolException(exceptionMsg); - } - - // Is it an expected client Certificate message? - boolean isClientMessage = false; - if (!upcomingStates.isEmpty()) { - // If the next expected message is ClientKeyExchange, - // this one should be an expected client Certificate - // message. - HandshakeState nextState = upcomingStates.getFirst(); - if (nextState == HS_CLIENT_KEY_EXCHANGE) { - isClientMessage = true; - } - } - - if (isClientMessage) { - if (handshakeState != HS_CLIENT_CERTIFICATE) { - throw new SSLProtocolException(exceptionMsg); - } - - // Not support CertificateURL extension yet. - /******************************************* - // clear up the alternatives list - if (!alternatives.isEmpty()) { - HandshakeState alternative = alternatives.pop(); - - if (alternative != HS_CERTIFICATE_URL) { - throw new SSLProtocolException(exceptionMsg); - } - } - ********************************************/ - } else { - if ((handshakeState != HS_SERVER_CERTIFICATE)) { - throw new SSLProtocolException(exceptionMsg); - } - } - - break; - } else if (!handshakeState.isOptional) { - throw new SSLProtocolException(exceptionMsg); - } // Otherwise, looking for next state track. - } - - // No present state. - if (!hasPresentState) { - throw new SSLProtocolException(exceptionMsg); - } - - // no new upcoming states. - - break; - - default: - // Check and update the present state. - while (!upcomingStates.isEmpty()) { - HandshakeState handshakeState = upcomingStates.pop(); - if (handshakeState.handshakeType == handshakeType) { - hasPresentState = true; - break; - } else if (!handshakeState.isOptional) { - throw new SSLProtocolException(exceptionMsg); - } // Otherwise, looking for next state track. - } - - // No present state. - if (!hasPresentState) { - throw new SSLProtocolException(exceptionMsg); - } - - // no new upcoming states. - } - - if (debugIsOn) { - for (HandshakeState handshakeState : upcomingStates) { - System.out.println( - "upcoming handshake states: " + handshakeState); - } - for (HandshakeState handshakeState : alternatives) { - System.out.println( - "upcoming handshake alternative state: " + handshakeState); - } - } - } - - void changeCipherSpec(boolean isInput, - boolean isClient) throws SSLProtocolException { - - if (debugIsOn) { - System.out.println( - "update handshake state: change_cipher_spec"); - } - - String exceptionMsg = "ChangeCipherSpec message sequence violation"; - - HandshakeState expectedState; - if ((isClient && isInput) || (!isClient && !isInput)) { - expectedState = HS_SERVER_CHANGE_CIPHER_SPEC; - } else { - expectedState = HS_CLIENT_CHANGE_CIPHER_SPEC; - } - - boolean hasPresentState = false; - - // Check and update the present state. - while (!upcomingStates.isEmpty()) { - HandshakeState handshakeState = upcomingStates.pop(); - if (handshakeState == expectedState) { - hasPresentState = true; - break; - } else if (!handshakeState.isOptional) { - throw new SSLProtocolException(exceptionMsg); - } // Otherwise, looking for next state track. - } - - // No present state. - if (!hasPresentState) { - throw new SSLProtocolException(exceptionMsg); - } - - // no new upcoming states. - - if (debugIsOn) { - for (HandshakeState handshakeState : upcomingStates) { - System.out.println( - "upcoming handshake states: " + handshakeState); - } - for (HandshakeState handshakeState : alternatives) { - System.out.println( - "upcoming handshake alternative state: " + handshakeState); - } - } - } - - private static String toString(byte handshakeType) { - String s = handshakeTypes.get(handshakeType); - if (s == null) { - s = "unknown"; - } - return (s + "[" + handshakeType + "]"); - } -}
--- a/src/share/classes/sun/security/ssl/Handshaker.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1587 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.util.*; -import java.util.function.BiFunction; -import java.security.*; - -import javax.crypto.*; -import javax.crypto.spec.*; - -import javax.net.ssl.*; -import sun.misc.HexDumpEncoder; - -import sun.security.internal.spec.*; -import sun.security.internal.interfaces.TlsMasterSecret; - -import sun.security.ssl.HandshakeMessage.*; -import sun.security.ssl.CipherSuite.*; - -import static sun.security.ssl.CipherSuite.PRF.*; -import static sun.security.ssl.CipherSuite.CipherType.*; - -/** - * Handshaker ... processes handshake records from an SSL V3.0 - * data stream, handling all the details of the handshake protocol. - * - * Note that the real protocol work is done in two subclasses, the base - * class just provides the control flow and key generation framework. - * - * @author David Brownell - */ -abstract class Handshaker { - - // protocol version being established using this Handshaker - ProtocolVersion protocolVersion; - - // the currently active protocol version during a renegotiation - ProtocolVersion activeProtocolVersion; - - // security parameters for secure renegotiation. - boolean secureRenegotiation; - byte[] clientVerifyData; - byte[] serverVerifyData; - - // Is it an initial negotiation or a renegotiation? - boolean isInitialHandshake; - - // List of enabled protocols - private ProtocolList enabledProtocols; - - // List of enabled CipherSuites - private CipherSuiteList enabledCipherSuites; - - // The endpoint identification protocol - String identificationProtocol; - - // The cryptographic algorithm constraints - AlgorithmConstraints algorithmConstraints = null; - - // Local supported signature and algorithms - private Collection<SignatureAndHashAlgorithm> localSupportedSignAlgs; - - // Peer supported signature and algorithms - Collection<SignatureAndHashAlgorithm> peerSupportedSignAlgs; - - /* - * List of active protocols - * - * Active protocols is a subset of enabled protocols, and will - * contain only those protocols that have vaild cipher suites - * enabled. - */ - private ProtocolList activeProtocols; - - /* - * List of active cipher suites - * - * Active cipher suites is a subset of enabled cipher suites, and will - * contain only those cipher suites available for the active protocols. - */ - private CipherSuiteList activeCipherSuites; - - // The server name indication and matchers - List<SNIServerName> serverNames = Collections.<SNIServerName>emptyList(); - Collection<SNIMatcher> sniMatchers = Collections.<SNIMatcher>emptyList(); - - // List of local ApplicationProtocols - String[] localApl = null; - - // Negotiated ALPN value - String applicationProtocol = null; - - // Application protocol callback function (for SSLEngine) - BiFunction<SSLEngine,List<String>,String> - appProtocolSelectorSSLEngine = null; - - // Application protocol callback function (for SSLSocket) - BiFunction<SSLSocket,List<String>,String> - appProtocolSelectorSSLSocket = null; - - private boolean isClient; - private boolean needCertVerify; - - SSLSocketImpl conn = null; - SSLEngineImpl engine = null; - - HandshakeHash handshakeHash; - HandshakeInStream input; - HandshakeOutStream output; - SSLContextImpl sslContext; - RandomCookie clnt_random, svr_random; - SSLSessionImpl session; - HandshakeStateManager handshakeState; - boolean clientHelloDelivered; - boolean serverHelloRequested; - boolean handshakeActivated; - boolean handshakeFinished; - - // current CipherSuite. Never null, initially SSL_NULL_WITH_NULL_NULL - CipherSuite cipherSuite; - - // current key exchange. Never null, initially K_NULL - KeyExchange keyExchange; - - // True if this session is being resumed (fast handshake) - boolean resumingSession; - - // True if it's OK to start a new SSL session - boolean enableNewSession; - - // Whether local cipher suites preference should be honored during - // handshaking? - // - // Note that in this provider, this option only applies to server side. - // Local cipher suites preference is always honored in client side in - // this provider. - boolean preferLocalCipherSuites = false; - - // Temporary storage for the individual keys. Set by - // calculateConnectionKeys() and cleared once the ciphers are - // activated. - private SecretKey clntWriteKey, svrWriteKey; - private IvParameterSpec clntWriteIV, svrWriteIV; - private SecretKey clntMacSecret, svrMacSecret; - - /* - * Delegated task subsystem data structures. - * - * If thrown is set, we need to propagate this back immediately - * on entry into processMessage(). - * - * Data is protected by the SSLEngine.this lock. - */ - private volatile boolean taskDelegated = false; - private volatile DelegatedTask<?> delegatedTask = null; - private volatile Exception thrown = null; - - // Could probably use a java.util.concurrent.atomic.AtomicReference - // here instead of using this lock. Consider changing. - private Object thrownLock = new Object(); - - // Class and subclass dynamic debugging support - static final Debug debug = Debug.getInstance("ssl"); - - // By default, disable the unsafe legacy session renegotiation - static final boolean allowUnsafeRenegotiation = Debug.getBooleanProperty( - "sun.security.ssl.allowUnsafeRenegotiation", false); - - // For maximum interoperability and backward compatibility, RFC 5746 - // allows server (or client) to accept ClientHello (or ServerHello) - // message without the secure renegotiation_info extension or SCSV. - // - // For maximum security, RFC 5746 also allows server (or client) to - // reject such message with a fatal "handshake_failure" alert. - // - // By default, allow such legacy hello messages. - static final boolean allowLegacyHelloMessages = Debug.getBooleanProperty( - "sun.security.ssl.allowLegacyHelloMessages", true); - - // To prevent the TLS renegotiation issues, by setting system property - // "jdk.tls.rejectClientInitiatedRenegotiation" to true, applications in - // server side can disable all client initiated SSL renegotiations - // regardless of the support of TLS protocols. - // - // By default, allow client initiated renegotiations. - static final boolean rejectClientInitiatedRenego = - Debug.getBooleanProperty( - "jdk.tls.rejectClientInitiatedRenegotiation", false); - - // To switch off the extended_master_secret extension. - static final boolean useExtendedMasterSecret; - - // Allow session resumption without Extended Master Secret extension. - static final boolean allowLegacyResumption = - Debug.getBooleanProperty("jdk.tls.allowLegacyResumption", true); - - // Allow full handshake without Extended Master Secret extension. - static final boolean allowLegacyMasterSecret = - Debug.getBooleanProperty("jdk.tls.allowLegacyMasterSecret", true); - - // Is it requested to use extended master secret extension? - boolean requestedToUseEMS = false; - - // need to dispose the object when it is invalidated - boolean invalidated; - - // Is the extended_master_secret extension supported? - static { - boolean supportExtendedMasterSecret = true; - try { - KeyGenerator kg = - JsseJce.getKeyGenerator("SunTlsExtendedMasterSecret"); - } catch (NoSuchAlgorithmException nae) { - supportExtendedMasterSecret = false; - } - - if (supportExtendedMasterSecret) { - useExtendedMasterSecret = Debug.getBooleanProperty( - "jdk.tls.useExtendedMasterSecret", true); - } else { - useExtendedMasterSecret = false; - } - } - - Handshaker(SSLSocketImpl c, SSLContextImpl context, - ProtocolList enabledProtocols, boolean needCertVerify, - boolean isClient, ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - this.conn = c; - init(context, enabledProtocols, needCertVerify, isClient, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - } - - Handshaker(SSLEngineImpl engine, SSLContextImpl context, - ProtocolList enabledProtocols, boolean needCertVerify, - boolean isClient, ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - this.engine = engine; - init(context, enabledProtocols, needCertVerify, isClient, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - } - - private void init(SSLContextImpl context, ProtocolList enabledProtocols, - boolean needCertVerify, boolean isClient, - ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Allow unsafe renegotiation: " + allowUnsafeRenegotiation + - "\nAllow legacy hello messages: " + allowLegacyHelloMessages + - "\nIs initial handshake: " + isInitialHandshake + - "\nIs secure renegotiation: " + secureRenegotiation); - } - - this.sslContext = context; - this.isClient = isClient; - this.needCertVerify = needCertVerify; - this.activeProtocolVersion = activeProtocolVersion; - this.isInitialHandshake = isInitialHandshake; - this.secureRenegotiation = secureRenegotiation; - this.clientVerifyData = clientVerifyData; - this.serverVerifyData = serverVerifyData; - this.enableNewSession = true; - this.invalidated = false; - this.handshakeState = new HandshakeStateManager(); - this.clientHelloDelivered = false; - this.serverHelloRequested = false; - this.handshakeActivated = false; - this.handshakeFinished = false; - - setCipherSuite(CipherSuite.C_NULL); - setEnabledProtocols(enabledProtocols); - - if (conn != null) { - algorithmConstraints = new SSLAlgorithmConstraints(conn, true); - } else { // engine != null - algorithmConstraints = new SSLAlgorithmConstraints(engine, true); - } - } - - /* - * Reroutes calls to the SSLSocket or SSLEngine (*SE). - * - * We could have also done it by extra classes - * and letting them override, but this seemed much - * less involved. - */ - void fatalSE(byte b, String diagnostic) throws IOException { - fatalSE(b, diagnostic, null); - } - - void fatalSE(byte b, Throwable cause) throws IOException { - fatalSE(b, null, cause); - } - - void fatalSE(byte b, String diagnostic, Throwable cause) - throws IOException { - if (conn != null) { - conn.fatal(b, diagnostic, cause); - } else { - engine.fatal(b, diagnostic, cause); - } - } - - void warningSE(byte b) { - if (conn != null) { - conn.warning(b); - } else { - engine.warning(b); - } - } - - // ONLY used by ClientHandshaker to setup the peer host in SSLSession. - String getHostSE() { - if (conn != null) { - return conn.getHost(); - } else { - return engine.getPeerHost(); - } - } - - // ONLY used by ServerHandshaker to setup the peer host in SSLSession. - String getHostAddressSE() { - if (conn != null) { - return conn.getInetAddress().getHostAddress(); - } else { - /* - * This is for caching only, doesn't matter that's is really - * a hostname. The main thing is that it doesn't do - * a reverse DNS lookup, potentially slowing things down. - */ - return engine.getPeerHost(); - } - } - - int getPortSE() { - if (conn != null) { - return conn.getPort(); - } else { - return engine.getPeerPort(); - } - } - - int getLocalPortSE() { - if (conn != null) { - return conn.getLocalPort(); - } else { - return -1; - } - } - - AccessControlContext getAccSE() { - if (conn != null) { - return conn.getAcc(); - } else { - return engine.getAcc(); - } - } - - String getEndpointIdentificationAlgorithmSE() { - SSLParameters paras; - if (conn != null) { - paras = conn.getSSLParameters(); - } else { - paras = engine.getSSLParameters(); - } - - return paras.getEndpointIdentificationAlgorithm(); - } - - private void setVersionSE(ProtocolVersion protocolVersion) { - if (conn != null) { - conn.setVersion(protocolVersion); - } else { - engine.setVersion(protocolVersion); - } - } - - /** - * Set the active protocol version and propagate it to the SSLSocket - * and our handshake streams. Called from ClientHandshaker - * and ServerHandshaker with the negotiated protocol version. - */ - void setVersion(ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; - setVersionSE(protocolVersion); - - output.r.setVersion(protocolVersion); - } - - /** - * Set the enabled protocols. Called from the constructor or - * SSLSocketImpl/SSLEngineImpl.setEnabledProtocols() (if the - * handshake is not yet in progress). - */ - void setEnabledProtocols(ProtocolList enabledProtocols) { - activeCipherSuites = null; - activeProtocols = null; - - this.enabledProtocols = enabledProtocols; - } - - /** - * Set the enabled cipher suites. Called from - * SSLSocketImpl/SSLEngineImpl.setEnabledCipherSuites() (if the - * handshake is not yet in progress). - */ - void setEnabledCipherSuites(CipherSuiteList enabledCipherSuites) { - activeCipherSuites = null; - activeProtocols = null; - this.enabledCipherSuites = enabledCipherSuites; - } - - /** - * Set the algorithm constraints. Called from the constructor or - * SSLSocketImpl/SSLEngineImpl.setAlgorithmConstraints() (if the - * handshake is not yet in progress). - */ - void setAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) { - activeCipherSuites = null; - activeProtocols = null; - - this.algorithmConstraints = - new SSLAlgorithmConstraints(algorithmConstraints); - this.localSupportedSignAlgs = null; - } - - Collection<SignatureAndHashAlgorithm> getLocalSupportedSignAlgs() { - if (localSupportedSignAlgs == null) { - localSupportedSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints); - } - - return localSupportedSignAlgs; - } - - void setPeerSupportedSignAlgs( - Collection<SignatureAndHashAlgorithm> algorithms) { - peerSupportedSignAlgs = - new ArrayList<SignatureAndHashAlgorithm>(algorithms); - } - - Collection<SignatureAndHashAlgorithm> getPeerSupportedSignAlgs() { - return peerSupportedSignAlgs; - } - - - /** - * Set the identification protocol. Called from the constructor or - * SSLSocketImpl/SSLEngineImpl.setIdentificationProtocol() (if the - * handshake is not yet in progress). - */ - void setIdentificationProtocol(String protocol) { - this.identificationProtocol = protocol; - } - - /** - * Sets the server name indication of the handshake. - */ - void setSNIServerNames(List<SNIServerName> serverNames) { - // The serverNames parameter is unmodifiable. - this.serverNames = serverNames; - } - - /** - * Sets the server name matchers of the handshaking. - */ - void setSNIMatchers(Collection<SNIMatcher> sniMatchers) { - // The sniMatchers parameter is unmodifiable. - this.sniMatchers = sniMatchers; - } - - /** - * Sets the Application Protocol list. - */ - void setApplicationProtocols(String[] apl) { - this.localApl = apl; - } - - /** - * Gets the "negotiated" ALPN value. - */ - String getHandshakeApplicationProtocol() { - return applicationProtocol; - } - - /** - * Sets the Application Protocol selector function for SSLEngine. - */ - void setApplicationProtocolSelectorSSLEngine( - BiFunction<SSLEngine,List<String>,String> selector) { - this.appProtocolSelectorSSLEngine = selector; - } - - /** - * Sets the Application Protocol selector function for SSLSocket. - */ - void setApplicationProtocolSelectorSSLSocket( - BiFunction<SSLSocket,List<String>,String> selector) { - this.appProtocolSelectorSSLSocket = selector; - } - - /** - * Sets the cipher suites preference. - */ - void setUseCipherSuitesOrder(boolean on) { - this.preferLocalCipherSuites = on; - } - - /** - * Prior to handshaking, activate the handshake and initialize the version, - * input stream and output stream. - */ - void activate(ProtocolVersion helloVersion) throws IOException { - if (activeProtocols == null) { - activeProtocols = getActiveProtocols(); - } - - if (activeProtocols.collection().isEmpty() || - activeProtocols.max.v == ProtocolVersion.NONE.v) { - throw new SSLHandshakeException( - "No appropriate protocol (protocol is disabled or " + - "cipher suites are inappropriate)"); - } - - if (activeCipherSuites == null) { - activeCipherSuites = getActiveCipherSuites(); - } - - if (activeCipherSuites.collection().isEmpty()) { - throw new SSLHandshakeException("No appropriate cipher suite"); - } - - // temporary protocol version until the actual protocol version - // is negotiated in the Hello exchange. This affects the record - // version we sent with the ClientHello. - if (!isInitialHandshake) { - protocolVersion = activeProtocolVersion; - } else { - protocolVersion = activeProtocols.max; - } - - if (helloVersion == null || helloVersion.v == ProtocolVersion.NONE.v) { - helloVersion = activeProtocols.helloVersion; - } - - // We accumulate digests of the handshake messages so that - // we can read/write CertificateVerify and Finished messages, - // getting assurance against some particular active attacks. - handshakeHash = new HandshakeHash(needCertVerify); - - // Generate handshake input/output stream. - input = new HandshakeInStream(handshakeHash); - if (conn != null) { - output = new HandshakeOutStream(protocolVersion, helloVersion, - handshakeHash, conn); - conn.getAppInputStream().r.setHandshakeHash(handshakeHash); - conn.getAppInputStream().r.setHelloVersion(helloVersion); - conn.getAppOutputStream().r.setHelloVersion(helloVersion); - } else { - output = new HandshakeOutStream(protocolVersion, helloVersion, - handshakeHash, engine); - engine.inputRecord.setHandshakeHash(handshakeHash); - engine.inputRecord.setHelloVersion(helloVersion); - engine.outputRecord.setHelloVersion(helloVersion); - } - - handshakeActivated = true; - } - - /** - * Set cipherSuite and keyExchange to the given CipherSuite. - * Does not perform any verification that this is a valid selection, - * this must be done before calling this method. - */ - void setCipherSuite(CipherSuite s) { - this.cipherSuite = s; - this.keyExchange = s.keyExchange; - } - - /** - * Check if the given ciphersuite is enabled and available within the - * current active cipher suites. - * - * Does not check if the required server certificates are available. - */ - boolean isNegotiable(CipherSuite s) { - if (activeCipherSuites == null) { - activeCipherSuites = getActiveCipherSuites(); - } - - return isNegotiable(activeCipherSuites, s); - } - - /** - * Check if the given ciphersuite is enabled and available within the - * proposed cipher suite list. - * - * Does not check if the required server certificates are available. - */ - final static boolean isNegotiable(CipherSuiteList proposed, CipherSuite s) { - return proposed.contains(s) && s.isNegotiable(); - } - - /** - * Check if the given protocol version is enabled and available. - */ - boolean isNegotiable(ProtocolVersion protocolVersion) { - if (activeProtocols == null) { - activeProtocols = getActiveProtocols(); - } - - return activeProtocols.contains(protocolVersion); - } - - /** - * Select a protocol version from the list. Called from - * ServerHandshaker to negotiate protocol version. - * - * Return the lower of the protocol version suggested in the - * clien hello and the highest supported by the server. - */ - ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) { - if (activeProtocols == null) { - activeProtocols = getActiveProtocols(); - } - - return activeProtocols.selectProtocolVersion(protocolVersion); - } - - /** - * Get the active cipher suites. - * - * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted, - * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT - * negotiate these cipher suites in TLS 1.1 or later mode. - * - * Therefore, when the active protocols only include TLS 1.1 or later, - * the client cannot request to negotiate those obsoleted cipher - * suites. That is, the obsoleted suites should not be included in the - * client hello. So we need to create a subset of the enabled cipher - * suites, the active cipher suites, which does not contain obsoleted - * cipher suites of the minimum active protocol. - * - * Return empty list instead of null if no active cipher suites. - */ - CipherSuiteList getActiveCipherSuites() { - if (activeCipherSuites == null) { - if (activeProtocols == null) { - activeProtocols = getActiveProtocols(); - } - - ArrayList<CipherSuite> suites = new ArrayList<>(); - if (!(activeProtocols.collection().isEmpty()) && - activeProtocols.min.v != ProtocolVersion.NONE.v) { - boolean checkedCurves = false; - boolean hasCurves = false; - for (CipherSuite suite : enabledCipherSuites.collection()) { - if (suite.obsoleted > activeProtocols.min.v && - suite.supported <= activeProtocols.max.v) { - if (algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - suite.name, null)) { - boolean available = true; - if (suite.keyExchange.isEC) { - if (!checkedCurves) { - hasCurves = EllipticCurvesExtension - .hasActiveCurves(algorithmConstraints); - checkedCurves = true; - - if (!hasCurves && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No available elliptic curves"); - } - } - - available = hasCurves; - - if (!available && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No active elliptic curves, ignore " + - suite); - } - } - - if (available) { - suites.add(suite); - } - } - } else if (debug != null && Debug.isOn("verbose")) { - if (suite.obsoleted <= activeProtocols.min.v) { - System.out.println( - "Ignoring obsoleted cipher suite: " + suite); - } else { - System.out.println( - "Ignoring unsupported cipher suite: " + suite); - } - } - } - } - activeCipherSuites = new CipherSuiteList(suites); - } - - return activeCipherSuites; - } - - /* - * Get the active protocol versions. - * - * In TLS 1.1, many weak or vulnerable cipher suites were obsoleted, - * such as TLS_RSA_EXPORT_WITH_RC4_40_MD5. The implementation MUST NOT - * negotiate these cipher suites in TLS 1.1 or later mode. - * - * For example, if "TLS_RSA_EXPORT_WITH_RC4_40_MD5" is the - * only enabled cipher suite, the client cannot request TLS 1.1 or - * later, even though TLS 1.1 or later is enabled. We need to create a - * subset of the enabled protocols, called the active protocols, which - * contains protocols appropriate to the list of enabled Ciphersuites. - * - * Return empty list instead of null if no active protocol versions. - */ - ProtocolList getActiveProtocols() { - if (activeProtocols == null) { - boolean enabledSSL20Hello = false; - boolean checkedCurves = false; - boolean hasCurves = false; - ArrayList<ProtocolVersion> protocols = new ArrayList<>(4); - for (ProtocolVersion protocol : enabledProtocols.collection()) { - // Need not to check the SSL20Hello protocol. - if (protocol.v == ProtocolVersion.SSL20Hello.v) { - enabledSSL20Hello = true; - continue; - } - - if (!algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - protocol.name, null)) { - if (debug != null && Debug.isOn("verbose")) { - System.out.println( - "Ignoring disabled protocol: " + protocol); - } - - continue; - } - boolean found = false; - for (CipherSuite suite : enabledCipherSuites.collection()) { - if (suite.isAvailable() && suite.obsoleted > protocol.v && - suite.supported <= protocol.v) { - if (algorithmConstraints.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - suite.name, null)) { - - boolean available = true; - if (suite.keyExchange.isEC) { - if (!checkedCurves) { - hasCurves = EllipticCurvesExtension - .hasActiveCurves(algorithmConstraints); - checkedCurves = true; - - if (!hasCurves && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No activated elliptic curves"); - } - } - - available = hasCurves; - - if (!available && debug != null && - Debug.isOn("verbose")) { - System.out.println( - "No active elliptic curves, ignore " + - suite + " for " + protocol); - } - } - - if (available) { - protocols.add(protocol); - found = true; - break; - } - } else if (debug != null && Debug.isOn("verbose")) { - System.out.println( - "Ignoring disabled cipher suite: " + suite + - " for " + protocol); - } - } else if (debug != null && Debug.isOn("verbose")) { - System.out.println( - "Ignoring unsupported cipher suite: " + suite + - " for " + protocol); - } - } - if (!found && (debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No available cipher suite for " + protocol); - } - } - - if (!protocols.isEmpty() && enabledSSL20Hello) { - protocols.add(ProtocolVersion.SSL20Hello); - } - - activeProtocols = new ProtocolList(protocols); - } - - return activeProtocols; - } - - /** - * As long as handshaking has not activated, we can - * change whether session creations are allowed. - * - * Callers should do their own checking if handshaking - * has activated. - */ - void setEnableSessionCreation(boolean newSessions) { - enableNewSession = newSessions; - } - - /** - * Create a new read cipher and return it to caller. - */ - CipherBox newReadCipher() throws NoSuchAlgorithmException { - BulkCipher cipher = cipherSuite.cipher; - CipherBox box; - if (isClient) { - box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV, - sslContext.getSecureRandom(), false); - svrWriteKey = null; - svrWriteIV = null; - } else { - box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV, - sslContext.getSecureRandom(), false); - clntWriteKey = null; - clntWriteIV = null; - } - return box; - } - - /** - * Create a new write cipher and return it to caller. - */ - CipherBox newWriteCipher() throws NoSuchAlgorithmException { - BulkCipher cipher = cipherSuite.cipher; - CipherBox box; - if (isClient) { - box = cipher.newCipher(protocolVersion, clntWriteKey, clntWriteIV, - sslContext.getSecureRandom(), true); - clntWriteKey = null; - clntWriteIV = null; - } else { - box = cipher.newCipher(protocolVersion, svrWriteKey, svrWriteIV, - sslContext.getSecureRandom(), true); - svrWriteKey = null; - svrWriteIV = null; - } - return box; - } - - /** - * Create a new read MAC and return it to caller. - */ - Authenticator newReadAuthenticator() - throws NoSuchAlgorithmException, InvalidKeyException { - - Authenticator authenticator = null; - if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { - authenticator = new Authenticator(protocolVersion); - } else { - MacAlg macAlg = cipherSuite.macAlg; - if (isClient) { - authenticator = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; - } else { - authenticator = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; - } - } - - return authenticator; - } - - /** - * Create a new write MAC and return it to caller. - */ - Authenticator newWriteAuthenticator() - throws NoSuchAlgorithmException, InvalidKeyException { - - Authenticator authenticator = null; - if (cipherSuite.cipher.cipherType == AEAD_CIPHER) { - authenticator = new Authenticator(protocolVersion); - } else { - MacAlg macAlg = cipherSuite.macAlg; - if (isClient) { - authenticator = macAlg.newMac(protocolVersion, clntMacSecret); - clntMacSecret = null; - } else { - authenticator = macAlg.newMac(protocolVersion, svrMacSecret); - svrMacSecret = null; - } - } - - return authenticator; - } - - /* - * Returns true iff the handshake sequence is done, so that - * this freshly created session can become the current one. - */ - boolean isDone() { - return started() && handshakeState.isEmpty() && handshakeFinished; - } - - /* - * Returns the session which was created through this - * handshake sequence ... should be called after isDone() - * returns true. - */ - SSLSessionImpl getSession() { - return session; - } - - /* - * Set the handshake session - */ - void setHandshakeSessionSE(SSLSessionImpl handshakeSession) { - if (conn != null) { - conn.setHandshakeSession(handshakeSession); - } else { - engine.setHandshakeSession(handshakeSession); - } - } - - /* - * Returns true if renegotiation is in use for this connection. - */ - boolean isSecureRenegotiation() { - return secureRenegotiation; - } - - /* - * Returns the verify_data from the Finished message sent by the client. - */ - byte[] getClientVerifyData() { - return clientVerifyData; - } - - /* - * Returns the verify_data from the Finished message sent by the server. - */ - byte[] getServerVerifyData() { - return serverVerifyData; - } - - /* - * This routine is fed SSL handshake records when they become available, - * and processes messages found therein. - */ - void process_record(InputRecord r, boolean expectingFinished) - throws IOException { - - checkThrown(); - - /* - * Store the incoming handshake data, then see if we can - * now process any completed handshake messages - */ - input.incomingRecord(r); - - /* - * We don't need to create a separate delegatable task - * for finished messages. - */ - if ((conn != null) || expectingFinished) { - processLoop(); - } else { - delegateTask(new PrivilegedExceptionAction<Void>() { - @Override - public Void run() throws Exception { - processLoop(); - return null; - } - }); - } - } - - /* - * On input, we hash messages one at a time since servers may need - * to access an intermediate hash to validate a CertificateVerify - * message. - * - * Note that many handshake messages can come in one record (and often - * do, to reduce network resource utilization), and one message can also - * require multiple records (e.g. very large Certificate messages). - */ - void processLoop() throws IOException { - - // need to read off 4 bytes at least to get the handshake - // message type and length. - while (input.available() >= 4) { - byte messageType; - int messageLen; - - /* - * See if we can read the handshake message header, and - * then the entire handshake message. If not, wait till - * we can read and process an entire message. - */ - input.mark(4); - - messageType = (byte)input.getInt8(); - messageLen = input.getInt24(); - - if (input.available() < messageLen) { - input.reset(); - return; - } - - // Set the flags in the message receiving side. - if (messageType == HandshakeMessage.ht_client_hello) { - clientHelloDelivered = true; - } else if (messageType == HandshakeMessage.ht_hello_request) { - serverHelloRequested = true; - } - - /* - * Process the message. We require - * that processMessage() consumes the entire message. In - * lieu of explicit error checks (how?!) we assume that the - * data will look like garbage on encoding/processing errors, - * and that other protocol code will detect such errors. - * - * Note that digesting is normally deferred till after the - * message has been processed, though to process at least the - * client's Finished message (i.e. send the server's) we need - * to acccelerate that digesting. - * - * Also, note that hello request messages are never hashed; - * that includes the hello request header, too. - */ - if (messageType == HandshakeMessage.ht_hello_request) { - input.reset(); - processMessage(messageType, messageLen); - input.ignore(4 + messageLen); - } else { - input.mark(messageLen); - processMessage(messageType, messageLen); - input.digestNow(); - } - } - } - - - /** - * Returns true iff the handshaker has been activated. - * - * In activated state, the handshaker may not send any messages out. - */ - boolean activated() { - return handshakeActivated; - } - - /** - * Returns true iff the handshaker has sent any messages. - */ - boolean started() { - return (serverHelloRequested || clientHelloDelivered); - } - - - /* - * Used to kickstart the negotiation ... either writing a - * ClientHello or a HelloRequest as appropriate, whichever - * the subclass returns. NOP if handshaking's already started. - */ - void kickstart() throws IOException { - if ((isClient && clientHelloDelivered) || - (!isClient && serverHelloRequested)) { - return; - } - - HandshakeMessage m = getKickstartMessage(); - handshakeState.update(m, resumingSession); - - if (debug != null && Debug.isOn("handshake")) { - m.print(System.out); - } - m.write(output); - output.flush(); - - // Set the flags in the message delivering side. - int handshakeType = m.messageType(); - if (handshakeType == HandshakeMessage.ht_hello_request) { - serverHelloRequested = true; - } else { // HandshakeMessage.ht_client_hello - clientHelloDelivered = true; - } - - } - - /** - * Both client and server modes can start handshaking; but the - * message they send to do so is different. - */ - abstract HandshakeMessage getKickstartMessage() throws SSLException; - - /* - * Client and Server side protocols are each driven though this - * call, which processes a single message and drives the appropriate - * side of the protocol state machine (depending on the subclass). - */ - abstract void processMessage(byte messageType, int messageLen) - throws IOException; - - /* - * Most alerts in the protocol relate to handshaking problems. - * Alerts are detected as the connection reads data. - */ - abstract void handshakeAlert(byte description) throws SSLProtocolException; - - /* - * Sends a change cipher spec message and updates the write side - * cipher state so that future messages use the just-negotiated spec. - */ - void sendChangeCipherSpec(Finished mesg, boolean lastMessage) - throws IOException { - - output.flush(); // i.e. handshake data - - OutputRecord r; - if (conn != null) { - r = new OutputRecord(Record.ct_change_cipher_spec); - } else { - r = new EngineOutputRecord(Record.ct_change_cipher_spec, engine); - } - - r.setVersion(protocolVersion); - r.write(1); // single byte of data - - /* - * The write cipher state is protected by the connection write lock - * so we must grab it while making the change. We also - * make sure no writes occur between sending the ChangeCipherSpec - * message, installing the new cipher state, and sending the - * Finished message. - * - * We already hold SSLEngine/SSLSocket "this" by virtue - * of this being called from the readRecord code. - */ - if (conn != null) { - conn.writeLock.lock(); - try { - handshakeState.changeCipherSpec(false, isClient); - conn.writeRecord(r); - conn.changeWriteCiphers(); - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - handshakeState.update(mesg, resumingSession); - mesg.write(output); - output.flush(); - } finally { - conn.writeLock.unlock(); - } - } else { - synchronized (engine.writeLock) { - handshakeState.changeCipherSpec(false, isClient); - engine.writeRecord((EngineOutputRecord)r); - engine.changeWriteCiphers(); - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - handshakeState.update(mesg, resumingSession); - mesg.write(output); - if (lastMessage) { - output.setFinishedMsg(); - } - output.flush(); - } - } - if (lastMessage) { - handshakeFinished = true; - } - } - - void receiveChangeCipherSpec() throws IOException { - handshakeState.changeCipherSpec(true, isClient); - } - - /* - * Single access point to key calculation logic. Given the - * pre-master secret and the nonces from client and server, - * produce all the keying material to be used. - */ - void calculateKeys(SecretKey preMasterSecret, ProtocolVersion version) { - SecretKey master = calculateMasterSecret(preMasterSecret, version); - session.setMasterSecret(master); - calculateConnectionKeys(master); - } - - - /* - * Calculate the master secret from its various components. This is - * used for key exchange by all cipher suites. - * - * The master secret is the catenation of three MD5 hashes, each - * consisting of the pre-master secret and a SHA1 hash. Those three - * SHA1 hashes are of (different) constant strings, the pre-master - * secret, and the nonces provided by the client and the server. - */ - @SuppressWarnings("deprecation") - private SecretKey calculateMasterSecret(SecretKey preMasterSecret, - ProtocolVersion requestedVersion) { - - if (debug != null && Debug.isOn("keygen")) { - HexDumpEncoder dump = new HexDumpEncoder(); - - System.out.println("SESSION KEYGEN:"); - - System.out.println("PreMaster Secret:"); - printHex(dump, preMasterSecret.getEncoded()); - - // Nonces are dumped with connection keygen, no - // benefit to doing it twice - } - - // What algs/params do we need to use? - String masterAlg; - PRF prf; - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - masterAlg = "SunTls12MasterSecret"; - prf = cipherSuite.prfAlg; - } else { - masterAlg = "SunTlsMasterSecret"; - prf = P_NONE; - } - - String prfHashAlg = prf.getPRFHashAlg(); - int prfHashLength = prf.getPRFHashLength(); - int prfBlockSize = prf.getPRFBlockSize(); - - TlsMasterSecretParameterSpec spec; - if (session.getUseExtendedMasterSecret()) { - // reset to use the extended master secret algorithm - masterAlg = "SunTlsExtendedMasterSecret"; - - byte[] sessionHash = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - sessionHash = handshakeHash.getFinishedHash(); - } else { - // TLS 1.0/1.1 - sessionHash = new byte[36]; - try { - handshakeHash.getMD5Clone().digest(sessionHash, 0, 16); - handshakeHash.getSHAClone().digest(sessionHash, 16, 20); - } catch (DigestException de) { - throw new ProviderException(de); - } - } - - spec = new TlsMasterSecretParameterSpec( - preMasterSecret, protocolVersion.major, protocolVersion.minor, - sessionHash, prfHashAlg, prfHashLength, prfBlockSize); - } else { - spec = new TlsMasterSecretParameterSpec( - preMasterSecret, protocolVersion.major, protocolVersion.minor, - clnt_random.random_bytes, svr_random.random_bytes, - prfHashAlg, prfHashLength, prfBlockSize); - } - - try { - KeyGenerator kg = JsseJce.getKeyGenerator(masterAlg); - kg.init(spec); - return kg.generateKey(); - } catch (InvalidAlgorithmParameterException | - NoSuchAlgorithmException iae) { - // unlikely to happen, otherwise, must be a provider exception - // - // For RSA premaster secrets, do not signal a protocol error - // due to the Bleichenbacher attack. See comments further down. - if (debug != null && Debug.isOn("handshake")) { - System.out.println("RSA master secret generation error:"); - iae.printStackTrace(System.out); - } - throw new ProviderException(iae); - - } - } - - /* - * Calculate the keys needed for this connection, once the session's - * master secret has been calculated. Uses the master key and nonces; - * the amount of keying material generated is a function of the cipher - * suite that's been negotiated. - * - * This gets called both on the "full handshake" (where we exchanged - * a premaster secret and started a new session) as well as on the - * "fast handshake" (where we just resumed a pre-existing session). - */ - void calculateConnectionKeys(SecretKey masterKey) { - /* - * For both the read and write sides of the protocol, we use the - * master to generate MAC secrets and cipher keying material. Block - * ciphers need initialization vectors, which we also generate. - * - * First we figure out how much keying material is needed. - */ - int hashSize = cipherSuite.macAlg.size; - boolean is_exportable = cipherSuite.exportable; - BulkCipher cipher = cipherSuite.cipher; - int expandedKeySize = is_exportable ? cipher.expandedKeySize : 0; - - // Which algs/params do we need to use? - String keyMaterialAlg; - PRF prf; - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - keyMaterialAlg = "SunTls12KeyMaterial"; - prf = cipherSuite.prfAlg; - } else { - keyMaterialAlg = "SunTlsKeyMaterial"; - prf = P_NONE; - } - - String prfHashAlg = prf.getPRFHashAlg(); - int prfHashLength = prf.getPRFHashLength(); - int prfBlockSize = prf.getPRFBlockSize(); - - // TLS v1.1 or later uses an explicit IV in CBC cipher suites to - // protect against the CBC attacks. AEAD/GCM cipher suites in TLS - // v1.2 or later use a fixed IV as the implicit part of the partially - // implicit nonce technique described in RFC 5116. - int ivSize = cipher.ivSize; - if (cipher.cipherType == AEAD_CIPHER) { - ivSize = cipher.fixedIvSize; - } else if (protocolVersion.v >= ProtocolVersion.TLS11.v && - cipher.cipherType == BLOCK_CIPHER) { - ivSize = 0; - } - - TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec( - masterKey, protocolVersion.major, protocolVersion.minor, - clnt_random.random_bytes, svr_random.random_bytes, - cipher.algorithm, cipher.keySize, expandedKeySize, - ivSize, hashSize, - prfHashAlg, prfHashLength, prfBlockSize); - - try { - KeyGenerator kg = JsseJce.getKeyGenerator(keyMaterialAlg); - kg.init(spec); - TlsKeyMaterialSpec keySpec = (TlsKeyMaterialSpec)kg.generateKey(); - - // Return null if cipher keys are not supposed to be generated. - clntWriteKey = keySpec.getClientCipherKey(); - svrWriteKey = keySpec.getServerCipherKey(); - - // Return null if IVs are not supposed to be generated. - clntWriteIV = keySpec.getClientIv(); - svrWriteIV = keySpec.getServerIv(); - - // Return null if MAC keys are not supposed to be generated. - clntMacSecret = keySpec.getClientMacKey(); - svrMacSecret = keySpec.getServerMacKey(); - } catch (GeneralSecurityException e) { - throw new ProviderException(e); - } - - // - // Dump the connection keys as they're generated. - // - if (debug != null && Debug.isOn("keygen")) { - synchronized (System.out) { - HexDumpEncoder dump = new HexDumpEncoder(); - - System.out.println("CONNECTION KEYGEN:"); - - // Inputs: - System.out.println("Client Nonce:"); - printHex(dump, clnt_random.random_bytes); - System.out.println("Server Nonce:"); - printHex(dump, svr_random.random_bytes); - System.out.println("Master Secret:"); - printHex(dump, masterKey.getEncoded()); - - // Outputs: - if (clntMacSecret != null) { - System.out.println("Client MAC write Secret:"); - printHex(dump, clntMacSecret.getEncoded()); - System.out.println("Server MAC write Secret:"); - printHex(dump, svrMacSecret.getEncoded()); - } else { - System.out.println("... no MAC keys used for this cipher"); - } - - if (clntWriteKey != null) { - System.out.println("Client write key:"); - printHex(dump, clntWriteKey.getEncoded()); - System.out.println("Server write key:"); - printHex(dump, svrWriteKey.getEncoded()); - } else { - System.out.println("... no encryption keys used"); - } - - if (clntWriteIV != null) { - System.out.println("Client write IV:"); - printHex(dump, clntWriteIV.getIV()); - System.out.println("Server write IV:"); - printHex(dump, svrWriteIV.getIV()); - } else { - if (protocolVersion.v >= ProtocolVersion.TLS11.v) { - System.out.println( - "... no IV derived for this protocol"); - } else { - System.out.println("... no IV used for this cipher"); - } - } - System.out.flush(); - } - } - } - - private static void printHex(HexDumpEncoder dump, byte[] bytes) { - if (bytes == null) { - System.out.println("(key bytes not available)"); - } else { - try { - dump.encodeBuffer(bytes, System.out); - } catch (IOException e) { - // just for debugging, ignore this - } - } - } - - /** - * Throw an SSLException with the specified message and cause. - * Shorthand until a new SSLException constructor is added. - * This method never returns. - */ - static void throwSSLException(String msg, Throwable cause) - throws SSLException { - SSLException e = new SSLException(msg); - e.initCause(cause); - throw e; - } - - - /* - * Implement a simple task delegator. - * - * We are currently implementing this as a single delegator, may - * try for parallel tasks later. Client Authentication could - * benefit from this, where ClientKeyExchange/CertificateVerify - * could be carried out in parallel. - */ - class DelegatedTask<E> implements Runnable { - - private PrivilegedExceptionAction<E> pea; - - DelegatedTask(PrivilegedExceptionAction<E> pea) { - this.pea = pea; - } - - public void run() { - synchronized (engine) { - try { - AccessController.doPrivileged(pea, engine.getAcc()); - } catch (PrivilegedActionException pae) { - thrown = pae.getException(); - } catch (RuntimeException rte) { - thrown = rte; - } - delegatedTask = null; - taskDelegated = false; - } - } - } - - private <T> void delegateTask(PrivilegedExceptionAction<T> pea) { - delegatedTask = new DelegatedTask<T>(pea); - taskDelegated = false; - thrown = null; - } - - DelegatedTask<?> getTask() { - if (!taskDelegated) { - taskDelegated = true; - return delegatedTask; - } else { - return null; - } - } - - /* - * See if there are any tasks which need to be delegated - * - * Locked by SSLEngine.this. - */ - boolean taskOutstanding() { - return (delegatedTask != null); - } - - /* - * The previous caller failed for some reason, report back the - * Exception. We won't worry about Error's. - * - * Locked by SSLEngine.this. - */ - void checkThrown() throws SSLException { - synchronized (thrownLock) { - if (thrown != null) { - - String msg = thrown.getMessage(); - - if (msg == null) { - msg = "Delegated task threw Exception/Error"; - } - - /* - * See what the underlying type of exception is. We should - * throw the same thing. Chain thrown to the new exception. - */ - Exception e = thrown; - thrown = null; - - if (e instanceof RuntimeException) { - throw new RuntimeException(msg, e); - } else if (e instanceof SSLHandshakeException) { - throw (SSLHandshakeException) - new SSLHandshakeException(msg).initCause(e); - } else if (e instanceof SSLKeyException) { - throw (SSLKeyException) - new SSLKeyException(msg).initCause(e); - } else if (e instanceof SSLPeerUnverifiedException) { - throw (SSLPeerUnverifiedException) - new SSLPeerUnverifiedException(msg).initCause(e); - } else if (e instanceof SSLProtocolException) { - throw (SSLProtocolException) - new SSLProtocolException(msg).initCause(e); - } else { - /* - * If it's SSLException or any other Exception, - * we'll wrap it in an SSLException. - */ - throw new SSLException(msg, e); - } - } - } - } -}
--- a/src/share/classes/sun/security/ssl/HelloExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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; - -abstract class HelloExtension { - - final ExtensionType type; - - HelloExtension(ExtensionType type) { - this.type = type; - } - - // Length of the encoded extension, including the type and length fields - abstract int length(); - - abstract void send(HandshakeOutStream s) throws IOException; - - @Override - public abstract String toString(); - -}
--- a/src/share/classes/sun/security/ssl/HelloExtensions.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,157 +0,0 @@ -/* - * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.io.PrintStream; -import java.util.*; -import javax.net.ssl.*; - -/** - * This file contains all the classes relevant to TLS Extensions for the - * ClientHello and ServerHello messages. The extension mechanism and - * several extensions are defined in RFC 6066. Additional extensions are - * defined in the ECC RFC 4492 and the ALPN extension is defined in RFC 7301. - * - * Currently, only the two ECC extensions are fully supported. - * - * The classes contained in this file are: - * . HelloExtensions: a List of extensions as used in the client hello - * and server hello messages. - * . ExtensionType: an enum style class for the extension type - * . HelloExtension: abstract base class for all extensions. All subclasses - * must be immutable. - * - * . UnknownExtension: used to represent all parsed extensions that we do not - * explicitly support. - * . ServerNameExtension: the server_name extension. - * . SignatureAlgorithmsExtension: the signature_algorithms extension. - * . EllipticCurvesExtension: the ECC supported curves extension. - * . EllipticPointFormatsExtension: the ECC supported point formats - * (compressed/uncompressed) extension. - * . ALPNExtension: the application_layer_protocol_negotiation extension. - * - * @since 1.6 - * @author Andreas Sterbenz - */ -final class HelloExtensions { - - private List<HelloExtension> extensions; - private int encodedLength; - - HelloExtensions() { - extensions = Collections.emptyList(); - } - - HelloExtensions(HandshakeInStream s) throws IOException { - int len = s.getInt16(); - extensions = new ArrayList<HelloExtension>(); - encodedLength = len + 2; - while (len > 0) { - int type = s.getInt16(); - int extlen = s.getInt16(); - ExtensionType extType = ExtensionType.get(type); - HelloExtension extension; - if (extType == ExtensionType.EXT_SERVER_NAME) { - extension = new ServerNameExtension(s, extlen); - } else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) { - extension = new SignatureAlgorithmsExtension(s, extlen); - } else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) { - extension = new EllipticCurvesExtension(s, extlen); - } else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) { - extension = new EllipticPointFormatsExtension(s, extlen); - } else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) { - extension = new RenegotiationInfoExtension(s, extlen); - } else if (extType == ExtensionType.EXT_EXTENDED_MASTER_SECRET) { - extension = new ExtendedMasterSecretExtension(s, extlen); - } else if (extType == ExtensionType.EXT_ALPN) { - extension = new ALPNExtension(s, extlen); - } else { - extension = new UnknownExtension(s, extlen, extType); - } - extensions.add(extension); - len -= extlen + 4; - } - if (len != 0) { - throw new SSLProtocolException( - "Error parsing extensions: extra data"); - } - } - - // Return the List of extensions. Must not be modified by the caller. - List<HelloExtension> list() { - return extensions; - } - - void add(HelloExtension ext) { - if (extensions.isEmpty()) { - extensions = new ArrayList<HelloExtension>(); - } - extensions.add(ext); - encodedLength = -1; - } - - HelloExtension get(ExtensionType type) { - for (HelloExtension ext : extensions) { - if (ext.type == type) { - return ext; - } - } - return null; - } - - int length() { - if (encodedLength >= 0) { - return encodedLength; - } - if (extensions.isEmpty()) { - encodedLength = 0; - } else { - encodedLength = 2; - for (HelloExtension ext : extensions) { - encodedLength += ext.length(); - } - } - return encodedLength; - } - - void send(HandshakeOutStream s) throws IOException { - int length = length(); - if (length == 0) { - return; - } - s.putInt16(length - 2); - for (HelloExtension ext : extensions) { - ext.send(s); - } - } - - void print(PrintStream s) throws IOException { - for (HelloExtension ext : extensions) { - s.println(ext.toString()); - } - } -}
--- a/src/share/classes/sun/security/ssl/InputRecord.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,872 +0,0 @@ -/* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; - -import javax.crypto.BadPaddingException; - -import javax.net.ssl.*; - -import sun.misc.HexDumpEncoder; - - -/** - * SSL 3.0 records, as pulled off a TCP stream. Input records are - * basically buffers tied to a particular input stream ... a layer - * above this must map these records into the model of a continuous - * stream of data. - * - * Since this returns SSL 3.0 records, it's the layer that needs to - * map SSL 2.0 style handshake records into SSL 3.0 ones for those - * "old" clients that interop with both V2 and V3 servers. Not as - * pretty as might be desired. - * - * NOTE: During handshaking, each message must be hashed to support - * verification that the handshake process wasn't compromised. - * - * @author David Brownell - */ -class InputRecord extends ByteArrayInputStream implements Record { - - private HandshakeHash handshakeHash; - private int lastHashed; - boolean formatVerified = true; // SSLv2 ruled out? - private boolean isClosed; - private boolean appDataValid; - - // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello - // and the first message we read is a ClientHello in V2 format, we convert - // it to V3. Otherwise we throw an exception when encountering a V2 hello. - private ProtocolVersion helloVersion; - - /* Class and subclass dynamic debugging support */ - static final Debug debug = Debug.getInstance("ssl"); - - /* The existing record length */ - private int exlen; - - /* V2 handshake message */ - private byte v2Buf[]; - - /* - * Construct the record to hold the maximum sized input record. - * Data will be filled in separately. - * - * The structure of the byte buffer looks like: - * - * |--------+---------+---------------------------------| - * | header | IV | content, MAC/TAG, padding, etc. | - * | headerPlusIVSize | - * - * header: the header of an SSL records - * IV: the optional IV/nonce field, it is only required for block - * (TLS 1.1 or later) and AEAD cipher suites. - * - */ - InputRecord() { - super(new byte[maxRecordSize]); - setHelloVersion(ProtocolVersion.DEFAULT_HELLO); - pos = headerSize; - count = headerSize; - lastHashed = count; - exlen = 0; - v2Buf = null; - } - - void setHelloVersion(ProtocolVersion helloVersion) { - this.helloVersion = helloVersion; - } - - ProtocolVersion getHelloVersion() { - return helloVersion; - } - - /* - * Enable format checks if initial handshaking hasn't completed - */ - void enableFormatChecks() { - formatVerified = false; - } - - // return whether the data in this record is valid, decrypted data - boolean isAppDataValid() { - return appDataValid; - } - - void setAppDataValid(boolean value) { - appDataValid = value; - } - - /* - * Return the content type of the record. - */ - byte contentType() { - return buf[0]; - } - - /* - * For handshaking, we need to be able to hash every byte above the - * record marking layer. This is where we're guaranteed to see those - * bytes, so this is where we can hash them ... especially in the - * case of hashing the initial V2 message! - */ - void setHandshakeHash(HandshakeHash handshakeHash) { - this.handshakeHash = handshakeHash; - } - - HandshakeHash getHandshakeHash() { - return handshakeHash; - } - - void decrypt(Authenticator authenticator, - CipherBox box) throws BadPaddingException { - BadPaddingException reservedBPE = null; - int tagLen = - (authenticator instanceof MAC) ? ((MAC)authenticator).MAClen() : 0; - int cipheredLength = count - headerSize; - - if (!box.isNullCipher()) { - try { - // apply explicit nonce for AEAD/CBC cipher suites if needed - int nonceSize = box.applyExplicitNonce(authenticator, - contentType(), buf, headerSize, cipheredLength); - pos = headerSize + nonceSize; - lastHashed = pos; // don't digest the explicit nonce - - // decrypt the content - int offset = headerSize; - if (box.isAEADMode()) { - // DON'T encrypt the nonce_explicit for AEAD mode - offset += nonceSize; - } // The explicit IV for CBC mode can be decrypted. - - // Note that the CipherBox.decrypt() does not change - // the capacity of the buffer. - count = offset + - box.decrypt(buf, offset, count - offset, tagLen); - - // Note that we don't remove the nonce from the buffer. - } catch (BadPaddingException bpe) { - // RFC 2246 states that decryption_failed should be used - // for this purpose. However, that allows certain attacks, - // so we just send bad record MAC. We also need to make - // sure to always check the MAC to avoid a timing attack - // for the same issue. See paper by Vaudenay et al and the - // update in RFC 4346/5246. - // - // Failover to message authentication code checking. - reservedBPE = bpe; - } - } - - // Requires message authentication code for null, stream and block - // cipher suites. - if (authenticator instanceof MAC && tagLen != 0) { - MAC signer = (MAC)authenticator; - int macOffset = count - tagLen; - int contentLen = macOffset - pos; - - // Note that although it is not necessary, we run the same MAC - // computation and comparison on the payload for both stream - // cipher and CBC block cipher. - if (contentLen < 0) { - // negative data length, something is wrong - if (reservedBPE == null) { - reservedBPE = new BadPaddingException("bad record"); - } - - // set offset of the dummy MAC - macOffset = headerSize + cipheredLength - tagLen; - contentLen = macOffset - headerSize; - } - - count -= tagLen; // Set the count before any MAC checking - // exception occurs, so that the following - // process can read the actual decrypted - // content (minus the MAC) in the fragment - // if necessary. - - // Run MAC computation and comparison on the payload. - if (checkMacTags(contentType(), - buf, pos, contentLen, signer, false)) { - if (reservedBPE == null) { - reservedBPE = new BadPaddingException("bad record MAC"); - } - } - - // Run MAC computation and comparison on the remainder. - // - // It is only necessary for CBC block cipher. It is used to get a - // constant time of MAC computation and comparison on each record. - if (box.isCBCMode()) { - int remainingLen = calculateRemainingLen( - signer, cipheredLength, contentLen); - - // NOTE: remainingLen may be bigger (less than 1 block of the - // hash algorithm of the MAC) than the cipheredLength. However, - // We won't need to worry about it because we always use a - // maximum buffer for every record. We need a change here if - // we use small buffer size in the future. - if (remainingLen > buf.length) { - // unlikely to happen, just a placehold - throw new RuntimeException( - "Internal buffer capacity error"); - } - - // Won't need to worry about the result on the remainder. And - // then we won't need to worry about what's actual data to - // check MAC tag on. We start the check from the header of the - // buffer so that we don't need to construct a new byte buffer. - checkMacTags(contentType(), buf, 0, remainingLen, signer, true); - } - } - - // Is it a failover? - if (reservedBPE != null) { - throw reservedBPE; - } - } - - /* - * Run MAC computation and comparison - * - * Please DON'T change the content of the byte buffer parameter! - */ - static boolean checkMacTags(byte contentType, byte[] buffer, - int offset, int contentLen, MAC signer, boolean isSimulated) { - - int tagLen = signer.MAClen(); - byte[] hash = signer.compute( - contentType, buffer, offset, contentLen, isSimulated); - if (hash == null || tagLen != hash.length) { - // Something is wrong with MAC implementation. - throw new RuntimeException("Internal MAC error"); - } - - int[] results = compareMacTags(buffer, offset + contentLen, hash); - return (results[0] != 0); - } - - /* - * A constant-time comparison of the MAC tags. - * - * Please DON'T change the content of the byte buffer parameter! - */ - private static int[] compareMacTags( - byte[] buffer, int offset, byte[] tag) { - - // An array of hits is used to prevent Hotspot optimization for - // the purpose of a constant-time check. - int[] results = {0, 0}; // {missed #, matched #} - - // The caller ensures there are enough bytes available in the buffer. - // So we won't need to check the length of the buffer. - for (int i = 0; i < tag.length; i++) { - if (buffer[offset + i] != tag[i]) { - results[0]++; // mismatched bytes - } else { - results[1]++; // matched bytes - } - } - - return results; - } - - /* - * Calculate the length of a dummy buffer to run MAC computation - * and comparison on the remainder. - * - * The caller MUST ensure that the fullLen is not less than usedLen. - */ - static int calculateRemainingLen( - MAC signer, int fullLen, int usedLen) { - - int blockLen = signer.hashBlockLen(); - int minimalPaddingLen = signer.minimalPaddingLen(); - - // (blockLen - minimalPaddingLen) is the maximum message size of - // the last block of hash function operation. See FIPS 180-4, or - // MD5 specification. - fullLen += 13 - (blockLen - minimalPaddingLen); - usedLen += 13 - (blockLen - minimalPaddingLen); - - // Note: fullLen is always not less than usedLen, and blockLen - // is always bigger than minimalPaddingLen, so we don't worry - // about negative values. 0x01 is added to the result to ensure - // that the return value is positive. The extra one byte does - // not impact the overall MAC compression function evaluations. - return 0x01 + (int)(Math.ceil(fullLen/(1.0d * blockLen)) - - Math.ceil(usedLen/(1.0d * blockLen))) * signer.hashBlockLen(); - } - - /* - * Well ... hello_request messages are _never_ hashed since we can't - * know when they'd appear in the sequence. - */ - void ignore(int bytes) { - if (bytes > 0) { - pos += bytes; - lastHashed = pos; - } - } - - /* - * We hash the (plaintext) we've processed, but only on demand. - * - * There is one place where we want to access the hash in the middle - * of a record: client cert message gets hashed, and part of the - * same record is the client cert verify message which uses that hash. - * So we track how much we've read and hashed. - */ - void doHashes() { - int len = pos - lastHashed; - - if (len > 0) { - hashInternal(buf, lastHashed, len); - lastHashed = pos; - } - } - - /* - * Need a helper function so we can hash the V2 hello correctly - */ - private void hashInternal(byte databuf [], int offset, int len) { - if (debug != null && Debug.isOn("data")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println("[read] MD5 and SHA1 hashes: len = " - + len); - hd.encodeBuffer(new ByteArrayInputStream(databuf, offset, len), - System.out); - } catch (IOException e) { } - } - handshakeHash.update(databuf, offset, len); - } - - - /* - * Handshake messages may cross record boundaries. We "queue" - * these in big buffers if we need to cope with this problem. - * This is not anticipated to be a common case; if this turns - * out to be wrong, this can readily be sped up. - */ - void queueHandshake(InputRecord r) throws IOException { - int len; - - /* - * Hash any data that's read but unhashed. - */ - doHashes(); - - /* - * Move any unread data to the front of the buffer, - * flagging it all as unhashed. - */ - if (pos > headerSize) { - len = count - pos; - if (len != 0) { - System.arraycopy(buf, pos, buf, headerSize, len); - } - pos = headerSize; - lastHashed = pos; - count = headerSize + len; - } - - /* - * Grow "buf" if needed - */ - len = r.available() + count; - if (buf.length < len) { - byte newbuf []; - - newbuf = new byte [len]; - System.arraycopy(buf, 0, newbuf, 0, count); - buf = newbuf; - } - - /* - * Append the new buffer to this one. - */ - System.arraycopy(r.buf, r.pos, buf, count, len - count); - count = len; - - /* - * Adjust lastHashed; important for now with clients which - * send SSL V2 client hellos. This will go away eventually, - * by buffer code cleanup. - */ - len = r.lastHashed - r.pos; - if (pos == headerSize) { - lastHashed += len; - } else { - throw new SSLProtocolException("?? confused buffer hashing ??"); - } - // we've read the record, advance the pointers - r.pos = r.count; - } - - - /** - * Prevent any more data from being read into this record, - * and flag the record as holding no data. - */ - @Override - public void close() { - appDataValid = false; - isClosed = true; - mark = 0; - pos = 0; - count = 0; - } - - - /* - * We may need to send this SSL v2 "No Cipher" message back, if we - * are faced with an SSLv2 "hello" that's not saying "I talk v3". - * It's the only one documented in the V2 spec as a fatal error. - */ - private static final byte[] v2NoCipher = { - (byte)0x80, (byte)0x03, // unpadded 3 byte record - (byte)0x00, // ... error message - (byte)0x00, (byte)0x01 // ... NO_CIPHER error - }; - - private int readFully(InputStream s, byte b[], int off, int len) - throws IOException { - int n = 0; - while (n < len) { - int readLen = s.read(b, off + n, len - n); - if (readLen < 0) { - return readLen; - } - - if (debug != null && Debug.isOn("packet")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - ByteBuffer bb = ByteBuffer.wrap(b, off + n, readLen); - - System.out.println("[Raw read]: length = " + - bb.remaining()); - hd.encodeBuffer(bb, System.out); - } catch (IOException e) { } - } - - n += readLen; - exlen += readLen; - } - - return n; - } - - /* - * Read the SSL V3 record ... first time around, check to see if it - * really IS a V3 record. Handle SSL V2 clients which can talk V3.0, - * as well as real V3 record format; otherwise report an error. - */ - void read(InputStream s, OutputStream o) throws IOException { - if (isClosed) { - return; - } - - /* - * For SSL it really _is_ an error if the other end went away - * so ungracefully as to not shut down cleanly. - */ - if(exlen < headerSize) { - int really = readFully(s, buf, exlen, headerSize - exlen); - if (really < 0) { - throw new EOFException("SSL peer shut down incorrectly"); - } - - pos = headerSize; - count = headerSize; - lastHashed = pos; - } - - /* - * The first record might use some other record marking convention, - * typically SSL v2 header. (PCT could also be detected here.) - * This case is currently common -- Navigator 3.0 usually works - * this way, as do IE 3.0 and other products. - */ - if (!formatVerified) { - formatVerified = true; - /* - * The first record must either be a handshake record or an - * alert message. If it's not, it is either invalid or an - * SSLv2 message. - */ - if (buf[0] != ct_handshake && buf[0] != ct_alert) { - handleUnknownRecord(s, o); - } else { - readV3Record(s, o); - } - } else { // formatVerified == true - readV3Record(s, o); - } - } - - /** - * Return true if the specified record protocol version is out of the - * range of the possible supported versions. - */ - static void checkRecordVersion(ProtocolVersion version, - boolean allowSSL20Hello) throws SSLException { - // Check if the record version is too old (currently not possible) - // or if the major version does not match. - // - // The actual version negotiation is in the handshaker classes - if ((version.v < ProtocolVersion.MIN.v) || - ((version.major & 0xFF) > (ProtocolVersion.MAX.major & 0xFF))) { - - // if it's not SSLv2, we're out of here. - if (!allowSSL20Hello || - (version.v != ProtocolVersion.SSL20Hello.v)) { - throw new SSLException("Unsupported record version " + version); - } - } - } - - /** - * Read a SSL/TLS record. Throw an IOException if the format is invalid. - */ - private void readV3Record(InputStream s, OutputStream o) - throws IOException { - ProtocolVersion recordVersion = ProtocolVersion.valueOf(buf[1], buf[2]); - - // check the record version - checkRecordVersion(recordVersion, false); - - /* - * Get and check length, then the data. - */ - int contentLen = ((buf[3] & 0x0ff) << 8) + (buf[4] & 0xff); - - /* - * Check for upper bound. - */ - if (contentLen < 0 || contentLen > maxLargeRecordSize - headerSize) { - throw new SSLProtocolException("Bad InputRecord size" - + ", count = " + contentLen - + ", buf.length = " + buf.length); - } - - /* - * Grow "buf" if needed. Since buf is maxRecordSize by default, - * this only occurs when we receive records which violate the - * SSL specification. This is a workaround for a Microsoft SSL bug. - */ - if (contentLen > buf.length - headerSize) { - byte[] newbuf = new byte[contentLen + headerSize]; - System.arraycopy(buf, 0, newbuf, 0, headerSize); - buf = newbuf; - } - - if (exlen < contentLen + headerSize) { - int really = readFully( - s, buf, exlen, contentLen + headerSize - exlen); - if (really < 0) { - throw new SSLException("SSL peer shut down incorrectly"); - } - } - - // now we've got a complete record. - count = contentLen + headerSize; - exlen = 0; - - if (debug != null && Debug.isOn("record")) { - if (count < 0 || count > (maxRecordSize - headerSize)) { - System.out.println(Thread.currentThread().getName() - + ", Bad InputRecord size" + ", count = " + count); - } - System.out.println(Thread.currentThread().getName() - + ", READ: " + recordVersion + " " - + contentName(contentType()) + ", length = " + available()); - } - /* - * then caller decrypts, verifies, and uncompresses - */ - } - - /** - * Deal with unknown records. Called if the first data we read on this - * connection does not look like an SSL/TLS record. It could a SSLv2 - * message, or just garbage. - */ - private void handleUnknownRecord(InputStream s, OutputStream o) - throws IOException { - /* - * No? Oh well; does it look like a V2 "ClientHello"? - * That'd be an unpadded handshake message; we don't - * bother checking length just now. - */ - if (((buf[0] & 0x080) != 0) && buf[2] == 1) { - /* - * if the user has disabled SSLv2Hello (using - * setEnabledProtocol) then throw an - * exception - */ - if (helloVersion != ProtocolVersion.SSL20Hello) { - throw new SSLHandshakeException("SSLv2Hello is disabled"); - } - - ProtocolVersion recordVersion = - ProtocolVersion.valueOf(buf[3], buf[4]); - - if (recordVersion == ProtocolVersion.SSL20Hello) { - /* - * Looks like a V2 client hello, but not one saying - * "let's talk SSLv3". So we send an SSLv2 error - * message, one that's treated as fatal by clients. - * (Otherwise we'll hang.) - */ - try { - writeBuffer(o, v2NoCipher, 0, v2NoCipher.length); - } catch (Exception e) { - /* NOTHING */ - } - throw new SSLException("Unsupported SSL v2.0 ClientHello"); - } - - /* - * If we can map this into a V3 ClientHello, read and - * hash the rest of the V2 handshake, turn it into a - * V3 ClientHello message, and pass it up. - */ - int len = ((buf[0] & 0x7f) << 8) + - (buf[1] & 0xff) - 3; - if (v2Buf == null) { - v2Buf = new byte[len]; - } - if (exlen < len + headerSize) { - int really = readFully( - s, v2Buf, exlen - headerSize, len + headerSize - exlen); - if (really < 0) { - throw new EOFException("SSL peer shut down incorrectly"); - } - } - - // now we've got a complete record. - exlen = 0; - - hashInternal(buf, 2, 3); - hashInternal(v2Buf, 0, len); - V2toV3ClientHello(v2Buf); - v2Buf = null; - lastHashed = count; - - if (debug != null && Debug.isOn("record")) { - System.out.println( - Thread.currentThread().getName() - + ", READ: SSL v2, contentType = " - + contentName(contentType()) - + ", translated length = " + available()); - } - return; - - } else { - /* - * Does it look like a V2 "ServerHello"? - */ - if (((buf [0] & 0x080) != 0) && buf [2] == 4) { - throw new SSLException( - "SSL V2.0 servers are not supported."); - } - - /* - * If this is a V2 NoCipher message then this means - * the other server doesn't support V3. Otherwise, we just - * don't understand what it's saying. - */ - for (int i = 0; i < v2NoCipher.length; i++) { - if (buf[i] != v2NoCipher[i]) { - throw new SSLException( - "Unrecognized SSL message, plaintext connection?"); - } - } - - throw new SSLException("SSL V2.0 servers are not supported."); - } - } - - /* - * Actually do the write here. For SSLEngine's HS data, - * we'll override this method and let it take the appropriate - * action. - */ - void writeBuffer(OutputStream s, byte [] buf, int off, int len) - throws IOException { - s.write(buf, 0, len); - s.flush(); - } - - /* - * Support "old" clients which are capable of SSL V3.0 protocol ... for - * example, Navigator 3.0 clients. The V2 message is in the header and - * the bytes passed as parameter. This routine translates the V2 message - * into an equivalent V3 one. - */ - private void V2toV3ClientHello(byte v2Msg []) throws SSLException - { - int i; - - /* - * Build the first part of the V3 record header from the V2 one - * that's now buffered up. (Lengths are fixed up later). - */ - buf [0] = ct_handshake; - buf [1] = buf [3]; // V3.x - buf[2] = buf[4]; - // header [3..4] for handshake message length - // count = 5; - - /* - * Store the generic V3 handshake header: 4 bytes - */ - buf [5] = 1; // HandshakeMessage.ht_client_hello - // buf [6..8] for length of ClientHello (int24) - // count += 4; - - /* - * ClientHello header starts with SSL version - */ - buf [9] = buf [1]; - buf [10] = buf [2]; - // count += 2; - count = 11; - - /* - * Start parsing the V2 message ... - */ - int cipherSpecLen, sessionIdLen, nonceLen; - - cipherSpecLen = ((v2Msg [0] & 0xff) << 8) + (v2Msg [1] & 0xff); - sessionIdLen = ((v2Msg [2] & 0xff) << 8) + (v2Msg [3] & 0xff); - nonceLen = ((v2Msg [4] & 0xff) << 8) + (v2Msg [5] & 0xff); - - /* - * Copy Random value/nonce ... if less than the 32 bytes of - * a V3 "Random", right justify and zero pad to the left. Else - * just take the last 32 bytes. - */ - int offset = 6 + cipherSpecLen + sessionIdLen; - - if (nonceLen < 32) { - for (i = 0; i < (32 - nonceLen); i++) - buf [count++] = 0; - System.arraycopy(v2Msg, offset, buf, count, nonceLen); - count += nonceLen; - } else { - System.arraycopy(v2Msg, offset + (nonceLen - 32), - buf, count, 32); - count += 32; - } - - /* - * Copy Session ID (only one byte length!) - */ - offset -= sessionIdLen; - buf [count++] = (byte) sessionIdLen; - - System.arraycopy(v2Msg, offset, buf, count, sessionIdLen); - count += sessionIdLen; - - /* - * Copy and translate cipher suites ... V2 specs with first byte zero - * are really V3 specs (in the last 2 bytes), just copy those and drop - * the other ones. Preference order remains unchanged. - * - * Example: Netscape Navigator 3.0 (exportable) says: - * - * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 - * 0/6, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - * - * Microsoft Internet Explorer 3.0 (exportable) supports only - * - * 0/3, SSL_RSA_EXPORT_WITH_RC4_40_MD5 - */ - int j; - - offset -= cipherSpecLen; - j = count + 2; - - for (i = 0; i < cipherSpecLen; i += 3) { - if (v2Msg [offset + i] != 0) - continue; - buf [j++] = v2Msg [offset + i + 1]; - buf [j++] = v2Msg [offset + i + 2]; - } - - j -= count + 2; - buf [count++] = (byte) (j >>> 8); - buf [count++] = (byte) j; - count += j; - - /* - * Append compression methods (default/null only) - */ - buf [count++] = 1; - buf [count++] = 0; // Session.compression_null - - /* - * Fill in lengths of the messages we synthesized (nested: - * V3 handshake message within V3 record) and then return - */ - buf [3] = (byte) (count - headerSize); - buf [4] = (byte) ((count - headerSize) >>> 8); - - buf [headerSize + 1] = 0; - buf [headerSize + 2] = (byte) (((count - headerSize) - 4) >>> 8); - buf [headerSize + 3] = (byte) ((count - headerSize) - 4); - - pos = headerSize; - } - - /** - * Return a description for the given content type. This method should be - * in Record, but since that is an interface this is not possible. - * Called from InputRecord and OutputRecord. - */ - static String contentName(int contentType) { - switch (contentType) { - case ct_change_cipher_spec: - return "Change Cipher Spec"; - case ct_alert: - return "Alert"; - case ct_handshake: - return "Handshake"; - case ct_application_data: - return "Application Data"; - default: - return "contentType = " + contentType; - } - } - -}
--- a/src/share/classes/sun/security/ssl/JsseJce.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,429 +0,0 @@ -/* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.*; -import java.math.BigInteger; - -import java.security.*; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.*; - -import javax.crypto.*; - -// explicit import to override the Provider class in this package -import java.security.Provider; - -// need internal Sun classes for FIPS tricks -import sun.security.jca.Providers; -import sun.security.jca.ProviderList; - -import sun.security.util.ECUtil; - -import static sun.security.ssl.SunJSSE.cryptoProvider; - -/** - * This class contains a few static methods for interaction with the JCA/JCE - * to obtain implementations, etc. - * - * @author Andreas Sterbenz - */ -final class JsseJce { - - private final static ProviderList fipsProviderList; - - // Flag indicating whether Kerberos crypto is available. - // If true, then all the Kerberos-based crypto we need is available. - private final static boolean kerberosAvailable; - static { - boolean temp; - try { - AccessController.doPrivileged( - new PrivilegedExceptionAction<Void>() { - @Override - public Void run() throws Exception { - // Test for Kerberos using the bootstrap class loader - Class.forName("sun.security.krb5.PrincipalName", true, - null); - return null; - } - }); - temp = true; - - } catch (Exception e) { - temp = false; - } - kerberosAvailable = temp; - } - - static { - // force FIPS flag initialization - // Because isFIPS() is synchronized and cryptoProvider is not modified - // after it completes, this also eliminates the need for any further - // synchronization when accessing cryptoProvider - if (SunJSSE.isFIPS() == false) { - fipsProviderList = null; - } else { - // Setup a ProviderList that can be used by the trust manager - // during certificate chain validation. All the crypto must be - // from the FIPS provider, but we also allow the required - // certificate related services from the SUN provider. - Provider sun = Security.getProvider("SUN"); - if (sun == null) { - throw new RuntimeException - ("FIPS mode: SUN provider must be installed"); - } - Provider sunCerts = new SunCertificates(sun); - fipsProviderList = ProviderList.newList(cryptoProvider, sunCerts); - } - } - - private static final class SunCertificates extends Provider { - private static final long serialVersionUID = -3284138292032213752L; - - SunCertificates(final Provider p) { - super("SunCertificates", 1.8d, "SunJSSE internal"); - AccessController.doPrivileged(new PrivilegedAction<Object>() { - @Override - public Object run() { - // copy certificate related services from the Sun provider - for (Map.Entry<Object,Object> entry : p.entrySet()) { - String key = (String)entry.getKey(); - if (key.startsWith("CertPathValidator.") - || key.startsWith("CertPathBuilder.") - || key.startsWith("CertStore.") - || key.startsWith("CertificateFactory.")) { - put(key, entry.getValue()); - } - } - return null; - } - }); - } - } - - /** - * JCE transformation string for RSA with PKCS#1 v1.5 padding. - * Can be used for encryption, decryption, signing, verifying. - */ - final static String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding"; - /** - * JCE transformation string for the stream cipher RC4. - */ - final static String CIPHER_RC4 = "RC4"; - /** - * JCE transformation string for DES in CBC mode without padding. - */ - final static String CIPHER_DES = "DES/CBC/NoPadding"; - /** - * JCE transformation string for (3-key) Triple DES in CBC mode - * without padding. - */ - final static String CIPHER_3DES = "DESede/CBC/NoPadding"; - /** - * JCE transformation string for AES in CBC mode - * without padding. - */ - final static String CIPHER_AES = "AES/CBC/NoPadding"; - /** - * JCE transformation string for AES in GCM mode - * without padding. - */ - final static String CIPHER_AES_GCM = "AES/GCM/NoPadding"; - /** - * JCA identifier string for DSA, i.e. a DSA with SHA-1. - */ - final static String SIGNATURE_DSA = "DSA"; - /** - * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1. - */ - final static String SIGNATURE_ECDSA = "SHA1withECDSA"; - /** - * JCA identifier string for Raw DSA, i.e. a DSA signature without - * hashing where the application provides the SHA-1 hash of the data. - * Note that the standard name is "NONEwithDSA" but we use "RawDSA" - * for compatibility. - */ - final static String SIGNATURE_RAWDSA = "RawDSA"; - /** - * JCA identifier string for Raw ECDSA, i.e. a DSA signature without - * hashing where the application provides the SHA-1 hash of the data. - */ - final static String SIGNATURE_RAWECDSA = "NONEwithECDSA"; - /** - * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature - * without hashing where the application provides the hash of the data. - * Used for RSA client authentication with a 36 byte hash. - */ - final static String SIGNATURE_RAWRSA = "NONEwithRSA"; - /** - * JCA identifier string for the SSL/TLS style RSA Signature. I.e. - * an signature using RSA with PKCS#1 v1.5 padding signing a - * concatenation of an MD5 and SHA-1 digest. - */ - final static String SIGNATURE_SSLRSA = "MD5andSHA1withRSA"; - - private JsseJce() { - // no instantiation of this class - } - - static boolean isEcAvailable() { - return EcAvailability.isAvailable; - } - - static boolean isKerberosAvailable() { - return kerberosAvailable; - } - - /** - * Return an JCE cipher implementation for the specified algorithm. - */ - static Cipher getCipher(String transformation) - throws NoSuchAlgorithmException { - try { - if (cryptoProvider == null) { - return Cipher.getInstance(transformation); - } else { - return Cipher.getInstance(transformation, cryptoProvider); - } - } catch (NoSuchPaddingException e) { - throw new NoSuchAlgorithmException(e); - } - } - - /** - * Return an JCA signature implementation for the specified algorithm. - * The algorithm string should be one of the constants defined - * in this class. - */ - static Signature getSignature(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return Signature.getInstance(algorithm); - } else { - // reference equality - if (algorithm == SIGNATURE_SSLRSA) { - // The SunPKCS11 provider currently does not support this - // special algorithm. We allow a fallback in this case because - // the SunJSSE implementation does the actual crypto using - // a NONEwithRSA signature obtained from the cryptoProvider. - if (cryptoProvider.getService("Signature", algorithm) == null) { - // Calling Signature.getInstance() and catching the - // exception would be cleaner, but exceptions are a little - // expensive. So we check directly via getService(). - try { - return Signature.getInstance(algorithm, "SunJSSE"); - } catch (NoSuchProviderException e) { - throw new NoSuchAlgorithmException(e); - } - } - } - return Signature.getInstance(algorithm, cryptoProvider); - } - } - - static KeyGenerator getKeyGenerator(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return KeyGenerator.getInstance(algorithm); - } else { - return KeyGenerator.getInstance(algorithm, cryptoProvider); - } - } - - static KeyPairGenerator getKeyPairGenerator(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return KeyPairGenerator.getInstance(algorithm); - } else { - return KeyPairGenerator.getInstance(algorithm, cryptoProvider); - } - } - - static KeyAgreement getKeyAgreement(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return KeyAgreement.getInstance(algorithm); - } else { - return KeyAgreement.getInstance(algorithm, cryptoProvider); - } - } - - static Mac getMac(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return Mac.getInstance(algorithm); - } else { - return Mac.getInstance(algorithm, cryptoProvider); - } - } - - static KeyFactory getKeyFactory(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return KeyFactory.getInstance(algorithm); - } else { - return KeyFactory.getInstance(algorithm, cryptoProvider); - } - } - - static AlgorithmParameters getAlgorithmParameters(String algorithm) - throws NoSuchAlgorithmException { - if (cryptoProvider == null) { - return AlgorithmParameters.getInstance(algorithm); - } else { - return AlgorithmParameters.getInstance(algorithm, cryptoProvider); - } - } - - static SecureRandom getSecureRandom() throws KeyManagementException { - if (cryptoProvider == null) { - return new SecureRandom(); - } - // Try "PKCS11" first. If that is not supported, iterate through - // the provider and return the first working implementation. - try { - return SecureRandom.getInstance("PKCS11", cryptoProvider); - } catch (NoSuchAlgorithmException e) { - // ignore - } - for (Provider.Service s : cryptoProvider.getServices()) { - if (s.getType().equals("SecureRandom")) { - try { - return SecureRandom.getInstance(s.getAlgorithm(), cryptoProvider); - } catch (NoSuchAlgorithmException ee) { - // ignore - } - } - } - throw new KeyManagementException("FIPS mode: no SecureRandom " - + " implementation found in provider " + cryptoProvider.getName()); - } - - static MessageDigest getMD5() { - return getMessageDigest("MD5"); - } - - static MessageDigest getSHA() { - return getMessageDigest("SHA"); - } - - static MessageDigest getMessageDigest(String algorithm) { - try { - if (cryptoProvider == null) { - return MessageDigest.getInstance(algorithm); - } else { - return MessageDigest.getInstance(algorithm, cryptoProvider); - } - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException - ("Algorithm " + algorithm + " not available", e); - } - } - - static int getRSAKeyLength(PublicKey key) { - BigInteger modulus; - if (key instanceof RSAPublicKey) { - modulus = ((RSAPublicKey)key).getModulus(); - } else { - RSAPublicKeySpec spec = getRSAPublicKeySpec(key); - modulus = spec.getModulus(); - } - return modulus.bitLength(); - } - - static RSAPublicKeySpec getRSAPublicKeySpec(PublicKey key) { - if (key instanceof RSAPublicKey) { - RSAPublicKey rsaKey = (RSAPublicKey)key; - return new RSAPublicKeySpec(rsaKey.getModulus(), - rsaKey.getPublicExponent()); - } - try { - KeyFactory factory = JsseJce.getKeyFactory("RSA"); - return factory.getKeySpec(key, RSAPublicKeySpec.class); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - static ECParameterSpec getECParameterSpec(String namedCurveOid) { - return ECUtil.getECParameterSpec(cryptoProvider, namedCurveOid); - } - - static String getNamedCurveOid(ECParameterSpec params) { - return ECUtil.getCurveName(cryptoProvider, params); - } - - static ECPoint decodePoint(byte[] encoded, EllipticCurve curve) - throws java.io.IOException { - return ECUtil.decodePoint(encoded, curve); - } - - static byte[] encodePoint(ECPoint point, EllipticCurve curve) { - return ECUtil.encodePoint(point, curve); - } - - // In FIPS mode, set thread local providers; otherwise a no-op. - // Must be paired with endFipsProvider. - static Object beginFipsProvider() { - if (fipsProviderList == null) { - return null; - } else { - return Providers.beginThreadProviderList(fipsProviderList); - } - } - - static void endFipsProvider(Object o) { - if (fipsProviderList != null) { - Providers.endThreadProviderList((ProviderList)o); - } - } - - - // lazy initialization holder class idiom for static default parameters - // - // See Effective Java Second Edition: Item 71. - private static class EcAvailability { - // Is EC crypto available? - private final static boolean isAvailable; - - static { - boolean mediator = true; - try { - JsseJce.getSignature(SIGNATURE_ECDSA); - JsseJce.getSignature(SIGNATURE_RAWECDSA); - JsseJce.getKeyAgreement("ECDH"); - JsseJce.getKeyFactory("EC"); - JsseJce.getKeyPairGenerator("EC"); - JsseJce.getAlgorithmParameters("EC"); - } catch (Exception e) { - mediator = false; - } - - isAvailable = mediator; - } - } -}
--- a/src/share/classes/sun/security/ssl/KeyManagerFactoryImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.List; -import java.util.Collections; - -import java.security.*; -import java.security.KeyStore.*; - -import javax.net.ssl.*; - -abstract class KeyManagerFactoryImpl extends KeyManagerFactorySpi { - - X509ExtendedKeyManager keyManager; - boolean isInitialized; - - KeyManagerFactoryImpl() { - // empty - } - - /** - * Returns one key manager for each type of key material. - */ - @Override - protected KeyManager[] engineGetKeyManagers() { - if (!isInitialized) { - throw new IllegalStateException( - "KeyManagerFactoryImpl is not initialized"); - } - return new KeyManager[] { keyManager }; - } - - // Factory for the SunX509 keymanager - public static final class SunX509 extends KeyManagerFactoryImpl { - - @Override - protected void engineInit(KeyStore ks, char[] password) throws - KeyStoreException, NoSuchAlgorithmException, - UnrecoverableKeyException { - if ((ks != null) && SunJSSE.isFIPS()) { - if (ks.getProvider() != SunJSSE.cryptoProvider) { - throw new KeyStoreException("FIPS mode: KeyStore must be " - + "from provider " + SunJSSE.cryptoProvider.getName()); - } - } - keyManager = new SunX509KeyManagerImpl(ks, password); - isInitialized = true; - } - - @Override - protected void engineInit(ManagerFactoryParameters spec) throws - InvalidAlgorithmParameterException { - throw new InvalidAlgorithmParameterException( - "SunX509KeyManager does not use ManagerFactoryParameters"); - } - - } - - // Factory for the X509 keymanager - public static final class X509 extends KeyManagerFactoryImpl { - - @Override - protected void engineInit(KeyStore ks, char[] password) throws - KeyStoreException, NoSuchAlgorithmException, - UnrecoverableKeyException { - if (ks == null) { - keyManager = new X509KeyManagerImpl( - Collections.<Builder>emptyList()); - } else { - if (SunJSSE.isFIPS() && (ks.getProvider() != SunJSSE.cryptoProvider)) { - throw new KeyStoreException("FIPS mode: KeyStore must be " - + "from provider " + SunJSSE.cryptoProvider.getName()); - } - try { - Builder builder = Builder.newInstance(ks, - new PasswordProtection(password)); - keyManager = new X509KeyManagerImpl(builder); - } catch (RuntimeException e) { - throw new KeyStoreException("initialization failed", e); - } - } - isInitialized = true; - } - - @Override - protected void engineInit(ManagerFactoryParameters params) throws - InvalidAlgorithmParameterException { - if (params instanceof KeyStoreBuilderParameters == false) { - throw new InvalidAlgorithmParameterException( - "Parameters must be instance of KeyStoreBuilderParameters"); - } - if (SunJSSE.isFIPS()) { - // XXX should be fixed - throw new InvalidAlgorithmParameterException - ("FIPS mode: KeyStoreBuilderParameters not supported"); - } - List<Builder> builders = - ((KeyStoreBuilderParameters)params).getParameters(); - keyManager = new X509KeyManagerImpl(builders); - isInitialized = true; - } - - } - -}
--- a/src/share/classes/sun/security/ssl/MAC.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,168 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; - -import java.nio.ByteBuffer; - -import javax.crypto.Mac; -import javax.crypto.SecretKey; - -import sun.security.ssl.CipherSuite.MacAlg; -import static sun.security.ssl.CipherSuite.*; - -/** - * This class computes the "Message Authentication Code" (MAC) for each - * SSL stream and block cipher message. This is essentially a shared-secret - * signature, used to provide integrity protection for SSL messages. The - * MAC is actually one of several keyed hashes, as associated with the cipher - * suite and protocol version. (SSL v3.0 uses one construct, TLS uses another.) - * - * @author David Brownell - * @author Andreas Sterbenz - */ -final class MAC extends Authenticator { - - final static MAC NULL = new MAC(); - - // Value of the null MAC is fixed - private static final byte nullMAC[] = new byte[0]; - - // internal identifier for the MAC algorithm - private final MacAlg macAlg; - - // JCE Mac object - private final Mac mac; - - private MAC() { - macAlg = M_NULL; - mac = null; - } - - /** - * Set up, configured for the given SSL/TLS MAC type and version. - */ - MAC(MacAlg macAlg, ProtocolVersion protocolVersion, SecretKey key) - throws NoSuchAlgorithmException, InvalidKeyException { - super(protocolVersion); - this.macAlg = macAlg; - - String algorithm; - boolean tls = (protocolVersion.v >= ProtocolVersion.TLS10.v); - - if (macAlg == M_MD5) { - algorithm = tls ? "HmacMD5" : "SslMacMD5"; - } else if (macAlg == M_SHA) { - algorithm = tls ? "HmacSHA1" : "SslMacSHA1"; - } else if (macAlg == M_SHA256) { - algorithm = "HmacSHA256"; // TLS 1.2+ - } else if (macAlg == M_SHA384) { - algorithm = "HmacSHA384"; // TLS 1.2+ - } else { - throw new RuntimeException("Unknown Mac " + macAlg); - } - - mac = JsseJce.getMac(algorithm); - mac.init(key); - } - - /** - * Returns the length of the MAC. - */ - int MAClen() { - return macAlg.size; - } - - /** - * Returns the hash function block length of the MAC alorithm. - */ - int hashBlockLen() { - return macAlg.hashBlockSize; - } - - /** - * Returns the hash function minimal padding length of the MAC alorithm. - */ - int minimalPaddingLen() { - return macAlg.minimalPaddingSize; - } - - /** - * Computes and returns the MAC for the data in this byte array. - * - * @param type record type - * @param buf compressed record on which the MAC is computed - * @param offset start of compressed record data - * @param len the size of the compressed record - * @param isSimulated if true, simulate the the MAC computation - */ - final byte[] compute(byte type, byte buf[], - int offset, int len, boolean isSimulated) { - if (macAlg.size == 0) { - return nullMAC; - } - - if (!isSimulated) { - byte[] additional = acquireAuthenticationBytes(type, len); - mac.update(additional); - } - mac.update(buf, offset, len); - - return mac.doFinal(); - } - - /** - * Compute and returns the MAC for the remaining data - * in this ByteBuffer. - * - * On return, the bb position == limit, and limit will - * have not changed. - * - * @param type record type - * @param bb a ByteBuffer in which the position and limit - * demarcate the data to be MAC'd. - * @param isSimulated if true, simulate the the MAC computation - */ - final byte[] compute(byte type, ByteBuffer bb, boolean isSimulated) { - if (macAlg.size == 0) { - return nullMAC; - } - - if (!isSimulated) { - byte[] additional = - acquireAuthenticationBytes(type, bb.remaining()); - mac.update(additional); - } - mac.update(bb); - - return mac.doFinal(); - } - -} -
--- a/src/share/classes/sun/security/ssl/OutputRecord.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,573 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; -import java.util.Arrays; - -import javax.net.ssl.SSLException; -import sun.misc.HexDumpEncoder; - - -/** - * SSL 3.0 records, as written to a TCP stream. - * - * Each record has a message area that starts out with data supplied by the - * application. It may grow/shrink due to compression and will be modified - * in place for mac-ing and encryption. - * - * Handshake records have additional needs, notably accumulation of a set - * of hashes which are used to establish that handshaking was done right. - * Handshake records usually have several handshake messages each, and we - * need message-level control over what's hashed. - * - * @author David Brownell - */ -class OutputRecord extends ByteArrayOutputStream implements Record { - - private HandshakeHash handshakeHash; - private int lastHashed; - private boolean firstMessage; - final private byte contentType; - private int headerOffset; - - // current protocol version, sent as record version - ProtocolVersion protocolVersion; - - // version for the ClientHello message. Only relevant if this is a - // client handshake record. If set to ProtocolVersion.SSL20Hello, - // the V3 client hello is converted to V2 format. - private ProtocolVersion helloVersion; - - /* Class and subclass dynamic debugging support */ - static final Debug debug = Debug.getInstance("ssl"); - - /* - * Default constructor makes a record supporting the maximum - * SSL record size. It allocates the header bytes directly. - * - * The structure of the byte buffer looks like: - * - * |---------+--------+-------+---------------------------------| - * | unused | header | IV | content, MAC/TAG, padding, etc. | - * | headerPlusMaxIVSize | - * - * unused: unused part of the buffer of size - * - * headerPlusMaxIVSize - header size - IV size - * - * When this object is created, we don't know the protocol - * version number, IV length, etc., so reserve space in front - * to avoid extra data movement (copies). - * header: the header of an SSL record - * IV: the optional IV/nonce field, it is only required for block - * (TLS 1.1 or later) and AEAD cipher suites. - * - * @param type the content type for the record - */ - OutputRecord(byte type, int size) { - super(size); - this.protocolVersion = ProtocolVersion.DEFAULT; - this.helloVersion = ProtocolVersion.DEFAULT_HELLO; - firstMessage = true; - count = headerPlusMaxIVSize; - contentType = type; - lastHashed = count; - headerOffset = headerPlusMaxIVSize - headerSize; - } - - OutputRecord(byte type) { - this(type, recordSize(type)); - } - - /** - * Get the size of the buffer we need for records of the specified - * type. - */ - private static int recordSize(byte type) { - if ((type == ct_change_cipher_spec) || (type == ct_alert)) { - return maxAlertRecordSize; - } else { - return maxRecordSize; - } - } - - /* - * Updates the SSL version of this record. - */ - synchronized void setVersion(ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; - } - - /* - * Updates helloVersion of this record. - */ - synchronized void setHelloVersion(ProtocolVersion helloVersion) { - this.helloVersion = helloVersion; - } - - /* - * Reset the record so that it can be refilled, starting - * immediately after the header. - */ - @Override - public synchronized void reset() { - super.reset(); - count = headerPlusMaxIVSize; - lastHashed = count; - headerOffset = headerPlusMaxIVSize - headerSize; - } - - /* - * For handshaking, we need to be able to hash every byte above the - * record marking layer. This is where we're guaranteed to see those - * bytes, so this is where we can hash them. - */ - void setHandshakeHash(HandshakeHash handshakeHash) { - assert(contentType == ct_handshake); - this.handshakeHash = handshakeHash; - } - - /* - * We hash (the plaintext) on demand. There is one place where - * we want to access the hash in the middle of a record: client - * cert message gets hashed, and part of the same record is the - * client cert verify message which uses that hash. So we track - * how much of each record we've hashed so far. - */ - void doHashes() { - int len = count - lastHashed; - - if (len > 0) { - hashInternal(buf, lastHashed, len); - lastHashed = count; - } - } - - /* - * Need a helper function so we can hash the V2 hello correctly - */ - private void hashInternal(byte buf [], int offset, int len) { - if (debug != null && Debug.isOn("data")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println("[write] MD5 and SHA1 hashes: len = " - + len); - hd.encodeBuffer(new ByteArrayInputStream(buf, - lastHashed, len), System.out); - } catch (IOException e) { } - } - - handshakeHash.update(buf, lastHashed, len); - lastHashed = count; - } - - /* - * Return true iff the record is empty -- to avoid doing the work - * of sending empty records over the network. - */ - boolean isEmpty() { - return count == headerPlusMaxIVSize; - } - - /* - * Return true if the record is of an alert of the given description. - * - * Per SSL/TLS specifications, alert messages convey the severity of the - * message (warning or fatal) and a description of the alert. An alert - * is defined with a two bytes struct, {byte level, byte description}, - * following after the header bytes. - */ - boolean isAlert(byte description) { - if ((count > (headerPlusMaxIVSize + 1)) && (contentType == ct_alert)) { - return buf[headerPlusMaxIVSize + 1] == description; - } - - return false; - } - - /* - * Encrypt ... length may grow due to block cipher padding, or - * message authentication code or tag. - */ - void encrypt(Authenticator authenticator, CipherBox box) - throws IOException { - - // In case we are automatically flushing a handshake stream, make - // sure we have hashed the message first. - // - // when we support compression, hashing can't go here - // since it'll need to be done on the uncompressed data, - // and the MAC applies to the compressed data. - if (contentType == ct_handshake) { - doHashes(); - } - - // Requires message authentication code for stream and block - // cipher suites. - if (authenticator instanceof MAC) { - MAC signer = (MAC)authenticator; - if (signer.MAClen() != 0) { - byte[] hash = signer.compute(contentType, buf, - headerPlusMaxIVSize, count - headerPlusMaxIVSize, false); - write(hash); - } - } - - if (!box.isNullCipher()) { - // Requires explicit IV/nonce for CBC/AEAD cipher suites for - // TLS 1.1 or later. - if ((protocolVersion.v >= ProtocolVersion.TLS11.v) && - (box.isCBCMode() || box.isAEADMode())) { - byte[] nonce = box.createExplicitNonce(authenticator, - contentType, count - headerPlusMaxIVSize); - int offset = headerPlusMaxIVSize - nonce.length; - System.arraycopy(nonce, 0, buf, offset, nonce.length); - headerOffset = offset - headerSize; - } else { - headerOffset = headerPlusMaxIVSize - headerSize; - } - - // encrypt the content - int offset = headerPlusMaxIVSize; - if (!box.isAEADMode()) { - // The explicit IV can be encrypted. - offset = headerOffset + headerSize; - } // Otherwise, DON'T encrypt the nonce_explicit for AEAD mode - - count = offset + box.encrypt(buf, offset, count - offset); - } - } - - /* - * Tell how full the buffer is ... for filling it with application or - * handshake data. - */ - final int availableDataBytes() { - int dataSize = count - headerPlusMaxIVSize; - return maxDataSize - dataSize; - } - - /* - * Increases the capacity if necessary to ensure that it can hold - * at least the number of elements specified by the minimum - * capacity argument. - * - * Note that the increased capacity is only can be used for held - * record buffer. Please DO NOT update the availableDataBytes() - * according to the expended buffer capacity. - * - * @see availableDataBytes() - */ - private void ensureCapacity(int minCapacity) { - // overflow-conscious code - if (minCapacity > buf.length) { - buf = Arrays.copyOf(buf, minCapacity); - } - } - - /* - * Return the type of SSL record that's buffered here. - */ - final byte contentType() { - return contentType; - } - - /* - * Write the record out on the stream. Note that you must have (in - * order) compressed the data, appended the MAC, and encrypted it in - * order for the record to be understood by the other end. (Some of - * those steps will be null early in handshaking.) - * - * Note that this does no locking for the connection, it's required - * that synchronization be done elsewhere. Also, this does its work - * in a single low level write, for efficiency. - */ - void write(OutputStream s, boolean holdRecord, - ByteArrayOutputStream heldRecordBuffer) throws IOException { - - /* - * Don't emit content-free records. (Even change cipher spec - * messages have a byte of data!) - */ - if (count == headerPlusMaxIVSize) { - return; - } - - int length = count - headerOffset - headerSize; - // "should" really never write more than about 14 Kb... - if (length < 0) { - throw new SSLException("output record size too small: " - + length); - } - - if (debug != null - && (Debug.isOn("record") || Debug.isOn("handshake"))) { - if ((debug != null && Debug.isOn("record")) - || contentType() == ct_change_cipher_spec) - System.out.println(Thread.currentThread().getName() - // v3.0/v3.1 ... - + ", WRITE: " + protocolVersion - + " " + InputRecord.contentName(contentType()) - + ", length = " + length); - } - - /* - * If this is the initial ClientHello on this connection and - * we're not trying to resume a (V3) session then send a V2 - * ClientHello instead so we can detect V2 servers cleanly. - */ - if (firstMessage && useV2Hello()) { - byte[] v3Msg = new byte[length - 4]; - System.arraycopy(buf, headerPlusMaxIVSize + 4, - v3Msg, 0, v3Msg.length); - headerOffset = 0; // reset the header offset - V3toV2ClientHello(v3Msg); - handshakeHash.reset(); - lastHashed = 2; - doHashes(); - if (debug != null && Debug.isOn("record")) { - System.out.println( - Thread.currentThread().getName() - + ", WRITE: SSLv2 client hello message" - + ", length = " + (count - 2)); // 2 byte SSLv2 header - } - } else { - /* - * Fill out the header, write it and the message. - */ - buf[headerOffset + 0] = contentType; - buf[headerOffset + 1] = protocolVersion.major; - buf[headerOffset + 2] = protocolVersion.minor; - buf[headerOffset + 3] = (byte)(length >> 8); - buf[headerOffset + 4] = (byte)(length); - } - firstMessage = false; - - /* - * The upper levels may want us to delay sending this packet so - * multiple TLS Records can be sent in one (or more) TCP packets. - * If so, add this packet to the heldRecordBuffer. - * - * NOTE: all writes have been synchronized by upper levels. - */ - int debugOffset = 0; - if (holdRecord) { - /* - * If holdRecord is true, we must have a heldRecordBuffer. - * - * Don't worry about the override of writeBuffer(), because - * when holdRecord is true, the implementation in this class - * will be used. - */ - writeBuffer(heldRecordBuffer, - buf, headerOffset, count - headerOffset, debugOffset); - } else { - // It's time to send, do we have buffered data? - // May or may not have a heldRecordBuffer. - if (heldRecordBuffer != null && heldRecordBuffer.size() > 0) { - int heldLen = heldRecordBuffer.size(); - - // Ensure the capacity of this buffer. - int newCount = count + heldLen - headerOffset; - ensureCapacity(newCount); - - // Slide everything in the buffer to the right. - System.arraycopy(buf, headerOffset, - buf, heldLen, count - headerOffset); - - // Prepend the held record to the buffer. - System.arraycopy( - heldRecordBuffer.toByteArray(), 0, buf, 0, heldLen); - count = newCount; - headerOffset = 0; - - // Clear the held buffer. - heldRecordBuffer.reset(); - - // The held buffer has been dumped, set the debug dump offset. - debugOffset = heldLen; - } - writeBuffer(s, buf, headerOffset, - count - headerOffset, debugOffset); - } - - reset(); - } - - /* - * Actually do the write here. For SSLEngine's HS data, - * we'll override this method and let it take the appropriate - * action. - */ - void writeBuffer(OutputStream s, byte [] buf, int off, int len, - int debugOffset) throws IOException { - s.write(buf, off, len); - s.flush(); - - // Output only the record from the specified debug offset. - if (debug != null && Debug.isOn("packet")) { - try { - HexDumpEncoder hd = new HexDumpEncoder(); - - System.out.println("[Raw write]: length = " + - (len - debugOffset)); - hd.encodeBuffer(new ByteArrayInputStream(buf, - off + debugOffset, len - debugOffset), System.out); - } catch (IOException e) { } - } - } - - /* - * Return whether the buffer contains a ClientHello message that should - * be converted to V2 format. - */ - private boolean useV2Hello() { - return firstMessage - && (helloVersion == ProtocolVersion.SSL20Hello) - && (contentType == ct_handshake) - && (buf[headerOffset + 5] == HandshakeMessage.ht_client_hello) - // 5: recode header size - && (buf[headerPlusMaxIVSize + 4 + 2 + 32] == 0); - // V3 session ID is empty - // 4: handshake header size - // 2: client_version in ClientHello - // 32: random in ClientHello - } - - /* - * Detect "old" servers which are capable of SSL V2.0 protocol ... for - * example, Netscape Commerce 1.0 servers. The V3 message is in the - * header and the bytes passed as parameter. This routine translates - * the V3 message into an equivalent V2 one. - * - * Note that the translation will strip off all hello extensions as - * SSL V2.0 does not support hello extension. - */ - private void V3toV2ClientHello(byte v3Msg []) throws SSLException { - int v3SessionIdLenOffset = 2 + 32; // version + nonce - int v3SessionIdLen = v3Msg[v3SessionIdLenOffset]; - int v3CipherSpecLenOffset = v3SessionIdLenOffset + 1 + v3SessionIdLen; - int v3CipherSpecLen = ((v3Msg[v3CipherSpecLenOffset] & 0xff) << 8) + - (v3Msg[v3CipherSpecLenOffset + 1] & 0xff); - int cipherSpecs = v3CipherSpecLen / 2; // 2 bytes each in V3 - - /* - * Copy over the cipher specs. We don't care about actually translating - * them for use with an actual V2 server since we only talk V3. - * Therefore, just copy over the V3 cipher spec values with a leading - * 0. - */ - int v3CipherSpecOffset = v3CipherSpecLenOffset + 2; // skip length - int v2CipherSpecLen = 0; - count = 11; - boolean containsRenegoInfoSCSV = false; - for (int i = 0; i < cipherSpecs; i++) { - byte byte1, byte2; - - byte1 = v3Msg[v3CipherSpecOffset++]; - byte2 = v3Msg[v3CipherSpecOffset++]; - v2CipherSpecLen += V3toV2CipherSuite(byte1, byte2); - if (!containsRenegoInfoSCSV && - byte1 == (byte)0x00 && byte2 == (byte)0xFF) { - containsRenegoInfoSCSV = true; - } - } - - if (!containsRenegoInfoSCSV) { - v2CipherSpecLen += V3toV2CipherSuite((byte)0x00, (byte)0xFF); - } - - /* - * Build the first part of the V3 record header from the V2 one - * that's now buffered up. (Lengths are fixed up later). - */ - buf[2] = HandshakeMessage.ht_client_hello; - buf[3] = v3Msg[0]; // major version - buf[4] = v3Msg[1]; // minor version - buf[5] = (byte)(v2CipherSpecLen >>> 8); - buf[6] = (byte)v2CipherSpecLen; - buf[7] = 0; - buf[8] = 0; // always no session - buf[9] = 0; - buf[10] = 32; // nonce length (always 32 in V3) - - /* - * Copy in the nonce. - */ - System.arraycopy(v3Msg, 2, buf, count, 32); - count += 32; - - /* - * Set the length of the message. - */ - count -= 2; // don't include length field itself - buf[0] = (byte)(count >>> 8); - buf[0] |= 0x80; - buf[1] = (byte)(count); - count += 2; - } - - /* - * Mappings from V3 cipher suite encodings to their pure V2 equivalents. - * This is taken from the SSL V3 specification, Appendix E. - */ - private static int[] V3toV2CipherMap1 = - {-1, -1, -1, 0x02, 0x01, -1, 0x04, 0x05, -1, 0x06, 0x07}; - private static int[] V3toV2CipherMap3 = - {-1, -1, -1, 0x80, 0x80, -1, 0x80, 0x80, -1, 0x40, 0xC0}; - - /* - * See which matching pure-V2 cipher specs we need to include. - * We are including these not because we are actually prepared - * to talk V2 but because the Oracle Web Server insists on receiving - * at least 1 "pure V2" cipher suite that it supports and returns an - * illegal_parameter alert unless one is present. Rather than mindlessly - * claiming to implement all documented pure V2 cipher suites the code below - * just claims to implement the V2 cipher suite that is "equivalent" - * in terms of cipher algorithm & exportability with the actual V3 cipher - * suite that we do support. - */ - private int V3toV2CipherSuite(byte byte1, byte byte2) { - buf[count++] = 0; - buf[count++] = byte1; - buf[count++] = byte2; - - if (((byte2 & 0xff) > 0xA) || - (V3toV2CipherMap1[byte2] == -1)) { - return 3; - } - - buf[count++] = (byte)V3toV2CipherMap1[byte2]; - buf[count++] = 0; - buf[count++] = (byte)V3toV2CipherMap3[byte2]; - - return 6; - } -}
--- a/src/share/classes/sun/security/ssl/ProtocolList.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.*; - -/** - * A list of ProtocolVersions. Also maintains the list of supported protocols. - * Instances of this class are immutable. Some member variables are final - * and can be accessed directly without method accessors. - * - * @author Andreas Sterbenz - * @since 1.4.1 - */ -final class ProtocolList { - - // the sorted protocol version list - private final ArrayList<ProtocolVersion> protocols; - - private String[] protocolNames; - - // the minimum and maximum ProtocolVersions in this list - final ProtocolVersion min, max; - - // the format for the hello version to use - final ProtocolVersion helloVersion; - - ProtocolList(String[] names) { - this(convert(names)); - } - - ProtocolList(ArrayList<ProtocolVersion> versions) { - this.protocols = versions; - - if ((protocols.size() == 1) && - protocols.contains(ProtocolVersion.SSL20Hello)) { - throw new IllegalArgumentException("SSLv2Hello cannot be " + - "enabled unless at least one other supported version " + - "is also enabled."); - } - - if (protocols.size() != 0) { - Collections.sort(protocols); - min = protocols.get(0); - max = protocols.get(protocols.size() - 1); - helloVersion = protocols.get(0); - } else { - min = ProtocolVersion.NONE; - max = ProtocolVersion.NONE; - helloVersion = ProtocolVersion.NONE; - } - } - - private static ArrayList<ProtocolVersion> convert(String[] names) { - if (names == null) { - throw new IllegalArgumentException("Protocols may not be null"); - } - - ArrayList<ProtocolVersion> versions = new ArrayList<>(names.length); - for (int i = 0; i < names.length; i++ ) { - ProtocolVersion version = ProtocolVersion.valueOf(names[i]); - if (versions.contains(version) == false) { - versions.add(version); - } - } - - return versions; - } - - /** - * Return whether this list contains the specified protocol version. - * SSLv2Hello is not a real protocol version we support, we always - * return false for it. - */ - boolean contains(ProtocolVersion protocolVersion) { - if (protocolVersion == ProtocolVersion.SSL20Hello) { - return false; - } - return protocols.contains(protocolVersion); - } - - /** - * Return a reference to the internal Collection of CipherSuites. - * The Collection MUST NOT be modified. - */ - Collection<ProtocolVersion> collection() { - return protocols; - } - - /** - * Select a protocol version from the list. - * - * Return the lower of the protocol version of that suggested by - * the <code>protocolVersion</code> and the highest version of this - * protocol list, or null if no protocol version is available. - * - * The method is used by TLS server to negotiated the protocol - * version between client suggested protocol version in the - * client hello and protocol versions supported by the server. - */ - ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) { - ProtocolVersion selectedVersion = null; - for (ProtocolVersion pv : protocols) { - if (pv.v > protocolVersion.v) { - break; // Safe to break here as this.protocols is sorted - } - selectedVersion = pv; - } - - return selectedVersion; - } - - /** - * Return an array with the names of the ProtocolVersions in this list. - */ - synchronized String[] toStringArray() { - if (protocolNames == null) { - protocolNames = new String[protocols.size()]; - int i = 0; - for (ProtocolVersion version : protocols) { - protocolNames[i++] = version.name; - } - } - return protocolNames.clone(); - } - - @Override - public String toString() { - return protocols.toString(); - } -}
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.*; -import java.security.CryptoPrimitive; - -/** - * Type safe enum for an SSL/TLS protocol version. Instances are obtained - * using the static factory methods or by referencing the static members - * in this class. Member variables are final and can be accessed without - * accessor methods. - * - * There is only ever one instance per supported protocol version, this - * means == can be used for comparision instead of equals() if desired. - * - * Checks for a particular version number should generally take this form: - * - * if (protocolVersion.v >= ProtocolVersion.TLS10) { - * // TLS 1.0 code goes here - * } else { - * // SSL 3.0 code here - * } - * - * @author Andreas Sterbenz - * @since 1.4.1 - */ -public final class ProtocolVersion implements Comparable<ProtocolVersion> { - - // The limit of maximum protocol version - final static int LIMIT_MAX_VALUE = 0xFFFF; - - // The limit of minimum protocol version - final static int LIMIT_MIN_VALUE = 0x0000; - - // Dummy protocol version value for invalid SSLSession - final static ProtocolVersion NONE = new ProtocolVersion(-1, "NONE"); - - // If enabled, send/ accept SSLv2 hello messages - final static ProtocolVersion SSL20Hello = new ProtocolVersion(0x0002, - "SSLv2Hello"); - - // SSL 3.0 - final static ProtocolVersion SSL30 = new ProtocolVersion(0x0300, "SSLv3"); - - // TLS 1.0 - final static ProtocolVersion TLS10 = new ProtocolVersion(0x0301, "TLSv1"); - - // TLS 1.1 - final static ProtocolVersion TLS11 = new ProtocolVersion(0x0302, "TLSv1.1"); - - // TLS 1.2 - final static ProtocolVersion TLS12 = new ProtocolVersion(0x0303, "TLSv1.2"); - - private static final boolean FIPS = SunJSSE.isFIPS(); - - // minimum version we implement (SSL 3.0) - final static ProtocolVersion MIN = FIPS ? TLS10 : SSL30; - - // maximum version we implement (TLS 1.2) - final static ProtocolVersion MAX = TLS12; - - // ProtocolVersion to use by default (TLS 1.2) - final static ProtocolVersion DEFAULT = TLS12; - - // Default version for hello messages (SSLv2Hello) - final static ProtocolVersion DEFAULT_HELLO = FIPS ? TLS10 : SSL30; - - // Available protocols - // - // Including all supported protocols except the disabled ones. - final static Set<ProtocolVersion> availableProtocols; - - // version in 16 bit MSB format as it appears in records and - // messages, i.e. 0x0301 for TLS 1.0 - public final int v; - - // major and minor version - public final byte major, minor; - - // name used in JSSE (e.g. TLSv1 for TLS 1.0) - final String name; - - // Initialize the available protocols. - static { - Set<ProtocolVersion> protocols = new HashSet<>(5); - - ProtocolVersion[] pvs = new ProtocolVersion[] { - SSL20Hello, SSL30, TLS10, TLS11, TLS12}; - for (ProtocolVersion p : pvs) { - if (SSLAlgorithmConstraints.DEFAULT_SSL_ONLY.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - p.name, null)) { - protocols.add(p); - } - } - - availableProtocols = - Collections.<ProtocolVersion>unmodifiableSet(protocols); - } - - // private - private ProtocolVersion(int v, String name) { - this.v = v; - this.name = name; - major = (byte)(v >>> 8); - minor = (byte)(v & 0xFF); - } - - // private - private static ProtocolVersion valueOf(int v) { - if (v == SSL30.v) { - return SSL30; - } else if (v == TLS10.v) { - return TLS10; - } else if (v == TLS11.v) { - return TLS11; - } else if (v == TLS12.v) { - return TLS12; - } else if (v == SSL20Hello.v) { - return SSL20Hello; - } else { - int major = (v >>> 8) & 0xFF; - int minor = v & 0xFF; - return new ProtocolVersion(v, "Unknown-" + major + "." + minor); - } - } - - /** - * Return a ProtocolVersion with the specified major and minor version - * numbers. Never throws exceptions. - */ - public static ProtocolVersion valueOf(int major, int minor) { - return valueOf(((major & 0xFF) << 8) | (minor & 0xFF)); - } - - /** - * Return a ProtocolVersion for the given name. - * - * @exception IllegalArgumentException if name is null or does not - * identify a supported protocol - */ - static ProtocolVersion valueOf(String name) { - if (name == null) { - throw new IllegalArgumentException("Protocol cannot be null"); - } - - if (FIPS && (name.equals(SSL30.name) || name.equals(SSL20Hello.name))) { - throw new IllegalArgumentException - ("Only TLS 1.0 or later allowed in FIPS mode"); - } - - if (name.equals(SSL30.name)) { - return SSL30; - } else if (name.equals(TLS10.name)) { - return TLS10; - } else if (name.equals(TLS11.name)) { - return TLS11; - } else if (name.equals(TLS12.name)) { - return TLS12; - } else if (name.equals(SSL20Hello.name)) { - return SSL20Hello; - } else { - throw new IllegalArgumentException(name); - } - } - - @Override - public String toString() { - return name; - } - - /** - * Compares this object with the specified object for order. - */ - @Override - public int compareTo(ProtocolVersion protocolVersion) { - return this.v - protocolVersion.v; - } -}
--- a/src/share/classes/sun/security/ssl/RSAClientKeyExchange.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.security.*; - -import javax.crypto.*; - -import javax.net.ssl.*; - -import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; -import sun.security.util.KeyUtil; - -/** - * This is the client key exchange message (CLIENT --> SERVER) used with - * all RSA key exchanges; it holds the RSA-encrypted pre-master secret. - * - * The message is encrypted using PKCS #1 block type 02 encryption with the - * server's public key. The padding and resulting message size is a function - * of this server's public key modulus size, but the pre-master secret is - * always exactly 48 bytes. - * - */ -final class RSAClientKeyExchange extends HandshakeMessage { - - /* - * The following field values were encrypted with the server's public - * key (or temp key from server key exchange msg) and are presented - * here in DECRYPTED form. - */ - private ProtocolVersion protocolVersion; // preMaster [0,1] - SecretKey preMaster; - private byte[] encrypted; // same size as public modulus - - /* - * Client randomly creates a pre-master secret and encrypts it - * using the server's RSA public key; only the server can decrypt - * it, using its RSA private key. Result is the same size as the - * server's public key, and uses PKCS #1 block format 02. - */ - RSAClientKeyExchange(ProtocolVersion protocolVersion, - ProtocolVersion maxVersion, - SecureRandom generator, PublicKey publicKey) throws IOException { - if (publicKey.getAlgorithm().equals("RSA") == false) { - throw new SSLKeyException("Public key not of type RSA: " + - publicKey.getAlgorithm()); - } - this.protocolVersion = protocolVersion; - - try { - String s = ((protocolVersion.v >= ProtocolVersion.TLS12.v) ? - "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); - KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec( - maxVersion.v, protocolVersion.v), generator); - preMaster = kg.generateKey(); - - Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); - cipher.init(Cipher.WRAP_MODE, publicKey, generator); - encrypted = cipher.wrap(preMaster); - } catch (GeneralSecurityException e) { - throw (SSLKeyException)new SSLKeyException - ("RSA premaster secret error").initCause(e); - } - } - - /* - * Retrieving the cipher's provider name for the debug purposes - * can throw an exception by itself. - */ - private static String safeProviderName(Cipher cipher) { - try { - return cipher.getProvider().toString(); - } catch (Exception e) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Retrieving The Cipher provider name" + - " caused exception " + e.getMessage()); - } - } - try { - return cipher.toString() + " (provider name not available)"; - } catch (Exception e) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Retrieving The Cipher name" + - " caused exception " + e.getMessage()); - } - } - return "(cipher/provider names not available)"; - } - - /* - * Server gets the PKCS #1 (block format 02) data, decrypts - * it with its private key. - */ - RSAClientKeyExchange(ProtocolVersion currentVersion, - ProtocolVersion maxVersion, - SecureRandom generator, HandshakeInStream input, - int messageSize, PrivateKey privateKey) throws IOException { - - if (privateKey.getAlgorithm().equals("RSA") == false) { - throw new SSLKeyException("Private key not of type RSA: " + - privateKey.getAlgorithm()); - } - - if (currentVersion.v >= ProtocolVersion.TLS10.v) { - encrypted = input.getBytes16(); - } else { - encrypted = new byte [messageSize]; - if (input.read(encrypted) != messageSize) { - throw new SSLProtocolException( - "SSL: read PreMasterSecret: short read"); - } - } - - byte[] encoded = null; - try { - boolean needFailover = false; - Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); - try { - // Try UNWRAP_MODE mode firstly. - cipher.init(Cipher.UNWRAP_MODE, privateKey, - new TlsRsaPremasterSecretParameterSpec( - maxVersion.v, currentVersion.v), - generator); - - // The provider selection can be delayed, please don't call - // any Cipher method before the call to Cipher.init(). - needFailover = !KeyUtil.isOracleJCEProvider( - cipher.getProvider().getName()); - } catch (InvalidKeyException | UnsupportedOperationException iue) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("The Cipher provider " - + safeProviderName(cipher) - + " caused exception: " + iue.getMessage()); - } - - needFailover = true; - } - - if (needFailover) { - // The cipher might be spoiled by unsuccessful call to init(), - // so request a fresh instance - cipher = JsseJce.getCipher(JsseJce.CIPHER_RSA_PKCS1); - - // Use DECRYPT_MODE and dispose the previous initialization. - cipher.init(Cipher.DECRYPT_MODE, privateKey); - boolean failed = false; - try { - encoded = cipher.doFinal(encrypted); - } catch (BadPaddingException bpe) { - // Note: encoded == null - failed = true; - } - encoded = KeyUtil.checkTlsPreMasterSecretKey( - maxVersion.v, currentVersion.v, - generator, encoded, failed); - preMaster = generatePreMasterSecret( - maxVersion.v, currentVersion.v, - encoded, generator); - } else { - // the cipher should have been initialized - preMaster = (SecretKey)cipher.unwrap(encrypted, - "TlsRsaPremasterSecret", Cipher.SECRET_KEY); - } - } catch (InvalidKeyException ibk) { - // the message is too big to process with RSA - throw new SSLException( - "Unable to process PreMasterSecret", ibk); - } catch (Exception e) { - // unlikely to happen, otherwise, must be a provider exception - if (debug != null && Debug.isOn("handshake")) { - System.out.println("RSA premaster secret decryption error:"); - e.printStackTrace(System.out); - } - throw new RuntimeException("Could not generate dummy secret", e); - } - } - - // generate a premaster secret with the specified version number - @SuppressWarnings("deprecation") - private static SecretKey generatePreMasterSecret( - int clientVersion, int serverVersion, - byte[] encodedSecret, SecureRandom generator) { - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Generating a premaster secret"); - } - - try { - String s = ((clientVersion >= ProtocolVersion.TLS12.v) ? - "SunTls12RsaPremasterSecret" : "SunTlsRsaPremasterSecret"); - KeyGenerator kg = JsseJce.getKeyGenerator(s); - kg.init(new TlsRsaPremasterSecretParameterSpec( - clientVersion, serverVersion, encodedSecret), - generator); - return kg.generateKey(); - } catch (InvalidAlgorithmParameterException | - NoSuchAlgorithmException iae) { - // unlikely to happen, otherwise, must be a provider exception - if (debug != null && Debug.isOn("handshake")) { - System.out.println("RSA premaster secret generation error:"); - iae.printStackTrace(System.out); - } - throw new RuntimeException("Could not generate premaster secret", iae); - } - } - - @Override - int messageType() { - return ht_client_key_exchange; - } - - @Override - int messageLength() { - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - return encrypted.length + 2; - } else { - return encrypted.length; - } - } - - @Override - void send(HandshakeOutStream s) throws IOException { - if (protocolVersion.v >= ProtocolVersion.TLS10.v) { - s.putBytes16(encrypted); - } else { - s.write(encrypted); - } - } - - @Override - void print(PrintStream s) throws IOException { - String version = "version not available/extractable"; - - byte[] ba = preMaster.getEncoded(); - if (ba != null && ba.length >= 2) { - version = ProtocolVersion.valueOf(ba[0], ba[1]).name; - } - - s.println("*** ClientKeyExchange, RSA PreMasterSecret, " + version); - } -}
--- a/src/share/classes/sun/security/ssl/RSASignature.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,220 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.*; -import java.security.spec.AlgorithmParameterSpec; - -/** - * Signature implementation for the SSL/TLS RSA Signature variant with both - * MD5 and SHA-1 MessageDigests. Used for explicit RSA server authentication - * (RSA signed server key exchange for RSA_EXPORT and DHE_RSA) and RSA client - * authentication (RSA signed certificate verify message). - * - * It conforms to the standard JCA Signature API. It is registered in the - * SunJSSE provider to avoid more complicated getInstance() code and - * negative interaction with the JCA mechanisms for hardware providers. - * - * The class should be instantiated via the getInstance() method in this class, - * which returns the implementation from the preferred provider. The internal - * implementation allows the hashes to be explicitly set, which is required - * for RSA client authentication. It can be obtained via the - * getInternalInstance() method. - * - * This class is not thread safe. - * - */ -public final class RSASignature extends SignatureSpi { - - private final Signature rawRsa; - private MessageDigest md5, sha; - - // flag indicating if the MessageDigests are in reset state - private boolean isReset; - - public RSASignature() throws NoSuchAlgorithmException { - super(); - rawRsa = JsseJce.getSignature(JsseJce.SIGNATURE_RAWRSA); - isReset = true; - } - - /** - * Get an implementation for the RSA signature. Follows the standard - * JCA getInstance() model, so it return the implementation from the - * provider with the highest precedence, which may be this class. - */ - static Signature getInstance() throws NoSuchAlgorithmException { - return JsseJce.getSignature(JsseJce.SIGNATURE_SSLRSA); - } - - /** - * Get an internal implementation for the RSA signature. Used for RSA - * client authentication, which needs the ability to set the digests - * to externally provided values via the setHashes() method. - */ - static Signature getInternalInstance() - throws NoSuchAlgorithmException, NoSuchProviderException { - return Signature.getInstance(JsseJce.SIGNATURE_SSLRSA, "SunJSSE"); - } - - /** - * Set the MD5 and SHA hashes to the provided objects. - */ - static void setHashes(Signature sig, MessageDigest md5, MessageDigest sha) { - sig.setParameter("hashes", new MessageDigest[] {md5, sha}); - } - - /** - * Reset the MessageDigests unless they are already reset. - */ - private void reset() { - if (isReset == false) { - md5.reset(); - sha.reset(); - isReset = true; - } - } - - private static void checkNull(Key key) throws InvalidKeyException { - if (key == null) { - throw new InvalidKeyException("Key must not be null"); - } - } - - @Override - protected void engineInitVerify(PublicKey publicKey) - throws InvalidKeyException { - checkNull(publicKey); - reset(); - rawRsa.initVerify(publicKey); - } - - @Override - protected void engineInitSign(PrivateKey privateKey) - throws InvalidKeyException { - engineInitSign(privateKey, null); - } - - @Override - protected void engineInitSign(PrivateKey privateKey, SecureRandom random) - throws InvalidKeyException { - checkNull(privateKey); - reset(); - rawRsa.initSign(privateKey, random); - } - - // lazily initialize the MessageDigests - private void initDigests() { - if (md5 == null) { - md5 = JsseJce.getMD5(); - sha = JsseJce.getSHA(); - } - } - - @Override - protected void engineUpdate(byte b) { - initDigests(); - isReset = false; - md5.update(b); - sha.update(b); - } - - @Override - protected void engineUpdate(byte[] b, int off, int len) { - initDigests(); - isReset = false; - md5.update(b, off, len); - sha.update(b, off, len); - } - - private byte[] getDigest() throws SignatureException { - try { - initDigests(); - byte[] data = new byte[36]; - md5.digest(data, 0, 16); - sha.digest(data, 16, 20); - isReset = true; - return data; - } catch (DigestException e) { - // should never occur - throw new SignatureException(e); - } - } - - @Override - protected byte[] engineSign() throws SignatureException { - rawRsa.update(getDigest()); - return rawRsa.sign(); - } - - @Override - protected boolean engineVerify(byte[] sigBytes) throws SignatureException { - return engineVerify(sigBytes, 0, sigBytes.length); - } - - @Override - protected boolean engineVerify(byte[] sigBytes, int offset, int length) - throws SignatureException { - rawRsa.update(getDigest()); - return rawRsa.verify(sigBytes, offset, length); - } - - @Override - protected void engineSetParameter(String param, Object value) - throws InvalidParameterException { - if (param.equals("hashes") == false) { - throw new InvalidParameterException - ("Parameter not supported: " + param); - } - if (value instanceof MessageDigest[] == false) { - throw new InvalidParameterException - ("value must be MessageDigest[]"); - } - MessageDigest[] digests = (MessageDigest[])value; - md5 = digests[0]; - sha = digests[1]; - } - - @Override - protected void engineSetParameter(AlgorithmParameterSpec params) - throws InvalidAlgorithmParameterException { - if (params != null) { - throw new InvalidAlgorithmParameterException("No parameters accepted"); - } - } - - @Override - protected Object engineGetParameter(String param) - throws InvalidParameterException { - throw new InvalidParameterException("Parameters not supported"); - } - - @Override - protected AlgorithmParameters engineGetParameters() { - return null; - } -}
--- a/src/share/classes/sun/security/ssl/RandomCookie.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - * Copyright (c) 1996, 2007, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.security.SecureRandom; - -/* - * RandomCookie ... SSL hands standard format random cookies (nonces) - * around. These know how to encode/decode themselves on SSL streams, - * and can be created and printed. - * - * @author David Brownell - */ -final class RandomCookie { - - byte random_bytes[]; // exactly 32 bytes - - RandomCookie(SecureRandom generator) { - long temp = System.currentTimeMillis() / 1000; - int gmt_unix_time; - if (temp < Integer.MAX_VALUE) { - gmt_unix_time = (int) temp; - } else { - gmt_unix_time = Integer.MAX_VALUE; // Whoops! - } - - random_bytes = new byte[32]; - generator.nextBytes(random_bytes); - - random_bytes[0] = (byte)(gmt_unix_time >> 24); - random_bytes[1] = (byte)(gmt_unix_time >> 16); - random_bytes[2] = (byte)(gmt_unix_time >> 8); - random_bytes[3] = (byte)gmt_unix_time; - } - - RandomCookie(HandshakeInStream m) throws IOException { - random_bytes = new byte[32]; - m.read(random_bytes, 0, 32); - } - - void send(HandshakeOutStream out) throws IOException { - out.write(random_bytes, 0, 32); - } - - void print(PrintStream s) { - int i, gmt_unix_time; - - gmt_unix_time = random_bytes[0] << 24; - gmt_unix_time += random_bytes[1] << 16; - gmt_unix_time += random_bytes[2] << 8; - gmt_unix_time += random_bytes[3]; - - s.print("GMT: " + gmt_unix_time + " "); - s.print("bytes = { "); - - for (i = 4; i < 32; i++) { - if (i != 4) { - s.print(", "); - } - s.print(random_bytes[i] & 0x0ff); - } - s.println(" }"); - } -}
--- a/src/share/classes/sun/security/ssl/Record.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,126 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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; - - -/** - * SSL/TLS records, as pulled off (and put onto) a TCP stream. This is - * the base interface, which defines common information and interfaces - * used by both Input and Output records. - * - * @author David Brownell - */ -interface Record { - /* - * There are four SSL record types, which are part of the interface - * to this level (along with the maximum record size) - * - * enum { change_cipher_spec(20), alert(21), handshake(22), - * application_data(23), (255) } ContentType; - */ - static final byte ct_change_cipher_spec = 20; - static final byte ct_alert = 21; - static final byte ct_handshake = 22; - static final byte ct_application_data = 23; - - static final int headerSize = 5; // SSLv3 record header - static final int maxExpansion = 1024; // for bad compression - static final int trailerSize = 20; // SHA1 hash size - static final int maxDataSize = 16384; // 2^14 bytes of data - static final int maxPadding = 256; // block cipher padding - static final int maxIVLength = 256; // IV length - - /* - * The size of the header plus the max IV length - */ - static final int headerPlusMaxIVSize = - headerSize // header - + maxIVLength; // iv - - /* - * SSL has a maximum record size. It's header, (compressed) data, - * padding, and a trailer for the message authentication information (MAC - * for block and stream ciphers, and message authentication tag for AEAD - * ciphers). - * - * Some compression algorithms have rare cases where they expand the data. - * As we don't support compression at this time, leave that out. - */ - static final int maxRecordSize = - headerPlusMaxIVSize // header + iv - + maxDataSize // data - + maxPadding // padding - + trailerSize; // MAC or AEAD tag - - static final boolean enableCBCProtection = - Debug.getBooleanProperty("jsse.enableCBCProtection", true); - - /* - * For CBC protection in SSL3/TLS1, we break some plaintext into two - * packets. Max application data size for the second packet. - */ - static final int maxDataSizeMinusOneByteRecord = - maxDataSize // max data size - - ( // max one byte record size - headerPlusMaxIVSize // header + iv - + 1 // one byte data - + maxPadding // padding - + trailerSize // MAC - ); - - /* - * The maximum large record size. - * - * Some SSL/TLS implementations support large fragment upto 2^15 bytes, - * such as Microsoft. We support large incoming fragments. - * - * The maximum large record size is defined as maxRecordSize plus 2^14, - * this is the amount OpenSSL is using. - */ - static final int maxLargeRecordSize = - maxRecordSize // Max size with a conforming implementation - + maxDataSize; // extra 2^14 bytes for large data packets. - - - /* - * Maximum record size for alert and change cipher spec records. - * They only contain 2 and 1 bytes of data, respectively. - * Allocate a smaller array. - */ - static final int maxAlertRecordSize = - headerPlusMaxIVSize // header + iv - + 2 // alert - + maxPadding // padding - + trailerSize; // MAC - - /* - * The overflow values of integers of 8, 16 and 24 bits. - */ - static final int OVERFLOW_OF_INT08 = (1 << 8); - static final int OVERFLOW_OF_INT16 = (1 << 16); - static final int OVERFLOW_OF_INT24 = (1 << 24); -}
--- a/src/share/classes/sun/security/ssl/RenegotiationInfoExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.net.ssl.SSLProtocolException; - -/* - * For secure renegotiation, RFC5746 defines a new TLS extension, - * "renegotiation_info" (with extension type 0xff01), which contains a - * cryptographic binding to the enclosing TLS connection (if any) for - * which the renegotiation is being performed. The "extension data" - * field of this extension contains a "RenegotiationInfo" structure: - * - * struct { - * opaque renegotiated_connection<0..255>; - * } RenegotiationInfo; - */ -final class RenegotiationInfoExtension extends HelloExtension { - private final byte[] renegotiated_connection; - - RenegotiationInfoExtension(byte[] clientVerifyData, - byte[] serverVerifyData) { - super(ExtensionType.EXT_RENEGOTIATION_INFO); - - if (clientVerifyData.length != 0) { - renegotiated_connection = - new byte[clientVerifyData.length + serverVerifyData.length]; - System.arraycopy(clientVerifyData, 0, renegotiated_connection, - 0, clientVerifyData.length); - - if (serverVerifyData.length != 0) { - System.arraycopy(serverVerifyData, 0, renegotiated_connection, - clientVerifyData.length, serverVerifyData.length); - } - } else { - // ignore both the client and server verify data. - renegotiated_connection = new byte[0]; - } - } - - RenegotiationInfoExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_RENEGOTIATION_INFO); - - // check the extension length - if (len < 1) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - int renegoInfoDataLen = s.getInt8(); - if (renegoInfoDataLen + 1 != len) { // + 1 = the byte we just read - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - renegotiated_connection = new byte[renegoInfoDataLen]; - if (renegoInfoDataLen != 0) { - s.read(renegotiated_connection, 0, renegoInfoDataLen); - } - } - - - // Length of the encoded extension, including the type and length fields - @Override - int length() { - return 5 + renegotiated_connection.length; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(renegotiated_connection.length + 1); - s.putBytes8(renegotiated_connection); - } - - boolean isEmpty() { - return renegotiated_connection.length == 0; - } - - byte[] getRenegotiatedConnection() { - return renegotiated_connection; - } - - @Override - public String toString() { - return "Extension " + type + ", renegotiated_connection: " + - (renegotiated_connection.length == 0 ? "<empty>" : - Debug.toString(renegotiated_connection)); - } - -}
--- a/src/share/classes/sun/security/ssl/SSLAlgorithmConstraints.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,275 +0,0 @@ -/* - * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.AlgorithmConstraints; -import java.security.CryptoPrimitive; -import java.security.AlgorithmParameters; - -import javax.net.ssl.*; - -import java.security.Key; - -import java.util.Set; - -import sun.security.util.DisabledAlgorithmConstraints; -import static sun.security.util.DisabledAlgorithmConstraints.*; -import sun.security.ssl.CipherSuite.*; - -/** - * Algorithm constraints for disabled algorithms property - * - * See the "jdk.certpath.disabledAlgorithms" specification in java.security - * for the syntax of the disabled algorithm string. - */ -final class SSLAlgorithmConstraints implements AlgorithmConstraints { - - private final static AlgorithmConstraints tlsDisabledAlgConstraints = - new DisabledAlgorithmConstraints(PROPERTY_TLS_DISABLED_ALGS, - new SSLAlgorithmDecomposer()); - - private final static AlgorithmConstraints x509DisabledAlgConstraints = - new DisabledAlgorithmConstraints(PROPERTY_CERTPATH_DISABLED_ALGS, - new SSLAlgorithmDecomposer(true)); - - private AlgorithmConstraints userAlgConstraints = null; - private AlgorithmConstraints peerAlgConstraints = null; - - private boolean enabledX509DisabledAlgConstraints = true; - - // the default algorithm constraints - final static AlgorithmConstraints DEFAULT = - new SSLAlgorithmConstraints(null); - - // the default SSL only algorithm constraints - final static AlgorithmConstraints DEFAULT_SSL_ONLY = - new SSLAlgorithmConstraints((SSLSocket)null, false); - - SSLAlgorithmConstraints(AlgorithmConstraints algorithmConstraints) { - userAlgConstraints = algorithmConstraints; - } - - SSLAlgorithmConstraints(SSLSocket socket, - boolean withDefaultCertPathConstraints) { - if (socket != null) { - userAlgConstraints = - socket.getSSLParameters().getAlgorithmConstraints(); - } - - if (!withDefaultCertPathConstraints) { - enabledX509DisabledAlgConstraints = false; - } - } - - SSLAlgorithmConstraints(SSLEngine engine, - boolean withDefaultCertPathConstraints) { - if (engine != null) { - userAlgConstraints = - engine.getSSLParameters().getAlgorithmConstraints(); - } - - if (!withDefaultCertPathConstraints) { - enabledX509DisabledAlgConstraints = false; - } - } - - SSLAlgorithmConstraints(SSLSocket socket, String[] supportedAlgorithms, - boolean withDefaultCertPathConstraints) { - if (socket != null) { - userAlgConstraints = - socket.getSSLParameters().getAlgorithmConstraints(); - peerAlgConstraints = - new SupportedSignatureAlgorithmConstraints(supportedAlgorithms); - } - - if (!withDefaultCertPathConstraints) { - enabledX509DisabledAlgConstraints = false; - } - } - - SSLAlgorithmConstraints(SSLEngine engine, String[] supportedAlgorithms, - boolean withDefaultCertPathConstraints) { - if (engine != null) { - userAlgConstraints = - engine.getSSLParameters().getAlgorithmConstraints(); - peerAlgConstraints = - new SupportedSignatureAlgorithmConstraints(supportedAlgorithms); - } - - if (!withDefaultCertPathConstraints) { - enabledX509DisabledAlgConstraints = false; - } - } - - @Override - public boolean permits(Set<CryptoPrimitive> primitives, - String algorithm, AlgorithmParameters parameters) { - - boolean permitted = true; - - if (peerAlgConstraints != null) { - permitted = peerAlgConstraints.permits( - primitives, algorithm, parameters); - } - - if (permitted && userAlgConstraints != null) { - permitted = userAlgConstraints.permits( - primitives, algorithm, parameters); - } - - if (permitted) { - permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, parameters); - } - - if (permitted && enabledX509DisabledAlgConstraints) { - permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, parameters); - } - - return permitted; - } - - @Override - public boolean permits(Set<CryptoPrimitive> primitives, Key key) { - - boolean permitted = true; - - if (peerAlgConstraints != null) { - permitted = peerAlgConstraints.permits(primitives, key); - } - - if (permitted && userAlgConstraints != null) { - permitted = userAlgConstraints.permits(primitives, key); - } - - if (permitted) { - permitted = tlsDisabledAlgConstraints.permits(primitives, key); - } - - if (permitted && enabledX509DisabledAlgConstraints) { - permitted = x509DisabledAlgConstraints.permits(primitives, key); - } - - return permitted; - } - - @Override - public boolean permits(Set<CryptoPrimitive> primitives, - String algorithm, Key key, AlgorithmParameters parameters) { - - boolean permitted = true; - - if (peerAlgConstraints != null) { - permitted = peerAlgConstraints.permits( - primitives, algorithm, key, parameters); - } - - if (permitted && userAlgConstraints != null) { - permitted = userAlgConstraints.permits( - primitives, algorithm, key, parameters); - } - - if (permitted) { - permitted = tlsDisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); - } - - if (permitted && enabledX509DisabledAlgConstraints) { - permitted = x509DisabledAlgConstraints.permits( - primitives, algorithm, key, parameters); - } - - return permitted; - } - - - static private class SupportedSignatureAlgorithmConstraints - implements AlgorithmConstraints { - // supported signature algorithms - private String[] supportedAlgorithms; - - SupportedSignatureAlgorithmConstraints(String[] supportedAlgorithms) { - if (supportedAlgorithms != null) { - this.supportedAlgorithms = supportedAlgorithms.clone(); - } else { - this.supportedAlgorithms = null; - } - } - - @Override - public boolean permits(Set<CryptoPrimitive> primitives, - String algorithm, AlgorithmParameters parameters) { - - if (algorithm == null || algorithm.length() == 0) { - throw new IllegalArgumentException( - "No algorithm name specified"); - } - - if (primitives == null || primitives.isEmpty()) { - throw new IllegalArgumentException( - "No cryptographic primitive specified"); - } - - if (supportedAlgorithms == null || - supportedAlgorithms.length == 0) { - return false; - } - - // trim the MGF part: <digest>with<encryption>and<mgf> - int position = algorithm.indexOf("and"); - if (position > 0) { - algorithm = algorithm.substring(0, position); - } - - for (String supportedAlgorithm : supportedAlgorithms) { - if (algorithm.equalsIgnoreCase(supportedAlgorithm)) { - return true; - } - } - - return false; - } - - @Override - final public boolean permits(Set<CryptoPrimitive> primitives, Key key) { - return true; - } - - @Override - final public boolean permits(Set<CryptoPrimitive> primitives, - String algorithm, Key key, AlgorithmParameters parameters) { - - if (algorithm == null || algorithm.length() == 0) { - throw new IllegalArgumentException( - "No algorithm name specified"); - } - - return permits(primitives, algorithm, parameters); - } - } - -}
--- a/src/share/classes/sun/security/ssl/SSLAlgorithmDecomposer.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.HashSet; -import java.util.Set; -import sun.security.util.AlgorithmDecomposer; -import static sun.security.ssl.CipherSuite.*; -import static sun.security.ssl.CipherSuite.KeyExchange.*; - -/** - * The class decomposes standard SSL/TLS cipher suites into sub-elements. - */ -class SSLAlgorithmDecomposer extends AlgorithmDecomposer { - - // indicates that only certification path algorithms need to be used - private final boolean onlyX509; - - SSLAlgorithmDecomposer(boolean onlyX509) { - this.onlyX509 = onlyX509; - } - - SSLAlgorithmDecomposer() { - this(false); - } - - private Set<String> decomposes(CipherSuite.KeyExchange keyExchange) { - Set<String> components = new HashSet<>(); - switch (keyExchange) { - case K_NULL: - if (!onlyX509) { - components.add("K_NULL"); - } - break; - case K_RSA: - components.add("RSA"); - break; - case K_RSA_EXPORT: - components.add("RSA"); - components.add("RSA_EXPORT"); - break; - case K_DH_RSA: - components.add("RSA"); - components.add("DH"); - components.add("DiffieHellman"); - components.add("DH_RSA"); - break; - case K_DH_DSS: - components.add("DSA"); - components.add("DSS"); - components.add("DH"); - components.add("DiffieHellman"); - components.add("DH_DSS"); - break; - case K_DHE_DSS: - components.add("DSA"); - components.add("DSS"); - components.add("DH"); - components.add("DHE"); - components.add("DiffieHellman"); - components.add("DHE_DSS"); - break; - case K_DHE_RSA: - components.add("RSA"); - components.add("DH"); - components.add("DHE"); - components.add("DiffieHellman"); - components.add("DHE_RSA"); - break; - case K_DH_ANON: - if (!onlyX509) { - components.add("ANON"); - components.add("DH"); - components.add("DiffieHellman"); - components.add("DH_ANON"); - } - break; - case K_ECDH_ECDSA: - components.add("ECDH"); - components.add("ECDSA"); - components.add("ECDH_ECDSA"); - break; - case K_ECDH_RSA: - components.add("ECDH"); - components.add("RSA"); - components.add("ECDH_RSA"); - break; - case K_ECDHE_ECDSA: - components.add("ECDHE"); - components.add("ECDSA"); - components.add("ECDHE_ECDSA"); - break; - case K_ECDHE_RSA: - components.add("ECDHE"); - components.add("RSA"); - components.add("ECDHE_RSA"); - break; - case K_ECDH_ANON: - if (!onlyX509) { - components.add("ECDH"); - components.add("ANON"); - components.add("ECDH_ANON"); - } - break; - case K_KRB5: - if (!onlyX509) { - components.add("KRB5"); - } - break; - case K_KRB5_EXPORT: - if (!onlyX509) { - components.add("KRB5_EXPORT"); - } - break; - default: - // ignore - } - - return components; - } - - private Set<String> decomposes(CipherSuite.BulkCipher bulkCipher) { - Set<String> components = new HashSet<>(); - - if (bulkCipher.transformation != null) { - components.addAll(super.decompose(bulkCipher.transformation)); - } - - if (bulkCipher == B_NULL) { - components.add("C_NULL"); - } else if (bulkCipher == B_RC2_40) { - components.add("RC2_CBC_40"); - } else if (bulkCipher == B_RC4_40) { - components.add("RC4_40"); - } else if (bulkCipher == B_RC4_128) { - components.add("RC4_128"); - } else if (bulkCipher == B_DES_40) { - components.add("DES40_CBC"); - components.add("DES_CBC_40"); - } else if (bulkCipher == B_DES) { - components.add("DES_CBC"); - } else if (bulkCipher == B_3DES) { - components.add("3DES_EDE_CBC"); - } else if (bulkCipher == B_AES_128) { - components.add("AES_128_CBC"); - } else if (bulkCipher == B_AES_256) { - components.add("AES_256_CBC"); - } else if (bulkCipher == B_AES_128_GCM) { - components.add("AES_128_GCM"); - } else if (bulkCipher == B_AES_256_GCM) { - components.add("AES_256_GCM"); - } - - return components; - } - - private Set<String> decomposes(CipherSuite.MacAlg macAlg, - BulkCipher cipher) { - Set<String> components = new HashSet<>(); - - if (macAlg == M_NULL - && cipher.cipherType != CipherType.AEAD_CIPHER) { - components.add("M_NULL"); - } else if (macAlg == M_MD5) { - components.add("MD5"); - components.add("HmacMD5"); - } else if (macAlg == M_SHA) { - components.add("SHA1"); - components.add("SHA-1"); - components.add("HmacSHA1"); - } else if (macAlg == M_SHA256) { - components.add("SHA256"); - components.add("SHA-256"); - components.add("HmacSHA256"); - } else if (macAlg == M_SHA384) { - components.add("SHA384"); - components.add("SHA-384"); - components.add("HmacSHA384"); - } - - return components; - } - - private Set<String> decompose(KeyExchange keyExchange, BulkCipher cipher, - MacAlg macAlg) { - Set<String> components = new HashSet<>(); - - if (keyExchange != null) { - components.addAll(decomposes(keyExchange)); - } - - if (onlyX509) { - // Certification path algorithm constraints do not apply - // to cipher and macAlg. - return components; - } - - if (cipher != null) { - components.addAll(decomposes(cipher)); - } - - if (macAlg != null) { - components.addAll(decomposes(macAlg, cipher)); - } - - return components; - } - - @Override - public Set<String> decompose(String algorithm) { - if (algorithm.startsWith("SSL_") || algorithm.startsWith("TLS_")) { - CipherSuite cipherSuite = null; - try { - cipherSuite = CipherSuite.valueOf(algorithm); - } catch (IllegalArgumentException iae) { - // ignore: unknown or unsupported ciphersuite - } - - if (cipherSuite != null && - cipherSuite != CipherSuite.C_SCSV /* TLS_EMPTY_RENEGOTIATION_INFO_SCSV */) { - return decompose(cipherSuite.keyExchange, cipherSuite.cipher, - cipherSuite.macAlg); - } - } - - return super.decompose(algorithm); - } - -}
--- a/src/share/classes/sun/security/ssl/SSLContextImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1466 +0,0 @@ -/* - * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.net.Socket; - -import java.io.*; -import java.util.*; -import java.security.*; -import java.security.cert.*; -import java.security.cert.Certificate; - -import javax.net.ssl.*; - -import sun.security.provider.certpath.AlgorithmChecker; -import sun.security.action.GetPropertyAction; -import sun.security.validator.Validator; - -public abstract class SSLContextImpl extends SSLContextSpi { - - private static final Debug debug = Debug.getInstance("ssl"); - - private final EphemeralKeyManager ephemeralKeyManager; - private final SSLSessionContextImpl clientCache; - private final SSLSessionContextImpl serverCache; - - private boolean isInitialized; - - private X509ExtendedKeyManager keyManager; - private X509TrustManager trustManager; - private SecureRandom secureRandom; - - private final static Collection<CipherSuite> clientCustomizedCipherSuites = - getCustomizedCipherSuites("jdk.tls.client.cipherSuites"); - private final static Collection<CipherSuite> serverCustomizedCipherSuites = - getCustomizedCipherSuites("jdk.tls.server.cipherSuites"); - - SSLContextImpl() { - ephemeralKeyManager = new EphemeralKeyManager(); - clientCache = new SSLSessionContextImpl(); - serverCache = new SSLSessionContextImpl(); - } - - @Override - protected void engineInit(KeyManager[] km, TrustManager[] tm, - SecureRandom sr) throws KeyManagementException { - isInitialized = false; - keyManager = chooseKeyManager(km); - - if (tm == null) { - try { - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - tmf.init((KeyStore)null); - tm = tmf.getTrustManagers(); - } catch (Exception e) { - // eat - } - } - trustManager = chooseTrustManager(tm); - - if (sr == null) { - secureRandom = JsseJce.getSecureRandom(); - } else { - if (SunJSSE.isFIPS() && - (sr.getProvider() != SunJSSE.cryptoProvider)) { - throw new KeyManagementException - ("FIPS mode: SecureRandom must be from provider " - + SunJSSE.cryptoProvider.getName()); - } - secureRandom = sr; - } - - /* - * The initial delay of seeding the random number generator - * could be long enough to cause the initial handshake on our - * first connection to timeout and fail. Make sure it is - * primed and ready by getting some initial output from it. - */ - if (debug != null && Debug.isOn("sslctx")) { - System.out.println("trigger seeding of SecureRandom"); - } - secureRandom.nextInt(); - if (debug != null && Debug.isOn("sslctx")) { - System.out.println("done seeding SecureRandom"); - } - isInitialized = true; - } - - private X509TrustManager chooseTrustManager(TrustManager[] tm) - throws KeyManagementException { - // We only use the first instance of X509TrustManager passed to us. - for (int i = 0; tm != null && i < tm.length; i++) { - if (tm[i] instanceof X509TrustManager) { - if (SunJSSE.isFIPS() && - !(tm[i] instanceof X509TrustManagerImpl)) { - throw new KeyManagementException - ("FIPS mode: only SunJSSE TrustManagers may be used"); - } - - if (tm[i] instanceof X509ExtendedTrustManager) { - return (X509TrustManager)tm[i]; - } else { - return new AbstractTrustManagerWrapper( - (X509TrustManager)tm[i]); - } - } - } - - // nothing found, return a dummy X509TrustManager. - return DummyX509TrustManager.INSTANCE; - } - - private X509ExtendedKeyManager chooseKeyManager(KeyManager[] kms) - throws KeyManagementException { - for (int i = 0; kms != null && i < kms.length; i++) { - KeyManager km = kms[i]; - if (!(km instanceof X509KeyManager)) { - continue; - } - if (SunJSSE.isFIPS()) { - // In FIPS mode, require that one of SunJSSE's own keymanagers - // is used. Otherwise, we cannot be sure that only keys from - // the FIPS token are used. - if ((km instanceof X509KeyManagerImpl) - || (km instanceof SunX509KeyManagerImpl)) { - return (X509ExtendedKeyManager)km; - } else { - // throw exception, we don't want to silently use the - // dummy keymanager without telling the user. - throw new KeyManagementException - ("FIPS mode: only SunJSSE KeyManagers may be used"); - } - } - if (km instanceof X509ExtendedKeyManager) { - return (X509ExtendedKeyManager)km; - } - if (debug != null && Debug.isOn("sslctx")) { - System.out.println( - "X509KeyManager passed to " + - "SSLContext.init(): need an " + - "X509ExtendedKeyManager for SSLEngine use"); - } - return new AbstractKeyManagerWrapper((X509KeyManager)km); - } - - // nothing found, return a dummy X509ExtendedKeyManager - return DummyX509KeyManager.INSTANCE; - } - - @Override - protected SSLSocketFactory engineGetSocketFactory() { - if (!isInitialized) { - throw new IllegalStateException( - "SSLContextImpl is not initialized"); - } - return new SSLSocketFactoryImpl(this); - } - - @Override - protected SSLServerSocketFactory engineGetServerSocketFactory() { - if (!isInitialized) { - throw new IllegalStateException("SSLContext is not initialized"); - } - return new SSLServerSocketFactoryImpl(this); - } - abstract SSLEngine createSSLEngineImpl(); - abstract SSLEngine createSSLEngineImpl(String host, int port); - - @Override - protected SSLEngine engineCreateSSLEngine() { - if (!isInitialized) { - throw new IllegalStateException( - "SSLContextImpl is not initialized"); - } - return createSSLEngineImpl(); - } - - @Override - protected SSLEngine engineCreateSSLEngine(String host, int port) { - if (!isInitialized) { - throw new IllegalStateException( - "SSLContextImpl is not initialized"); - } - return createSSLEngineImpl(host, port); - } - - @Override - protected SSLSessionContext engineGetClientSessionContext() { - return clientCache; - } - - @Override - protected SSLSessionContext engineGetServerSessionContext() { - return serverCache; - } - - SecureRandom getSecureRandom() { - return secureRandom; - } - - X509ExtendedKeyManager getX509KeyManager() { - return keyManager; - } - - X509TrustManager getX509TrustManager() { - return trustManager; - } - - EphemeralKeyManager getEphemeralKeyManager() { - return ephemeralKeyManager; - } - - - // Get supported ProtocolList. - abstract ProtocolList getSuportedProtocolList(); - - // Get default ProtocolList for server mode. - abstract ProtocolList getServerDefaultProtocolList(); - - // Get default ProtocolList for client mode. - abstract ProtocolList getClientDefaultProtocolList(); - - // Get supported CipherSuiteList. - abstract CipherSuiteList getSupportedCipherSuiteList(); - - // Get default CipherSuiteList for server mode. - abstract CipherSuiteList getServerDefaultCipherSuiteList(); - - // Get default CipherSuiteList for client mode. - abstract CipherSuiteList getClientDefaultCipherSuiteList(); - - // Get default ProtocolList. - ProtocolList getDefaultProtocolList(boolean roleIsServer) { - return roleIsServer ? getServerDefaultProtocolList() - : getClientDefaultProtocolList(); - } - - // Get default CipherSuiteList. - CipherSuiteList getDefaultCipherSuiteList(boolean roleIsServer) { - return roleIsServer ? getServerDefaultCipherSuiteList() - : getClientDefaultCipherSuiteList(); - } - - /** - * Return whether a protocol list is the original default enabled - * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols() - */ - boolean isDefaultProtocolList(ProtocolList protocols) { - return (protocols == getServerDefaultProtocolList()) || - (protocols == getClientDefaultProtocolList()); - } - - /** - * Return whether a protocol list is the original default enabled - * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols() - */ - boolean isDefaultCipherSuiteList(CipherSuiteList cipherSuites) { - return (cipherSuites == getServerDefaultCipherSuiteList()) || - (cipherSuites == getClientDefaultCipherSuiteList()); - } - - /* - * Return the list of all available CipherSuites that are supported - * using currently installed providers. - */ - private static CipherSuiteList getApplicableSupportedCipherSuiteList( - ProtocolList protocols) { - - return getApplicableCipherSuiteList( - CipherSuite.allowedCipherSuites(), - protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); - } - - /* - * Return the list of all available CipherSuites that are default enabled - * in client or server side. - */ - private static CipherSuiteList getApplicableEnabledCipherSuiteList( - ProtocolList protocols, boolean isClient) { - - if (isClient) { - if (!clientCustomizedCipherSuites.isEmpty()) { - return getApplicableCipherSuiteList( - clientCustomizedCipherSuites, - protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); - } - } else { - if (!serverCustomizedCipherSuites.isEmpty()) { - return getApplicableCipherSuiteList( - serverCustomizedCipherSuites, - protocols, CipherSuite.SUPPORTED_SUITES_PRIORITY); - } - } - - return getApplicableCipherSuiteList( - CipherSuite.allowedCipherSuites(), - protocols, CipherSuite.DEFAULT_SUITES_PRIORITY); - } - - /* - * Return the list of available CipherSuites which are applicable to - * the specified protocols. - */ - private static CipherSuiteList getApplicableCipherSuiteList( - Collection<CipherSuite> allowedCipherSuites, - ProtocolList protocols, int minPriority) { - - TreeSet<CipherSuite> suites = new TreeSet<>(); - if (!(protocols.collection().isEmpty()) && - protocols.min.v != ProtocolVersion.NONE.v) { - for (CipherSuite suite : allowedCipherSuites) { - if (!suite.allowed || suite.priority < minPriority) { - continue; - } - - if (suite.isAvailable() && - suite.obsoleted > protocols.min.v && - suite.supported <= protocols.max.v) { - if (SSLAlgorithmConstraints.DEFAULT.permits( - EnumSet.of(CryptoPrimitive.KEY_AGREEMENT), - suite.name, null)) { - suites.add(suite); - } else { - if (debug != null && Debug.isOn("sslctx") && - Debug.isOn("verbose")) { - System.out.println( - "Ignoring disabled cipher suite: " + - suite.name); - } - } - } else if (debug != null && - Debug.isOn("sslctx") && Debug.isOn("verbose")) { - if (suite.obsoleted <= protocols.min.v) { - System.out.println( - "Ignoring obsoleted cipher suite: " + suite); - } else if (suite.supported > protocols.max.v) { - System.out.println( - "Ignoring unsupported cipher suite: " + suite); - } else { - System.out.println( - "Ignoring unavailable cipher suite: " + suite); - } - } - } - } - - return new CipherSuiteList(suites); - } - - /* - * Get the customized cipher suites specified by the given system property. - */ - private static Collection<CipherSuite> getCustomizedCipherSuites( - String propertyName) { - - String property = AccessController.doPrivileged( - new GetPropertyAction(propertyName)); - if (debug != null && Debug.isOn("sslctx")) { - System.out.println( - "System property " + propertyName + " is set to '" + - property + "'"); - } - if (property != null && property.length() != 0) { - // remove double quote marks from beginning/end of the property - if (property.length() > 1 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - } - - if (property != null && property.length() != 0) { - String[] cipherSuiteNames = property.split(","); - Collection<CipherSuite> cipherSuites = - new ArrayList<>(cipherSuiteNames.length); - for (int i = 0; i < cipherSuiteNames.length; i++) { - cipherSuiteNames[i] = cipherSuiteNames[i].trim(); - if (cipherSuiteNames[i].isEmpty()) { - continue; - } - - CipherSuite suite; - try { - suite = CipherSuite.valueOf(cipherSuiteNames[i]); - } catch (IllegalArgumentException iae) { - if (debug != null && Debug.isOn("sslctx")) { - System.out.println( - "Unknown or unsupported cipher suite name: " + - cipherSuiteNames[i]); - } - - continue; - } - - if (suite.isAvailable()) { - cipherSuites.add(suite); - } else { - if (debug != null && Debug.isOn("sslctx")) { - System.out.println( - "The current installed providers do not " + - "support cipher suite: " + cipherSuiteNames[i]); - } - } - } - - return cipherSuites; - } - - return Collections.emptyList(); - } - - private static String[] getAvailableProtocols( - ProtocolVersion[] protocolCandidates) { - - List<String> availableProtocols = Collections.<String>emptyList(); - if (protocolCandidates != null && protocolCandidates.length != 0) { - availableProtocols = new ArrayList<>(protocolCandidates.length); - for (ProtocolVersion p : protocolCandidates) { - if (ProtocolVersion.availableProtocols.contains(p)) { - availableProtocols.add(p.name); - } - } - } - - return availableProtocols.toArray(new String[0]); - } - - /* - * The SSLContext implementation for TLS/SSL algorithm - * - * SSL/TLS protocols specify the forward compatibility and version - * roll-back attack protections, however, a number of SSL/TLS server - * vendors did not implement these aspects properly, and some current - * SSL/TLS servers may refuse to talk to a TLS 1.1 or later client. - * - * Considering above interoperability issues, SunJSSE will not set - * TLS 1.1 and TLS 1.2 as the enabled protocols for client by default. - * - * For SSL/TLS servers, there is no such interoperability issues as - * SSL/TLS clients. In SunJSSE, TLS 1.1 or later version will be the - * enabled protocols for server by default. - * - * We may change the behavior when popular TLS/SSL vendors support TLS - * forward compatibility properly. - * - * SSLv2Hello is no longer necessary. This interoperability option was - * put in place in the late 90's when SSLv3/TLS1.0 were relatively new - * and there were a fair number of SSLv2-only servers deployed. Because - * of the security issues in SSLv2, it is rarely (if ever) used, as - * deployments should now be using SSLv3 and TLSv1. - * - * Considering the issues of SSLv2Hello, we should not enable SSLv2Hello - * by default. Applications still can use it by enabling SSLv2Hello with - * the series of setEnabledProtocols APIs. - */ - - /* - * The base abstract SSLContext implementation for the Transport Layer - * Security (TLS) protocols. - * - * This abstract class encapsulates supported and the default server - * SSL/TLS parameters. - * - * @see SSLContext - */ - private abstract static class AbstractTLSContext extends SSLContextImpl { - private static final ProtocolList supportedProtocolList; - private static final ProtocolList serverDefaultProtocolList; - - private static final CipherSuiteList supportedCipherSuiteList; - private static final CipherSuiteList serverDefaultCipherSuiteList; - - static { - if (SunJSSE.isFIPS()) { - supportedProtocolList = new ProtocolList(new String[] { - ProtocolVersion.TLS10.name, - ProtocolVersion.TLS11.name, - ProtocolVersion.TLS12.name - }); - - serverDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - })); - } else { - supportedProtocolList = new ProtocolList(new String[] { - ProtocolVersion.SSL20Hello.name, - ProtocolVersion.SSL30.name, - ProtocolVersion.TLS10.name, - ProtocolVersion.TLS11.name, - ProtocolVersion.TLS12.name - }); - - serverDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.SSL20Hello, - ProtocolVersion.SSL30, - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - })); - } - - supportedCipherSuiteList = getApplicableSupportedCipherSuiteList( - supportedProtocolList); - serverDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( - serverDefaultProtocolList, false); - } - - @Override - ProtocolList getSuportedProtocolList() { - return supportedProtocolList; - } - - @Override - CipherSuiteList getSupportedCipherSuiteList() { - return supportedCipherSuiteList; - } - - @Override - ProtocolList getServerDefaultProtocolList() { - return serverDefaultProtocolList; - } - - @Override - CipherSuiteList getServerDefaultCipherSuiteList() { - return serverDefaultCipherSuiteList; - } - - @Override - SSLEngine createSSLEngineImpl() { - return new SSLEngineImpl(this); - } - - @Override - SSLEngine createSSLEngineImpl(String host, int port) { - return new SSLEngineImpl(this, host, port); - } - } - - /* - * The SSLContext implementation for SSLv3 and TLS10 algorithm - * - * @see SSLContext - */ - public static final class TLS10Context extends AbstractTLSContext { - private static final ProtocolList clientDefaultProtocolList; - private static final CipherSuiteList clientDefaultCipherSuiteList; - - static { - if (SunJSSE.isFIPS()) { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.TLS10 - })); - } else { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.SSL30, - ProtocolVersion.TLS10 - })); - } - - clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( - clientDefaultProtocolList, true); - } - - @Override - ProtocolList getClientDefaultProtocolList() { - return clientDefaultProtocolList; - } - - @Override - CipherSuiteList getClientDefaultCipherSuiteList() { - return clientDefaultCipherSuiteList; - } - } - - /* - * The SSLContext implementation for TLS11 algorithm - * - * @see SSLContext - */ - public static final class TLS11Context extends AbstractTLSContext { - private static final ProtocolList clientDefaultProtocolList; - private static final CipherSuiteList clientDefaultCipherSuiteList; - - static { - if (SunJSSE.isFIPS()) { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.TLS10, - ProtocolVersion.TLS11 - })); - } else { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.SSL30, - ProtocolVersion.TLS10, - ProtocolVersion.TLS11 - })); - } - - clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( - clientDefaultProtocolList, true); - - } - - @Override - ProtocolList getClientDefaultProtocolList() { - return clientDefaultProtocolList; - } - - @Override - CipherSuiteList getClientDefaultCipherSuiteList() { - return clientDefaultCipherSuiteList; - } - } - - /* - * The SSLContext implementation for TLS12 algorithm - * - * @see SSLContext - */ - public static final class TLS12Context extends AbstractTLSContext { - private static final ProtocolList clientDefaultProtocolList; - private static final CipherSuiteList clientDefaultCipherSuiteList; - - static { - if (SunJSSE.isFIPS()) { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - })); - } else { - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(new ProtocolVersion[] { - ProtocolVersion.SSL30, - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - })); - } - - clientDefaultCipherSuiteList = getApplicableEnabledCipherSuiteList( - clientDefaultProtocolList, true); - } - - @Override - ProtocolList getClientDefaultProtocolList() { - return clientDefaultProtocolList; - } - - @Override - CipherSuiteList getClientDefaultCipherSuiteList() { - return clientDefaultCipherSuiteList; - } - } - - /* - * The interface for the customized SSL/(D)TLS SSLContext. - * - * @see SSLContext - */ - private static class CustomizedSSLProtocols { - private static final String PROPERTY_NAME = "jdk.tls.client.protocols"; - static IllegalArgumentException reservedException = null; - static ArrayList<ProtocolVersion> - customizedProtocols = new ArrayList<>(); - - // Don't want a java.lang.LinkageError for illegal system property. - // - // Please don't throw exception in this static block. Otherwise, - // java.lang.LinkageError may be thrown during the instantiation of - // the provider service. Instead, please handle the initialization - // exception in the caller's constructor. - static { - String property = AccessController.doPrivileged( - new GetPropertyAction(PROPERTY_NAME)); - if (property != null && property.length() != 0) { - // remove double quote marks from beginning/end of the property - if (property.length() > 1 && property.charAt(0) == '"' && - property.charAt(property.length() - 1) == '"') { - property = property.substring(1, property.length() - 1); - } - } - - if (property != null && property.length() != 0) { - String[] protocols = property.split(","); - for (int i = 0; i < protocols.length; i++) { - protocols[i] = protocols[i].trim(); - // Is it a supported protocol name? - try { - ProtocolVersion pro = - ProtocolVersion.valueOf(protocols[i]); - - if (SunJSSE.isFIPS() && - ((pro.v == ProtocolVersion.SSL30.v) || - (pro.v == ProtocolVersion.SSL20Hello.v))) { - reservedException = new IllegalArgumentException( - PROPERTY_NAME + ": " + pro + - " is not FIPS compliant"); - - break; - } - - // ignore duplicated protocols - if (!customizedProtocols.contains(pro)) { - customizedProtocols.add(pro); - } - } catch (IllegalArgumentException iae) { - reservedException = new IllegalArgumentException( - PROPERTY_NAME + ": " + protocols[i] + - " is not a standard SSL protocol name", iae); - } - } - } - } - } - - /* - * The SSLContext implementation for customized TLS protocols - * - * @see SSLContext - */ - private static class CustomizedTLSContext extends AbstractTLSContext { - - private static final ProtocolList clientDefaultProtocolList; - private static final CipherSuiteList clientDefaultCipherSuiteList; - - private static IllegalArgumentException reservedException = null; - - // Don't want a java.lang.LinkageError for illegal system property. - // - // Please don't throw exception in this static block. Otherwise, - // java.lang.LinkageError may be thrown during the instantiation of - // the provider service. Instead, let's handle the initialization - // exception in constructor. - static { - reservedException = CustomizedSSLProtocols.reservedException; - if (reservedException == null) { - ArrayList<ProtocolVersion> - customizedTLSProtocols = new ArrayList<>(); - for (ProtocolVersion protocol : - CustomizedSSLProtocols.customizedProtocols) { - customizedTLSProtocols.add(protocol); - } - - // candidates for available protocols - ProtocolVersion[] candidates; - if (customizedTLSProtocols.isEmpty()) { - // Use the default enabled client protocols if no - // customized TLS protocols. - if (SunJSSE.isFIPS()) { - candidates = new ProtocolVersion[] { - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - }; - } else { - candidates = new ProtocolVersion[] { - ProtocolVersion.SSL30, - ProtocolVersion.TLS10, - ProtocolVersion.TLS11, - ProtocolVersion.TLS12 - }; - } - } else { - // Use the customized TLS protocols. - candidates = - new ProtocolVersion[customizedTLSProtocols.size()]; - candidates = customizedTLSProtocols.toArray(candidates); - } - - clientDefaultProtocolList = new ProtocolList( - getAvailableProtocols(candidates)); - clientDefaultCipherSuiteList = - getApplicableEnabledCipherSuiteList( - clientDefaultProtocolList, true); - } else { - clientDefaultProtocolList = null; // unlikely to be used - clientDefaultCipherSuiteList = null; // unlikely to be used - } - } - - protected CustomizedTLSContext() { - if (reservedException != null) { - throw reservedException; - } - } - - @Override - ProtocolList getClientDefaultProtocolList() { - return clientDefaultProtocolList; - } - - @Override - CipherSuiteList getClientDefaultCipherSuiteList() { - return clientDefaultCipherSuiteList; - } - } - - /* - * The SSLContext implementation for default "TLS" algorithm - * - * @see SSLContext - */ - public static final class TLSContext extends CustomizedTLSContext { - // use the default constructor and methods - } - - // lazy initialization holder class idiom for static default parameters - // - // See Effective Java Second Edition: Item 71. - private static final class DefaultManagersHolder { - private static final String NONE = "NONE"; - private static final String P11KEYSTORE = "PKCS11"; - - private static final TrustManager[] trustManagers; - private static final KeyManager[] keyManagers; - - static Exception reservedException = null; - - static { - TrustManager[] tmMediator; - try { - tmMediator = getTrustManagers(); - } catch (Exception e) { - reservedException = e; - tmMediator = new TrustManager[0]; - } - trustManagers = tmMediator; - - if (reservedException == null) { - KeyManager[] kmMediator; - try { - kmMediator = getKeyManagers(); - } catch (Exception e) { - reservedException = e; - kmMediator = new KeyManager[0]; - } - keyManagers = kmMediator; - } else { - keyManagers = new KeyManager[0]; - } - } - - private static TrustManager[] getTrustManagers() throws Exception { - TrustManagerFactory tmf = TrustManagerFactory.getInstance( - TrustManagerFactory.getDefaultAlgorithm()); - if ("SunJSSE".equals(tmf.getProvider().getName())) { - // The implementation will load the default KeyStore - // automatically. Cached trust materials may be used - // for performance improvement. - tmf.init((KeyStore)null); - } else { - // Use the explicitly specified KeyStore for third party's - // TrustManagerFactory implementation. - KeyStore ks = TrustStoreManager.getTrustedKeyStore(); - tmf.init(ks); - } - - return tmf.getTrustManagers(); - } - - private static KeyManager[] getKeyManagers() throws Exception { - - final Map<String,String> props = new HashMap<>(); - AccessController.doPrivileged( - new PrivilegedExceptionAction<Object>() { - @Override - public Object run() throws Exception { - props.put("keyStore", System.getProperty( - "javax.net.ssl.keyStore", "")); - props.put("keyStoreType", System.getProperty( - "javax.net.ssl.keyStoreType", - KeyStore.getDefaultType())); - props.put("keyStoreProvider", System.getProperty( - "javax.net.ssl.keyStoreProvider", "")); - props.put("keyStorePasswd", System.getProperty( - "javax.net.ssl.keyStorePassword", "")); - return null; - } - }); - - final String defaultKeyStore = props.get("keyStore"); - String defaultKeyStoreType = props.get("keyStoreType"); - String defaultKeyStoreProvider = props.get("keyStoreProvider"); - if (debug != null && Debug.isOn("defaultctx")) { - System.out.println("keyStore is : " + defaultKeyStore); - System.out.println("keyStore type is : " + - defaultKeyStoreType); - System.out.println("keyStore provider is : " + - defaultKeyStoreProvider); - } - - if (P11KEYSTORE.equals(defaultKeyStoreType) && - !NONE.equals(defaultKeyStore)) { - throw new IllegalArgumentException("if keyStoreType is " - + P11KEYSTORE + ", then keyStore must be " + NONE); - } - - FileInputStream fs = null; - KeyStore ks = null; - char[] passwd = null; - try { - if (defaultKeyStore.length() != 0 && - !NONE.equals(defaultKeyStore)) { - fs = AccessController.doPrivileged( - new PrivilegedExceptionAction<FileInputStream>() { - @Override - public FileInputStream run() throws Exception { - return new FileInputStream(defaultKeyStore); - } - }); - } - - String defaultKeyStorePassword = props.get("keyStorePasswd"); - if (defaultKeyStorePassword.length() != 0) { - passwd = defaultKeyStorePassword.toCharArray(); - } - - /** - * Try to initialize key store. - */ - if ((defaultKeyStoreType.length()) != 0) { - if (debug != null && Debug.isOn("defaultctx")) { - System.out.println("init keystore"); - } - if (defaultKeyStoreProvider.length() == 0) { - ks = KeyStore.getInstance(defaultKeyStoreType); - } else { - ks = KeyStore.getInstance(defaultKeyStoreType, - defaultKeyStoreProvider); - } - - // if defaultKeyStore is NONE, fs will be null - ks.load(fs, passwd); - } - } finally { - if (fs != null) { - fs.close(); - fs = null; - } - } - - /* - * Try to initialize key manager. - */ - if (debug != null && Debug.isOn("defaultctx")) { - System.out.println("init keymanager of type " + - KeyManagerFactory.getDefaultAlgorithm()); - } - KeyManagerFactory kmf = KeyManagerFactory.getInstance( - KeyManagerFactory.getDefaultAlgorithm()); - - if (P11KEYSTORE.equals(defaultKeyStoreType)) { - kmf.init(ks, null); // do not pass key passwd if using token - } else { - kmf.init(ks, passwd); - } - - return kmf.getKeyManagers(); - } - } - - // lazy initialization holder class idiom for static default parameters - // - // See Effective Java Second Edition: Item 71. - private static final class DefaultSSLContextHolder { - - private static final SSLContextImpl sslContext; - static Exception reservedException = null; - - static { - SSLContextImpl mediator = null; - if (DefaultManagersHolder.reservedException != null) { - reservedException = DefaultManagersHolder.reservedException; - } else { - try { - mediator = new DefaultSSLContext(); - } catch (Exception e) { - reservedException = e; - } - } - - sslContext = mediator; - } - } - - /* - * The SSLContext implementation for default "Default" algorithm - * - * @see SSLContext - */ - public static final class DefaultSSLContext extends CustomizedTLSContext { - - // public constructor for SSLContext.getInstance("Default") - public DefaultSSLContext() throws Exception { - if (DefaultManagersHolder.reservedException != null) { - throw DefaultManagersHolder.reservedException; - } - - try { - super.engineInit(DefaultManagersHolder.keyManagers, - DefaultManagersHolder.trustManagers, null); - } catch (Exception e) { - if (debug != null && Debug.isOn("defaultctx")) { - System.out.println("default context init failed: " + e); - } - throw e; - } - } - - @Override - protected void engineInit(KeyManager[] km, TrustManager[] tm, - SecureRandom sr) throws KeyManagementException { - throw new KeyManagementException - ("Default SSLContext is initialized automatically"); - } - - static SSLContextImpl getDefaultImpl() throws Exception { - if (DefaultSSLContextHolder.reservedException != null) { - throw DefaultSSLContextHolder.reservedException; - } - - return DefaultSSLContextHolder.sslContext; - } - } - - -} - - -final class AbstractTrustManagerWrapper extends X509ExtendedTrustManager - implements X509TrustManager { - - // the delegated trust manager - private final X509TrustManager tm; - - AbstractTrustManagerWrapper(X509TrustManager tm) { - this.tm = tm; - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - tm.checkClientTrusted(chain, authType); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - tm.checkServerTrusted(chain, authType); - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return tm.getAcceptedIssuers(); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - tm.checkClientTrusted(chain, authType); - checkAdditionalTrust(chain, authType, socket, true); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - tm.checkServerTrusted(chain, authType); - checkAdditionalTrust(chain, authType, socket, false); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - tm.checkClientTrusted(chain, authType); - checkAdditionalTrust(chain, authType, engine, true); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - tm.checkServerTrusted(chain, authType); - checkAdditionalTrust(chain, authType, engine, false); - } - - private void checkAdditionalTrust(X509Certificate[] chain, - String authType, Socket socket, - boolean checkClientTrusted) throws CertificateException { - if (socket != null && socket.isConnected() && - socket instanceof SSLSocket) { - - SSLSocket sslSocket = (SSLSocket)socket; - SSLSession session = sslSocket.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - // check endpoint identity - String identityAlg = sslSocket.getSSLParameters(). - getEndpointIdentificationAlgorithm(); - if (identityAlg != null && identityAlg.length() != 0) { - X509TrustManagerImpl.checkIdentity(session, chain, - identityAlg, checkClientTrusted); - } - - // try the best to check the algorithm constraints - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - AlgorithmConstraints constraints = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - String[] peerSupportedSignAlgs = - extSession.getLocalSupportedSignatureAlgorithms(); - - constraints = new SSLAlgorithmConstraints( - sslSocket, peerSupportedSignAlgs, true); - } else { - constraints = - new SSLAlgorithmConstraints(sslSocket, true); - } - } else { - constraints = new SSLAlgorithmConstraints(sslSocket, true); - } - - checkAlgorithmConstraints(chain, constraints, checkClientTrusted); - } - } - - private void checkAdditionalTrust(X509Certificate[] chain, - String authType, SSLEngine engine, - boolean checkClientTrusted) throws CertificateException { - if (engine != null) { - SSLSession session = engine.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - // check endpoint identity - String identityAlg = engine.getSSLParameters(). - getEndpointIdentificationAlgorithm(); - if (identityAlg != null && identityAlg.length() != 0) { - X509TrustManagerImpl.checkIdentity(session, chain, - identityAlg, checkClientTrusted); - } - - // try the best to check the algorithm constraints - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - AlgorithmConstraints constraints = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - String[] peerSupportedSignAlgs = - extSession.getLocalSupportedSignatureAlgorithms(); - - constraints = new SSLAlgorithmConstraints( - engine, peerSupportedSignAlgs, true); - } else { - constraints = - new SSLAlgorithmConstraints(engine, true); - } - } else { - constraints = new SSLAlgorithmConstraints(engine, true); - } - - checkAlgorithmConstraints(chain, constraints, checkClientTrusted); - } - } - - private void checkAlgorithmConstraints(X509Certificate[] chain, - AlgorithmConstraints constraints, - boolean checkClientTrusted) throws CertificateException { - - try { - // Does the certificate chain end with a trusted certificate? - int checkedLength = chain.length - 1; - - Collection<X509Certificate> trustedCerts = new HashSet<>(); - X509Certificate[] certs = tm.getAcceptedIssuers(); - if ((certs != null) && (certs.length > 0)){ - Collections.addAll(trustedCerts, certs); - } - - if (trustedCerts.contains(chain[checkedLength])) { - checkedLength--; - } - - // A forward checker, need to check from trust to target - if (checkedLength >= 0) { - AlgorithmChecker checker = - new AlgorithmChecker(constraints, null, - (checkClientTrusted ? Validator.VAR_TLS_CLIENT : - Validator.VAR_TLS_SERVER)); - checker.init(false); - for (int i = checkedLength; i >= 0; i--) { - Certificate cert = chain[i]; - // We don't care about the unresolved critical extensions. - checker.check(cert, Collections.<String>emptySet()); - } - } - } catch (CertPathValidatorException cpve) { - throw new CertificateException( - "Certificates do not conform to algorithm constraints", cpve); - } - } -} - -// Dummy X509TrustManager implementation, rejects all peer certificates. -// Used if the application did not specify a proper X509TrustManager. -final class DummyX509TrustManager extends X509ExtendedTrustManager - implements X509TrustManager { - - static final X509TrustManager INSTANCE = new DummyX509TrustManager(); - - private DummyX509TrustManager() { - // empty - } - - /* - * Given the partial or complete certificate chain - * provided by the peer, build a certificate path - * to a trusted root and return if it can be - * validated and is trusted for client SSL authentication. - * If not, it throws an exception. - */ - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation avaiable"); - } - - /* - * Given the partial or complete certificate chain - * provided by the peer, build a certificate path - * to a trusted root and return if it can be - * validated and is trusted for server SSL authentication. - * If not, it throws an exception. - */ - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation available"); - } - - /* - * Return an array of issuer certificates which are trusted - * for authenticating peers. - */ - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation available"); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation available"); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation available"); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - throw new CertificateException( - "No X509TrustManager implementation available"); - } -} - -/* - * A wrapper class to turn a X509KeyManager into an X509ExtendedKeyManager - */ -final class AbstractKeyManagerWrapper extends X509ExtendedKeyManager { - - private final X509KeyManager km; - - AbstractKeyManagerWrapper(X509KeyManager km) { - this.km = km; - } - - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return km.getClientAliases(keyType, issuers); - } - - @Override - public String chooseClientAlias(String[] keyType, Principal[] issuers, - Socket socket) { - return km.chooseClientAlias(keyType, issuers, socket); - } - - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return km.getServerAliases(keyType, issuers); - } - - @Override - public String chooseServerAlias(String keyType, Principal[] issuers, - Socket socket) { - return km.chooseServerAlias(keyType, issuers, socket); - } - - @Override - public X509Certificate[] getCertificateChain(String alias) { - return km.getCertificateChain(alias); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - return km.getPrivateKey(alias); - } - - // Inherit chooseEngineClientAlias() and chooseEngineServerAlias() from - // X509ExtendedKeymanager. It defines them to return null; -} - - -// Dummy X509KeyManager implementation, never returns any certificates/keys. -// Used if the application did not specify a proper X509TrustManager. -final class DummyX509KeyManager extends X509ExtendedKeyManager { - - static final X509ExtendedKeyManager INSTANCE = new DummyX509KeyManager(); - - private DummyX509KeyManager() { - // empty - } - - /* - * Get the matching aliases for authenticating the client side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return null; - } - - /* - * Choose an alias to authenticate the client side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseClientAlias(String[] keyTypes, Principal[] issuers, - Socket socket) { - return null; - } - - /* - * Choose an alias to authenticate the client side of an - * engine given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseEngineClientAlias( - String[] keyTypes, Principal[] issuers, SSLEngine engine) { - return null; - } - - /* - * Get the matching aliases for authenticating the server side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return null; - } - - /* - * Choose an alias to authenticate the server side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseServerAlias(String keyType, Principal[] issuers, - Socket socket) { - return null; - } - - /* - * Choose an alias to authenticate the server side of an engine - * given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseEngineServerAlias( - String keyType, Principal[] issuers, SSLEngine engine) { - return null; - } - - /** - * Returns the certificate chain associated with the given alias. - * - * @param alias the alias name - * - * @return the certificate chain (ordered with the user's certificate first - * and the root certificate authority last) - */ - @Override - public X509Certificate[] getCertificateChain(String alias) { - return null; - } - - /* - * Returns the key associated with the given alias, using the given - * password to recover it. - * - * @param alias the alias name - * - * @return the requested key - */ - @Override - public PrivateKey getPrivateKey(String alias) { - return null; - } -}
--- a/src/share/classes/sun/security/ssl/SSLEngineImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2203 +0,0 @@ -/* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.nio.*; -import java.util.*; -import java.security.*; -import java.util.function.BiFunction; - -import javax.crypto.BadPaddingException; - -import javax.net.ssl.*; -import javax.net.ssl.SSLEngineResult.*; - -/** - * Implementation of an non-blocking SSLEngine. - * - * *Currently*, the SSLEngine code exists in parallel with the current - * SSLSocket. As such, the current implementation is using legacy code - * with many of the same abstractions. However, it varies in many - * areas, most dramatically in the IO handling. - * - * There are three main I/O threads that can be existing in parallel: - * wrap(), unwrap(), and beginHandshake(). We are encouraging users to - * not call multiple instances of wrap or unwrap, because the data could - * appear to flow out of the SSLEngine in a non-sequential order. We - * take all steps we can to at least make sure the ordering remains - * consistent, but once the calls returns, anything can happen. For - * example, thread1 and thread2 both call wrap, thread1 gets the first - * packet, thread2 gets the second packet, but thread2 gets control back - * before thread1, and sends the data. The receiving side would see an - * out-of-order error. - * - * Handshaking is still done the same way as SSLSocket using the normal - * InputStream/OutputStream abstactions. We create - * ClientHandshakers/ServerHandshakers, which produce/consume the - * handshaking data. The transfer of the data is largely handled by the - * HandshakeInStream/HandshakeOutStreams. Lastly, the - * InputRecord/OutputRecords still have the same functionality, except - * that they are overridden with EngineInputRecord/EngineOutputRecord, - * which provide SSLEngine-specific functionality. - * - * Some of the major differences are: - * - * EngineInputRecord/EngineOutputRecord/EngineWriter: - * - * In order to avoid writing whole new control flows for - * handshaking, and to reuse most of the same code, we kept most - * of the actual handshake code the same. As usual, reading - * handshake data may trigger output of more handshake data, so - * what we do is write this data to internal buffers, and wait for - * wrap() to be called to give that data a ride. - * - * All data is routed through - * EngineInputRecord/EngineOutputRecord. However, all handshake - * data (ct_alert/ct_change_cipher_spec/ct_handshake) are passed - * through to the the underlying InputRecord/OutputRecord, and - * the data uses the internal buffers. - * - * Application data is handled slightly different, we copy the data - * directly from the src to the dst buffers, and do all operations - * on those buffers, saving the overhead of multiple copies. - * - * In the case of an inbound record, unwrap passes the inbound - * ByteBuffer to the InputRecord. If the data is handshake data, - * the data is read into the InputRecord's internal buffer. If - * the data is application data, the data is decoded directly into - * the dst buffer. - * - * In the case of an outbound record, when the write to the - * "real" OutputStream's would normally take place, instead we - * call back up to the EngineOutputRecord's version of - * writeBuffer, at which time we capture the resulting output in a - * ByteBuffer, and send that back to the EngineWriter for internal - * storage. - * - * EngineWriter is responsible for "handling" all outbound - * data, be it handshake or app data, and for returning the data - * to wrap() in the proper order. - * - * ClientHandshaker/ServerHandshaker/Handshaker: - * Methods which relied on SSLSocket now have work on either - * SSLSockets or SSLEngines. - * - * @author Brad Wetmore - */ -final public class SSLEngineImpl extends SSLEngine { - - // - // Fields and global comments - // - - /* - * There's a state machine associated with each connection, which - * among other roles serves to negotiate session changes. - * - * - START with constructor, until the TCP connection's around. - * - HANDSHAKE picks session parameters before allowing traffic. - * There are many substates due to sequencing requirements - * for handshake messages. - * - DATA may be transmitted. - * - RENEGOTIATE state allows concurrent data and handshaking - * traffic ("same" substates as HANDSHAKE), and terminates - * in selection of new session (and connection) parameters - * - ERROR state immediately precedes abortive disconnect. - * - CLOSED when one side closes down, used to start the shutdown - * process. SSL connection objects are not reused. - * - * State affects what SSL record types may legally be sent: - * - * - Handshake ... only in HANDSHAKE and RENEGOTIATE states - * - App Data ... only in DATA and RENEGOTIATE states - * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE - * - * Re what may be received: same as what may be sent, except that - * HandshakeRequest handshaking messages can come from servers even - * in the application data state, to request entry to RENEGOTIATE. - * - * The state machine within HANDSHAKE and RENEGOTIATE states controls - * the pending session, not the connection state, until the change - * cipher spec and "Finished" handshake messages are processed and - * make the "new" session become the current one. - * - * NOTE: details of the SMs always need to be nailed down better. - * The text above illustrates the core ideas. - * - * +---->-------+------>--------->-------+ - * | | | - * <-----< ^ ^ <-----< | - *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE | - * v v v | - * | | | | - * +------------+---------------+ | - * | | - * v | - * ERROR>------>----->CLOSED<--------<----+ - * - * ALSO, note that the the purpose of handshaking (renegotiation is - * included) is to assign a different, and perhaps new, session to - * the connection. The SSLv3 spec is a bit confusing on that new - * protocol feature. - */ - private int connectionState; - - private static final int cs_START = 0; - private static final int cs_HANDSHAKE = 1; - private static final int cs_DATA = 2; - private static final int cs_RENEGOTIATE = 3; - private static final int cs_ERROR = 4; - private static final int cs_CLOSED = 6; - - /* - * Once we're in state cs_CLOSED, we can continue to - * wrap/unwrap until we finish sending/receiving the messages - * for close_notify. EngineWriter handles outboundDone. - */ - private boolean inboundDone = false; - - EngineWriter writer; - - /* - * The authentication context holds all information used to establish - * who this end of the connection is (certificate chains, private keys, - * etc) and who is trusted (e.g. as CAs or websites). - */ - private SSLContextImpl sslContext; - - /* - * This connection is one of (potentially) many associated with - * any given session. The output of the handshake protocol is a - * new session ... although all the protocol description talks - * about changing the cipher spec (and it does change), in fact - * that's incidental since it's done by changing everything that - * is associated with a session at the same time. (TLS/IETF may - * change that to add client authentication w/o new key exchg.) - */ - private Handshaker handshaker; - private SSLSessionImpl sess; - private volatile SSLSessionImpl handshakeSession; - - - /* - * Client authentication be off, requested, or required. - * - * This will be used by both this class and SSLSocket's variants. - */ - static final byte clauth_none = 0; - static final byte clauth_requested = 1; - static final byte clauth_required = 2; - - /* - * Flag indicating if the next record we receive MUST be a Finished - * message. Temporarily set during the handshake to ensure that - * a change cipher spec message is followed by a finished message. - */ - private boolean expectingFinished; - - - /* - * If someone tries to closeInbound() (say at End-Of-Stream) - * our engine having received a close_notify, we need to - * notify the app that we may have a truncation attack underway. - */ - private boolean recvCN; - - /* - * For improved diagnostics, we detail connection closure - * If the engine is closed (connectionState >= cs_ERROR), - * closeReason != null indicates if the engine was closed - * because of an error or because or normal shutdown. - */ - private SSLException closeReason; - - /* - * Per-connection private state that doesn't change when the - * session is changed. - */ - private byte doClientAuth; - private boolean enableSessionCreation = true; - EngineInputRecord inputRecord; - EngineOutputRecord outputRecord; - private AccessControlContext acc; - - // The cipher suites enabled for use on this connection. - private CipherSuiteList enabledCipherSuites; - - // the endpoint identification protocol - private String identificationProtocol = null; - - // The cryptographic algorithm constraints - private AlgorithmConstraints algorithmConstraints = null; - - // The server name indication and matchers - List<SNIServerName> serverNames = - Collections.<SNIServerName>emptyList(); - Collection<SNIMatcher> sniMatchers = - Collections.<SNIMatcher>emptyList(); - - // Configured application protocol values - String[] applicationProtocols = new String[0]; - - // Negotiated application protocol value. - // - // The value under negotiation will be obtained from handshaker. - String applicationProtocol = null; - - - // Callback function that selects the application protocol value during - // the SSL/TLS handshake. - BiFunction<SSLEngine, List<String>, String> applicationProtocolSelector; - - // Have we been told whether we're client or server? - private boolean serverModeSet = false; - private boolean roleIsServer; - - /* - * The protocol versions enabled for use on this connection. - * - * Note: we support a pseudo protocol called SSLv2Hello which when - * set will result in an SSL v2 Hello being sent with SSL (version 3.0) - * or TLS (version 3.1, 3.2, etc.) version info. - */ - private ProtocolList enabledProtocols; - - /* - * The SSL version associated with this connection. - */ - private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT; - - /* - * Crypto state that's reinitialized when the session changes. - */ - private Authenticator readAuthenticator, writeAuthenticator; - private CipherBox readCipher, writeCipher; - // NOTE: compression state would be saved here - - /* - * security parameters for secure renegotiation. - */ - private boolean secureRenegotiation; - private byte[] clientVerifyData; - private byte[] serverVerifyData; - - /* - * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * - * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES. - * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * - * - * There are several locks here. - * - * The primary lock is the per-instance lock used by - * synchronized(this) and the synchronized methods. It controls all - * access to things such as the connection state and variables which - * affect handshaking. If we are inside a synchronized method, we - * can access the state directly, otherwise, we must use the - * synchronized equivalents. - * - * Note that we must never acquire the <code>this</code> lock after - * <code>writeLock</code> or run the risk of deadlock. - * - * Grab some coffee, and be careful with any code changes. - */ - private Object wrapLock; - private Object unwrapLock; - Object writeLock; - - /* - * Is it the first application record to write? - */ - private boolean isFirstAppOutputRecord = true; - - /* - * Whether local cipher suites preference in server side should be - * honored during handshaking? - */ - private boolean preferLocalCipherSuites = false; - - /* - * Class and subclass dynamic debugging support - */ - private static final Debug debug = Debug.getInstance("ssl"); - - // - // Initialization/Constructors - // - - /** - * Constructor for an SSLEngine from SSLContext, without - * host/port hints. This Engine will not be able to cache - * sessions, but must renegotiate everything by hand. - */ - SSLEngineImpl(SSLContextImpl ctx) { - super(); - init(ctx); - } - - /** - * Constructor for an SSLEngine from SSLContext. - */ - SSLEngineImpl(SSLContextImpl ctx, String host, int port) { - super(host, port); - init(ctx); - } - - /** - * Initializes the Engine - */ - private void init(SSLContextImpl ctx) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println("Using SSLEngineImpl."); - } - - sslContext = ctx; - sess = new SSLSessionImpl(); - handshakeSession = null; - - /* - * State is cs_START until we initialize the handshaker. - * - * Apps using SSLEngine are probably going to be server. - * Somewhat arbitrary choice. - */ - roleIsServer = true; - connectionState = cs_START; - - // default server name indication - serverNames = - Utilities.addToSNIServerNameList(serverNames, getPeerHost()); - - /* - * default read and write side cipher and MAC support - * - * Note: compression support would go here too - */ - readCipher = CipherBox.NULL; - readAuthenticator = MAC.NULL; - writeCipher = CipherBox.NULL; - writeAuthenticator = MAC.NULL; - - // default security parameters for secure renegotiation - secureRenegotiation = false; - clientVerifyData = new byte[0]; - serverVerifyData = new byte[0]; - - enabledCipherSuites = - sslContext.getDefaultCipherSuiteList(roleIsServer); - enabledProtocols = - sslContext.getDefaultProtocolList(roleIsServer); - - wrapLock = new Object(); - unwrapLock = new Object(); - writeLock = new Object(); - - /* - * Save the Access Control Context. This will be used later - * for a couple of things, including providing a context to - * run tasks in, and for determining which credentials - * to use for Subject based (JAAS) decisions - */ - acc = AccessController.getContext(); - - /* - * All outbound application data goes through this OutputRecord, - * other data goes through their respective records created - * elsewhere. All inbound data goes through this one - * input record. - */ - outputRecord = - new EngineOutputRecord(Record.ct_application_data, this); - inputRecord = new EngineInputRecord(this); - inputRecord.enableFormatChecks(); - - writer = new EngineWriter(); - } - - /** - * Initialize the handshaker object. This means: - * - * . if a handshake is already in progress (state is cs_HANDSHAKE - * or cs_RENEGOTIATE), do nothing and return - * - * . if the engine is already closed, throw an Exception (internal error) - * - * . otherwise (cs_START or cs_DATA), create the appropriate handshaker - * object and advance the connection state (to cs_HANDSHAKE or - * cs_RENEGOTIATE, respectively). - * - * This method is called right after a new engine is created, when - * starting renegotiation, or when changing client/server mode of the - * engine. - */ - private void initHandshaker() { - switch (connectionState) { - - // - // Starting a new handshake. - // - case cs_START: - case cs_DATA: - break; - - // - // We're already in the middle of a handshake. - // - case cs_HANDSHAKE: - case cs_RENEGOTIATE: - return; - - // - // Anyone allowed to call this routine is required to - // do so ONLY if the connection state is reasonable... - // - default: - throw new IllegalStateException("Internal error"); - } - - // state is either cs_START or cs_DATA - if (connectionState == cs_START) { - connectionState = cs_HANDSHAKE; - } else { // cs_DATA - connectionState = cs_RENEGOTIATE; - } - if (roleIsServer) { - handshaker = new ServerHandshaker(this, sslContext, - enabledProtocols, doClientAuth, - protocolVersion, connectionState == cs_HANDSHAKE, - secureRenegotiation, clientVerifyData, serverVerifyData); - handshaker.setSNIMatchers(sniMatchers); - handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites); - } else { - handshaker = new ClientHandshaker(this, sslContext, - enabledProtocols, - protocolVersion, connectionState == cs_HANDSHAKE, - secureRenegotiation, clientVerifyData, serverVerifyData); - handshaker.setSNIServerNames(serverNames); - } - handshaker.setEnabledCipherSuites(enabledCipherSuites); - handshaker.setEnableSessionCreation(enableSessionCreation); - handshaker.setApplicationProtocols(applicationProtocols); - handshaker.setApplicationProtocolSelectorSSLEngine( - applicationProtocolSelector); - } - - /* - * Report the current status of the Handshaker - */ - private HandshakeStatus getHSStatus(HandshakeStatus hss) { - - if (hss != null) { - return hss; - } - - synchronized (this) { - if (writer.hasOutboundData()) { - return HandshakeStatus.NEED_WRAP; - } else if (handshaker != null) { - if (handshaker.taskOutstanding()) { - return HandshakeStatus.NEED_TASK; - } else { - return HandshakeStatus.NEED_UNWRAP; - } - } else if (connectionState == cs_CLOSED) { - /* - * Special case where we're closing, but - * still need the close_notify before we - * can officially be closed. - * - * Note isOutboundDone is taken care of by - * hasOutboundData() above. - */ - if (!isInboundDone()) { - return HandshakeStatus.NEED_UNWRAP; - } // else not handshaking - } - return HandshakeStatus.NOT_HANDSHAKING; - } - } - - synchronized private void checkTaskThrown() throws SSLException { - if (handshaker != null) { - handshaker.checkThrown(); - } - } - - // - // Handshaking and connection state code - // - - /* - * Provides "this" synchronization for connection state. - * Otherwise, you can access it directly. - */ - synchronized private int getConnectionState() { - return connectionState; - } - - synchronized private void setConnectionState(int state) { - connectionState = state; - } - - /* - * Get the Access Control Context. - * - * Used for a known context to - * run tasks in, and for determining which credentials - * to use for Subject-based (JAAS) decisions. - */ - AccessControlContext getAcc() { - return acc; - } - - /* - * Is a handshake currently underway? - */ - @Override - public SSLEngineResult.HandshakeStatus getHandshakeStatus() { - return getHSStatus(null); - } - - /* - * When a connection finishes handshaking by enabling use of a newly - * negotiated session, each end learns about it in two halves (read, - * and write). When both read and write ciphers have changed, and the - * last handshake message has been read, the connection has joined - * (rejoined) the new session. - * - * NOTE: The SSLv3 spec is rather unclear on the concepts here. - * Sessions don't change once they're established (including cipher - * suite and master secret) but connections can join them (and leave - * them). They're created by handshaking, though sometime handshaking - * causes connections to join up with pre-established sessions. - * - * Synchronized on "this" from readRecord. - */ - private void changeReadCiphers() throws SSLException { - CipherBox oldCipher = readCipher; - - try { - readCipher = handshaker.newReadCipher(); - readAuthenticator = handshaker.newReadAuthenticator(); - } catch (GeneralSecurityException e) { - // "can't happen" - throw new SSLException("Algorithm missing: ", e); - } - - /* - * Dispose of any intermediate state in the underlying cipher. - * For PKCS11 ciphers, this will release any attached sessions, - * and thus make finalization faster. - * - * Since MAC's doFinal() is called for every SSL/TLS packet, it's - * not necessary to do the same with MAC's. - */ - oldCipher.dispose(); - } - - /* - * used by Handshaker to change the active write cipher, follows - * the output of the CCS message. - * - * Also synchronized on "this" from readRecord/delegatedTask. - */ - void changeWriteCiphers() throws SSLException { - if (connectionState != cs_HANDSHAKE - && connectionState != cs_RENEGOTIATE) { - throw new SSLProtocolException( - "State error, change cipher specs"); - } - - // ... create compressor - - CipherBox oldCipher = writeCipher; - - try { - writeCipher = handshaker.newWriteCipher(); - writeAuthenticator = handshaker.newWriteAuthenticator(); - } catch (GeneralSecurityException e) { - // "can't happen" - throw new SSLException("Algorithm missing: ", e); - } - - // See comment above. - oldCipher.dispose(); - - // reset the flag of the first application record - isFirstAppOutputRecord = true; - } - - /* - * Updates the SSL version associated with this connection. - * Called from Handshaker once it has determined the negotiated version. - */ - synchronized void setVersion(ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; - outputRecord.setVersion(protocolVersion); - } - - - /** - * Kickstart the handshake if it is not already in progress. - * This means: - * - * . if handshaking is already underway, do nothing and return - * - * . if the engine is not connected or already closed, throw an - * Exception. - * - * . otherwise, call initHandshake() to initialize the handshaker - * object and progress the state. Then, send the initial - * handshaking message if appropriate (always on clients and - * on servers when renegotiating). - */ - private synchronized void kickstartHandshake() throws IOException { - switch (connectionState) { - - case cs_START: - if (!serverModeSet) { - throw new IllegalStateException( - "Client/Server mode not yet set."); - } - initHandshaker(); - break; - - case cs_HANDSHAKE: - // handshaker already setup, proceed - break; - - case cs_DATA: - if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) { - throw new SSLHandshakeException( - "Insecure renegotiation is not allowed"); - } - - if (!secureRenegotiation) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning: Using insecure renegotiation"); - } - } - - // initialize the handshaker, move to cs_RENEGOTIATE - initHandshaker(); - break; - - case cs_RENEGOTIATE: - // handshaking already in progress, return - return; - - default: - // cs_ERROR/cs_CLOSED - throw new SSLException("SSLEngine is closing/closed"); - } - - // - // Kickstart handshake state machine if we need to ... - // - // Note that handshaker.kickstart() writes the message - // to its HandshakeOutStream, which calls back into - // SSLSocketImpl.writeRecord() to send it. - // - if (!handshaker.activated()) { - // prior to handshaking, activate the handshake - if (connectionState == cs_RENEGOTIATE) { - // don't use SSLv2Hello when renegotiating - handshaker.activate(protocolVersion); - } else { - handshaker.activate(null); - } - - if (handshaker instanceof ClientHandshaker) { - // send client hello - handshaker.kickstart(); - } else { // instanceof ServerHandshaker - if (connectionState == cs_HANDSHAKE) { - // initial handshake, no kickstart message to send - } else { - // we want to renegotiate, send hello request - handshaker.kickstart(); - - // hello request is not included in the handshake - // hashes, reset them - handshaker.handshakeHash.reset(); - } - } - } - } - - /* - * Start a SSLEngine handshake - */ - @Override - public void beginHandshake() throws SSLException { - try { - kickstartHandshake(); - } catch (Exception e) { - fatal(Alerts.alert_handshake_failure, - "Couldn't kickstart handshaking", e); - } - } - - - // - // Read/unwrap side - // - - - /** - * Unwraps a buffer. Does a variety of checks before grabbing - * the unwrapLock, which blocks multiple unwraps from occurring. - */ - @Override - public SSLEngineResult unwrap(ByteBuffer netData, ByteBuffer [] appData, - int offset, int length) throws SSLException { - - EngineArgs ea = new EngineArgs(netData, appData, offset, length); - - try { - synchronized (unwrapLock) { - return readNetRecord(ea); - } - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe); - return null; // make compiler happy - } catch (Exception e) { - /* - * Don't reset position so it looks like we didn't - * consume anything. We did consume something, and it - * got us into this situation, so report that much back. - * Our days of consuming are now over anyway. - */ - fatal(Alerts.alert_internal_error, - "problem unwrapping net record", e); - return null; // make compiler happy - } finally { - /* - * Just in case something failed to reset limits properly. - */ - ea.resetLim(); - } - } - - /* - * Makes additional checks for unwrap, but this time more - * specific to this packet and the current state of the machine. - */ - private SSLEngineResult readNetRecord(EngineArgs ea) throws IOException { - - Status status = null; - HandshakeStatus hsStatus = null; - - /* - * See if the handshaker needs to report back some SSLException. - */ - checkTaskThrown(); - - /* - * Check if we are closing/closed. - */ - if (isInboundDone()) { - return new SSLEngineResult(Status.CLOSED, getHSStatus(null), 0, 0); - } - - /* - * If we're still in cs_HANDSHAKE, make sure it's been - * started. - */ - synchronized (this) { - if ((connectionState == cs_HANDSHAKE) || - (connectionState == cs_START)) { - kickstartHandshake(); - - /* - * If there's still outbound data to flush, we - * can return without trying to unwrap anything. - */ - hsStatus = getHSStatus(null); - - if (hsStatus == HandshakeStatus.NEED_WRAP) { - return new SSLEngineResult(Status.OK, hsStatus, 0, 0); - } - } - } - - /* - * Grab a copy of this if it doesn't already exist, - * and we can use it several places before anything major - * happens on this side. Races aren't critical - * here. - */ - if (hsStatus == null) { - hsStatus = getHSStatus(null); - } - - /* - * If we have a task outstanding, this *MUST* be done before - * doing any more unwrapping, because we could be in the middle - * of receiving a handshake message, for example, a finished - * message which would change the ciphers. - */ - if (hsStatus == HandshakeStatus.NEED_TASK) { - return new SSLEngineResult( - Status.OK, hsStatus, 0, 0); - } - - /* - * Check the packet to make sure enough is here. - * This will also indirectly check for 0 len packets. - */ - int packetLen = inputRecord.bytesInCompletePacket(ea.netData); - - // Is this packet bigger than SSL/TLS normally allows? - if (packetLen > sess.getPacketBufferSize()) { - if (packetLen > Record.maxLargeRecordSize) { - throw new SSLProtocolException( - "Input SSL/TLS record too big: max = " + - Record.maxLargeRecordSize + - " len = " + packetLen); - } else { - // Expand the expected maximum packet/application buffer - // sizes. - sess.expandBufferSizes(); - } - } - - /* - * Check for OVERFLOW. - * - * To be considered: We could delay enforcing the application buffer - * free space requirement until after the initial handshaking. - */ - if ((packetLen - Record.headerSize) > ea.getAppRemaining()) { - return new SSLEngineResult(Status.BUFFER_OVERFLOW, hsStatus, 0, 0); - } - - // check for UNDERFLOW. - if ((packetLen == -1) || (ea.netData.remaining() < packetLen)) { - return new SSLEngineResult( - Status.BUFFER_UNDERFLOW, hsStatus, 0, 0); - } - - /* - * We're now ready to actually do the read. - * The only result code we really need to be exactly - * right is the HS finished, for signaling to - * HandshakeCompletedListeners. - */ - try { - hsStatus = readRecord(ea); - } catch (SSLException e) { - throw e; - } catch (IOException e) { - throw new SSLException("readRecord", e); - } - - /* - * Check the various condition that we could be reporting. - * - * It's *possible* something might have happened between the - * above and now, but it was better to minimally lock "this" - * during the read process. We'll return the current - * status, which is more representative of the current state. - * - * status above should cover: FINISHED, NEED_TASK - */ - status = (isInboundDone() ? Status.CLOSED : Status.OK); - hsStatus = getHSStatus(hsStatus); - - return new SSLEngineResult(status, hsStatus, - ea.deltaNet(), ea.deltaApp()); - } - - /* - * Actually do the read record processing. - * - * Returns a Status if it can make specific determinations - * of the engine state. In particular, we need to signal - * that a handshake just completed. - * - * It would be nice to be symmetrical with the write side and move - * the majority of this to EngineInputRecord, but there's too much - * SSLEngine state to do that cleanly. It must still live here. - */ - private HandshakeStatus readRecord(EngineArgs ea) throws IOException { - - HandshakeStatus hsStatus = null; - - /* - * The various operations will return new sliced BB's, - * this will avoid having to worry about positions and - * limits in the netBB. - */ - ByteBuffer readBB = null; - ByteBuffer decryptedBB = null; - - if (getConnectionState() != cs_ERROR) { - - /* - * Read a record ... maybe emitting an alert if we get a - * comprehensible but unsupported "hello" message during - * format checking (e.g. V2). - */ - try { - readBB = inputRecord.read(ea.netData); - } catch (IOException e) { - fatal(Alerts.alert_unexpected_message, e); - } - - /* - * The basic SSLv3 record protection involves (optional) - * encryption for privacy, and an integrity check ensuring - * data origin authentication. We do them both here, and - * throw a fatal alert if the integrity check fails. - */ - try { - decryptedBB = inputRecord.decrypt( - readAuthenticator, readCipher, readBB); - } catch (BadPaddingException e) { - byte alertType = (inputRecord.contentType() == - Record.ct_handshake) ? - Alerts.alert_handshake_failure : - Alerts.alert_bad_record_mac; - fatal(alertType, e.getMessage(), e); - } - - // if (!inputRecord.decompress(c)) - // fatal(Alerts.alert_decompression_failure, - // "decompression failure"); - - - /* - * Process the record. - */ - - synchronized (this) { - switch (inputRecord.contentType()) { - case Record.ct_handshake: - /* - * Handshake messages always go to a pending session - * handshaker ... if there isn't one, create one. This - * must work asynchronously, for renegotiation. - * - * NOTE that handshaking will either resume a session - * which was in the cache (and which might have other - * connections in it already), or else will start a new - * session (new keys exchanged) with just this connection - * in it. - */ - - initHandshaker(); - if (!handshaker.activated()) { - // prior to handshaking, activate the handshake - if (connectionState == cs_RENEGOTIATE) { - // don't use SSLv2Hello when renegotiating - handshaker.activate(protocolVersion); - } else { - handshaker.activate(null); - } - } - - /* - * process the handshake record ... may contain just - * a partial handshake message or multiple messages. - * - * The handshaker state machine will ensure that it's - * a finished message. - */ - handshaker.process_record(inputRecord, expectingFinished); - expectingFinished = false; - - if (handshaker.invalidated) { - handshaker = null; - // if state is cs_RENEGOTIATE, revert it to cs_DATA - if (connectionState == cs_RENEGOTIATE) { - connectionState = cs_DATA; - } - } else if (handshaker.isDone()) { - // reset the parameters for secure renegotiation. - secureRenegotiation = - handshaker.isSecureRenegotiation(); - clientVerifyData = handshaker.getClientVerifyData(); - serverVerifyData = handshaker.getServerVerifyData(); - // set connection ALPN value - applicationProtocol = - handshaker.getHandshakeApplicationProtocol(); - - sess = handshaker.getSession(); - handshakeSession = null; - if (!writer.hasOutboundData()) { - hsStatus = HandshakeStatus.FINISHED; - } - handshaker = null; - connectionState = cs_DATA; - // No handshakeListeners here. That's a - // SSLSocket thing. - } else if (handshaker.taskOutstanding()) { - hsStatus = HandshakeStatus.NEED_TASK; - } - break; - - case Record.ct_application_data: - // Pass this right back up to the application. - if ((connectionState != cs_DATA) - && (connectionState != cs_RENEGOTIATE) - && (connectionState != cs_CLOSED)) { - throw new SSLProtocolException( - "Data received in non-data state: " + - connectionState); - } - - if (expectingFinished) { - throw new SSLProtocolException - ("Expecting finished message, received data"); - } - - /* - * Don't return data once the inbound side is - * closed. - */ - if (!inboundDone) { - ea.scatter(decryptedBB.slice()); - } - break; - - case Record.ct_alert: - recvAlert(); - break; - - case Record.ct_change_cipher_spec: - if ((connectionState != cs_HANDSHAKE - && connectionState != cs_RENEGOTIATE)) { - // For the CCS message arriving in the wrong state - fatal(Alerts.alert_unexpected_message, - "illegal change cipher spec msg, conn state = " - + connectionState); - } else if (inputRecord.available() != 1 - || inputRecord.read() != 1) { - // For structural/content issues with the CCS - fatal(Alerts.alert_unexpected_message, - "Malformed change cipher spec msg"); - } - - // - // The first message after a change_cipher_spec - // record MUST be a "Finished" handshake record, - // else it's a protocol violation. We force this - // to be checked by a minor tweak to the state - // machine. - // - handshaker.receiveChangeCipherSpec(); - changeReadCiphers(); - // next message MUST be a finished message - expectingFinished = true; - break; - - default: - // - // TLS requires that unrecognized records be ignored. - // - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", Received record type: " - + inputRecord.contentType()); - } - break; - } // switch - - /* - * We only need to check the sequence number state for - * non-handshaking record. - * - * Note that in order to maintain the handshake status - * properly, we check the sequence number after the last - * record reading process. As we request renegotiation - * or close the connection for wrapped sequence number - * when there is enough sequence number space left to - * handle a few more records, so the sequence number - * of the last record cannot be wrapped. - */ - hsStatus = getHSStatus(hsStatus); - if (connectionState < cs_ERROR && !isInboundDone() && - (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(readAuthenticator, - inputRecord.contentType())) { - hsStatus = getHSStatus(null); - } - } - } // synchronized (this) - } - return hsStatus; - } - - - // - // write/wrap side - // - - - /** - * Wraps a buffer. Does a variety of checks before grabbing - * the wrapLock, which blocks multiple wraps from occurring. - */ - @Override - public SSLEngineResult wrap(ByteBuffer [] appData, - int offset, int length, ByteBuffer netData) throws SSLException { - - EngineArgs ea = new EngineArgs(appData, offset, length, netData); - - /* - * We can be smarter about using smaller buffer sizes later. - * For now, force it to be large enough to handle any - * valid SSL/TLS record. - */ - if (netData.remaining() < EngineOutputRecord.maxRecordSize) { - return new SSLEngineResult( - Status.BUFFER_OVERFLOW, getHSStatus(null), 0, 0); - } - - try { - synchronized (wrapLock) { - return writeAppRecord(ea); - } - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - fatal(Alerts.alert_unexpected_message, spe.getMessage(), spe); - return null; // make compiler happy - } catch (Exception e) { - ea.resetPos(); - - fatal(Alerts.alert_internal_error, - "problem wrapping app data", e); - return null; // make compiler happy - } finally { - /* - * Just in case something didn't reset limits properly. - */ - ea.resetLim(); - } - } - - /* - * Makes additional checks for unwrap, but this time more - * specific to this packet and the current state of the machine. - */ - private SSLEngineResult writeAppRecord(EngineArgs ea) throws IOException { - - Status status = null; - HandshakeStatus hsStatus = null; - - /* - * See if the handshaker needs to report back some SSLException. - */ - checkTaskThrown(); - /* - * short circuit if we're closed/closing. - */ - if (writer.isOutboundDone()) { - return new SSLEngineResult(Status.CLOSED, getHSStatus(null), 0, 0); - } - - /* - * If we're still in cs_HANDSHAKE, make sure it's been - * started. - */ - synchronized (this) { - if ((connectionState == cs_HANDSHAKE) || - (connectionState == cs_START)) { - kickstartHandshake(); - - /* - * If there's no HS data available to write, we can return - * without trying to wrap anything. - */ - hsStatus = getHSStatus(null); - if (hsStatus == HandshakeStatus.NEED_UNWRAP) { - return new SSLEngineResult(Status.OK, hsStatus, 0, 0); - } - } - } - - /* - * Grab a copy of this if it doesn't already exist, - * and we can use it several places before anything major - * happens on this side. Races aren't critical - * here. - */ - if (hsStatus == null) { - hsStatus = getHSStatus(null); - } - - /* - * If we have a task outstanding, this *MUST* be done before - * doing any more wrapping, because we could be in the middle - * of receiving a handshake message, for example, a finished - * message which would change the ciphers. - */ - if (hsStatus == HandshakeStatus.NEED_TASK) { - return new SSLEngineResult( - Status.OK, hsStatus, 0, 0); - } - - /* - * This will obtain any waiting outbound data, or will - * process the outbound appData. - */ - try { - synchronized (writeLock) { - hsStatus = writeRecord(outputRecord, ea); - } - } catch (SSLException e) { - throw e; - } catch (IOException e) { - throw new SSLException("Write problems", e); - } - - /* - * writeRecord might have reported some status. - * Now check for the remaining cases. - * - * status above should cover: NEED_WRAP/FINISHED - */ - status = (isOutboundDone() ? Status.CLOSED : Status.OK); - hsStatus = getHSStatus(hsStatus); - - return new SSLEngineResult(status, hsStatus, - ea.deltaApp(), ea.deltaNet()); - } - - /* - * Central point to write/get all of the outgoing data. - */ - private HandshakeStatus writeRecord(EngineOutputRecord eor, - EngineArgs ea) throws IOException { - - // eventually compress as well. - HandshakeStatus hsStatus = - writer.writeRecord(eor, ea, writeAuthenticator, writeCipher); - - /* - * We only need to check the sequence number state for - * non-handshaking record. - * - * Note that in order to maintain the handshake status - * properly, we check the sequence number after the last - * record writing process. As we request renegotiation - * or close the connection for wrapped sequence number - * when there is enough sequence number space left to - * handle a few more records, so the sequence number - * of the last record cannot be wrapped. - */ - hsStatus = getHSStatus(hsStatus); - if (connectionState < cs_ERROR && !isOutboundDone() && - (hsStatus == HandshakeStatus.NOT_HANDSHAKING)) { - if (checkSequenceNumber(writeAuthenticator, eor.contentType())) { - hsStatus = getHSStatus(null); - } - } - - /* - * turn off the flag of the first application record if we really - * consumed at least byte. - */ - if (isFirstAppOutputRecord && ea.deltaApp() > 0) { - isFirstAppOutputRecord = false; - } - - return hsStatus; - } - - /* - * Need to split the payload except the following cases: - * - * 1. protocol version is TLS 1.1 or later; - * 2. bulk cipher does not use CBC mode, including null bulk cipher suites. - * 3. the payload is the first application record of a freshly - * negotiated TLS session. - * 4. the CBC protection is disabled; - * - * More details, please refer to - * EngineOutputRecord.write(EngineArgs, MAC, CipherBox). - */ - boolean needToSplitPayload(CipherBox cipher, ProtocolVersion protocol) { - return (protocol.v <= ProtocolVersion.TLS10.v) && - cipher.isCBCMode() && !isFirstAppOutputRecord && - Record.enableCBCProtection; - } - - /* - * Non-application OutputRecords go through here. - */ - void writeRecord(EngineOutputRecord eor) throws IOException { - // eventually compress as well. - writer.writeRecord(eor, writeAuthenticator, writeCipher); - - /* - * Check the sequence number state - * - * Note that in order to maintain the connection I/O - * properly, we check the sequence number after the last - * record writing process. As we request renegotiation - * or close the connection for wrapped sequence number - * when there is enough sequence number space left to - * handle a few more records, so the sequence number - * of the last record cannot be wrapped. - */ - if ((connectionState < cs_ERROR) && !isOutboundDone()) { - checkSequenceNumber(writeAuthenticator, eor.contentType()); - } - } - - // - // Close code - // - - /** - * Check the sequence number state - * - * RFC 4346 states that, "Sequence numbers are of type uint64 and - * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead." - * - * Return true if the handshake status may be changed. - */ - private boolean checkSequenceNumber(Authenticator authenticator, byte type) - throws IOException { - - /* - * Don't bother to check the sequence number for error or - * closed connections, or NULL MAC - */ - if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { - return false; - } - - /* - * Conservatively, close the connection immediately when the - * sequence number is close to overflow - */ - if (authenticator.seqNumOverflow()) { - /* - * TLS protocols do not define a error alert for sequence - * number overflow. We use handshake_failure error alert - * for handshaking and bad_record_mac for other records. - */ - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", sequence number extremely close to overflow " + - "(2^64-1 packets). Closing connection."); - } - - fatal(Alerts.alert_handshake_failure, "sequence number overflow"); - - return true; // make the compiler happy - } - - /* - * Ask for renegotiation when need to renew sequence number. - * - * Don't bother to kickstart the renegotiation when the local is - * asking for it. - */ - if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", request renegotiation " + - "to avoid sequence number overflow"); - } - - beginHandshake(); - return true; - } - - return false; - } - - /** - * Signals that no more outbound application data will be sent - * on this <code>SSLEngine</code>. - */ - private void closeOutboundInternal() { - - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", closeOutboundInternal()"); - } - - /* - * Already closed, ignore - */ - if (writer.isOutboundDone()) { - return; - } - - switch (connectionState) { - - /* - * If we haven't even started yet, don't bother reading inbound. - */ - case cs_START: - writer.closeOutbound(); - inboundDone = true; - break; - - case cs_ERROR: - case cs_CLOSED: - break; - - /* - * Otherwise we indicate clean termination. - */ - // case cs_HANDSHAKE: - // case cs_DATA: - // case cs_RENEGOTIATE: - default: - warning(Alerts.alert_close_notify); - writer.closeOutbound(); - break; - } - - // See comment in changeReadCiphers() - writeCipher.dispose(); - - connectionState = cs_CLOSED; - } - - @Override - synchronized public void closeOutbound() { - /* - * Dump out a close_notify to the remote side - */ - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called closeOutbound()"); - } - - closeOutboundInternal(); - } - - /** - * Returns the outbound application data closure state - */ - @Override - public boolean isOutboundDone() { - return writer.isOutboundDone(); - } - - /** - * Signals that no more inbound network data will be sent - * to this <code>SSLEngine</code>. - */ - private void closeInboundInternal() { - - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", closeInboundInternal()"); - } - - /* - * Already closed, ignore - */ - if (inboundDone) { - return; - } - - closeOutboundInternal(); - inboundDone = true; - - // See comment in changeReadCiphers() - readCipher.dispose(); - - connectionState = cs_CLOSED; - } - - /* - * Close the inbound side of the connection. We grab the - * lock here, and do the real work in the internal verison. - * We do check for truncation attacks. - */ - @Override - synchronized public void closeInbound() throws SSLException { - /* - * Currently closes the outbound side as well. The IETF TLS - * working group has expressed the opinion that 1/2 open - * connections are not allowed by the spec. May change - * someday in the future. - */ - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called closeInbound()"); - } - - /* - * No need to throw an Exception if we haven't even started yet. - */ - if ((connectionState != cs_START) && !recvCN) { - recvCN = true; // Only receive the Exception once - fatal(Alerts.alert_internal_error, - "Inbound closed before receiving peer's close_notify: " + - "possible truncation attack?"); - } else { - /* - * Currently, this is a no-op, but in case we change - * the close inbound code later. - */ - closeInboundInternal(); - } - } - - /** - * Returns the network inbound data closure state - */ - @Override - synchronized public boolean isInboundDone() { - return inboundDone; - } - - - // - // Misc stuff - // - - - /** - * Returns the current <code>SSLSession</code> for this - * <code>SSLEngine</code> - * <P> - * These can be long lived, and frequently correspond to an - * entire login session for some user. - */ - @Override - synchronized public SSLSession getSession() { - return sess; - } - - @Override - synchronized public SSLSession getHandshakeSession() { - return handshakeSession; - } - - synchronized void setHandshakeSession(SSLSessionImpl session) { - handshakeSession = session; - } - - /** - * Returns a delegated <code>Runnable</code> task for - * this <code>SSLEngine</code>. - */ - @Override - synchronized public Runnable getDelegatedTask() { - if (handshaker != null) { - return handshaker.getTask(); - } - return null; - } - - - // - // EXCEPTION AND ALERT HANDLING - // - - /* - * Send a warning alert. - */ - void warning(byte description) { - sendAlert(Alerts.alert_warning, description); - } - - synchronized void fatal(byte description, String diagnostic) - throws SSLException { - fatal(description, diagnostic, null); - } - - synchronized void fatal(byte description, Throwable cause) - throws SSLException { - fatal(description, null, cause); - } - - /* - * We've got a fatal error here, so start the shutdown process. - * - * Because of the way the code was written, we have some code - * calling fatal directly when the "description" is known - * and some throwing Exceptions which are then caught by higher - * levels which then call here. This code needs to determine - * if one of the lower levels has already started the process. - * - * We won't worry about Error's, if we have one of those, - * we're in worse trouble. Note: the networking code doesn't - * deal with Errors either. - */ - synchronized void fatal(byte description, String diagnostic, - Throwable cause) throws SSLException { - - /* - * If we have no further information, make a general-purpose - * message for folks to see. We generally have one or the other. - */ - if (diagnostic == null) { - diagnostic = "General SSLEngine problem"; - } - if (cause == null) { - cause = Alerts.getSSLException(description, cause, diagnostic); - } - - /* - * If we've already shutdown because of an error, - * there is nothing we can do except rethrow the exception. - * - * Most exceptions seen here will be SSLExceptions. - * We may find the occasional Exception which hasn't been - * converted to a SSLException, so we'll do it here. - */ - if (closeReason != null) { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", fatal: engine already closed. Rethrowing " + - cause.toString()); - } - if (cause instanceof RuntimeException) { - throw (RuntimeException)cause; - } else if (cause instanceof SSLException) { - throw (SSLException)cause; - } else if (cause instanceof Exception) { - throw new SSLException("fatal SSLEngine condition", cause); - } - } - - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() - + ", fatal error: " + description + - ": " + diagnostic + "\n" + cause.toString()); - } - - /* - * Ok, this engine's going down. - */ - int oldState = connectionState; - connectionState = cs_ERROR; - - inboundDone = true; - - sess.invalidate(); - if (handshakeSession != null) { - handshakeSession.invalidate(); - } - - /* - * If we haven't even started handshaking yet, no need - * to generate the fatal close alert. - */ - if (oldState != cs_START) { - sendAlert(Alerts.alert_fatal, description); - } - - if (cause instanceof SSLException) { // only true if != null - closeReason = (SSLException)cause; - } else { - /* - * Including RuntimeExceptions, but we'll throw those - * down below. The closeReason isn't used again, - * except for null checks. - */ - closeReason = - Alerts.getSSLException(description, cause, diagnostic); - } - - writer.closeOutbound(); - - connectionState = cs_CLOSED; - - // See comment in changeReadCiphers() - readCipher.dispose(); - writeCipher.dispose(); - - if (cause instanceof RuntimeException) { - throw (RuntimeException)cause; - } else { - throw closeReason; - } - } - - /* - * Process an incoming alert ... caller must already have synchronized - * access to "this". - */ - private void recvAlert() throws IOException { - byte level = (byte)inputRecord.read(); - byte description = (byte)inputRecord.read(); - if (description == -1) { // check for short message - fatal(Alerts.alert_illegal_parameter, "Short alert message"); - } - - if (debug != null && (Debug.isOn("record") || - Debug.isOn("handshake"))) { - synchronized (System.out) { - System.out.print(Thread.currentThread().getName()); - System.out.print(", RECV " + protocolVersion + " ALERT: "); - if (level == Alerts.alert_fatal) { - System.out.print("fatal, "); - } else if (level == Alerts.alert_warning) { - System.out.print("warning, "); - } else { - System.out.print("<level " + (0x0ff & level) + ">, "); - } - System.out.println(Alerts.alertDescription(description)); - } - } - - if (level == Alerts.alert_warning) { - if (description == Alerts.alert_close_notify) { - if (connectionState == cs_HANDSHAKE) { - fatal(Alerts.alert_unexpected_message, - "Received close_notify during handshake"); - } else { - recvCN = true; - closeInboundInternal(); // reply to close - } - } else { - - // - // The other legal warnings relate to certificates, - // e.g. no_certificate, bad_certificate, etc; these - // are important to the handshaking code, which can - // also handle illegal protocol alerts if needed. - // - if (handshaker != null) { - handshaker.handshakeAlert(description); - } - } - } else { // fatal or unknown level - String reason = "Received fatal alert: " - + Alerts.alertDescription(description); - if (closeReason == null) { - closeReason = Alerts.getSSLException(description, reason); - } - fatal(Alerts.alert_unexpected_message, reason); - } - } - - - /* - * Emit alerts. Caller must have synchronized with "this". - */ - private void sendAlert(byte level, byte description) { - // the connectionState cannot be cs_START - if (connectionState >= cs_CLOSED) { - return; - } - - // For initial handshaking, don't send alert message to peer if - // handshaker has not started. - if (connectionState == cs_HANDSHAKE && - (handshaker == null || !handshaker.started())) { - return; - } - - EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this); - r.setVersion(protocolVersion); - - boolean useDebug = debug != null && Debug.isOn("ssl"); - if (useDebug) { - synchronized (System.out) { - System.out.print(Thread.currentThread().getName()); - System.out.print(", SEND " + protocolVersion + " ALERT: "); - if (level == Alerts.alert_fatal) { - System.out.print("fatal, "); - } else if (level == Alerts.alert_warning) { - System.out.print("warning, "); - } else { - System.out.print("<level = " + (0x0ff & level) + ">, "); - } - System.out.println("description = " - + Alerts.alertDescription(description)); - } - } - - r.write(level); - r.write(description); - try { - writeRecord(r); - } catch (IOException e) { - if (useDebug) { - System.out.println(Thread.currentThread().getName() + - ", Exception sending alert: " + e); - } - } - } - - - // - // VARIOUS OTHER METHODS (COMMON TO SSLSocket) - // - - - /** - * Controls whether new connections may cause creation of new SSL - * sessions. - * - * As long as handshaking has not started, we can change - * whether we enable session creations. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setEnableSessionCreation(boolean flag) { - enableSessionCreation = flag; - - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnableSessionCreation(enableSessionCreation); - } - } - - /** - * Returns true if new connections may cause creation of new SSL - * sessions. - */ - @Override - synchronized public boolean getEnableSessionCreation() { - return enableSessionCreation; - } - - - /** - * Sets the flag controlling whether a server mode engine - * *REQUIRES* SSL client authentication. - * - * As long as handshaking has not started, we can change - * whether client authentication is needed. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setNeedClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); - - if ((handshaker != null) && - (handshaker instanceof ServerHandshaker) && - !handshaker.activated()) { - ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); - } - } - - @Override - synchronized public boolean getNeedClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_required); - } - - /** - * Sets the flag controlling whether a server mode engine - * *REQUESTS* SSL client authentication. - * - * As long as handshaking has not started, we can change - * whether client authentication is requested. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setWantClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); - - if ((handshaker != null) && - (handshaker instanceof ServerHandshaker) && - !handshaker.activated()) { - ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); - } - } - - @Override - synchronized public boolean getWantClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_requested); - } - - - /** - * Sets the flag controlling whether the engine is in SSL - * client or server mode. Must be called before any SSL - * traffic has started. - */ - @Override - @SuppressWarnings("fallthrough") - synchronized public void setUseClientMode(boolean flag) { - switch (connectionState) { - - case cs_START: - /* - * If we need to change the socket mode and the enabled - * protocols and cipher suites haven't specifically been - * set by the user, change them to the corresponding - * default ones. - */ - if (roleIsServer != (!flag)) { - if (sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = - sslContext.getDefaultProtocolList(!flag); - } - - if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) { - enabledCipherSuites = - sslContext.getDefaultCipherSuiteList(!flag); - } - } - - roleIsServer = !flag; - serverModeSet = true; - break; - - case cs_HANDSHAKE: - /* - * If we have a handshaker, but haven't started - * SSL traffic, we can throw away our current - * handshaker, and start from scratch. Don't - * need to call doneConnect() again, we already - * have the streams. - */ - assert(handshaker != null); - if (!handshaker.activated()) { - /* - * If we need to change the engine mode and the enabled - * protocols haven't specifically been set by the user, - * change them to the corresponding default ones. - */ - if (roleIsServer != (!flag) && - sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = sslContext.getDefaultProtocolList(!flag); - } - - roleIsServer = !flag; - connectionState = cs_START; - initHandshaker(); - break; - } - - // If handshake has started, that's an error. Fall through... - - default: - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", setUseClientMode() invoked in state = " + - connectionState); - } - - /* - * We can let them continue if they catch this correctly, - * we don't need to shut this down. - */ - throw new IllegalArgumentException( - "Cannot change mode after SSL traffic has started"); - } - } - - @Override - synchronized public boolean getUseClientMode() { - return !roleIsServer; - } - - - /** - * Returns the names of the cipher suites which could be enabled for use - * on an SSL connection. Normally, only a subset of these will actually - * be enabled by default, since this list may include cipher suites which - * do not support the mutual authentication of servers and clients, or - * which do not protect data confidentiality. Servers may also need - * certain kinds of certificates to use certain cipher suites. - * - * @return an array of cipher suite names - */ - @Override - public String[] getSupportedCipherSuites() { - return sslContext.getSupportedCipherSuiteList().toStringArray(); - } - - /** - * Controls which particular cipher suites are enabled for use on - * this connection. The cipher suites must have been listed by - * getCipherSuites() as being supported. Even if a suite has been - * enabled, it might never be used if no peer supports it or the - * requisite certificates (and private keys) are not available. - * - * @param suites Names of all the cipher suites to enable. - */ - @Override - synchronized public void setEnabledCipherSuites(String[] suites) { - enabledCipherSuites = new CipherSuiteList(suites); - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnabledCipherSuites(enabledCipherSuites); - } - } - - /** - * Returns the names of the SSL cipher suites which are currently enabled - * for use on this connection. When an SSL engine is first created, - * all enabled cipher suites <em>(a)</em> protect data confidentiality, - * by traffic encryption, and <em>(b)</em> can mutually authenticate - * both clients and servers. Thus, in some environments, this value - * might be empty. - * - * @return an array of cipher suite names - */ - @Override - synchronized public String[] getEnabledCipherSuites() { - return enabledCipherSuites.toStringArray(); - } - - - /** - * Returns the protocols that are supported by this implementation. - * A subset of the supported protocols may be enabled for this connection - * @return an array of protocol names. - */ - @Override - public String[] getSupportedProtocols() { - return sslContext.getSuportedProtocolList().toStringArray(); - } - - /** - * Controls which protocols are enabled for use on - * this connection. The protocols must have been listed by - * getSupportedProtocols() as being supported. - * - * @param protocols protocols to enable. - * @exception IllegalArgumentException when one of the protocols - * named by the parameter is not supported. - */ - @Override - synchronized public void setEnabledProtocols(String[] protocols) { - enabledProtocols = new ProtocolList(protocols); - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnabledProtocols(enabledProtocols); - } - } - - @Override - synchronized public String[] getEnabledProtocols() { - return enabledProtocols.toStringArray(); - } - - /** - * Returns the SSLParameters in effect for this SSLEngine. - */ - @Override - synchronized public SSLParameters getSSLParameters() { - SSLParameters params = super.getSSLParameters(); - - // the super implementation does not handle the following parameters - params.setEndpointIdentificationAlgorithm(identificationProtocol); - params.setAlgorithmConstraints(algorithmConstraints); - params.setSNIMatchers(sniMatchers); - params.setServerNames(serverNames); - params.setUseCipherSuitesOrder(preferLocalCipherSuites); - params.setApplicationProtocols(applicationProtocols); - - return params; - } - - /** - * Applies SSLParameters to this engine. - */ - @Override - synchronized public void setSSLParameters(SSLParameters params) { - super.setSSLParameters(params); - - // the super implementation does not handle the following parameters - identificationProtocol = params.getEndpointIdentificationAlgorithm(); - algorithmConstraints = params.getAlgorithmConstraints(); - preferLocalCipherSuites = params.getUseCipherSuitesOrder(); - - List<SNIServerName> sniNames = params.getServerNames(); - if (sniNames != null) { - serverNames = sniNames; - } - - Collection<SNIMatcher> matchers = params.getSNIMatchers(); - if (matchers != null) { - sniMatchers = matchers; - } - applicationProtocols = params.getApplicationProtocols(); - - if ((handshaker != null) && !handshaker.started()) { - handshaker.setIdentificationProtocol(identificationProtocol); - handshaker.setAlgorithmConstraints(algorithmConstraints); - applicationProtocols = params.getApplicationProtocols(); - if (roleIsServer) { - handshaker.setSNIMatchers(sniMatchers); - handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites); - } else { - handshaker.setSNIServerNames(serverNames); - } - } - } - - @Override - public synchronized String getApplicationProtocol() { - return applicationProtocol; - } - - @Override - public synchronized String getHandshakeApplicationProtocol() { - if ((handshaker != null) && handshaker.started()) { - return handshaker.getHandshakeApplicationProtocol(); - } - return null; - } - - @Override - public synchronized void setHandshakeApplicationProtocolSelector( - BiFunction<SSLEngine, List<String>, String> selector) { - applicationProtocolSelector = selector; - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setApplicationProtocolSelectorSSLEngine(selector); - } - } - - @Override - public synchronized BiFunction<SSLEngine, List<String>, String> - getHandshakeApplicationProtocolSelector() { - return this.applicationProtocolSelector; - } - - /** - * Returns a printable representation of this end of the connection. - */ - @Override - public String toString() { - StringBuilder retval = new StringBuilder(80); - - retval.append(Integer.toHexString(hashCode())); - retval.append("["); - retval.append("SSLEngine[hostname="); - String host = getPeerHost(); - retval.append((host == null) ? "null" : host); - retval.append(" port="); - retval.append(Integer.toString(getPeerPort())); - retval.append("] "); - retval.append(getSession().getCipherSuite()); - retval.append("]"); - - return retval.toString(); - } -}
--- a/src/share/classes/sun/security/ssl/SSLServerSocketFactoryImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.net.InetAddress; -import java.net.ServerSocket; - -import javax.net.ssl.SSLServerSocketFactory; - -/** - * This class creates SSL server sockets. - * - * @author David Brownell - */ -final -public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory -{ - private static final int DEFAULT_BACKLOG = 50; - private SSLContextImpl context; - - - /** - * Constructor used to instantiate the default factory. This method is - * only called if the old "ssl.ServerSocketFactory.provider" property in the - * java.security file is set. - */ - public SSLServerSocketFactoryImpl() throws Exception { - this.context = SSLContextImpl.DefaultSSLContext.getDefaultImpl(); - } - - /** - * Called from SSLContextImpl's getSSLServerSocketFactory(). - */ - SSLServerSocketFactoryImpl (SSLContextImpl context) - { - this.context = context; - } - - /** - * Returns an unbound server socket. - * - * @return the unbound socket - * @throws IOException if the socket cannot be created - * @see java.net.Socket#bind(java.net.SocketAddress) - */ - @Override - public ServerSocket createServerSocket() throws IOException { - return new SSLServerSocketImpl(context); - } - - @Override - public ServerSocket createServerSocket (int port) - throws IOException - { - return new SSLServerSocketImpl (port, DEFAULT_BACKLOG, context); - } - - - @Override - public ServerSocket createServerSocket (int port, int backlog) - throws IOException - { - return new SSLServerSocketImpl (port, backlog, context); - } - - @Override - public ServerSocket - createServerSocket (int port, int backlog, InetAddress ifAddress) - throws IOException - { - return new SSLServerSocketImpl (port, backlog, ifAddress, context); - } - - /** - * Returns the subset of the supported cipher suites which are - * enabled by default. These cipher suites all provide a minimum - * quality of service whereby the server authenticates itself - * (preventing person-in-the-middle attacks) and where traffic - * is encrypted to provide confidentiality. - */ - @Override - public String[] getDefaultCipherSuites() { - return context.getDefaultCipherSuiteList(true).toStringArray(); - } - - /** - * Returns the names of the cipher suites which could be enabled for use - * on an SSL connection. Normally, only a subset of these will actually - * be enabled by default, since this list may include cipher suites which - * do not support the mutual authentication of servers and clients, or - * which do not protect data confidentiality. Servers may also need - * certain kinds of certificates to use certain cipher suites. - * - * @return an array of cipher suite names - */ - @Override - public String[] getSupportedCipherSuites() { - return context.getSupportedCipherSuiteList().toStringArray(); - } - -}
--- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,364 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.net.InetAddress; -import java.net.Socket; - -import java.security.AlgorithmConstraints; - -import java.util.*; - -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLParameters; -import javax.net.ssl.SNIMatcher; - - -/** - * This class provides a simple way for servers to support conventional - * use of the Secure Sockets Layer (SSL). Application code uses an - * SSLServerSocketImpl exactly like it uses a regular TCP ServerSocket; the - * difference is that the connections established are secured using SSL. - * - * <P> Also, the constructors take an explicit authentication context - * parameter, giving flexibility with respect to how the server socket - * authenticates itself. That policy flexibility is not exposed through - * the standard SSLServerSocketFactory API. - * - * <P> System security defaults prevent server sockets from accepting - * connections if they the authentication context has not been given - * a certificate chain and its matching private key. If the clients - * of your application support "anonymous" cipher suites, you may be - * able to configure a server socket to accept those suites. - * - * @see SSLSocketImpl - * @see SSLServerSocketFactoryImpl - * - * @author David Brownell - */ -final -class SSLServerSocketImpl extends SSLServerSocket -{ - private SSLContextImpl sslContext; - - /* Do newly accepted connections require clients to authenticate? */ - private byte doClientAuth = SSLEngineImpl.clauth_none; - - /* Do new connections created here use the "server" mode of SSL? */ - private boolean useServerMode = true; - - /* Can new connections created establish new sessions? */ - private boolean enableSessionCreation = true; - - /* what cipher suites to use by default */ - private CipherSuiteList enabledCipherSuites = null; - - /* which protocol to use by default */ - private ProtocolList enabledProtocols = null; - - // the endpoint identification protocol to use by default - private String identificationProtocol = null; - - // The cryptographic algorithm constraints - private AlgorithmConstraints algorithmConstraints = null; - - // The server name indication - Collection<SNIMatcher> sniMatchers = - Collections.<SNIMatcher>emptyList(); - - // Configured application protocol values - String[] applicationProtocols = new String[0]; - - /* - * Whether local cipher suites preference in server side should be - * honored during handshaking? - */ - private boolean preferLocalCipherSuites = false; - - /** - * Create an SSL server socket on a port, using a non-default - * authentication context and a specified connection backlog. - * - * @param port the port on which to listen - * @param backlog how many connections may be pending before - * the system should start rejecting new requests - * @param context authentication context for this server - */ - SSLServerSocketImpl(int port, int backlog, SSLContextImpl context) - throws IOException, SSLException - { - super(port, backlog); - initServer(context); - } - - - /** - * Create an SSL server socket on a port, using a specified - * authentication context and a specified backlog of connections - * as well as a particular specified network interface. This - * constructor is used on multihomed hosts, such as those used - * for firewalls or as routers, to control through which interface - * a network service is provided. - * - * @param port the port on which to listen - * @param backlog how many connections may be pending before - * the system should start rejecting new requests - * @param address the address of the network interface through - * which connections will be accepted - * @param context authentication context for this server - */ - SSLServerSocketImpl( - int port, - int backlog, - InetAddress address, - SSLContextImpl context) - throws IOException - { - super(port, backlog, address); - initServer(context); - } - - - /** - * Creates an unbound server socket. - */ - SSLServerSocketImpl(SSLContextImpl context) throws IOException { - super(); - initServer(context); - } - - - /** - * Initializes the server socket. - */ - private void initServer(SSLContextImpl context) throws SSLException { - if (context == null) { - throw new SSLException("No Authentication context given"); - } - sslContext = context; - enabledCipherSuites = sslContext.getDefaultCipherSuiteList(true); - enabledProtocols = sslContext.getDefaultProtocolList(true); - } - - /** - * Returns the names of the cipher suites which could be enabled for use - * on an SSL connection. Normally, only a subset of these will actually - * be enabled by default, since this list may include cipher suites which - * do not support the mutual authentication of servers and clients, or - * which do not protect data confidentiality. Servers may also need - * certain kinds of certificates to use certain cipher suites. - * - * @return an array of cipher suite names - */ - @Override - public String[] getSupportedCipherSuites() { - return sslContext.getSupportedCipherSuiteList().toStringArray(); - } - - /** - * Returns the list of cipher suites which are currently enabled - * for use by newly accepted connections. A null return indicates - * that the system defaults are in effect. - */ - @Override - synchronized public String[] getEnabledCipherSuites() { - return enabledCipherSuites.toStringArray(); - } - - /** - * Controls which particular SSL cipher suites are enabled for use - * by accepted connections. - * - * @param suites Names of all the cipher suites to enable; null - * means to accept system defaults. - */ - @Override - synchronized public void setEnabledCipherSuites(String[] suites) { - enabledCipherSuites = new CipherSuiteList(suites); - } - - @Override - public String[] getSupportedProtocols() { - return sslContext.getSuportedProtocolList().toStringArray(); - } - - /** - * Controls which protocols are enabled for use. - * The protocols must have been listed by - * getSupportedProtocols() as being supported. - * - * @param protocols protocols to enable. - * @exception IllegalArgumentException when one of the protocols - * named by the parameter is not supported. - */ - @Override - synchronized public void setEnabledProtocols(String[] protocols) { - enabledProtocols = new ProtocolList(protocols); - } - - @Override - synchronized public String[] getEnabledProtocols() { - return enabledProtocols.toStringArray(); - } - - /** - * Controls whether the connections which are accepted must include - * client authentication. - */ - @Override - public void setNeedClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); - } - - @Override - public boolean getNeedClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_required); - } - - /** - * Controls whether the connections which are accepted should request - * client authentication. - */ - @Override - public void setWantClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); - } - - @Override - public boolean getWantClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_requested); - } - - /** - * Makes the returned sockets act in SSL "client" mode, not the usual - * server mode. The canonical example of why this is needed is for - * FTP clients, which accept connections from servers and should be - * rejoining the already-negotiated SSL connection. - */ - @Override - public void setUseClientMode(boolean flag) { - /* - * If we need to change the socket mode and the enabled - * protocols haven't specifically been set by the user, - * change them to the corresponding default ones. - */ - if (useServerMode != (!flag) && - sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = sslContext.getDefaultProtocolList(!flag); - } - - useServerMode = !flag; - } - - @Override - public boolean getUseClientMode() { - return !useServerMode; - } - - - /** - * Controls whether new connections may cause creation of new SSL - * sessions. - */ - @Override - public void setEnableSessionCreation(boolean flag) { - enableSessionCreation = flag; - } - - /** - * Returns true if new connections may cause creation of new SSL - * sessions. - */ - @Override - public boolean getEnableSessionCreation() { - return enableSessionCreation; - } - - /** - * Returns the SSLParameters in effect for newly accepted connections. - */ - @Override - synchronized public SSLParameters getSSLParameters() { - SSLParameters params = super.getSSLParameters(); - - // the super implementation does not handle the following parameters - params.setEndpointIdentificationAlgorithm(identificationProtocol); - params.setAlgorithmConstraints(algorithmConstraints); - params.setSNIMatchers(sniMatchers); - params.setUseCipherSuitesOrder(preferLocalCipherSuites); - params.setApplicationProtocols(applicationProtocols); - - return params; - } - - /** - * Applies SSLParameters to newly accepted connections. - */ - @Override - synchronized public void setSSLParameters(SSLParameters params) { - super.setSSLParameters(params); - - // the super implementation does not handle the following parameters - identificationProtocol = params.getEndpointIdentificationAlgorithm(); - algorithmConstraints = params.getAlgorithmConstraints(); - preferLocalCipherSuites = params.getUseCipherSuitesOrder(); - Collection<SNIMatcher> matchers = params.getSNIMatchers(); - if (matchers != null) { - sniMatchers = params.getSNIMatchers(); - } - applicationProtocols = params.getApplicationProtocols(); - } - - /** - * Accept a new SSL connection. This server identifies itself with - * information provided in the authentication context which was - * presented during construction. - */ - @Override - public Socket accept() throws IOException { - SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode, - enabledCipherSuites, doClientAuth, enableSessionCreation, - enabledProtocols, identificationProtocol, algorithmConstraints, - sniMatchers, preferLocalCipherSuites, applicationProtocols); - - implAccept(s); - s.doneConnect(); - return s; - } - - /** - * Provides a brief description of this SSL socket. - */ - @Override - public String toString() { - return "[SSL: "+ super.toString() + "]"; - } -}
--- a/src/share/classes/sun/security/ssl/SSLSessionContextImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,255 +0,0 @@ -/* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.Enumeration; -import java.util.Vector; -import java.util.Locale; - -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; - -import sun.security.action.GetIntegerAction; -import sun.security.util.Cache; - - -final class SSLSessionContextImpl implements SSLSessionContext { - private final static int DEFAULT_MAX_CACHE_SIZE = 20480; - - private Cache<SessionId, SSLSessionImpl> sessionCache; - // session cache, session id as key - private Cache<String, SSLSessionImpl> sessionHostPortCache; - // session cache, "host:port" as key - private int cacheLimit; // the max cache size - private int timeout; // timeout in seconds - - // package private - SSLSessionContextImpl() { - cacheLimit = getDefaultCacheLimit(); // default cache size - timeout = 86400; // default, 24 hours - - // use soft reference - sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); - sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout); - } - - /** - * Returns the <code>SSLSession</code> bound to the specified session id. - */ - @Override - public SSLSession getSession(byte[] sessionId) { - if (sessionId == null) { - throw new NullPointerException("session id cannot be null"); - } - - SSLSessionImpl sess = sessionCache.get(new SessionId(sessionId)); - if (!isTimedout(sess)) { - return sess; - } - - return null; - } - - /** - * Returns an enumeration of the active SSL sessions. - */ - @Override - public Enumeration<byte[]> getIds() { - SessionCacheVisitor scVisitor = new SessionCacheVisitor(); - sessionCache.accept(scVisitor); - - return scVisitor.getSessionIds(); - } - - /** - * Sets the timeout limit for cached <code>SSLSession</code> objects - * - * Note that after reset the timeout, the cached session before - * should be timed within the shorter one of the old timeout and the - * new timeout. - */ - @Override - public void setSessionTimeout(int seconds) - throws IllegalArgumentException { - if (seconds < 0) { - throw new IllegalArgumentException(); - } - - if (timeout != seconds) { - sessionCache.setTimeout(seconds); - sessionHostPortCache.setTimeout(seconds); - timeout = seconds; - } - } - - /** - * Gets the timeout limit for cached <code>SSLSession</code> objects - */ - @Override - public int getSessionTimeout() { - return timeout; - } - - /** - * Sets the size of the cache used for storing - * <code>SSLSession</code> objects. - */ - @Override - public void setSessionCacheSize(int size) - throws IllegalArgumentException { - if (size < 0) - throw new IllegalArgumentException(); - - if (cacheLimit != size) { - sessionCache.setCapacity(size); - sessionHostPortCache.setCapacity(size); - cacheLimit = size; - } - } - - /** - * Gets the size of the cache used for storing - * <code>SSLSession</code> objects. - */ - @Override - public int getSessionCacheSize() { - return cacheLimit; - } - - - // package-private method, used ONLY by ServerHandshaker - SSLSessionImpl get(byte[] id) { - return (SSLSessionImpl)getSession(id); - } - - // package-private method, used ONLY by ClientHandshaker - SSLSessionImpl get(String hostname, int port) { - /* - * If no session caching info is available, we won't - * get one, so exit before doing a lookup. - */ - if (hostname == null && port == -1) { - return null; - } - - SSLSessionImpl sess = sessionHostPortCache.get(getKey(hostname, port)); - if (!isTimedout(sess)) { - return sess; - } - - return null; - } - - private String getKey(String hostname, int port) { - return (hostname + ":" + - String.valueOf(port)).toLowerCase(Locale.ENGLISH); - } - - // cache a SSLSession - // - // In SunJSSE implementation, a session is created while getting a - // client hello or a server hello message, and cached while the - // handshaking finished. - // Here we time the session from the time it cached instead of the - // time it created, which is a little longer than the expected. So - // please do check isTimedout() while getting entry from the cache. - void put(SSLSessionImpl s) { - sessionCache.put(s.getSessionId(), s); - - // If no hostname/port info is available, don't add this one. - if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) { - sessionHostPortCache.put( - getKey(s.getPeerHost(), s.getPeerPort()), s); - } - - s.setContext(this); - } - - // package-private method, remove a cached SSLSession - void remove(SessionId key) { - SSLSessionImpl s = sessionCache.get(key); - if (s != null) { - sessionCache.remove(key); - sessionHostPortCache.remove( - getKey(s.getPeerHost(), s.getPeerPort())); - } - } - - private int getDefaultCacheLimit() { - try { - int defaultCacheLimit = - java.security.AccessController.doPrivileged( - new GetIntegerAction("javax.net.ssl.sessionCacheSize", - DEFAULT_MAX_CACHE_SIZE)).intValue(); - - if (defaultCacheLimit >= 0) { - return defaultCacheLimit; - } - } catch (Exception e) { - } - - return DEFAULT_MAX_CACHE_SIZE; - } - - boolean isTimedout(SSLSession sess) { - if (timeout == 0) { - return false; - } - - if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L) - <= (System.currentTimeMillis()))) { - sess.invalidate(); - return true; - } - - return false; - } - - final class SessionCacheVisitor - implements Cache.CacheVisitor<SessionId, SSLSessionImpl> { - Vector<byte[]> ids = null; - - // public void visit(java.util.Map<K,V> map) {} - @Override - public void visit(java.util.Map<SessionId, SSLSessionImpl> map) { - ids = new Vector<>(map.size()); - - for (SessionId key : map.keySet()) { - SSLSessionImpl value = map.get(key); - if (!isTimedout(value)) { - ids.addElement(key.getId()); - } - } - } - - public Enumeration<byte[]> getSessionIds() { - return ids != null ? ids.elements() : - new Vector<byte[]>().elements(); - } - } - -}
--- a/src/share/classes/sun/security/ssl/SSLSessionImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,907 +0,0 @@ -/* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.net.*; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.ArrayList; - -import java.security.Principal; -import java.security.PrivateKey; -import java.security.SecureRandom; -import java.security.cert.X509Certificate; -import java.security.cert.CertificateEncodingException; - -import javax.crypto.SecretKey; - -import javax.net.ssl.SSLSessionContext; -import javax.net.ssl.SSLSessionBindingListener; -import javax.net.ssl.SSLSessionBindingEvent; -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLPermission; -import javax.net.ssl.ExtendedSSLSession; -import javax.net.ssl.SNIServerName; - -import static sun.security.ssl.CipherSuite.KeyExchange.*; - -/** - * Implements the SSL session interface, and exposes the session context - * which is maintained by SSL servers. - * - * <P> Servers have the ability to manage the sessions associated with - * their authentication context(s). They can do this by enumerating the - * IDs of the sessions which are cached, examining those sessions, and then - * perhaps invalidating a given session so that it can't be used again. - * If servers do not explicitly manage the cache, sessions will linger - * until memory is low enough that the runtime environment purges cache - * entries automatically to reclaim space. - * - * <P><em> The only reason this class is not package-private is that - * there's no other public way to get at the server session context which - * is associated with any given authentication context. </em> - * - * @author David Brownell - */ -final class SSLSessionImpl extends ExtendedSSLSession { - - // compression methods - private static final byte compression_null = 0; - - /* - * The state of a single session, as described in section 7.1 - * of the SSLv3 spec. - */ - private final ProtocolVersion protocolVersion; - private final SessionId sessionId; - private X509Certificate[] peerCerts; - private byte compressionMethod; - private CipherSuite cipherSuite; - private SecretKey masterSecret; - private final boolean useExtendedMasterSecret; - - /* - * Information not part of the SSLv3 protocol spec, but used - * to support session management policies. - */ - private final long creationTime = System.currentTimeMillis(); - private long lastUsedTime = 0; - private final String host; - private final int port; - private SSLSessionContextImpl context; - private int sessionCount; - private boolean invalidated; - private X509Certificate[] localCerts; - private PrivateKey localPrivateKey; - private String[] localSupportedSignAlgs; - private String[] peerSupportedSignAlgs; - private List<SNIServerName> requestedServerNames; - - - // Principals for non-certificate based cipher suites - private Principal peerPrincipal; - private Principal localPrincipal; - - // The endpoint identification algorithm used to check certificates - // in this session. - private final String endpointIdentificationAlgorithm; - - /* - * Is the session currently re-established with a session-resumption - * abbreviated initial handshake? - * - * Note that currently we only set this variable in client side. - */ - private boolean isSessionResumption = false; - - /* - * We count session creations, eventually for statistical data but - * also since counters make shorter debugging IDs than the big ones - * we use in the protocol for uniqueness-over-time. - */ - private static volatile int counter = 0; - - /* - * Use of session caches is globally enabled/disabled. - */ - private static boolean defaultRejoinable = true; - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - /* - * Create a new non-rejoinable session, using the default (null) - * cipher spec. This constructor returns a session which could - * be used either by a client or by a server, as a connection is - * first opened and before handshaking begins. - */ - SSLSessionImpl() { - this(ProtocolVersion.NONE, CipherSuite.C_NULL, null, - new SessionId(false, null), null, -1, false, null); - } - - /* - * Create a new session, using a given cipher spec. This will - * be rejoinable if session caching is enabled; the constructor - * is intended mostly for use by serves. - */ - SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, - Collection<SignatureAndHashAlgorithm> algorithms, - SecureRandom generator, String host, int port, - boolean useExtendedMasterSecret, String endpointIdAlgorithm) { - this(protocolVersion, cipherSuite, algorithms, - new SessionId(defaultRejoinable, generator), host, port, - useExtendedMasterSecret, endpointIdAlgorithm); - } - - /* - * Record a new session, using a given cipher spec and session ID. - */ - SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, - Collection<SignatureAndHashAlgorithm> algorithms, - SessionId id, String host, int port, - boolean useExtendedMasterSecret, - String endpointIdAlgorithm){ - this.protocolVersion = protocolVersion; - sessionId = id; - peerCerts = null; - compressionMethod = compression_null; - this.cipherSuite = cipherSuite; - masterSecret = null; - this.host = host; - this.port = port; - sessionCount = ++counter; - localSupportedSignAlgs = - SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); - this.useExtendedMasterSecret = useExtendedMasterSecret; - this.endpointIdentificationAlgorithm = endpointIdAlgorithm; - - if (debug != null && Debug.isOn("session")) { - System.out.println("%% Initialized: " + this); - } - } - - void setMasterSecret(SecretKey secret) { - if (masterSecret == null) { - masterSecret = secret; - } else { - throw new RuntimeException("setMasterSecret() error"); - } - } - - /** - * Returns the master secret ... treat with extreme caution! - */ - SecretKey getMasterSecret() { - return masterSecret; - } - - boolean getUseExtendedMasterSecret() { - return useExtendedMasterSecret; - } - - void setPeerCertificates(X509Certificate[] peer) { - if (peerCerts == null) { - peerCerts = peer; - } - } - - void setLocalCertificates(X509Certificate[] local) { - localCerts = local; - } - - void setLocalPrivateKey(PrivateKey privateKey) { - localPrivateKey = privateKey; - } - - void setPeerSupportedSignatureAlgorithms( - Collection<SignatureAndHashAlgorithm> algorithms) { - peerSupportedSignAlgs = - SignatureAndHashAlgorithm.getAlgorithmNames(algorithms); - } - - void setRequestedServerNames(List<SNIServerName> requestedServerNames) { - this.requestedServerNames = new ArrayList<>(requestedServerNames); - } - - /** - * Set the peer principal. - */ - void setPeerPrincipal(Principal principal) { - if (peerPrincipal == null) { - peerPrincipal = principal; - } - } - - /** - * Set the local principal. - */ - void setLocalPrincipal(Principal principal) { - localPrincipal = principal; - } - - String getEndpointIdentificationAlgorithm() { - return this.endpointIdentificationAlgorithm; - } - - /** - * Returns true iff this session may be resumed ... sessions are - * usually resumable. Security policies may suggest otherwise, - * for example sessions that haven't been used for a while (say, - * a working day) won't be resumable, and sessions might have a - * maximum lifetime in any case. - */ - boolean isRejoinable() { - return sessionId != null && sessionId.length() != 0 && - !invalidated && isLocalAuthenticationValid(); - } - - @Override - public synchronized boolean isValid() { - return isRejoinable(); - } - - /** - * Check if the authentication used when establishing this session - * is still valid. Returns true if no authentication was used - */ - boolean isLocalAuthenticationValid() { - if (localPrivateKey != null) { - try { - // if the private key is no longer valid, getAlgorithm() - // should throw an exception - // (e.g. Smartcard has been removed from the reader) - localPrivateKey.getAlgorithm(); - } catch (Exception e) { - invalidate(); - return false; - } - } - return true; - } - - /** - * Returns the ID for this session. The ID is fixed for the - * duration of the session; neither it, nor its value, changes. - */ - @Override - public byte[] getId() { - return sessionId.getId(); - } - - /** - * For server sessions, this returns the set of sessions which - * are currently valid in this process. For client sessions, - * this returns null. - */ - @Override - public SSLSessionContext getSessionContext() { - /* - * An interim security policy until we can do something - * more specific in 1.2. Only allow trusted code (code which - * can set system properties) to get an - * SSLSessionContext. This is to limit the ability of code to - * look up specific sessions or enumerate over them. Otherwise, - * code can only get session objects from successful SSL - * connections which implies that they must have had permission - * to make the network connection in the first place. - */ - SecurityManager sm; - if ((sm = System.getSecurityManager()) != null) { - sm.checkPermission(new SSLPermission("getSSLSessionContext")); - } - - return context; - } - - - SessionId getSessionId() { - return sessionId; - } - - - /** - * Returns the cipher spec in use on this session - */ - CipherSuite getSuite() { - return cipherSuite; - } - - /** - * Resets the cipher spec in use on this session - */ - void setSuite(CipherSuite suite) { - cipherSuite = suite; - - if (debug != null && Debug.isOn("session")) { - System.out.println("%% Negotiating: " + this); - } - } - - /** - * Return true if the session is currently re-established with a - * session-resumption abbreviated initial handshake. - */ - boolean isSessionResumption() { - return isSessionResumption; - } - - /** - * Resets whether the session is re-established with a session-resumption - * abbreviated initial handshake. - */ - void setAsSessionResumption(boolean flag) { - isSessionResumption = flag; - } - - /** - * Returns the name of the cipher suite in use on this session - */ - @Override - public String getCipherSuite() { - return getSuite().name; - } - - ProtocolVersion getProtocolVersion() { - return protocolVersion; - } - - /** - * Returns the standard name of the protocol in use on this session - */ - @Override - public String getProtocol() { - return getProtocolVersion().name; - } - - /** - * Returns the compression technique used in this session - */ - byte getCompression() { - return compressionMethod; - } - - /** - * Returns the hashcode for this session - */ - @Override - public int hashCode() { - return sessionId.hashCode(); - } - - - /** - * Returns true if sessions have same ids, false otherwise. - */ - @Override - public boolean equals(Object obj) { - - if (obj == this) { - return true; - } - - if (obj instanceof SSLSessionImpl) { - SSLSessionImpl sess = (SSLSessionImpl) obj; - return (sessionId != null) && (sessionId.equals( - sess.getSessionId())); - } - - return false; - } - - - /** - * Return the cert chain presented by the peer in the - * java.security.cert format. - * Note: This method can be used only when using certificate-based - * cipher suites; using it with non-certificate-based cipher suites, - * such as Kerberos, will throw an SSLPeerUnverifiedException. - * - * @return array of peer X.509 certs, with the peer's own cert - * first in the chain, and with the "root" CA last. - */ - @Override - public java.security.cert.Certificate[] getPeerCertificates() - throws SSLPeerUnverifiedException { - // - // clone to preserve integrity of session ... caller can't - // change record of peer identity even by accident, much - // less do it intentionally. - // - if ((cipherSuite.keyExchange == K_KRB5) || - (cipherSuite.keyExchange == K_KRB5_EXPORT)) { - throw new SSLPeerUnverifiedException("no certificates expected" - + " for Kerberos cipher suites"); - } - if (peerCerts == null) { - throw new SSLPeerUnverifiedException("peer not authenticated"); - } - // Certs are immutable objects, therefore we don't clone them. - // But do need to clone the array, so that nothing is inserted - // into peerCerts. - return (java.security.cert.Certificate[])peerCerts.clone(); - } - - /** - * Return the cert chain presented to the peer in the - * java.security.cert format. - * Note: This method is useful only when using certificate-based - * cipher suites. - * - * @return array of peer X.509 certs, with the peer's own cert - * first in the chain, and with the "root" CA last. - */ - @Override - public java.security.cert.Certificate[] getLocalCertificates() { - // - // clone to preserve integrity of session ... caller can't - // change record of peer identity even by accident, much - // less do it intentionally. - return (localCerts == null ? null : - (java.security.cert.Certificate[])localCerts.clone()); - } - - /** - * Return the cert chain presented by the peer in the - * javax.security.cert format. - * Note: This method can be used only when using certificate-based - * cipher suites; using it with non-certificate-based cipher suites, - * such as Kerberos, will throw an SSLPeerUnverifiedException. - * - * @return array of peer X.509 certs, with the peer's own cert - * first in the chain, and with the "root" CA last. - */ - @Override - public javax.security.cert.X509Certificate[] getPeerCertificateChain() - throws SSLPeerUnverifiedException { - // - // clone to preserve integrity of session ... caller can't - // change record of peer identity even by accident, much - // less do it intentionally. - // - if ((cipherSuite.keyExchange == K_KRB5) || - (cipherSuite.keyExchange == K_KRB5_EXPORT)) { - throw new SSLPeerUnverifiedException("no certificates expected" - + " for Kerberos cipher suites"); - } - if (peerCerts == null) { - throw new SSLPeerUnverifiedException("peer not authenticated"); - } - javax.security.cert.X509Certificate[] certs; - certs = new javax.security.cert.X509Certificate[peerCerts.length]; - for (int i = 0; i < peerCerts.length; i++) { - byte[] der = null; - try { - der = peerCerts[i].getEncoded(); - certs[i] = javax.security.cert.X509Certificate.getInstance(der); - } catch (CertificateEncodingException e) { - throw new SSLPeerUnverifiedException(e.getMessage()); - } catch (javax.security.cert.CertificateException e) { - throw new SSLPeerUnverifiedException(e.getMessage()); - } - } - - return certs; - } - - /** - * Return the cert chain presented by the peer. - * Note: This method can be used only when using certificate-based - * cipher suites; using it with non-certificate-based cipher suites, - * such as Kerberos, will throw an SSLPeerUnverifiedException. - * - * @return array of peer X.509 certs, with the peer's own cert - * first in the chain, and with the "root" CA last. - */ - public X509Certificate[] getCertificateChain() - throws SSLPeerUnverifiedException { - /* - * clone to preserve integrity of session ... caller can't - * change record of peer identity even by accident, much - * less do it intentionally. - */ - if ((cipherSuite.keyExchange == K_KRB5) || - (cipherSuite.keyExchange == K_KRB5_EXPORT)) { - throw new SSLPeerUnverifiedException("no certificates expected" - + " for Kerberos cipher suites"); - } - if (peerCerts != null) { - return peerCerts.clone(); - } else { - throw new SSLPeerUnverifiedException("peer not authenticated"); - } - } - - /** - * Returns the identity of the peer which was established as part of - * defining the session. - * - * @return the peer's principal. Returns an X500Principal of the - * end-entity certificate for X509-based cipher suites, and - * Principal for Kerberos cipher suites. - * - * @throws SSLPeerUnverifiedException if the peer's identity has not - * been verified - */ - @Override - public Principal getPeerPrincipal() - throws SSLPeerUnverifiedException - { - if ((cipherSuite.keyExchange == K_KRB5) || - (cipherSuite.keyExchange == K_KRB5_EXPORT)) { - if (peerPrincipal == null) { - throw new SSLPeerUnverifiedException("peer not authenticated"); - } else { - // Eliminate dependency on KerberosPrincipal - return peerPrincipal; - } - } - if (peerCerts == null) { - throw new SSLPeerUnverifiedException("peer not authenticated"); - } - return peerCerts[0].getSubjectX500Principal(); - } - - /** - * Returns the principal that was sent to the peer during handshaking. - * - * @return the principal sent to the peer. Returns an X500Principal - * of the end-entity certificate for X509-based cipher suites, and - * Principal for Kerberos cipher suites. If no principal was - * sent, then null is returned. - */ - @Override - public Principal getLocalPrincipal() { - - if ((cipherSuite.keyExchange == K_KRB5) || - (cipherSuite.keyExchange == K_KRB5_EXPORT)) { - // Eliminate dependency on KerberosPrincipal - return (localPrincipal == null ? null : localPrincipal); - } - return (localCerts == null ? null : - localCerts[0].getSubjectX500Principal()); - } - - /** - * Returns the time this session was created. - */ - @Override - public long getCreationTime() { - return creationTime; - } - - /** - * Returns the last time this session was used to initialize - * a connection. - */ - @Override - public long getLastAccessedTime() { - return (lastUsedTime != 0) ? lastUsedTime : creationTime; - } - - void setLastAccessedTime(long time) { - lastUsedTime = time; - } - - - /** - * Returns the network address of the session's peer. This - * implementation does not insist that connections between - * different ports on the same host must necessarily belong - * to different sessions, though that is of course allowed. - */ - public InetAddress getPeerAddress() { - try { - return InetAddress.getByName(host); - } catch (java.net.UnknownHostException e) { - return null; - } - } - - @Override - public String getPeerHost() { - return host; - } - - /** - * Need to provide the port info for caching sessions based on - * host and port. Accessed by SSLSessionContextImpl - */ - @Override - public int getPeerPort() { - return port; - } - - void setContext(SSLSessionContextImpl ctx) { - if (context == null) { - context = ctx; - } - } - - /** - * Invalidate a session. Active connections may still exist, but - * no connections will be able to rejoin this session. - */ - @Override - synchronized public void invalidate() { - invalidated = true; - if (debug != null && Debug.isOn("session")) { - System.out.println("%% Invalidated: " + this); - } - if (context != null) { - context.remove(sessionId); - context = null; - } - } - - /* - * Table of application-specific session data indexed by an application - * key and the calling security context. This is important since - * sessions can be shared across different protection domains. - */ - private Hashtable<SecureKey, Object> table = new Hashtable<>(); - - /** - * Assigns a session value. Session change events are given if - * appropriate, to any original value as well as the new value. - */ - @Override - public void putValue(String key, Object value) { - if ((key == null) || (value == null)) { - throw new IllegalArgumentException("arguments can not be null"); - } - - SecureKey secureKey = new SecureKey(key); - Object oldValue = table.put(secureKey, value); - - if (oldValue instanceof SSLSessionBindingListener) { - SSLSessionBindingEvent e; - - e = new SSLSessionBindingEvent(this, key); - ((SSLSessionBindingListener)oldValue).valueUnbound(e); - } - if (value instanceof SSLSessionBindingListener) { - SSLSessionBindingEvent e; - - e = new SSLSessionBindingEvent(this, key); - ((SSLSessionBindingListener)value).valueBound(e); - } - } - - - /** - * Returns the specified session value. - */ - @Override - public Object getValue(String key) { - if (key == null) { - throw new IllegalArgumentException("argument can not be null"); - } - - SecureKey secureKey = new SecureKey(key); - return table.get(secureKey); - } - - - /** - * Removes the specified session value, delivering a session changed - * event as appropriate. - */ - @Override - public void removeValue(String key) { - if (key == null) { - throw new IllegalArgumentException("argument can not be null"); - } - - SecureKey secureKey = new SecureKey(key); - Object value = table.remove(secureKey); - - if (value instanceof SSLSessionBindingListener) { - SSLSessionBindingEvent e; - - e = new SSLSessionBindingEvent(this, key); - ((SSLSessionBindingListener)value).valueUnbound(e); - } - } - - - /** - * Lists the names of the session values. - */ - @Override - public String[] getValueNames() { - Enumeration<SecureKey> e; - Vector<Object> v = new Vector<>(); - SecureKey key; - Object securityCtx = SecureKey.getCurrentSecurityContext(); - - for (e = table.keys(); e.hasMoreElements(); ) { - key = e.nextElement(); - - if (securityCtx.equals(key.getSecurityContext())) { - v.addElement(key.getAppKey()); - } - } - String[] names = new String[v.size()]; - v.copyInto(names); - - return names; - } - - /** - * Use large packet sizes now or follow RFC 2246 packet sizes (2^14) - * until changed. - * - * In the TLS specification (section 6.2.1, RFC2246), it is not - * recommended that the plaintext has more than 2^14 bytes. - * However, some TLS implementations violate the specification. - * This is a workaround for interoperability with these stacks. - * - * Application could accept large fragments up to 2^15 bytes by - * setting the system property jsse.SSLEngine.acceptLargeFragments - * to "true". - */ - private boolean acceptLargeFragments = - Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false); - - /** - * Expand the buffer size of both SSL/TLS network packet and - * application data. - */ - protected synchronized void expandBufferSizes() { - acceptLargeFragments = true; - } - - /** - * Gets the current size of the largest SSL/TLS packet that is expected - * when using this session. - */ - @Override - public synchronized int getPacketBufferSize() { - return acceptLargeFragments ? - Record.maxLargeRecordSize : Record.maxRecordSize; - } - - /** - * Gets the current size of the largest application data that is - * expected when using this session. - */ - @Override - public synchronized int getApplicationBufferSize() { - return getPacketBufferSize() - Record.headerSize; - } - - /** - * Gets an array of supported signature algorithms that the local side is - * willing to verify. - */ - @Override - public String[] getLocalSupportedSignatureAlgorithms() { - if (localSupportedSignAlgs != null) { - return localSupportedSignAlgs.clone(); - } - - return new String[0]; - } - - /** - * Gets an array of supported signature algorithms that the peer is - * able to verify. - */ - @Override - public String[] getPeerSupportedSignatureAlgorithms() { - if (peerSupportedSignAlgs != null) { - return peerSupportedSignAlgs.clone(); - } - - return new String[0]; - } - - /** - * Obtains a <code>List</code> containing all {@link SNIServerName}s - * of the requested Server Name Indication (SNI) extension. - */ - @Override - public List<SNIServerName> getRequestedServerNames() { - if (requestedServerNames != null && !requestedServerNames.isEmpty()) { - return Collections.<SNIServerName>unmodifiableList( - requestedServerNames); - } - - return Collections.<SNIServerName>emptyList(); - } - - /** Returns a string representation of this SSL session */ - @Override - public String toString() { - return "[Session-" + sessionCount - + ", " + getCipherSuite() - + "]"; - } - - /** - * When SSL sessions are finalized, all values bound to - * them are removed. - */ - @Override - protected void finalize() throws Throwable { - String[] names = getValueNames(); - for (int i = 0; i < names.length; i++) { - removeValue(names[i]); - } - } -} - - -/** - * This "struct" class serves as a Hash Key that combines an - * application-specific key and a security context. - */ -class SecureKey { - private static Object nullObject = new Object(); - private Object appKey; - private Object securityCtx; - - static Object getCurrentSecurityContext() { - SecurityManager sm = System.getSecurityManager(); - Object context = null; - - if (sm != null) - context = sm.getSecurityContext(); - if (context == null) - context = nullObject; - return context; - } - - SecureKey(Object key) { - this.appKey = key; - this.securityCtx = getCurrentSecurityContext(); - } - - Object getAppKey() { - return appKey; - } - - Object getSecurityContext() { - return securityCtx; - } - - @Override - public int hashCode() { - return appKey.hashCode() ^ securityCtx.hashCode(); - } - - @Override - public boolean equals(Object o) { - return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey) - && ((SecureKey)o).securityCtx.equals(securityCtx); - } -}
--- a/src/share/classes/sun/security/ssl/SSLSocketFactoryImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,198 +0,0 @@ -/* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.net.*; -import javax.net.ssl.SSLSocketFactory; - - -/** - * Implementation of an SSL socket factory. This provides the public - * hooks to create SSL sockets, using a "high level" programming - * interface which encapsulates system security policy defaults rather than - * offering application flexibility. In particular, it uses a configurable - * authentication context (and the keys held there) rather than offering - * any flexibility about which keys to use; that context defaults to the - * process-default context, but may be explicitly specified. - * - * @author David Brownell - */ -final public class SSLSocketFactoryImpl extends SSLSocketFactory { - - private SSLContextImpl context; - - /** - * Constructor used to instantiate the default factory. This method is - * only called if the old "ssl.SocketFactory.provider" property in the - * java.security file is set. - */ - public SSLSocketFactoryImpl() throws Exception { - this.context = SSLContextImpl.DefaultSSLContext.getDefaultImpl(); - } - - /** - * Constructs an SSL socket factory. - */ - SSLSocketFactoryImpl(SSLContextImpl context) { - this.context = context; - } - - /** - * Creates an unconnected socket. - * - * @return the unconnected socket - * @see java.net.Socket#connect(java.net.SocketAddress, int) - */ - @Override - public Socket createSocket() { - return new SSLSocketImpl(context); - } - - /** - * Constructs an SSL connection to a named host at a specified port. - * This acts as the SSL client, and may authenticate itself or rejoin - * existing SSL sessions allowed by the authentication context which - * has been configured. - * - * @param host name of the host with which to connect - * @param port number of the server's port - */ - @Override - public Socket createSocket(String host, int port) - throws IOException, UnknownHostException - { - return new SSLSocketImpl(context, host, port); - } - - /** - * Returns a socket layered over an existing socket to a - * ServerSocket on the named host, at the given port. This - * constructor can be used when tunneling SSL through a proxy. The - * host and port refer to the logical destination server. This - * socket is configured using the socket options established for - * this factory. - * - * @param s the existing socket - * @param host the server host - * @param port the server port - * @param autoClose close the underlying socket when this socket is closed - * - * @exception IOException if the connection can't be established - * @exception UnknownHostException if the host is not known - */ - @Override - public Socket createSocket(Socket s, String host, int port, - boolean autoClose) throws IOException { - return new SSLSocketImpl(context, s, host, port, autoClose); - } - - @Override - public Socket createSocket(Socket s, InputStream consumed, - boolean autoClose) throws IOException { - if (s == null) { - throw new NullPointerException( - "the existing socket cannot be null"); - } - - return new SSLSocketImpl(context, s, consumed, autoClose); - } - - /** - * Constructs an SSL connection to a server at a specified address - * and TCP port. This acts as the SSL client, and may authenticate - * itself or rejoin existing SSL sessions allowed by the authentication - * context which has been configured. - * - * @param address the server's host - * @param port its port - */ - @Override - public Socket createSocket(InetAddress address, int port) - throws IOException - { - return new SSLSocketImpl(context, address, port); - } - - - /** - * Constructs an SSL connection to a named host at a specified port. - * This acts as the SSL client, and may authenticate itself or rejoin - * existing SSL sessions allowed by the authentication context which - * has been configured. The socket will also bind() to the local - * address and port supplied. - */ - @Override - public Socket createSocket(String host, int port, - InetAddress clientAddress, int clientPort) - throws IOException - { - return new SSLSocketImpl(context, host, port, - clientAddress, clientPort); - } - - /** - * Constructs an SSL connection to a server at a specified address - * and TCP port. This acts as the SSL client, and may authenticate - * itself or rejoin existing SSL sessions allowed by the authentication - * context which has been configured. The socket will also bind() to - * the local address and port supplied. - */ - @Override - public Socket createSocket(InetAddress address, int port, - InetAddress clientAddress, int clientPort) - throws IOException - { - return new SSLSocketImpl(context, address, port, - clientAddress, clientPort); - } - - - /** - * Returns the subset of the supported cipher suites which are - * enabled by default. These cipher suites all provide a minimum - * quality of service whereby the server authenticates itself - * (preventing person-in-the-middle attacks) and where traffic - * is encrypted to provide confidentiality. - */ - @Override - public String[] getDefaultCipherSuites() { - return context.getDefaultCipherSuiteList(false).toStringArray(); - } - - /** - * Returns the names of the cipher suites which could be enabled for use - * on an SSL connection. Normally, only a subset of these will actually - * be enabled by default, since this list may include cipher suites which - * do not support the mutual authentication of servers and clients, or - * which do not protect data confidentiality. Servers may also need - * certain kinds of certificates to use certain cipher suites. - */ - @Override - public String[] getSupportedCipherSuites() { - return context.getSupportedCipherSuiteList().toStringArray(); - } -}
--- a/src/share/classes/sun/security/ssl/SSLSocketImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2769 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.net.*; -import java.security.GeneralSecurityException; -import java.security.AccessController; -import java.security.AccessControlContext; -import java.security.PrivilegedAction; -import java.security.AlgorithmConstraints; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.BiFunction; - -import javax.crypto.BadPaddingException; -import javax.net.ssl.*; - -import sun.misc.JavaNetAccess; -import sun.misc.SharedSecrets; - -/** - * Implementation of an SSL socket. This is a normal connection type - * socket, implementing SSL over some lower level socket, such as TCP. - * Because it is layered over some lower level socket, it MUST override - * all default socket methods. - * - * <P> This API offers a non-traditional option for establishing SSL - * connections. You may first establish the connection directly, then pass - * that connection to the SSL socket constructor with a flag saying which - * role should be taken in the handshake protocol. (The two ends of the - * connection must not choose the same role!) This allows setup of SSL - * proxying or tunneling, and also allows the kind of "role reversal" - * that is required for most FTP data transfers. - * - * @see javax.net.ssl.SSLSocket - * @see SSLServerSocket - * - * @author David Brownell - */ -final public class SSLSocketImpl extends BaseSSLSocketImpl { - - /* - * ERROR HANDLING GUIDELINES - * (which exceptions to throw and catch and which not to throw and catch) - * - * . if there is an IOException (SocketException) when accessing the - * underlying Socket, pass it through - * - * . do not throw IOExceptions, throw SSLExceptions (or a subclass) - * - * . for internal errors (things that indicate a bug in JSSE or a - * grossly misconfigured J2RE), throw either an SSLException or - * a RuntimeException at your convenience. - * - * . handshaking code (Handshaker or HandshakeMessage) should generally - * pass through exceptions, but can handle them if they know what to - * do. - * - * . exception chaining should be used for all new code. If you happen - * to touch old code that does not use chaining, you should change it. - * - * . there is a top level exception handler that sits at all entry - * points from application code to SSLSocket read/write code. It - * makes sure that all errors are handled (see handleException()). - * - * . JSSE internal code should generally not call close(), call - * closeInternal(). - */ - - /* - * There's a state machine associated with each connection, which - * among other roles serves to negotiate session changes. - * - * - START with constructor, until the TCP connection's around. - * - HANDSHAKE picks session parameters before allowing traffic. - * There are many substates due to sequencing requirements - * for handshake messages. - * - DATA may be transmitted. - * - RENEGOTIATE state allows concurrent data and handshaking - * traffic ("same" substates as HANDSHAKE), and terminates - * in selection of new session (and connection) parameters - * - ERROR state immediately precedes abortive disconnect. - * - SENT_CLOSE sent a close_notify to the peer. For layered, - * non-autoclose socket, must now read close_notify - * from peer before closing the connection. For nonlayered or - * non-autoclose socket, close connection and go onto - * cs_CLOSED state. - * - CLOSED after sending close_notify alert, & socket is closed. - * SSL connection objects are not reused. - * - APP_CLOSED once the application calls close(). Then it behaves like - * a closed socket, e.g.. getInputStream() throws an Exception. - * - * State affects what SSL record types may legally be sent: - * - * - Handshake ... only in HANDSHAKE and RENEGOTIATE states - * - App Data ... only in DATA and RENEGOTIATE states - * - Alert ... in HANDSHAKE, DATA, RENEGOTIATE - * - * Re what may be received: same as what may be sent, except that - * HandshakeRequest handshaking messages can come from servers even - * in the application data state, to request entry to RENEGOTIATE. - * - * The state machine within HANDSHAKE and RENEGOTIATE states controls - * the pending session, not the connection state, until the change - * cipher spec and "Finished" handshake messages are processed and - * make the "new" session become the current one. - * - * NOTE: details of the SMs always need to be nailed down better. - * The text above illustrates the core ideas. - * - * +---->-------+------>--------->-------+ - * | | | - * <-----< ^ ^ <-----< v - *START>----->HANDSHAKE>----->DATA>----->RENEGOTIATE SENT_CLOSE - * v v v | | - * | | | | v - * +------------+---------------+ v ERROR - * | | | - * v | | - * ERROR>------>----->CLOSED<--------<----+-- + - * | - * v - * APP_CLOSED - * - * ALSO, note that the the purpose of handshaking (renegotiation is - * included) is to assign a different, and perhaps new, session to - * the connection. The SSLv3 spec is a bit confusing on that new - * protocol feature. - */ - private static final int cs_START = 0; - private static final int cs_HANDSHAKE = 1; - private static final int cs_DATA = 2; - private static final int cs_RENEGOTIATE = 3; - private static final int cs_ERROR = 4; - private static final int cs_SENT_CLOSE = 5; - private static final int cs_CLOSED = 6; - private static final int cs_APP_CLOSED = 7; - - - /* - * Client authentication be off, requested, or required. - * - * Migrated to SSLEngineImpl: - * clauth_none/cl_auth_requested/clauth_required - */ - - /* - * Drives the protocol state machine. - */ - private volatile int connectionState; - - /* - * Flag indicating if the next record we receive MUST be a Finished - * message. Temporarily set during the handshake to ensure that - * a change cipher spec message is followed by a finished message. - */ - private boolean expectingFinished; - - /* - * For improved diagnostics, we detail connection closure - * If the socket is closed (connectionState >= cs_ERROR), - * closeReason != null indicates if the socket was closed - * because of an error or because or normal shutdown. - */ - private SSLException closeReason; - - /* - * Per-connection private state that doesn't change when the - * session is changed. - */ - private byte doClientAuth; - private boolean roleIsServer; - private boolean enableSessionCreation = true; - private String host; - private boolean autoClose = true; - private AccessControlContext acc; - - // The cipher suites enabled for use on this connection. - private CipherSuiteList enabledCipherSuites; - - // The endpoint identification protocol - private String identificationProtocol = null; - - // The cryptographic algorithm constraints - private AlgorithmConstraints algorithmConstraints = null; - - // The server name indication and matchers - List<SNIServerName> serverNames = - Collections.<SNIServerName>emptyList(); - Collection<SNIMatcher> sniMatchers = - Collections.<SNIMatcher>emptyList(); - // Is the serverNames set to empty with SSLParameters.setServerNames()? - private boolean noSniExtension = false; - - // Is the sniMatchers set to empty with SSLParameters.setSNIMatchers()? - private boolean noSniMatcher = false; - - // Configured application protocol values - String[] applicationProtocols = new String[0]; - - // Negotiated application protocol value. - // - // The value under negotiation will be obtained from handshaker. - String applicationProtocol = null; - - // Callback function that selects the application protocol value during - // the SSL/TLS handshake. - BiFunction<SSLSocket, List<String>, String> applicationProtocolSelector; - - /* - * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * - * IMPORTANT STUFF TO UNDERSTANDING THE SYNCHRONIZATION ISSUES. - * READ ME * READ ME * READ ME * READ ME * READ ME * READ ME * - * - * There are several locks here. - * - * The primary lock is the per-instance lock used by - * synchronized(this) and the synchronized methods. It controls all - * access to things such as the connection state and variables which - * affect handshaking. If we are inside a synchronized method, we - * can access the state directly, otherwise, we must use the - * synchronized equivalents. - * - * The handshakeLock is used to ensure that only one thread performs - * the *complete initial* handshake. If someone is handshaking, any - * stray application or startHandshake() requests who find the - * connection state is cs_HANDSHAKE will stall on handshakeLock - * until handshaking is done. Once the handshake is done, we either - * succeeded or failed, but we can never go back to the cs_HANDSHAKE - * or cs_START state again. - * - * Note that the read/write() calls here in SSLSocketImpl are not - * obviously synchronized. In fact, it's very nonintuitive, and - * requires careful examination of code paths. Grab some coffee, - * and be careful with any code changes. - * - * There can be only three threads active at a time in the I/O - * subsection of this class. - * 1. startHandshake - * 2. AppInputStream - * 3. AppOutputStream - * One thread could call startHandshake(). - * AppInputStream/AppOutputStream read() and write() calls are each - * synchronized on 'this' in their respective classes, so only one - * app. thread will be doing a SSLSocketImpl.read() or .write()'s at - * a time. - * - * If handshaking is required (state cs_HANDSHAKE), and - * getConnectionState() for some/all threads returns cs_HANDSHAKE, - * only one can grab the handshakeLock, and the rest will stall - * either on getConnectionState(), or on the handshakeLock if they - * happen to successfully race through the getConnectionState(). - * - * If a writer is doing the initial handshaking, it must create a - * temporary reader to read the responses from the other side. As a - * side-effect, the writer's reader will have priority over any - * other reader. However, the writer's reader is not allowed to - * consume any application data. When handshakeLock is finally - * released, we either have a cs_DATA connection, or a - * cs_CLOSED/cs_ERROR socket. - * - * The writeLock is held while writing on a socket connection and - * also to protect the MAC and cipher for their direction. The - * writeLock is package private for Handshaker which holds it while - * writing the ChangeCipherSpec message. - * - * To avoid the problem of a thread trying to change operational - * modes on a socket while handshaking is going on, we synchronize - * on 'this'. If handshaking has not started yet, we tell the - * handshaker to change its mode. If handshaking has started, - * we simply store that request until the next pending session - * is created, at which time the new handshaker's state is set. - * - * The readLock is held during readRecord(), which is responsible - * for reading an InputRecord, decrypting it, and processing it. - * The readLock ensures that these three steps are done atomically - * and that once started, no other thread can block on InputRecord.read. - * This is necessary so that processing of close_notify alerts - * from the peer are handled properly. - */ - final private Object handshakeLock = new Object(); - final ReentrantLock writeLock = new ReentrantLock(); - final private Object readLock = new Object(); - - private InputRecord inrec; - - /* - * Crypto state that's reinitialized when the session changes. - */ - private Authenticator readAuthenticator, writeAuthenticator; - private CipherBox readCipher, writeCipher; - // NOTE: compression state would be saved here - - /* - * security parameters for secure renegotiation. - */ - private boolean secureRenegotiation; - private byte[] clientVerifyData; - private byte[] serverVerifyData; - - /* - * The authentication context holds all information used to establish - * who this end of the connection is (certificate chains, private keys, - * etc) and who is trusted (e.g. as CAs or websites). - */ - private SSLContextImpl sslContext; - - - /* - * This connection is one of (potentially) many associated with - * any given session. The output of the handshake protocol is a - * new session ... although all the protocol description talks - * about changing the cipher spec (and it does change), in fact - * that's incidental since it's done by changing everything that - * is associated with a session at the same time. (TLS/IETF may - * change that to add client authentication w/o new key exchg.) - */ - private Handshaker handshaker; - private SSLSessionImpl sess; - private volatile SSLSessionImpl handshakeSession; - - - /* - * If anyone wants to get notified about handshake completions, - * they'll show up on this list. - */ - private HashMap<HandshakeCompletedListener, AccessControlContext> - handshakeListeners; - - /* - * Reuse the same internal input/output streams. - */ - private InputStream sockInput; - private OutputStream sockOutput; - - - /* - * These input and output streams block their data in SSL records, - * and usually arrange integrity and privacy protection for those - * records. The guts of the SSL protocol are wrapped up in these - * streams, and in the handshaking that establishes the details of - * that integrity and privacy protection. - */ - private AppInputStream input; - private AppOutputStream output; - - /* - * The protocol versions enabled for use on this connection. - * - * Note: we support a pseudo protocol called SSLv2Hello which when - * set will result in an SSL v2 Hello being sent with SSL (version 3.0) - * or TLS (version 3.1, 3.2, etc.) version info. - */ - private ProtocolList enabledProtocols; - - /* - * The SSL version associated with this connection. - */ - private ProtocolVersion protocolVersion = ProtocolVersion.DEFAULT; - - /* Class and subclass dynamic debugging support */ - private static final Debug debug = Debug.getInstance("ssl"); - - /* - * Is it the first application record to write? - */ - private boolean isFirstAppOutputRecord = true; - - /* - * If AppOutputStream needs to delay writes of small packets, we - * will use this to store the data until we actually do the write. - */ - private ByteArrayOutputStream heldRecordBuffer = null; - - /* - * Whether local cipher suites preference in server side should be - * honored during handshaking? - */ - private boolean preferLocalCipherSuites = false; - - /* - * Is the local name service trustworthy? - * - * If the local name service is not trustworthy, reverse host name - * resolution should not be performed for endpoint identification. - */ - static final boolean trustNameService = - Debug.getBooleanProperty("jdk.tls.trustNameService", false); - - // - // CONSTRUCTORS AND INITIALIZATION CODE - // - - /** - * Constructs an SSL connection to a named host at a specified port, - * using the authentication context provided. This endpoint acts as - * the client, and may rejoin an existing SSL session if appropriate. - * - * @param context authentication context to use - * @param host name of the host with which to connect - * @param port number of the server's port - */ - SSLSocketImpl(SSLContextImpl context, String host, int port) - throws IOException, UnknownHostException { - super(); - this.host = host; - this.serverNames = - Utilities.addToSNIServerNameList(this.serverNames, this.host); - init(context, false); - SocketAddress socketAddress = - host != null ? new InetSocketAddress(host, port) : - new InetSocketAddress(InetAddress.getByName(null), port); - connect(socketAddress, 0); - } - - - /** - * Constructs an SSL connection to a server at a specified address. - * and TCP port, using the authentication context provided. This - * endpoint acts as the client, and may rejoin an existing SSL session - * if appropriate. - * - * @param context authentication context to use - * @param address the server's host - * @param port its port - */ - SSLSocketImpl(SSLContextImpl context, InetAddress host, int port) - throws IOException { - super(); - init(context, false); - SocketAddress socketAddress = new InetSocketAddress(host, port); - connect(socketAddress, 0); - } - - /** - * Constructs an SSL connection to a named host at a specified port, - * using the authentication context provided. This endpoint acts as - * the client, and may rejoin an existing SSL session if appropriate. - * - * @param context authentication context to use - * @param host name of the host with which to connect - * @param port number of the server's port - * @param localAddr the local address the socket is bound to - * @param localPort the local port the socket is bound to - */ - SSLSocketImpl(SSLContextImpl context, String host, int port, - InetAddress localAddr, int localPort) - throws IOException, UnknownHostException { - super(); - this.host = host; - this.serverNames = - Utilities.addToSNIServerNameList(this.serverNames, this.host); - init(context, false); - bind(new InetSocketAddress(localAddr, localPort)); - SocketAddress socketAddress = - host != null ? new InetSocketAddress(host, port) : - new InetSocketAddress(InetAddress.getByName(null), port); - connect(socketAddress, 0); - } - - - /** - * Constructs an SSL connection to a server at a specified address. - * and TCP port, using the authentication context provided. This - * endpoint acts as the client, and may rejoin an existing SSL session - * if appropriate. - * - * @param context authentication context to use - * @param address the server's host - * @param port its port - * @param localAddr the local address the socket is bound to - * @param localPort the local port the socket is bound to - */ - SSLSocketImpl(SSLContextImpl context, InetAddress host, int port, - InetAddress localAddr, int localPort) - throws IOException { - super(); - init(context, false); - bind(new InetSocketAddress(localAddr, localPort)); - SocketAddress socketAddress = new InetSocketAddress(host, port); - connect(socketAddress, 0); - } - - /* - * Package-private constructor used ONLY by SSLServerSocket. The - * java.net package accepts the TCP connection after this call is - * made. This just initializes handshake state to use "server mode", - * giving control over the use of SSL client authentication. - */ - SSLSocketImpl(SSLContextImpl context, boolean serverMode, - CipherSuiteList suites, byte clientAuth, - boolean sessionCreation, ProtocolList protocols, - String identificationProtocol, - AlgorithmConstraints algorithmConstraints, - Collection<SNIMatcher> sniMatchers, - boolean preferLocalCipherSuites, - String[] applicationProtocols) throws IOException { - - super(); - doClientAuth = clientAuth; - enableSessionCreation = sessionCreation; - this.identificationProtocol = identificationProtocol; - this.algorithmConstraints = algorithmConstraints; - this.sniMatchers = sniMatchers; - this.preferLocalCipherSuites = preferLocalCipherSuites; - this.applicationProtocols = applicationProtocols; - init(context, serverMode); - - /* - * Override what was picked out for us. - */ - enabledCipherSuites = suites; - enabledProtocols = protocols; - } - - - /** - * Package-private constructor used to instantiate an unconnected - * socket. The java.net package will connect it, either when the - * connect() call is made by the application. This instance is - * meant to set handshake state to use "client mode". - */ - SSLSocketImpl(SSLContextImpl context) { - super(); - init(context, false); - } - - - /** - * Layer SSL traffic over an existing connection, rather than creating - * a new connection. The existing connection may be used only for SSL - * traffic (using this SSLSocket) until the SSLSocket.close() call - * returns. However, if a protocol error is detected, that existing - * connection is automatically closed. - * - * <P> This particular constructor always uses the socket in the - * role of an SSL client. It may be useful in cases which start - * using SSL after some initial data transfers, for example in some - * SSL tunneling applications or as part of some kinds of application - * protocols which negotiate use of a SSL based security. - * - * @param sock the existing connection - * @param context the authentication context to use - */ - SSLSocketImpl(SSLContextImpl context, Socket sock, String host, - int port, boolean autoClose) throws IOException { - super(sock); - // We always layer over a connected socket - if (!sock.isConnected()) { - throw new SocketException("Underlying socket is not connected"); - } - this.host = host; - this.serverNames = - Utilities.addToSNIServerNameList(this.serverNames, this.host); - init(context, false); - this.autoClose = autoClose; - doneConnect(); - } - - /** - * Creates a server mode {@link Socket} layered over an - * existing connected socket, and is able to read data which has - * already been consumed/removed from the {@link Socket}'s - * underlying {@link InputStream}. - */ - SSLSocketImpl(SSLContextImpl context, Socket sock, - InputStream consumed, boolean autoClose) throws IOException { - super(sock, consumed); - // We always layer over a connected socket - if (!sock.isConnected()) { - throw new SocketException("Underlying socket is not connected"); - } - - // In server mode, it is not necessary to set host and serverNames. - // Otherwise, would require a reverse DNS lookup to get the hostname. - - init(context, true); - this.autoClose = autoClose; - doneConnect(); - } - - /** - * Initializes the client socket. - */ - private void init(SSLContextImpl context, boolean isServer) { - sslContext = context; - sess = new SSLSessionImpl(); - handshakeSession = null; - - /* - * role is as specified, state is START until after - * the low level connection's established. - */ - roleIsServer = isServer; - connectionState = cs_START; - - /* - * default read and write side cipher and MAC support - * - * Note: compression support would go here too - */ - readCipher = CipherBox.NULL; - readAuthenticator = MAC.NULL; - writeCipher = CipherBox.NULL; - writeAuthenticator = MAC.NULL; - - // initial security parameters for secure renegotiation - secureRenegotiation = false; - clientVerifyData = new byte[0]; - serverVerifyData = new byte[0]; - - enabledCipherSuites = - sslContext.getDefaultCipherSuiteList(roleIsServer); - enabledProtocols = - sslContext.getDefaultProtocolList(roleIsServer); - - inrec = null; - - // save the acc - acc = AccessController.getContext(); - - input = new AppInputStream(this); - output = new AppOutputStream(this); - } - - /** - * Connects this socket to the server with a specified timeout - * value. - * - * This method is either called on an unconnected SSLSocketImpl by the - * application, or it is called in the constructor of a regular - * SSLSocketImpl. If we are layering on top on another socket, then - * this method should not be called, because we assume that the - * underlying socket is already connected by the time it is passed to - * us. - * - * @param endpoint the <code>SocketAddress</code> - * @param timeout the timeout value to be used, 0 is no timeout - * @throws IOException if an error occurs during the connection - * @throws SocketTimeoutException if timeout expires before connecting - */ - @Override - public void connect(SocketAddress endpoint, int timeout) - throws IOException { - - if (isLayered()) { - throw new SocketException("Already connected"); - } - - if (!(endpoint instanceof InetSocketAddress)) { - throw new SocketException( - "Cannot handle non-Inet socket addresses."); - } - - super.connect(endpoint, timeout); - - if (host == null || host.length() == 0) { - useImplicitHost(false); - } - - doneConnect(); - } - - /** - * Initialize the handshaker and socket streams. - * - * Called by connect, the layered constructor, and SSLServerSocket. - */ - void doneConnect() throws IOException { - /* - * Save the input and output streams. May be done only after - * java.net actually connects using the socket "self", else - * we get some pretty bizarre failure modes. - */ - sockInput = super.getInputStream(); - sockOutput = super.getOutputStream(); - - /* - * Move to handshaking state, with pending session initialized - * to defaults and the appropriate kind of handshaker set up. - */ - initHandshaker(); - } - - synchronized private int getConnectionState() { - return connectionState; - } - - synchronized private void setConnectionState(int state) { - connectionState = state; - } - - AccessControlContext getAcc() { - return acc; - } - - // - // READING AND WRITING RECORDS - // - - /* - * AppOutputStream calls may need to buffer multiple outbound - * application packets. - * - * All other writeRecord() calls will not buffer, so do not hold - * these records. - */ - void writeRecord(OutputRecord r) throws IOException { - writeRecord(r, false); - } - - /* - * Record Output. Application data can't be sent until the first - * handshake establishes a session. - * - * NOTE: we let empty records be written as a hook to force some - * TCP-level activity, notably handshaking, to occur. - */ - void writeRecord(OutputRecord r, boolean holdRecord) throws IOException { - /* - * The loop is in case of HANDSHAKE --> ERROR transitions, etc - */ - loop: - while (r.contentType() == Record.ct_application_data) { - /* - * Not all states support passing application data. We - * synchronize access to the connection state, so that - * synchronous handshakes can complete cleanly. - */ - switch (getConnectionState()) { - - /* - * We've deferred the initial handshaking till just now, - * when presumably a thread's decided it's OK to block for - * longish periods of time for I/O purposes (as well as - * configured the cipher suites it wants to use). - */ - case cs_HANDSHAKE: - performInitialHandshake(); - break; - - case cs_DATA: - case cs_RENEGOTIATE: - break loop; - - case cs_ERROR: - fatal(Alerts.alert_close_notify, - "error while writing to socket"); - break; // dummy - - case cs_SENT_CLOSE: - case cs_CLOSED: - case cs_APP_CLOSED: - // we should never get here (check in AppOutputStream) - // this is just a fallback - if (closeReason != null) { - throw closeReason; - } else { - throw new SocketException("Socket closed"); - } - - /* - * Else something's goofy in this state machine's use. - */ - default: - throw new SSLProtocolException("State error, send app data"); - } - } - - // - // Don't bother to really write empty records. We went this - // far to drive the handshake machinery, for correctness; not - // writing empty records improves performance by cutting CPU - // time and network resource usage. However, some protocol - // implementations are fragile and don't like to see empty - // records, so this also increases robustness. - // - if (!r.isEmpty()) { - - // If the record is a close notify alert, we need to honor - // socket option SO_LINGER. Note that we will try to send - // the close notify even if the SO_LINGER set to zero. - if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) { - - // keep and clear the current thread interruption status. - boolean interrupted = Thread.interrupted(); - try { - if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) { - try { - writeRecordInternal(r, holdRecord); - } finally { - writeLock.unlock(); - } - } else { - SSLException ssle = new SSLException( - "SO_LINGER timeout," + - " close_notify message cannot be sent."); - - - // For layered, non-autoclose sockets, we are not - // able to bring them into a usable state, so we - // treat it as fatal error. - if (isLayered() && !autoClose) { - // Note that the alert description is - // specified as -1, so no message will be send - // to peer anymore. - fatal((byte)(-1), ssle); - } else if ((debug != null) && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - ", received Exception: " + ssle); - } - - // RFC2246 requires that the session becomes - // unresumable if any connection is terminated - // without proper close_notify messages with - // level equal to warning. - // - // RFC4346 no longer requires that a session not be - // resumed if failure to properly close a connection. - // - // We choose to make the session unresumable if - // failed to send the close_notify message. - // - sess.invalidate(); - } - } catch (InterruptedException ie) { - // keep interrupted status - interrupted = true; - } - - // restore the interrupted status - if (interrupted) { - Thread.currentThread().interrupt(); - } - } else { - writeLock.lock(); - try { - writeRecordInternal(r, holdRecord); - } finally { - writeLock.unlock(); - } - } - } - } - - private void writeRecordInternal(OutputRecord r, - boolean holdRecord) throws IOException { - - // r.compress(c); - r.encrypt(writeAuthenticator, writeCipher); - - if (holdRecord) { - // If we were requested to delay the record due to possibility - // of Nagle's being active when finally got to writing, and - // it's actually not, we don't really need to delay it. - if (getTcpNoDelay()) { - holdRecord = false; - } else { - // We need to hold the record, so let's provide - // a per-socket place to do it. - if (heldRecordBuffer == null) { - // Likely only need 37 bytes. - heldRecordBuffer = new ByteArrayOutputStream(40); - } - } - } - r.write(sockOutput, holdRecord, heldRecordBuffer); - - /* - * Check the sequence number state - * - * Note that in order to maintain the connection I/O - * properly, we check the sequence number after the last - * record writing process. As we request renegotiation - * or close the connection for wrapped sequence number - * when there is enough sequence number space left to - * handle a few more records, so the sequence number - * of the last record cannot be wrapped. - */ - if (connectionState < cs_ERROR) { - checkSequenceNumber(writeAuthenticator, r.contentType()); - } - - // turn off the flag of the first application record - if (isFirstAppOutputRecord && - r.contentType() == Record.ct_application_data) { - isFirstAppOutputRecord = false; - } - } - - /* - * Need to split the payload except the following cases: - * - * 1. protocol version is TLS 1.1 or later; - * 2. bulk cipher does not use CBC mode, including null bulk cipher suites. - * 3. the payload is the first application record of a freshly - * negotiated TLS session. - * 4. the CBC protection is disabled; - * - * More details, please refer to AppOutputStream.write(byte[], int, int). - */ - boolean needToSplitPayload() { - writeLock.lock(); - try { - return (protocolVersion.v <= ProtocolVersion.TLS10.v) && - writeCipher.isCBCMode() && !isFirstAppOutputRecord && - Record.enableCBCProtection; - } finally { - writeLock.unlock(); - } - } - - /* - * Read an application data record. Alerts and handshake - * messages are handled directly. - */ - void readDataRecord(InputRecord r) throws IOException { - if (getConnectionState() == cs_HANDSHAKE) { - performInitialHandshake(); - } - readRecord(r, true); - } - - /* - * Clear the pipeline of records from the peer, optionally returning - * application data. Caller is responsible for knowing that it's - * possible to do this kind of clearing, if they don't want app - * data -- e.g. since it's the initial SSL handshake. - * - * Don't synchronize (this) during a blocking read() since it - * protects data which is accessed on the write side as well. - */ - private void readRecord(InputRecord r, boolean needAppData) - throws IOException { - int state; - - // readLock protects reading and processing of an InputRecord. - // It keeps the reading from sockInput and processing of the record - // atomic so that no two threads can be blocked on the - // read from the same input stream at the same time. - // This is required for example when a reader thread is - // blocked on the read and another thread is trying to - // close the socket. For a non-autoclose, layered socket, - // the thread performing the close needs to read the close_notify. - // - // Use readLock instead of 'this' for locking because - // 'this' also protects data accessed during writing. - synchronized (readLock) { - /* - * Read and handle records ... return application data - * ONLY if it's needed. - */ - - while (((state = getConnectionState()) != cs_CLOSED) && - (state != cs_ERROR) && (state != cs_APP_CLOSED)) { - /* - * Read a record ... maybe emitting an alert if we get a - * comprehensible but unsupported "hello" message during - * format checking (e.g. V2). - */ - try { - r.setAppDataValid(false); - r.read(sockInput, sockOutput); - } catch (SSLProtocolException e) { - try { - fatal(Alerts.alert_unexpected_message, e); - } catch (IOException x) { - // discard this exception - } - throw e; - } catch (EOFException eof) { - boolean handshaking = (getConnectionState() <= cs_HANDSHAKE); - boolean rethrow = requireCloseNotify || handshaking; - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", received EOFException: " - + (rethrow ? "error" : "ignored")); - } - if (rethrow) { - SSLException e; - if (handshaking) { - e = new SSLHandshakeException - ("Remote host closed connection during handshake"); - } else { - e = new SSLProtocolException - ("Remote host closed connection incorrectly"); - } - e.initCause(eof); - throw e; - } else { - // treat as if we had received a close_notify - closeInternal(false); - continue; - } - } - - - /* - * The basic SSLv3 record protection involves (optional) - * encryption for privacy, and an integrity check ensuring - * data origin authentication. We do them both here, and - * throw a fatal alert if the integrity check fails. - */ - try { - r.decrypt(readAuthenticator, readCipher); - } catch (BadPaddingException e) { - byte alertType = (r.contentType() == Record.ct_handshake) - ? Alerts.alert_handshake_failure - : Alerts.alert_bad_record_mac; - fatal(alertType, e.getMessage(), e); - } - - // if (!r.decompress(c)) - // fatal(Alerts.alert_decompression_failure, - // "decompression failure"); - - /* - * Process the record. - */ - synchronized (this) { - switch (r.contentType()) { - case Record.ct_handshake: - /* - * Handshake messages always go to a pending session - * handshaker ... if there isn't one, create one. This - * must work asynchronously, for renegotiation. - * - * NOTE that handshaking will either resume a session - * which was in the cache (and which might have other - * connections in it already), or else will start a new - * session (new keys exchanged) with just this connection - * in it. - */ - initHandshaker(); - if (!handshaker.activated()) { - // prior to handshaking, activate the handshake - if (connectionState == cs_RENEGOTIATE) { - // don't use SSLv2Hello when renegotiating - handshaker.activate(protocolVersion); - } else { - handshaker.activate(null); - } - } - - /* - * process the handshake record ... may contain just - * a partial handshake message or multiple messages. - * - * The handshaker state machine will ensure that it's - * a finished message. - */ - handshaker.process_record(r, expectingFinished); - expectingFinished = false; - - if (handshaker.invalidated) { - handshaker = null; - inrec.setHandshakeHash(null); - - // if state is cs_RENEGOTIATE, revert it to cs_DATA - if (connectionState == cs_RENEGOTIATE) { - connectionState = cs_DATA; - } - } else if (handshaker.isDone()) { - // reset the parameters for secure renegotiation. - secureRenegotiation = - handshaker.isSecureRenegotiation(); - clientVerifyData = handshaker.getClientVerifyData(); - serverVerifyData = handshaker.getServerVerifyData(); - // set connection ALPN value - applicationProtocol = - handshaker.getHandshakeApplicationProtocol(); - - sess = handshaker.getSession(); - handshakeSession = null; - handshaker = null; - connectionState = cs_DATA; - - // - // Tell folk about handshake completion, but do - // it in a separate thread. - // - if (handshakeListeners != null) { - HandshakeCompletedEvent event = - new HandshakeCompletedEvent(this, sess); - - Thread t = new NotifyHandshakeThread( - handshakeListeners.entrySet(), event); - t.start(); - } - } - - if (needAppData || connectionState != cs_DATA) { - continue; - } - break; - - case Record.ct_application_data: - // Pass this right back up to the application. - if (connectionState != cs_DATA - && connectionState != cs_RENEGOTIATE - && connectionState != cs_SENT_CLOSE) { - throw new SSLProtocolException( - "Data received in non-data state: " + - connectionState); - } - if (expectingFinished) { - throw new SSLProtocolException - ("Expecting finished message, received data"); - } - if (!needAppData) { - throw new SSLException("Discarding app data"); - } - - r.setAppDataValid(true); - break; - - case Record.ct_alert: - recvAlert(r); - continue; - - case Record.ct_change_cipher_spec: - if ((connectionState != cs_HANDSHAKE - && connectionState != cs_RENEGOTIATE)) { - // For the CCS message arriving in the wrong state - fatal(Alerts.alert_unexpected_message, - "illegal change cipher spec msg, conn state = " - + connectionState); - } else if (r.available() != 1 || r.read() != 1) { - // For structural/content issues with the CCS - fatal(Alerts.alert_unexpected_message, - "Malformed change cipher spec msg"); - } - - // - // The first message after a change_cipher_spec - // record MUST be a "Finished" handshake record, - // else it's a protocol violation. We force this - // to be checked by a minor tweak to the state - // machine. - // - handshaker.receiveChangeCipherSpec(); - changeReadCiphers(); - // next message MUST be a finished message - expectingFinished = true; - continue; - - default: - // - // TLS requires that unrecognized records be ignored. - // - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", Received record type: " - + r.contentType()); - } - continue; - } // switch - - /* - * Check the sequence number state - * - * Note that in order to maintain the connection I/O - * properly, we check the sequence number after the last - * record reading process. As we request renegotiation - * or close the connection for wrapped sequence number - * when there is enough sequence number space left to - * handle a few more records, so the sequence number - * of the last record cannot be wrapped. - */ - if (connectionState < cs_ERROR) { - checkSequenceNumber(readAuthenticator, r.contentType()); - } - - return; - } // synchronized (this) - } - - // - // couldn't read, due to some kind of error - // - r.close(); - return; - } // synchronized (readLock) - } - - /** - * Check the sequence number state - * - * RFC 4346 states that, "Sequence numbers are of type uint64 and - * may not exceed 2^64-1. Sequence numbers do not wrap. If a TLS - * implementation would need to wrap a sequence number, it must - * renegotiate instead." - */ - private void checkSequenceNumber(Authenticator authenticator, byte type) - throws IOException { - - /* - * Don't bother to check the sequence number for error or - * closed connections, or NULL MAC. - */ - if (connectionState >= cs_ERROR || authenticator == MAC.NULL) { - return; - } - - /* - * Conservatively, close the connection immediately when the - * sequence number is close to overflow - */ - if (authenticator.seqNumOverflow()) { - /* - * TLS protocols do not define a error alert for sequence - * number overflow. We use handshake_failure error alert - * for handshaking and bad_record_mac for other records. - */ - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", sequence number extremely close to overflow " + - "(2^64-1 packets). Closing connection."); - - } - - fatal(Alerts.alert_handshake_failure, "sequence number overflow"); - } - - /* - * Ask for renegotiation when need to renew sequence number. - * - * Don't bother to kickstart the renegotiation when the local is - * asking for it. - */ - if ((type != Record.ct_handshake) && authenticator.seqNumIsHuge()) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", request renegotiation " + - "to avoid sequence number overflow"); - } - - startHandshake(); - } - } - - // - // HANDSHAKE RELATED CODE - // - - /** - * Return the AppInputStream. For use by Handshaker only. - */ - AppInputStream getAppInputStream() { - return input; - } - - /** - * Return the AppOutputStream. For use by Handshaker only. - */ - AppOutputStream getAppOutputStream() { - return output; - } - - /** - * Initialize the handshaker object. This means: - * - * . if a handshake is already in progress (state is cs_HANDSHAKE - * or cs_RENEGOTIATE), do nothing and return - * - * . if the socket is already closed, throw an Exception (internal error) - * - * . otherwise (cs_START or cs_DATA), create the appropriate handshaker - * object, and advance the connection state (to cs_HANDSHAKE or - * cs_RENEGOTIATE, respectively). - * - * This method is called right after a new socket is created, when - * starting renegotiation, or when changing client/ server mode of the - * socket. - */ - private void initHandshaker() { - switch (connectionState) { - - // - // Starting a new handshake. - // - case cs_START: - case cs_DATA: - break; - - // - // We're already in the middle of a handshake. - // - case cs_HANDSHAKE: - case cs_RENEGOTIATE: - return; - - // - // Anyone allowed to call this routine is required to - // do so ONLY if the connection state is reasonable... - // - default: - throw new IllegalStateException("Internal error"); - } - - // state is either cs_START or cs_DATA - if (connectionState == cs_START) { - connectionState = cs_HANDSHAKE; - } else { // cs_DATA - connectionState = cs_RENEGOTIATE; - } - if (roleIsServer) { - handshaker = new ServerHandshaker(this, sslContext, - enabledProtocols, doClientAuth, - protocolVersion, connectionState == cs_HANDSHAKE, - secureRenegotiation, clientVerifyData, serverVerifyData); - handshaker.setSNIMatchers(sniMatchers); - handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites); - } else { - handshaker = new ClientHandshaker(this, sslContext, - enabledProtocols, - protocolVersion, connectionState == cs_HANDSHAKE, - secureRenegotiation, clientVerifyData, serverVerifyData); - handshaker.setSNIServerNames(serverNames); - } - handshaker.setEnabledCipherSuites(enabledCipherSuites); - handshaker.setEnableSessionCreation(enableSessionCreation); - handshaker.setApplicationProtocols(applicationProtocols); - handshaker.setApplicationProtocolSelectorSSLSocket( - applicationProtocolSelector); - } - - /** - * Synchronously perform the initial handshake. - * - * If the handshake is already in progress, this method blocks until it - * is completed. If the initial handshake has already been completed, - * it returns immediately. - */ - private void performInitialHandshake() throws IOException { - // use handshakeLock and the state check to make sure only - // one thread performs the handshake - synchronized (handshakeLock) { - if (getConnectionState() == cs_HANDSHAKE) { - kickstartHandshake(); - - /* - * All initial handshaking goes through this operation - * until we have a valid SSL connection. - * - * Handle handshake messages only, need no application data. - */ - if (inrec == null) { - inrec = new InputRecord(); - - /* - * Grab the characteristics already assigned to - * AppInputStream's InputRecord. Enable checking for - * SSLv2 hellos on this first handshake. - */ - inrec.setHandshakeHash(input.r.getHandshakeHash()); - inrec.setHelloVersion(input.r.getHelloVersion()); - inrec.enableFormatChecks(); - } - - readRecord(inrec, false); - inrec = null; - } - } - } - - /** - * Starts an SSL handshake on this connection. - */ - @Override - public void startHandshake() throws IOException { - // start an ssl handshake that could be resumed from timeout exception - startHandshake(true); - } - - /** - * Starts an ssl handshake on this connection. - * - * @param resumable indicates the handshake process is resumable from a - * certain exception. If <code>resumable</code>, the socket will - * be reserved for exceptions like timeout; otherwise, the socket - * will be closed, no further communications could be done. - */ - private void startHandshake(boolean resumable) throws IOException { - checkWrite(); - try { - if (getConnectionState() == cs_HANDSHAKE) { - // do initial handshake - performInitialHandshake(); - } else { - // start renegotiation - kickstartHandshake(); - } - } catch (Exception e) { - // shutdown and rethrow (wrapped) exception as appropriate - handleException(e, resumable); - } - } - - /** - * Kickstart the handshake if it is not already in progress. - * This means: - * - * . if handshaking is already underway, do nothing and return - * - * . if the socket is not connected or already closed, throw an - * Exception. - * - * . otherwise, call initHandshake() to initialize the handshaker - * object and progress the state. Then, send the initial - * handshaking message if appropriate (always on clients and - * on servers when renegotiating). - */ - private synchronized void kickstartHandshake() throws IOException { - - switch (connectionState) { - - case cs_HANDSHAKE: - // handshaker already setup, proceed - break; - - case cs_DATA: - if (!secureRenegotiation && !Handshaker.allowUnsafeRenegotiation) { - throw new SSLHandshakeException( - "Insecure renegotiation is not allowed"); - } - - if (!secureRenegotiation) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning: Using insecure renegotiation"); - } - } - - // initialize the handshaker, move to cs_RENEGOTIATE - initHandshaker(); - break; - - case cs_RENEGOTIATE: - // handshaking already in progress, return - return; - - /* - * The only way to get a socket in the state is when - * you have an unconnected socket. - */ - case cs_START: - throw new SocketException( - "handshaking attempted on unconnected socket"); - - default: - throw new SocketException("connection is closed"); - } - - // - // Kickstart handshake state machine if we need to ... - // - // Note that handshaker.kickstart() writes the message - // to its HandshakeOutStream, which calls back into - // SSLSocketImpl.writeRecord() to send it. - // - if (!handshaker.activated()) { - // prior to handshaking, activate the handshake - if (connectionState == cs_RENEGOTIATE) { - // don't use SSLv2Hello when renegotiating - handshaker.activate(protocolVersion); - } else { - handshaker.activate(null); - } - - if (handshaker instanceof ClientHandshaker) { - // send client hello - handshaker.kickstart(); - } else { - if (connectionState == cs_HANDSHAKE) { - // initial handshake, no kickstart message to send - } else { - // we want to renegotiate, send hello request - handshaker.kickstart(); - // hello request is not included in the handshake - // hashes, reset them - handshaker.handshakeHash.reset(); - } - } - } - } - - // - // CLOSURE RELATED CALLS - // - - /** - * Return whether the socket has been explicitly closed by the application. - */ - @Override - public boolean isClosed() { - return connectionState == cs_APP_CLOSED; - } - - /** - * Return whether we have reached end-of-file. - * - * If the socket is not connected, has been shutdown because of an error - * or has been closed, throw an Exception. - */ - boolean checkEOF() throws IOException { - switch (getConnectionState()) { - case cs_START: - throw new SocketException("Socket is not connected"); - - case cs_HANDSHAKE: - case cs_DATA: - case cs_RENEGOTIATE: - case cs_SENT_CLOSE: - return false; - - case cs_APP_CLOSED: - throw new SocketException("Socket is closed"); - - case cs_ERROR: - case cs_CLOSED: - default: - // either closed because of error, or normal EOF - if (closeReason == null) { - return true; - } - IOException e = new SSLException - ("Connection has been shutdown: " + closeReason); - e.initCause(closeReason); - throw e; - - } - } - - /** - * Check if we can write data to this socket. If not, throw an IOException. - */ - void checkWrite() throws IOException { - if (checkEOF() || (getConnectionState() == cs_SENT_CLOSE)) { - // we are at EOF, write must throw Exception - throw new SocketException("Connection closed by remote host"); - } - } - - protected void closeSocket() throws IOException { - - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called closeSocket()"); - } - - super.close(); - } - - private void closeSocket(boolean selfInitiated) throws IOException { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called closeSocket(" + selfInitiated + ")"); - } - if (!isLayered() || autoClose) { - super.close(); - } else if (selfInitiated) { - // layered && non-autoclose - // read close_notify alert to clear input stream - waitForClose(false); - } - } - - /* - * Closing the connection is tricky ... we can't officially close the - * connection until we know the other end is ready to go away too, - * and if ever the connection gets aborted we must forget session - * state (it becomes invalid). - */ - - /** - * Closes the SSL connection. SSL includes an application level - * shutdown handshake; you should close SSL sockets explicitly - * rather than leaving it for finalization, so that your remote - * peer does not experience a protocol error. - */ - @Override - public void close() throws IOException { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called close()"); - } - closeInternal(true); // caller is initiating close - setConnectionState(cs_APP_CLOSED); - } - - /** - * Don't synchronize the whole method because waitForClose() - * (which calls readRecord()) might be called. - * - * @param selfInitiated Indicates which party initiated the close. - * If selfInitiated, this side is initiating a close; for layered and - * non-autoclose socket, wait for close_notify response. - * If !selfInitiated, peer sent close_notify; we reciprocate but - * no need to wait for response. - */ - private void closeInternal(boolean selfInitiated) throws IOException { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", called closeInternal(" + selfInitiated + ")"); - } - - int state = getConnectionState(); - boolean closeSocketCalled = false; - Throwable cachedThrowable = null; - try { - switch (state) { - case cs_START: - // unconnected socket or handshaking has not been initialized - closeSocket(selfInitiated); - break; - - /* - * If we're closing down due to error, we already sent (or else - * received) the fatal alert ... no niceties, blow the connection - * away as quickly as possible (even if we didn't allocate the - * socket ourselves; it's unusable, regardless). - */ - case cs_ERROR: - closeSocket(); - break; - - /* - * Sometimes close() gets called more than once. - */ - case cs_CLOSED: - case cs_APP_CLOSED: - break; - - /* - * Otherwise we indicate clean termination. - */ - // case cs_HANDSHAKE: - // case cs_DATA: - // case cs_RENEGOTIATE: - // case cs_SENT_CLOSE: - default: - synchronized (this) { - if (((state = getConnectionState()) == cs_CLOSED) || - (state == cs_ERROR) || (state == cs_APP_CLOSED)) { - return; // connection was closed while we waited - } - if (state != cs_SENT_CLOSE) { - try { - warning(Alerts.alert_close_notify); - connectionState = cs_SENT_CLOSE; - } catch (Throwable th) { - // we need to ensure socket is closed out - // if we encounter any errors. - connectionState = cs_ERROR; - // cache this for later use - cachedThrowable = th; - closeSocketCalled = true; - closeSocket(selfInitiated); - } - } - } - // If state was cs_SENT_CLOSE before, we don't do the actual - // closing since it is already in progress. - if (state == cs_SENT_CLOSE) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", close invoked again; state = " + - getConnectionState()); - } - if (selfInitiated == false) { - // We were called because a close_notify message was - // received. This may be due to another thread calling - // read() or due to our call to waitForClose() below. - // In either case, just return. - return; - } - // Another thread explicitly called close(). We need to - // wait for the closing to complete before returning. - synchronized (this) { - while (connectionState < cs_CLOSED) { - try { - this.wait(); - } catch (InterruptedException e) { - // ignore - } - } - } - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", after primary close; state = " + - getConnectionState()); - } - return; - } - - if (!closeSocketCalled) { - closeSocketCalled = true; - closeSocket(selfInitiated); - } - - break; - } - } finally { - synchronized (this) { - // Upon exit from this method, the state is always >= cs_CLOSED - connectionState = (connectionState == cs_APP_CLOSED) - ? cs_APP_CLOSED : cs_CLOSED; - // notify any threads waiting for the closing to finish - this.notifyAll(); - } - if (closeSocketCalled) { - // Dispose of ciphers since we've closed socket - disposeCiphers(); - } - if (cachedThrowable != null) { - /* - * Rethrow the error to the calling method - * The Throwable caught can only be an Error or RuntimeException - */ - if (cachedThrowable instanceof Error) - throw (Error) cachedThrowable; - if (cachedThrowable instanceof RuntimeException) - throw (RuntimeException) cachedThrowable; - } - } - } - - /** - * Reads a close_notify or a fatal alert from the input stream. - * Keep reading records until we get a close_notify or until - * the connection is otherwise closed. The close_notify or alert - * might be read by another reader, - * which will then process the close and set the connection state. - */ - void waitForClose(boolean rethrow) throws IOException { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", waiting for close_notify or alert: state " - + getConnectionState()); - } - - try { - int state; - - while (((state = getConnectionState()) != cs_CLOSED) && - (state != cs_ERROR) && (state != cs_APP_CLOSED)) { - // create the InputRecord if it isn't initialized. - if (inrec == null) { - inrec = new InputRecord(); - } - - // Ask for app data and then throw it away - try { - readRecord(inrec, true); - } catch (SocketTimeoutException e) { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println( - Thread.currentThread().getName() + - ", received Exception: " + e); - } - fatal((byte)(-1), "Did not receive close_notify from peer", e); - } - } - inrec = null; - } catch (IOException e) { - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", Exception while waiting for close " +e); - } - if (rethrow) { - throw e; // pass exception up - } - } - } - - /** - * Called by closeInternal() only. Be sure to consider the - * synchronization locks carefully before calling it elsewhere. - */ - private void disposeCiphers() { - // See comment in changeReadCiphers() - synchronized (readLock) { - readCipher.dispose(); - } - // See comment in changeReadCiphers() - writeLock.lock(); - try { - writeCipher.dispose(); - } finally { - writeLock.unlock(); - } - } - - // - // EXCEPTION AND ALERT HANDLING - // - - /** - * Handle an exception. This method is called by top level exception - * handlers (in read(), write()) to make sure we always shutdown the - * connection correctly and do not pass runtime exception to the - * application. - */ - void handleException(Exception e) throws IOException { - handleException(e, true); - } - - /** - * Handle an exception. This method is called by top level exception - * handlers (in read(), write(), startHandshake()) to make sure we - * always shutdown the connection correctly and do not pass runtime - * exception to the application. - * - * This method never returns normally, it always throws an IOException. - * - * We first check if the socket has already been shutdown because of an - * error. If so, we just rethrow the exception. If the socket has not - * been shutdown, we sent a fatal alert and remember the exception. - * - * @param e the Exception - * @param resumable indicates the caller process is resumable from the - * exception. If <code>resumable</code>, the socket will be - * reserved for exceptions like timeout; otherwise, the socket - * will be closed, no further communications could be done. - */ - synchronized private void handleException(Exception e, boolean resumable) - throws IOException { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", handling exception: " + e.toString()); - } - - // don't close the Socket in case of timeouts or interrupts if - // the process is resumable. - if (e instanceof InterruptedIOException && resumable) { - throw (IOException)e; - } - - // if we've already shutdown because of an error, - // there is nothing to do except rethrow the exception - if (closeReason != null) { - if (e instanceof IOException) { // includes SSLException - throw (IOException)e; - } else { - // this is odd, not an IOException. - // normally, this should not happen - // if closeReason has been already been set - throw Alerts.getSSLException(Alerts.alert_internal_error, e, - "Unexpected exception"); - } - } - - // need to perform error shutdown - boolean isSSLException = (e instanceof SSLException); - if ((isSSLException == false) && (e instanceof IOException)) { - // IOException from the socket - // this means the TCP connection is already dead - // we call fatal just to set the error status - try { - fatal(Alerts.alert_unexpected_message, e); - } catch (IOException ee) { - // ignore (IOException wrapped in SSLException) - } - // rethrow original IOException - throw (IOException)e; - } - - // must be SSLException or RuntimeException - byte alertType; - if (isSSLException) { - if (e instanceof SSLHandshakeException) { - alertType = Alerts.alert_handshake_failure; - } else { - alertType = Alerts.alert_unexpected_message; - } - } else { - alertType = Alerts.alert_internal_error; - } - fatal(alertType, e); - } - - /* - * Send a warning alert. - */ - void warning(byte description) { - sendAlert(Alerts.alert_warning, description); - } - - synchronized void fatal(byte description, String diagnostic) - throws IOException { - fatal(description, diagnostic, null); - } - - synchronized void fatal(byte description, Throwable cause) - throws IOException { - fatal(description, null, cause); - } - - /* - * Send a fatal alert, and throw an exception so that callers will - * need to stand on their heads to accidentally continue processing. - */ - synchronized void fatal(byte description, String diagnostic, - Throwable cause) throws IOException { - if ((input != null) && (input.r != null)) { - input.r.close(); - } - sess.invalidate(); - if (handshakeSession != null) { - handshakeSession.invalidate(); - } - - int oldState = connectionState; - if (connectionState < cs_ERROR) { - connectionState = cs_ERROR; - } - - /* - * Has there been an error received yet? If not, remember it. - * By RFC 2246, we don't bother waiting for a response. - * Fatal errors require immediate shutdown. - */ - if (closeReason == null) { - /* - * Try to clear the kernel buffer to avoid TCP connection resets. - */ - if (oldState == cs_HANDSHAKE) { - sockInput.skip(sockInput.available()); - } - - // If the description equals -1, the alert won't be sent to peer. - if (description != -1) { - sendAlert(Alerts.alert_fatal, description); - } - if (cause instanceof SSLException) { // only true if != null - closeReason = (SSLException)cause; - } else { - closeReason = - Alerts.getSSLException(description, cause, diagnostic); - } - } - - /* - * Clean up our side. - */ - closeSocket(); - // Another thread may have disposed the ciphers during closing - if (connectionState < cs_CLOSED) { - connectionState = (oldState == cs_APP_CLOSED) ? cs_APP_CLOSED - : cs_CLOSED; - - // We should lock readLock and writeLock if no deadlock risks. - // See comment in changeReadCiphers() - readCipher.dispose(); - writeCipher.dispose(); - } - - throw closeReason; - } - - - /* - * Process an incoming alert ... caller must already have synchronized - * access to "this". - */ - private void recvAlert(InputRecord r) throws IOException { - byte level = (byte)r.read(); - byte description = (byte)r.read(); - if (description == -1) { // check for short message - fatal(Alerts.alert_illegal_parameter, "Short alert message"); - } - - if (debug != null && (Debug.isOn("record") || - Debug.isOn("handshake"))) { - synchronized (System.out) { - System.out.print(Thread.currentThread().getName()); - System.out.print(", RECV " + protocolVersion + " ALERT: "); - if (level == Alerts.alert_fatal) { - System.out.print("fatal, "); - } else if (level == Alerts.alert_warning) { - System.out.print("warning, "); - } else { - System.out.print("<level " + (0x0ff & level) + ">, "); - } - System.out.println(Alerts.alertDescription(description)); - } - } - - if (level == Alerts.alert_warning) { - if (description == Alerts.alert_close_notify) { - if (connectionState == cs_HANDSHAKE) { - fatal(Alerts.alert_unexpected_message, - "Received close_notify during handshake"); - } else { - closeInternal(false); // reply to close - } - } else { - - // - // The other legal warnings relate to certificates, - // e.g. no_certificate, bad_certificate, etc; these - // are important to the handshaking code, which can - // also handle illegal protocol alerts if needed. - // - if (handshaker != null) { - handshaker.handshakeAlert(description); - } - } - } else { // fatal or unknown level - String reason = "Received fatal alert: " - + Alerts.alertDescription(description); - if (closeReason == null) { - closeReason = Alerts.getSSLException(description, reason); - } - fatal(Alerts.alert_unexpected_message, reason); - } - } - - - /* - * Emit alerts. Caller must have synchronized with "this". - */ - private void sendAlert(byte level, byte description) { - // the connectionState cannot be cs_START - if (connectionState >= cs_SENT_CLOSE) { - return; - } - - // For initial handshaking, don't send alert message to peer if - // handshaker has not started. - if (connectionState == cs_HANDSHAKE && - (handshaker == null || !handshaker.started())) { - return; - } - - OutputRecord r = new OutputRecord(Record.ct_alert); - r.setVersion(protocolVersion); - - boolean useDebug = debug != null && Debug.isOn("ssl"); - if (useDebug) { - synchronized (System.out) { - System.out.print(Thread.currentThread().getName()); - System.out.print(", SEND " + protocolVersion + " ALERT: "); - if (level == Alerts.alert_fatal) { - System.out.print("fatal, "); - } else if (level == Alerts.alert_warning) { - System.out.print("warning, "); - } else { - System.out.print("<level = " + (0x0ff & level) + ">, "); - } - System.out.println("description = " - + Alerts.alertDescription(description)); - } - } - - r.write(level); - r.write(description); - try { - writeRecord(r); - } catch (IOException e) { - if (useDebug) { - System.out.println(Thread.currentThread().getName() + - ", Exception sending alert: " + e); - } - } - } - - // - // VARIOUS OTHER METHODS - // - - /* - * When a connection finishes handshaking by enabling use of a newly - * negotiated session, each end learns about it in two halves (read, - * and write). When both read and write ciphers have changed, and the - * last handshake message has been read, the connection has joined - * (rejoined) the new session. - * - * NOTE: The SSLv3 spec is rather unclear on the concepts here. - * Sessions don't change once they're established (including cipher - * suite and master secret) but connections can join them (and leave - * them). They're created by handshaking, though sometime handshaking - * causes connections to join up with pre-established sessions. - */ - private void changeReadCiphers() throws SSLException { - if (connectionState != cs_HANDSHAKE - && connectionState != cs_RENEGOTIATE) { - throw new SSLProtocolException( - "State error, change cipher specs"); - } - - // ... create decompressor - - CipherBox oldCipher = readCipher; - - try { - readCipher = handshaker.newReadCipher(); - readAuthenticator = handshaker.newReadAuthenticator(); - } catch (GeneralSecurityException e) { - // "can't happen" - throw new SSLException("Algorithm missing: ", e); - } - - /* - * Dispose of any intermediate state in the underlying cipher. - * For PKCS11 ciphers, this will release any attached sessions, - * and thus make finalization faster. - * - * Since MAC's doFinal() is called for every SSL/TLS packet, it's - * not necessary to do the same with MAC's. - */ - oldCipher.dispose(); - } - - // used by Handshaker - void changeWriteCiphers() throws SSLException { - if (connectionState != cs_HANDSHAKE - && connectionState != cs_RENEGOTIATE) { - throw new SSLProtocolException( - "State error, change cipher specs"); - } - - // ... create compressor - - CipherBox oldCipher = writeCipher; - - try { - writeCipher = handshaker.newWriteCipher(); - writeAuthenticator = handshaker.newWriteAuthenticator(); - } catch (GeneralSecurityException e) { - // "can't happen" - throw new SSLException("Algorithm missing: ", e); - } - - // See comment above. - oldCipher.dispose(); - - // reset the flag of the first application record - isFirstAppOutputRecord = true; - } - - /* - * Updates the SSL version associated with this connection. - * Called from Handshaker once it has determined the negotiated version. - */ - synchronized void setVersion(ProtocolVersion protocolVersion) { - this.protocolVersion = protocolVersion; - output.r.setVersion(protocolVersion); - } - - // - // ONLY used by ClientHandshaker for the server hostname during handshaking - // - synchronized String getHost() { - // Note that the host may be null or empty for localhost. - if (host == null || host.length() == 0) { - useImplicitHost(true); - } - - return host; - } - - /* - * Try to set and use the implicit specified hostname - */ - private synchronized void useImplicitHost(boolean noSniUpdate) { - - // Note: If the local name service is not trustworthy, reverse - // host name resolution should not be performed for endpoint - // identification. Use the application original specified - // hostname or IP address instead. - - // Get the original hostname via jdk.internal.misc.SharedSecrets - InetAddress inetAddress = getInetAddress(); - if (inetAddress == null) { // not connected - return; - } - - JavaNetAccess jna = SharedSecrets.getJavaNetAccess(); - String originalHostname = jna.getOriginalHostName(inetAddress); - if ((originalHostname != null) && - (originalHostname.length() != 0)) { - - host = originalHostname; - if (!noSniUpdate && serverNames.isEmpty() && !noSniExtension) { - serverNames = - Utilities.addToSNIServerNameList(serverNames, host); - - if (!roleIsServer && - (handshaker != null) && !handshaker.started()) { - handshaker.setSNIServerNames(serverNames); - } - } - - return; - } - - // No explicitly specified hostname, no server name indication. - if (!trustNameService) { - // The local name service is not trustworthy, use IP address. - host = inetAddress.getHostAddress(); - } else { - // Use the underlying reverse host name resolution service. - host = getInetAddress().getHostName(); - } - } - - - // ONLY used by HttpsClient to setup the URI specified hostname - // - // Please NOTE that this method MUST be called before calling to - // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter - // may override SNIHostName in the customized server name indication. - synchronized public void setHost(String host) { - this.host = host; - this.serverNames = - Utilities.addToSNIServerNameList(this.serverNames, this.host); - - if (!roleIsServer && (handshaker != null) && !handshaker.started()) { - handshaker.setSNIServerNames(serverNames); - } - } - - /** - * Gets an input stream to read from the peer on the other side. - * Data read from this stream was always integrity protected in - * transit, and will usually have been confidentiality protected. - */ - @Override - synchronized public InputStream getInputStream() throws IOException { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } - - /* - * Can't call isConnected() here, because the Handshakers - * do some initialization before we actually connect. - */ - if (connectionState == cs_START) { - throw new SocketException("Socket is not connected"); - } - - return input; - } - - /** - * Gets an output stream to write to the peer on the other side. - * Data written on this stream is always integrity protected, and - * will usually be confidentiality protected. - */ - @Override - synchronized public OutputStream getOutputStream() throws IOException { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } - - /* - * Can't call isConnected() here, because the Handshakers - * do some initialization before we actually connect. - */ - if (connectionState == cs_START) { - throw new SocketException("Socket is not connected"); - } - - return output; - } - - /** - * Returns the the SSL Session in use by this connection. These can - * be long lived, and frequently correspond to an entire login session - * for some user. - */ - @Override - public SSLSession getSession() { - /* - * Force a synchronous handshake, if appropriate. - */ - if (getConnectionState() == cs_HANDSHAKE) { - try { - // start handshaking, if failed, the connection will be closed. - startHandshake(false); - } catch (IOException e) { - // handshake failed. log and return a nullSession - if (debug != null && Debug.isOn("handshake")) { - System.out.println(Thread.currentThread().getName() + - ", IOException in getSession(): " + e); - } - } - } - synchronized (this) { - return sess; - } - } - - @Override - synchronized public SSLSession getHandshakeSession() { - return handshakeSession; - } - - synchronized void setHandshakeSession(SSLSessionImpl session) { - handshakeSession = session; - } - - /** - * Controls whether new connections may cause creation of new SSL - * sessions. - * - * As long as handshaking has not started, we can change - * whether we enable session creations. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setEnableSessionCreation(boolean flag) { - enableSessionCreation = flag; - - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnableSessionCreation(enableSessionCreation); - } - } - - /** - * Returns true if new connections may cause creation of new SSL - * sessions. - */ - @Override - synchronized public boolean getEnableSessionCreation() { - return enableSessionCreation; - } - - - /** - * Sets the flag controlling whether a server mode socket - * *REQUIRES* SSL client authentication. - * - * As long as handshaking has not started, we can change - * whether client authentication is needed. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setNeedClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); - - if ((handshaker != null) && - (handshaker instanceof ServerHandshaker) && - !handshaker.activated()) { - ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); - } - } - - @Override - synchronized public boolean getNeedClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_required); - } - - /** - * Sets the flag controlling whether a server mode socket - * *REQUESTS* SSL client authentication. - * - * As long as handshaking has not started, we can change - * whether client authentication is requested. Otherwise, - * we will need to wait for the next handshake. - */ - @Override - synchronized public void setWantClientAuth(boolean flag) { - doClientAuth = (flag ? - SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); - - if ((handshaker != null) && - (handshaker instanceof ServerHandshaker) && - !handshaker.activated()) { - ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); - } - } - - @Override - synchronized public boolean getWantClientAuth() { - return (doClientAuth == SSLEngineImpl.clauth_requested); - } - - - /** - * Sets the flag controlling whether the socket is in SSL - * client or server mode. Must be called before any SSL - * traffic has started. - */ - @Override - @SuppressWarnings("fallthrough") - synchronized public void setUseClientMode(boolean flag) { - switch (connectionState) { - - case cs_START: - /* - * If we need to change the socket mode and the enabled - * protocols and cipher suites haven't specifically been - * set by the user, change them to the corresponding - * default ones. - */ - if (roleIsServer != (!flag)) { - if (sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = - sslContext.getDefaultProtocolList(!flag); - } - - if (sslContext.isDefaultCipherSuiteList(enabledCipherSuites)) { - enabledCipherSuites = - sslContext.getDefaultCipherSuiteList(!flag); - } - } - - roleIsServer = !flag; - break; - - case cs_HANDSHAKE: - /* - * If we have a handshaker, but haven't started - * SSL traffic, we can throw away our current - * handshaker, and start from scratch. Don't - * need to call doneConnect() again, we already - * have the streams. - */ - assert(handshaker != null); - if (!handshaker.activated()) { - /* - * If we need to change the socket mode and the enabled - * protocols haven't specifically been set by the user, - * change them to the corresponding default ones. - */ - if (roleIsServer != (!flag) && - sslContext.isDefaultProtocolList(enabledProtocols)) { - enabledProtocols = sslContext.getDefaultProtocolList(!flag); - } - roleIsServer = !flag; - connectionState = cs_START; - initHandshaker(); - break; - } - - // If handshake has started, that's an error. Fall through... - - default: - if (debug != null && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", setUseClientMode() invoked in state = " + - connectionState); - } - throw new IllegalArgumentException( - "Cannot change mode after SSL traffic has started"); - } - } - - @Override - synchronized public boolean getUseClientMode() { - return !roleIsServer; - } - - - /** - * Returns the names of the cipher suites which could be enabled for use - * on an SSL connection. Normally, only a subset of these will actually - * be enabled by default, since this list may include cipher suites which - * do not support the mutual authentication of servers and clients, or - * which do not protect data confidentiality. Servers may also need - * certain kinds of certificates to use certain cipher suites. - * - * @return an array of cipher suite names - */ - @Override - public String[] getSupportedCipherSuites() { - return sslContext.getSupportedCipherSuiteList().toStringArray(); - } - - /** - * Controls which particular cipher suites are enabled for use on - * this connection. The cipher suites must have been listed by - * getCipherSuites() as being supported. Even if a suite has been - * enabled, it might never be used if no peer supports it or the - * requisite certificates (and private keys) are not available. - * - * @param suites Names of all the cipher suites to enable. - */ - @Override - synchronized public void setEnabledCipherSuites(String[] suites) { - enabledCipherSuites = new CipherSuiteList(suites); - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnabledCipherSuites(enabledCipherSuites); - } - } - - /** - * Returns the names of the SSL cipher suites which are currently enabled - * for use on this connection. When an SSL socket is first created, - * all enabled cipher suites <em>(a)</em> protect data confidentiality, - * by traffic encryption, and <em>(b)</em> can mutually authenticate - * both clients and servers. Thus, in some environments, this value - * might be empty. - * - * @return an array of cipher suite names - */ - @Override - synchronized public String[] getEnabledCipherSuites() { - return enabledCipherSuites.toStringArray(); - } - - - /** - * Returns the protocols that are supported by this implementation. - * A subset of the supported protocols may be enabled for this connection - * @return an array of protocol names. - */ - @Override - public String[] getSupportedProtocols() { - return sslContext.getSuportedProtocolList().toStringArray(); - } - - /** - * Controls which protocols are enabled for use on - * this connection. The protocols must have been listed by - * getSupportedProtocols() as being supported. - * - * @param protocols protocols to enable. - * @exception IllegalArgumentException when one of the protocols - * named by the parameter is not supported. - */ - @Override - synchronized public void setEnabledProtocols(String[] protocols) { - enabledProtocols = new ProtocolList(protocols); - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setEnabledProtocols(enabledProtocols); - } - } - - @Override - synchronized public String[] getEnabledProtocols() { - return enabledProtocols.toStringArray(); - } - - /** - * Assigns the socket timeout. - * @see java.net.Socket#setSoTimeout - */ - @Override - public void setSoTimeout(int timeout) throws SocketException { - if ((debug != null) && Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", setSoTimeout(" + timeout + ") called"); - } - - super.setSoTimeout(timeout); - } - - /** - * Registers an event listener to receive notifications that an - * SSL handshake has completed on this connection. - */ - @Override - public synchronized void addHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener is null"); - } - if (handshakeListeners == null) { - handshakeListeners = new - HashMap<HandshakeCompletedListener, AccessControlContext>(4); - } - handshakeListeners.put(listener, AccessController.getContext()); - } - - - /** - * Removes a previously registered handshake completion listener. - */ - @Override - public synchronized void removeHandshakeCompletedListener( - HandshakeCompletedListener listener) { - if (handshakeListeners == null) { - throw new IllegalArgumentException("no listeners"); - } - if (handshakeListeners.remove(listener) == null) { - throw new IllegalArgumentException("listener not registered"); - } - if (handshakeListeners.isEmpty()) { - handshakeListeners = null; - } - } - - /** - * Returns the SSLParameters in effect for this SSLSocket. - */ - @Override - synchronized public SSLParameters getSSLParameters() { - SSLParameters params = super.getSSLParameters(); - - // the super implementation does not handle the following parameters - params.setEndpointIdentificationAlgorithm(identificationProtocol); - params.setAlgorithmConstraints(algorithmConstraints); - - if (sniMatchers.isEmpty() && !noSniMatcher) { - // 'null' indicates none has been set - params.setSNIMatchers(null); - } else { - params.setSNIMatchers(sniMatchers); - } - - if (serverNames.isEmpty() && !noSniExtension) { - // 'null' indicates none has been set - params.setServerNames(null); - } else { - params.setServerNames(serverNames); - } - - params.setUseCipherSuitesOrder(preferLocalCipherSuites); - params.setApplicationProtocols(applicationProtocols); - - return params; - } - - /** - * Applies SSLParameters to this socket. - */ - @Override - synchronized public void setSSLParameters(SSLParameters params) { - super.setSSLParameters(params); - - // the super implementation does not handle the following parameters - identificationProtocol = params.getEndpointIdentificationAlgorithm(); - algorithmConstraints = params.getAlgorithmConstraints(); - preferLocalCipherSuites = params.getUseCipherSuitesOrder(); - - List<SNIServerName> sniNames = params.getServerNames(); - if (sniNames != null) { - noSniExtension = sniNames.isEmpty(); - serverNames = sniNames; - } - - Collection<SNIMatcher> matchers = params.getSNIMatchers(); - if (matchers != null) { - noSniMatcher = matchers.isEmpty(); - sniMatchers = matchers; - } - - applicationProtocols = params.getApplicationProtocols(); - - if ((handshaker != null) && !handshaker.started()) { - handshaker.setIdentificationProtocol(identificationProtocol); - handshaker.setAlgorithmConstraints(algorithmConstraints); - handshaker.setApplicationProtocols(applicationProtocols); - if (roleIsServer) { - handshaker.setSNIMatchers(sniMatchers); - handshaker.setUseCipherSuitesOrder(preferLocalCipherSuites); - } else { - handshaker.setSNIServerNames(serverNames); - } - } - } - - @Override - public synchronized String getApplicationProtocol() { - return applicationProtocol; - } - - @Override - public synchronized String getHandshakeApplicationProtocol() { - if ((handshaker != null) && handshaker.started()) { - return handshaker.getHandshakeApplicationProtocol(); - } - return null; - } - - @Override - public synchronized void setHandshakeApplicationProtocolSelector( - BiFunction<SSLSocket, List<String>, String> selector) { - applicationProtocolSelector = selector; - if ((handshaker != null) && !handshaker.activated()) { - handshaker.setApplicationProtocolSelectorSSLSocket(selector); - } - } - - @Override - public synchronized BiFunction<SSLSocket, List<String>, String> - getHandshakeApplicationProtocolSelector() { - return this.applicationProtocolSelector; - } - - // - // We allocate a separate thread to deliver handshake completion - // events. This ensures that the notifications don't block the - // protocol state machine. - // - private static class NotifyHandshakeThread extends Thread { - - private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> - targets; // who gets notified - private HandshakeCompletedEvent event; // the notification - - NotifyHandshakeThread( - Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> - entrySet, HandshakeCompletedEvent e) { - - super("HandshakeCompletedNotify-Thread"); - targets = new HashSet<>(entrySet); // clone the entry set - event = e; - } - - @Override - public void run() { - // Don't need to synchronize, as it only runs in one thread. - for (Map.Entry<HandshakeCompletedListener,AccessControlContext> - entry : targets) { - - final HandshakeCompletedListener l = entry.getKey(); - AccessControlContext acc = entry.getValue(); - AccessController.doPrivileged(new PrivilegedAction<Void>() { - @Override - public Void run() { - l.handshakeCompleted(event); - return null; - } - }, acc); - } - } - } - - /** - * Returns a printable representation of this end of the connection. - */ - @Override - public String toString() { - StringBuffer retval = new StringBuffer(80); - - retval.append(Integer.toHexString(hashCode())); - retval.append("["); - retval.append(sess.getCipherSuite()); - retval.append(": "); - - retval.append(super.toString()); - retval.append("]"); - - return retval.toString(); - } -}
--- a/src/share/classes/sun/security/ssl/ServerHandshaker.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2062 +0,0 @@ -/* - * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.*; -import java.util.*; -import java.security.*; -import java.security.cert.*; -import java.security.interfaces.*; -import java.security.spec.ECParameterSpec; -import java.math.BigInteger; -import java.util.function.BiFunction; - -import javax.crypto.SecretKey; -import javax.crypto.spec.SecretKeySpec; - -import javax.net.ssl.*; - -import javax.security.auth.Subject; - -import sun.security.util.KeyUtil; -import sun.security.util.LegacyAlgorithmConstraints; -import sun.security.action.GetPropertyAction; -import sun.security.ssl.HandshakeMessage.*; -import sun.security.ssl.CipherSuite.*; -import sun.security.ssl.SignatureAndHashAlgorithm.*; -import static sun.security.ssl.CipherSuite.KeyExchange.*; - -/** - * ServerHandshaker does the protocol handshaking from the point - * of view of a server. It is driven asychronously by handshake messages - * as delivered by the parent Handshaker class, and also uses - * common functionality (e.g. key generation) that is provided there. - * - * @author David Brownell - */ -final class ServerHandshaker extends Handshaker { - - // is the server going to require the client to authenticate? - private byte doClientAuth; - - // our authentication info - private X509Certificate[] certs; - private PrivateKey privateKey; - - private Object serviceCreds; - - // flag to check for clientCertificateVerify message - private boolean needClientVerify = false; - - /* - * For exportable ciphersuites using non-exportable key sizes, we use - * ephemeral RSA keys. We could also do anonymous RSA in the same way - * but there are no such ciphersuites currently defined. - */ - private PrivateKey tempPrivateKey; - private PublicKey tempPublicKey; - - /* - * For anonymous and ephemeral Diffie-Hellman key exchange, we use - * ephemeral Diffie-Hellman keys. - */ - private DHCrypt dh; - - // Helper for ECDH based key exchanges - private ECDHCrypt ecdh; - - // version request by the client in its ClientHello - // we remember it for the RSA premaster secret version check - private ProtocolVersion clientRequestedVersion; - - // client supported elliptic curves - private EllipticCurvesExtension requestedCurves; - - // the preferable signature algorithm used by ServerKeyExchange message - SignatureAndHashAlgorithm preferableSignatureAlgorithm; - - // Flag to use smart ephemeral DH key which size matches the corresponding - // authentication key - private static final boolean useSmartEphemeralDHKeys; - - // Flag to use legacy ephemeral DH key which size is 512 bits for - // exportable cipher suites, and 768 bits for others - private static final boolean useLegacyEphemeralDHKeys; - - // The customized ephemeral DH key size for non-exportable cipher suites. - private static final int customizedDHKeySize; - - // legacy algorithm constraints - private static final AlgorithmConstraints legacyAlgorithmConstraints = - new LegacyAlgorithmConstraints( - LegacyAlgorithmConstraints.PROPERTY_TLS_LEGACY_ALGS, - new SSLAlgorithmDecomposer()); - - static { - String property = AccessController.doPrivileged( - new GetPropertyAction("jdk.tls.ephemeralDHKeySize")); - if (property == null || property.length() == 0) { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = false; - customizedDHKeySize = -1; - } else if ("matched".equals(property)) { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = true; - customizedDHKeySize = -1; - } else if ("legacy".equals(property)) { - useLegacyEphemeralDHKeys = true; - useSmartEphemeralDHKeys = false; - customizedDHKeySize = -1; - } else { - useLegacyEphemeralDHKeys = false; - useSmartEphemeralDHKeys = false; - - try { - // DH parameter generation can be extremely slow, best to - // use one of the supported pre-computed DH parameters - // (see DHCrypt class). - customizedDHKeySize = Integer.parseUnsignedInt(property); - if (customizedDHKeySize < 1024 || customizedDHKeySize > 8192 || - (customizedDHKeySize & 0x3f) != 0) { - throw new IllegalArgumentException( - "Unsupported customized DH key size: " + - customizedDHKeySize + ". " + - "The key size must be multiple of 64, " + - "and can only range from 1024 to 8192 (inclusive)"); - } - } catch (NumberFormatException nfe) { - throw new IllegalArgumentException( - "Invalid system property jdk.tls.ephemeralDHKeySize"); - } - } - } - - /* - * Constructor ... use the keys found in the auth context. - */ - ServerHandshaker(SSLSocketImpl socket, SSLContextImpl context, - ProtocolList enabledProtocols, byte clientAuth, - ProtocolVersion activeProtocolVersion, boolean isInitialHandshake, - boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - super(socket, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - doClientAuth = clientAuth; - } - - /* - * Constructor ... use the keys found in the auth context. - */ - ServerHandshaker(SSLEngineImpl engine, SSLContextImpl context, - ProtocolList enabledProtocols, byte clientAuth, - ProtocolVersion activeProtocolVersion, - boolean isInitialHandshake, boolean secureRenegotiation, - byte[] clientVerifyData, byte[] serverVerifyData) { - - super(engine, context, enabledProtocols, - (clientAuth != SSLEngineImpl.clauth_none), false, - activeProtocolVersion, isInitialHandshake, secureRenegotiation, - clientVerifyData, serverVerifyData); - doClientAuth = clientAuth; - } - - /* - * As long as handshaking has not started, we can change - * whether client authentication is required. Otherwise, - * we will need to wait for the next handshake. - */ - void setClientAuth(byte clientAuth) { - doClientAuth = clientAuth; - } - - /* - * This routine handles all the server side handshake messages, one at - * a time. Given the message type (and in some cases the pending cipher - * spec) it parses the type-specific message. Then it calls a function - * that handles that specific message. - * - * It updates the state machine as each message is processed, and writes - * responses as needed using the connection in the constructor. - */ - @Override - void processMessage(byte type, int message_len) - throws IOException { - - // check the handshake state - handshakeState.check(type); - - switch (type) { - case HandshakeMessage.ht_client_hello: - ClientHello ch = new ClientHello(input, message_len); - handshakeState.update(ch, resumingSession); - /* - * send it off for processing. - */ - this.clientHello(ch); - break; - - case HandshakeMessage.ht_certificate: - if (doClientAuth == SSLEngineImpl.clauth_none) { - fatalSE(Alerts.alert_unexpected_message, - "client sent unsolicited cert chain"); - // NOTREACHED - } - CertificateMsg certificateMsg = new CertificateMsg(input); - handshakeState.update(certificateMsg, resumingSession); - this.clientCertificate(certificateMsg); - break; - - case HandshakeMessage.ht_client_key_exchange: - SecretKey preMasterSecret; - switch (keyExchange) { - case K_RSA: - case K_RSA_EXPORT: - /* - * The client's pre-master secret is decrypted using - * either the server's normal private RSA key, or the - * temporary one used for non-export or signing-only - * certificates/keys. - */ - RSAClientKeyExchange pms = new RSAClientKeyExchange( - protocolVersion, clientRequestedVersion, - sslContext.getSecureRandom(), input, - message_len, privateKey); - handshakeState.update(pms, resumingSession); - preMasterSecret = this.clientKeyExchange(pms); - break; - case K_KRB5: - case K_KRB5_EXPORT: - KerberosClientKeyExchange kke = - new KerberosClientKeyExchange(protocolVersion, - clientRequestedVersion, - sslContext.getSecureRandom(), - input, - this.getAccSE(), - serviceCreds); - handshakeState.update(kke, resumingSession); - preMasterSecret = this.clientKeyExchange(kke); - break; - case K_DHE_RSA: - case K_DHE_DSS: - case K_DH_ANON: - /* - * The pre-master secret is derived using the normal - * Diffie-Hellman calculation. Note that the main - * protocol difference in these five flavors is in how - * the ServerKeyExchange message was constructed! - */ - DHClientKeyExchange dhcke = new DHClientKeyExchange(input); - handshakeState.update(dhcke, resumingSession); - preMasterSecret = this.clientKeyExchange(dhcke); - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - ECDHClientKeyExchange ecdhcke = - new ECDHClientKeyExchange(input); - handshakeState.update(ecdhcke, resumingSession); - preMasterSecret = this.clientKeyExchange(ecdhcke); - break; - default: - throw new SSLProtocolException - ("Unrecognized key exchange: " + keyExchange); - } - - // Need to add the hash for RFC 7627. - if (session.getUseExtendedMasterSecret()) { - input.digestNow(); - } - - // - // All keys are calculated from the premaster secret - // and the exchanged nonces in the same way. - // - calculateKeys(preMasterSecret, clientRequestedVersion); - break; - - case HandshakeMessage.ht_certificate_verify: - CertificateVerify cvm = - new CertificateVerify(input, - getLocalSupportedSignAlgs(), protocolVersion); - handshakeState.update(cvm, resumingSession); - this.clientCertificateVerify(cvm); - break; - - case HandshakeMessage.ht_finished: - Finished cfm = - new Finished(protocolVersion, input, cipherSuite); - handshakeState.update(cfm, resumingSession); - this.clientFinished(cfm); - break; - - default: - throw new SSLProtocolException( - "Illegal server handshake msg, " + type); - } - } - - - /* - * ClientHello presents the server with a bunch of options, to which the - * server replies with a ServerHello listing the ones which this session - * will use. If needed, it also writes its Certificate plus in some cases - * a ServerKeyExchange message. It may also write a CertificateRequest, - * to elicit a client certificate. - * - * All these messages are terminated by a ServerHelloDone message. In - * most cases, all this can be sent in a single Record. - */ - private void clientHello(ClientHello mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - // Reject client initiated renegotiation? - // - // If server side should reject client-initiated renegotiation, - // send an alert_handshake_failure fatal alert, not a no_renegotiation - // warning alert (no_renegotiation must be a warning: RFC 2246). - // no_renegotiation might seem more natural at first, but warnings - // are not appropriate because the sending party does not know how - // the receiving party will behave. This state must be treated as - // a fatal server condition. - // - // This will not have any impact on server initiated renegotiation. - if (rejectClientInitiatedRenego && !isInitialHandshake && - !serverHelloRequested) { - fatalSE(Alerts.alert_handshake_failure, - "Client initiated renegotiation is not allowed"); - } - - // check the server name indication if required - ServerNameExtension clientHelloSNIExt = (ServerNameExtension) - mesg.extensions.get(ExtensionType.EXT_SERVER_NAME); - if (!sniMatchers.isEmpty()) { - // we do not reject client without SNI extension - if (clientHelloSNIExt != null && - !clientHelloSNIExt.isMatched(sniMatchers)) { - fatalSE(Alerts.alert_unrecognized_name, - "Unrecognized server name indication"); - } - } - - // Does the message include security renegotiation indication? - boolean renegotiationIndicated = false; - - // check the TLS_EMPTY_RENEGOTIATION_INFO_SCSV - CipherSuiteList cipherSuites = mesg.getCipherSuites(); - if (cipherSuites.contains(CipherSuite.C_SCSV)) { - renegotiationIndicated = true; - if (isInitialHandshake) { - secureRenegotiation = true; - } else { - // abort the handshake with a fatal handshake_failure alert - if (secureRenegotiation) { - fatalSE(Alerts.alert_handshake_failure, - "The SCSV is present in a secure renegotiation"); - } else { - fatalSE(Alerts.alert_handshake_failure, - "The SCSV is present in a insecure renegotiation"); - } - } - } - - // check the "renegotiation_info" extension - RenegotiationInfoExtension clientHelloRI = (RenegotiationInfoExtension) - mesg.extensions.get(ExtensionType.EXT_RENEGOTIATION_INFO); - if (clientHelloRI != null) { - renegotiationIndicated = true; - if (isInitialHandshake) { - // verify the length of the "renegotiated_connection" field - if (!clientHelloRI.isEmpty()) { - // abort the handshake with a fatal handshake_failure alert - fatalSE(Alerts.alert_handshake_failure, - "The renegotiation_info field is not empty"); - } - - secureRenegotiation = true; - } else { - if (!secureRenegotiation) { - // unexpected RI extension for insecure renegotiation, - // abort the handshake with a fatal handshake_failure alert - fatalSE(Alerts.alert_handshake_failure, - "The renegotiation_info is present in a insecure " + - "renegotiation"); - } - - // verify the client_verify_data value - if (!MessageDigest.isEqual(clientVerifyData, - clientHelloRI.getRenegotiatedConnection())) { - fatalSE(Alerts.alert_handshake_failure, - "Incorrect verify data in ClientHello " + - "renegotiation_info message"); - } - } - } else if (!isInitialHandshake && secureRenegotiation) { - // if the connection's "secure_renegotiation" flag is set to TRUE - // and the "renegotiation_info" extension is not present, abort - // the handshake. - fatalSE(Alerts.alert_handshake_failure, - "Inconsistent secure renegotiation indication"); - } - - // if there is no security renegotiation indication or the previous - // handshake is insecure. - if (!renegotiationIndicated || !secureRenegotiation) { - if (isInitialHandshake) { - if (!allowLegacyHelloMessages) { - // abort the handshake with a fatal handshake_failure alert - fatalSE(Alerts.alert_handshake_failure, - "Failed to negotiate the use of secure renegotiation"); - } - - // continue with legacy ClientHello - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Warning: No renegotiation " + - "indication in ClientHello, allow legacy ClientHello"); - } - } else if (!allowUnsafeRenegotiation) { - // abort the handshake - if (activeProtocolVersion.v >= ProtocolVersion.TLS10.v) { - // respond with a no_renegotiation warning - warningSE(Alerts.alert_no_renegotiation); - - // invalidate the handshake so that the caller can - // dispose this object. - invalidated = true; - - // If there is still unread block in the handshake - // input stream, it would be truncated with the disposal - // and the next handshake message will become incomplete. - // - // However, according to SSL/TLS specifications, no more - // handshake message could immediately follow ClientHello - // or HelloRequest. But in case of any improper messages, - // we'd better check to ensure there is no remaining bytes - // in the handshake input stream. - if (input.available() > 0) { - fatalSE(Alerts.alert_unexpected_message, - "ClientHello followed by an unexpected " + - "handshake message"); - } - - return; - } else { - // For SSLv3, send the handshake_failure fatal error. - // Note that SSLv3 does not define a no_renegotiation - // alert like TLSv1. However we cannot ignore the message - // simply, otherwise the other side was waiting for a - // response that would never come. - fatalSE(Alerts.alert_handshake_failure, - "Renegotiation is not allowed"); - } - } else { // !isInitialHandshake && allowUnsafeRenegotiation - // continue with unsafe renegotiation. - if (debug != null && Debug.isOn("handshake")) { - System.out.println( - "Warning: continue with insecure renegotiation"); - } - } - } - - // check out the "extended_master_secret" extension - if (useExtendedMasterSecret) { - ExtendedMasterSecretExtension extendedMasterSecretExtension = - (ExtendedMasterSecretExtension)mesg.extensions.get( - ExtensionType.EXT_EXTENDED_MASTER_SECRET); - if (extendedMasterSecretExtension != null) { - requestedToUseEMS = true; - } else if (mesg.protocolVersion.v >= ProtocolVersion.TLS10.v) { - if (!allowLegacyMasterSecret) { - // For full handshake, if the server receives a ClientHello - // without the extension, it SHOULD abort the handshake if - // it does not wish to interoperate with legacy clients. - // - // As if extended master extension is required for full - // handshake, it MUST be used in abbreviated handshake too. - fatalSE(Alerts.alert_handshake_failure, - "Extended Master Secret extension is required"); - } - } - } - - // check the ALPN extension - ALPNExtension clientHelloALPN = (ALPNExtension) - mesg.extensions.get(ExtensionType.EXT_ALPN); - - // Use the application protocol callback when provided. - // Otherwise use the local list of application protocols. - boolean hasAPCallback = - ((engine != null && appProtocolSelectorSSLEngine != null) || - (conn != null && appProtocolSelectorSSLSocket != null)); - - if (!hasAPCallback) { - if ((clientHelloALPN != null) && (localApl.length > 0)) { - - // Intersect the requested and the locally supported, - // and save for later. - String negotiatedValue = null; - List<String> protocols = clientHelloALPN.getPeerAPs(); - - // Use server preference order - for (String ap : localApl) { - if (protocols.contains(ap)) { - negotiatedValue = ap; - break; - } - } - - if (negotiatedValue == null) { - fatalSE(Alerts.alert_no_application_protocol, - new SSLHandshakeException( - "No matching ALPN values")); - } - applicationProtocol = negotiatedValue; - - } else { - applicationProtocol = ""; - } - } // Otherwise, applicationProtocol will be set by the callback. - - /* - * Always make sure this entire record has been digested before we - * start emitting output, to ensure correct digesting order. - */ - input.digestNow(); - - /* - * FIRST, construct the ServerHello using the options and priorities - * from the ClientHello. Update the (pending) cipher spec as we do - * so, and save the client's version to protect against rollback - * attacks. - * - * There are a bunch of minor tasks here, and one major one: deciding - * if the short or the full handshake sequence will be used. - */ - ServerHello m1 = new ServerHello(); - - clientRequestedVersion = mesg.protocolVersion; - - // select a proper protocol version. - ProtocolVersion selectedVersion = - selectProtocolVersion(clientRequestedVersion); - if (selectedVersion == null || - selectedVersion.v == ProtocolVersion.SSL20Hello.v) { - fatalSE(Alerts.alert_handshake_failure, - "Client requested protocol " + clientRequestedVersion + - " not enabled or not supported"); - } - - handshakeHash.protocolDetermined(selectedVersion); - setVersion(selectedVersion); - - m1.protocolVersion = protocolVersion; - - // - // random ... save client and server values for later use - // in computing the master secret (from pre-master secret) - // and thence the other crypto keys. - // - // NOTE: this use of three inputs to generating _each_ set - // of ciphers slows things down, but it does increase the - // security since each connection in the session can hold - // its own authenticated (and strong) keys. One could make - // creation of a session a rare thing... - // - clnt_random = mesg.clnt_random; - svr_random = new RandomCookie(sslContext.getSecureRandom()); - m1.svr_random = svr_random; - - session = null; // forget about the current session - // - // Here we go down either of two paths: (a) the fast one, where - // the client's asked to rejoin an existing session, and the server - // permits this; (b) the other one, where a new session is created. - // - if (mesg.sessionId.length() != 0) { - // client is trying to resume a session, let's see... - - SSLSessionImpl previous = ((SSLSessionContextImpl)sslContext - .engineGetServerSessionContext()) - .get(mesg.sessionId.getId()); - // - // Check if we can use the fast path, resuming a session. We - // can do so iff we have a valid record for that session, and - // the cipher suite for that session was on the list which the - // client requested, and if we're not forgetting any needed - // authentication on the part of the client. - // - if (previous != null) { - resumingSession = previous.isRejoinable(); - - if (resumingSession) { - ProtocolVersion oldVersion = previous.getProtocolVersion(); - // cannot resume session with different version - if (oldVersion != mesg.protocolVersion) { - resumingSession = false; - } - } - - if (resumingSession && useExtendedMasterSecret) { - if (requestedToUseEMS && - !previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, If the original - // session did not use the "extended_master_secret" - // extension but the new ClientHello contains the - // extension, then the server MUST NOT perform the - // abbreviated handshake. Instead, it SHOULD continue - // with a full handshake. - resumingSession = false; - } else if (!requestedToUseEMS && - previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, if the original - // session used the "extended_master_secret" extension - // but the new ClientHello does not contain it, the - // server MUST abort the abbreviated handshake. - fatalSE(Alerts.alert_handshake_failure, - "Missing Extended Master Secret extension " + - "on session resumption"); - } else if (!requestedToUseEMS && - !previous.getUseExtendedMasterSecret()) { - // For abbreviated handshake request, if neither the - // original session nor the new ClientHello uses the - // extension, the server SHOULD abort the handshake. - if (!allowLegacyResumption) { - fatalSE(Alerts.alert_handshake_failure, - "Missing Extended Master Secret extension " + - "on session resumption"); - } else { // Otherwise, continue with a full handshake. - resumingSession = false; - } - } - } - - // cannot resume session with different server name indication - if (resumingSession) { - List<SNIServerName> oldServerNames = - previous.getRequestedServerNames(); - if (clientHelloSNIExt != null) { - if (!clientHelloSNIExt.isIdentical(oldServerNames)) { - resumingSession = false; - } - } else if (!oldServerNames.isEmpty()) { - resumingSession = false; - } - - if (!resumingSession && - debug != null && Debug.isOn("handshake")) { - System.out.println( - "The requested server name indication " + - "is not identical to the previous one"); - } - } - - if (resumingSession && - (doClientAuth == SSLEngineImpl.clauth_required)) { - try { - previous.getPeerPrincipal(); - } catch (SSLPeerUnverifiedException e) { - resumingSession = false; - } - } - - // validate subject identity - if (resumingSession) { - CipherSuite suite = previous.getSuite(); - if (suite.keyExchange == K_KRB5 || - suite.keyExchange == K_KRB5_EXPORT) { - Principal localPrincipal = previous.getLocalPrincipal(); - - Subject subject = null; - try { - subject = AccessController.doPrivileged( - new PrivilegedExceptionAction<Subject>() { - @Override - public Subject run() throws Exception { - return - Krb5Helper.getServerSubject(getAccSE()); - }}); - } catch (PrivilegedActionException e) { - subject = null; - if (debug != null && Debug.isOn("session")) { - System.out.println("Attempt to obtain" + - " subject failed!"); - } - } - - if (subject != null) { - // Eliminate dependency on KerberosPrincipal - if (Krb5Helper.isRelated(subject, localPrincipal)) { - if (debug != null && Debug.isOn("session")) - System.out.println("Subject can" + - " provide creds for princ"); - } else { - resumingSession = false; - if (debug != null && Debug.isOn("session")) - System.out.println("Subject cannot" + - " provide creds for princ"); - } - } else { - resumingSession = false; - if (debug != null && Debug.isOn("session")) - System.out.println("Kerberos credentials are" + - " not present in the current Subject;" + - " check if " + - " javax.security.auth.useSubjectAsCreds" + - " system property has been set to false"); - } - } - } - - // ensure that the endpoint identification algorithm matches the - // one in the session - String identityAlg = getEndpointIdentificationAlgorithmSE(); - if (resumingSession && identityAlg != null) { - - String sessionIdentityAlg = - previous.getEndpointIdentificationAlgorithm(); - if (!identityAlg.equalsIgnoreCase(sessionIdentityAlg)) { - - if (debug != null && Debug.isOn("session")) { - System.out.println("%% can't resume, endpoint id" - + " algorithm does not match, requested: " + - identityAlg + ", cached: " + - sessionIdentityAlg); - } - resumingSession = false; - } - } - - if (resumingSession) { - CipherSuite suite = previous.getSuite(); - // verify that the ciphersuite from the cached session - // is in the list of client requested ciphersuites and - // we have it enabled - if ((isNegotiable(suite) == false) || - (mesg.getCipherSuites().contains(suite) == false)) { - resumingSession = false; - } else { - // everything looks ok, set the ciphersuite - // this should be done last when we are sure we - // will resume - setCipherSuite(suite); - } - } - - if (resumingSession) { - session = previous; - if (debug != null && - (Debug.isOn("handshake") || Debug.isOn("session"))) { - System.out.println("%% Resuming " + session); - } - } - } - } // else client did not try to resume - - // - // If client hasn't specified a session we can resume, start a - // new one and choose its cipher suite and compression options. - // Unless new session creation is disabled for this connection! - // - if (session == null) { - if (!enableNewSession) { - throw new SSLException("Client did not resume a session"); - } - - requestedCurves = (EllipticCurvesExtension) - mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES); - - // We only need to handle the "signature_algorithm" extension - // for full handshakes and TLS 1.2 or later. - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - SignatureAlgorithmsExtension signAlgs = - (SignatureAlgorithmsExtension)mesg.extensions.get( - ExtensionType.EXT_SIGNATURE_ALGORITHMS); - if (signAlgs != null) { - Collection<SignatureAndHashAlgorithm> peerSignAlgs = - signAlgs.getSignAlgorithms(); - if (peerSignAlgs == null || peerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No peer supported signature algorithms"); - } - - Collection<SignatureAndHashAlgorithm> - supportedPeerSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints, peerSignAlgs); - if (supportedPeerSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No signature and hash algorithm in common"); - } - - setPeerSupportedSignAlgs(supportedPeerSignAlgs); - } // else, need to use peer implicit supported signature algs - } - - session = new SSLSessionImpl(protocolVersion, CipherSuite.C_NULL, - getLocalSupportedSignAlgs(), - sslContext.getSecureRandom(), - getHostAddressSE(), getPortSE(), - (requestedToUseEMS && - (protocolVersion.v >= ProtocolVersion.TLS10.v)), - getEndpointIdentificationAlgorithmSE()); - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (peerSupportedSignAlgs != null) { - session.setPeerSupportedSignatureAlgorithms( - peerSupportedSignAlgs); - } // else, we will set the implicit peer supported signature - // algorithms in chooseCipherSuite() - } - - // set the server name indication in the session - List<SNIServerName> clientHelloSNI = - Collections.<SNIServerName>emptyList(); - if (clientHelloSNIExt != null) { - clientHelloSNI = clientHelloSNIExt.getServerNames(); - } - session.setRequestedServerNames(clientHelloSNI); - - // set the handshake session - setHandshakeSessionSE(session); - - // choose cipher suite and corresponding private key - chooseCipherSuite(mesg); - - session.setSuite(cipherSuite); - session.setLocalPrivateKey(privateKey); - - // chooseCompression(mesg); - } else { - // set the handshake session - setHandshakeSessionSE(session); - } - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - handshakeHash.setFinishedAlg(cipherSuite.prfAlg.getPRFHashAlg()); - } - - m1.cipherSuite = cipherSuite; - m1.sessionId = session.getSessionId(); - m1.compression_method = session.getCompression(); - - if (secureRenegotiation) { - // For ServerHellos that are initial handshakes, then the - // "renegotiated_connection" field in "renegotiation_info" - // extension is of zero length. - // - // For ServerHellos that are renegotiating, this field contains - // the concatenation of client_verify_data and server_verify_data. - // - // Note that for initial handshakes, both the clientVerifyData - // variable and serverVerifyData variable are of zero length. - HelloExtension serverHelloRI = new RenegotiationInfoExtension( - clientVerifyData, serverVerifyData); - m1.extensions.add(serverHelloRI); - } - - if (!sniMatchers.isEmpty() && clientHelloSNIExt != null) { - // When resuming a session, the server MUST NOT include a - // server_name extension in the server hello. - if (!resumingSession) { - ServerNameExtension serverHelloSNI = new ServerNameExtension(); - m1.extensions.add(serverHelloSNI); - } - } - - if (session.getUseExtendedMasterSecret()) { - m1.extensions.add(new ExtendedMasterSecretExtension()); - } - - // Prepare the ALPN response - if (clientHelloALPN != null) { - List<String> peerAPs = clientHelloALPN.getPeerAPs(); - - // check for a callback function - if (hasAPCallback) { - if (conn != null) { - applicationProtocol = - appProtocolSelectorSSLSocket.apply(conn, peerAPs); - } else { - applicationProtocol = - appProtocolSelectorSSLEngine.apply(engine, peerAPs); - } - } - - // check for no-match and that the selected name was also proposed - // by the TLS peer - if (applicationProtocol == null || - (!applicationProtocol.isEmpty() && - !peerAPs.contains(applicationProtocol))) { - - fatalSE(Alerts.alert_no_application_protocol, - new SSLHandshakeException( - "No matching ALPN values")); - - } else if (!applicationProtocol.isEmpty()) { - m1.extensions.add(new ALPNExtension(applicationProtocol)); - } - } else { - // Nothing was negotiated, returned at end of the handshake - applicationProtocol = ""; - } - - if (debug != null && Debug.isOn("handshake")) { - m1.print(System.out); - System.out.println("Cipher suite: " + session.getSuite()); - } - m1.write(output); - handshakeState.update(m1, resumingSession); - - // - // If we are resuming a session, we finish writing handshake - // messages right now and then finish. - // - if (resumingSession) { - calculateConnectionKeys(session.getMasterSecret()); - sendChangeCipherAndFinish(false); - return; - } - - - /* - * SECOND, write the server Certificate(s) if we need to. - * - * NOTE: while an "anonymous RSA" mode is explicitly allowed by - * the protocol, we can't support it since all of the SSL flavors - * defined in the protocol spec are explicitly stated to require - * using RSA certificates. - */ - if (keyExchange == K_KRB5 || keyExchange == K_KRB5_EXPORT) { - // Server certificates are omitted for Kerberos ciphers - - } else if ((keyExchange != K_DH_ANON) && (keyExchange != K_ECDH_ANON)) { - if (certs == null) { - throw new RuntimeException("no certificates"); - } - - CertificateMsg m2 = new CertificateMsg(certs); - - /* - * Set local certs in the SSLSession, output - * debug info, and then actually write to the client. - */ - session.setLocalCertificates(certs); - if (debug != null && Debug.isOn("handshake")) { - m2.print(System.out); - } - m2.write(output); - handshakeState.update(m2, resumingSession); - - // XXX has some side effects with OS TCP buffering, - // leave it out for now - - // let client verify chain in the meantime... - // output.flush(); - } else { - if (certs != null) { - throw new RuntimeException("anonymous keyexchange with certs"); - } - } - - /* - * THIRD, the ServerKeyExchange message ... iff it's needed. - * - * It's usually needed unless there's an encryption-capable - * RSA cert, or a D-H cert. The notable exception is that - * exportable ciphers used with big RSA keys need to downgrade - * to use short RSA keys, even when the key/cert encrypts OK. - */ - - ServerKeyExchange m3; - switch (keyExchange) { - case K_RSA: - case K_KRB5: - case K_KRB5_EXPORT: - // no server key exchange for RSA or KRB5 ciphersuites - m3 = null; - break; - case K_RSA_EXPORT: - if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { - try { - m3 = new RSA_ServerKeyExchange( - tempPublicKey, privateKey, - clnt_random, svr_random, - sslContext.getSecureRandom()); - privateKey = tempPrivateKey; - } catch (GeneralSecurityException e) { - throwSSLException - ("Error generating RSA server key exchange", e); - m3 = null; // make compiler happy - } - } else { - // RSA_EXPORT with short key, don't need ServerKeyExchange - m3 = null; - } - break; - case K_DHE_RSA: - case K_DHE_DSS: - try { - m3 = new DH_ServerKeyExchange(dh, - privateKey, - clnt_random.random_bytes, - svr_random.random_bytes, - sslContext.getSecureRandom(), - preferableSignatureAlgorithm, - protocolVersion); - } catch (GeneralSecurityException e) { - throwSSLException("Error generating DH server key exchange", e); - m3 = null; // make compiler happy - } - break; - case K_DH_ANON: - m3 = new DH_ServerKeyExchange(dh, protocolVersion); - break; - case K_ECDHE_RSA: - case K_ECDHE_ECDSA: - case K_ECDH_ANON: - try { - m3 = new ECDH_ServerKeyExchange(ecdh, - privateKey, - clnt_random.random_bytes, - svr_random.random_bytes, - sslContext.getSecureRandom(), - preferableSignatureAlgorithm, - protocolVersion); - } catch (GeneralSecurityException e) { - throwSSLException( - "Error generating ECDH server key exchange", e); - m3 = null; // make compiler happy - } - break; - case K_ECDH_RSA: - case K_ECDH_ECDSA: - // ServerKeyExchange not used for fixed ECDH - m3 = null; - break; - default: - throw new RuntimeException("internal error: " + keyExchange); - } - if (m3 != null) { - if (debug != null && Debug.isOn("handshake")) { - m3.print(System.out); - } - m3.write(output); - handshakeState.update(m3, resumingSession); - } - - // - // FOURTH, the CertificateRequest message. The details of - // the message can be affected by the key exchange algorithm - // in use. For example, certs with fixed Diffie-Hellman keys - // are only useful with the DH_DSS and DH_RSA key exchange - // algorithms. - // - // Needed only if server requires client to authenticate self. - // Illegal for anonymous flavors, so we need to check that. - // - // CertificateRequest is omitted for Kerberos ciphers - if (doClientAuth != SSLEngineImpl.clauth_none && - keyExchange != K_DH_ANON && keyExchange != K_ECDH_ANON && - keyExchange != K_KRB5 && keyExchange != K_KRB5_EXPORT) { - - CertificateRequest m4; - X509Certificate caCerts[]; - - Collection<SignatureAndHashAlgorithm> localSignAlgs = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - // We currently use all local upported signature and hash - // algorithms. However, to minimize the computation cost - // of requested hash algorithms, we may use a restricted - // set of signature algorithms in the future. - localSignAlgs = getLocalSupportedSignAlgs(); - if (localSignAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - - Set<String> localHashAlgs = - SignatureAndHashAlgorithm.getHashAlgorithmNames( - localSignAlgs); - if (localHashAlgs.isEmpty()) { - throw new SSLHandshakeException( - "No supported signature algorithm"); - } - } - - caCerts = sslContext.getX509TrustManager().getAcceptedIssuers(); - m4 = new CertificateRequest(caCerts, keyExchange, - localSignAlgs, protocolVersion); - - if (debug != null && Debug.isOn("handshake")) { - m4.print(System.out); - } - m4.write(output); - handshakeState.update(m4, resumingSession); - } - - /* - * FIFTH, say ServerHelloDone. - */ - ServerHelloDone m5 = new ServerHelloDone(); - - if (debug != null && Debug.isOn("handshake")) { - m5.print(System.out); - } - m5.write(output); - handshakeState.update(m5, resumingSession); - - /* - * Flush any buffered messages so the client will see them. - * Ideally, all the messages above go in a single network level - * message to the client. Without big Certificate chains, it's - * going to be the common case. - */ - output.flush(); - } - - /* - * Choose cipher suite from among those supported by client. Sets - * the cipherSuite and keyExchange variables. - */ - private void chooseCipherSuite(ClientHello mesg) throws IOException { - CipherSuiteList prefered; - CipherSuiteList proposed; - if (preferLocalCipherSuites) { - prefered = getActiveCipherSuites(); - proposed = mesg.getCipherSuites(); - } else { - prefered = mesg.getCipherSuites(); - proposed = getActiveCipherSuites(); - } - - List<CipherSuite> legacySuites = new ArrayList<>(); - for (CipherSuite suite : prefered.collection()) { - if (isNegotiable(proposed, suite) == false) { - continue; - } - - if (doClientAuth == SSLEngineImpl.clauth_required) { - if ((suite.keyExchange == K_DH_ANON) || - (suite.keyExchange == K_ECDH_ANON)) { - continue; - } - } - - if (!legacyAlgorithmConstraints.permits(null, suite.name, null)) { - legacySuites.add(suite); - continue; - } - - if (trySetCipherSuite(suite) == false) { - continue; - } - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Standard ciphersuite chosen: " + suite); - } - return; - } - - for (CipherSuite suite : legacySuites) { - if (trySetCipherSuite(suite)) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Legacy ciphersuite chosen: " + suite); - } - return; - } - } - - fatalSE(Alerts.alert_handshake_failure, "no cipher suites in common"); - } - - /** - * Set the given CipherSuite, if possible. Return the result. - * The call succeeds if the CipherSuite is available and we have - * the necessary certificates to complete the handshake. We don't - * check if the CipherSuite is actually enabled. - * - * If successful, this method also generates ephemeral keys if - * required for this ciphersuite. This may take some time, so this - * method should only be called if you really want to use the - * CipherSuite. - * - * This method is called from chooseCipherSuite() in this class. - */ - boolean trySetCipherSuite(CipherSuite suite) { - /* - * If we're resuming a session we know we can - * support this key exchange algorithm and in fact - * have already cached the result of it in - * the session state. - */ - if (resumingSession) { - return true; - } - - if (suite.isNegotiable() == false) { - return false; - } - - // must not negotiate the obsoleted weak cipher suites. - if (protocolVersion.v >= suite.obsoleted) { - return false; - } - - // must not negotiate unsupported cipher suites. - if (protocolVersion.v < suite.supported) { - return false; - } - - KeyExchange keyExchange = suite.keyExchange; - - // null out any existing references - privateKey = null; - certs = null; - dh = null; - tempPrivateKey = null; - tempPublicKey = null; - - Collection<SignatureAndHashAlgorithm> supportedSignAlgs = null; - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (peerSupportedSignAlgs != null) { - supportedSignAlgs = peerSupportedSignAlgs; - } else { - SignatureAndHashAlgorithm algorithm = null; - - // we may optimize the performance - switch (keyExchange) { - // If the negotiated key exchange algorithm is one of - // (RSA, DHE_RSA, DH_RSA, RSA_PSK, ECDH_RSA, ECDHE_RSA), - // behave as if client had sent the value {sha1,rsa}. - case K_RSA: - case K_DHE_RSA: - case K_DH_RSA: - // case K_RSA_PSK: - case K_ECDH_RSA: - case K_ECDHE_RSA: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.RSA.value, 0); - break; - // If the negotiated key exchange algorithm is one of - // (DHE_DSS, DH_DSS), behave as if the client had - // sent the value {sha1,dsa}. - case K_DHE_DSS: - case K_DH_DSS: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.DSA.value, 0); - break; - // If the negotiated key exchange algorithm is one of - // (ECDH_ECDSA, ECDHE_ECDSA), behave as if the client - // had sent value {sha1,ecdsa}. - case K_ECDH_ECDSA: - case K_ECDHE_ECDSA: - algorithm = SignatureAndHashAlgorithm.valueOf( - HashAlgorithm.SHA1.value, - SignatureAlgorithm.ECDSA.value, 0); - break; - default: - // no peer supported signature algorithms - } - - if (algorithm == null) { - supportedSignAlgs = - Collections.<SignatureAndHashAlgorithm>emptySet(); - } else { - supportedSignAlgs = - new ArrayList<SignatureAndHashAlgorithm>(1); - supportedSignAlgs.add(algorithm); - - supportedSignAlgs = - SignatureAndHashAlgorithm.getSupportedAlgorithms( - algorithmConstraints, supportedSignAlgs); - - // May be no default activated signature algorithm, but - // let the following process make the final decision. - } - - // Sets the peer supported signature algorithm to use in KM - // temporarily. - session.setPeerSupportedSignatureAlgorithms(supportedSignAlgs); - } - } - - switch (keyExchange) { - case K_RSA: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - break; - case K_RSA_EXPORT: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - try { - if (JsseJce.getRSAKeyLength(certs[0].getPublicKey()) > 512) { - if (!setupEphemeralRSAKeys(suite.exportable)) { - return false; - } - } - } catch (RuntimeException e) { - // could not determine keylength, ignore key - return false; - } - break; - case K_DHE_RSA: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "RSA", privateKey); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - setupEphemeralDHKeys(suite.exportable, privateKey); - break; - case K_ECDHE_RSA: - // need RSA certs for authentication - if (setupPrivateKeyAndChain("RSA") == false) { - return false; - } - - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "RSA", privateKey); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - if (setupEphemeralECDHKeys() == false) { - return false; - } - break; - case K_DHE_DSS: - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "DSA"); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - // need DSS certs for authentication - if (setupPrivateKeyAndChain("DSA") == false) { - return false; - } - - setupEphemeralDHKeys(suite.exportable, privateKey); - break; - case K_ECDHE_ECDSA: - // get preferable peer signature algorithm for server key exchange - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - preferableSignatureAlgorithm = - SignatureAndHashAlgorithm.getPreferableAlgorithm( - supportedSignAlgs, "ECDSA"); - if (preferableSignatureAlgorithm == null) { - if ((debug != null) && Debug.isOn("handshake")) { - System.out.println( - "No signature and hash algorithm for cipher " + - suite); - } - return false; - } - } - - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - if (setupEphemeralECDHKeys() == false) { - return false; - } - break; - case K_ECDH_RSA: - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - setupStaticECDHKeys(); - break; - case K_ECDH_ECDSA: - // need EC cert - if (setupPrivateKeyAndChain("EC") == false) { - return false; - } - setupStaticECDHKeys(); - break; - case K_KRB5: - case K_KRB5_EXPORT: - // need Kerberos Key - if (!setupKerberosKeys()) { - return false; - } - break; - case K_DH_ANON: - // no certs needed for anonymous - setupEphemeralDHKeys(suite.exportable, null); - break; - case K_ECDH_ANON: - // no certs needed for anonymous - if (setupEphemeralECDHKeys() == false) { - return false; - } - break; - default: - // internal error, unknown key exchange - throw new RuntimeException( - "Unrecognized cipherSuite: " + suite); - } - setCipherSuite(suite); - - // set the peer implicit supported signature algorithms - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (peerSupportedSignAlgs == null) { - setPeerSupportedSignAlgs(supportedSignAlgs); - // we had alreay update the session - } - } - return true; - } - - /* - * Get some "ephemeral" RSA keys for this context. This means - * generating them if it's not already been done. - * - * Note that we currently do not implement any ciphersuites that use - * strong ephemeral RSA. (We do not support the EXPORT1024 ciphersuites - * and standard RSA ciphersuites prohibit ephemeral mode for some reason) - * This means that export is always true and 512 bit keys are generated. - */ - private boolean setupEphemeralRSAKeys(boolean export) { - KeyPair kp = sslContext.getEphemeralKeyManager(). - getRSAKeyPair(export, sslContext.getSecureRandom()); - if (kp == null) { - return false; - } else { - tempPublicKey = kp.getPublic(); - tempPrivateKey = kp.getPrivate(); - return true; - } - } - - /* - * Acquire some "ephemeral" Diffie-Hellman keys for this handshake. - * We don't reuse these, for improved forward secrecy. - */ - private void setupEphemeralDHKeys(boolean export, Key key) { - /* - * 768 bits ephemeral DH private keys were used to be used in - * ServerKeyExchange except that exportable ciphers max out at 512 - * bits modulus values. We still adhere to this behavior in legacy - * mode (system property "jdk.tls.ephemeralDHKeySize" is defined - * as "legacy"). - * - * Old JDK (JDK 7 and previous) releases don't support DH keys bigger - * than 1024 bits. We have to consider the compatibility requirement. - * 1024 bits DH key is always used for non-exportable cipher suites - * in default mode (system property "jdk.tls.ephemeralDHKeySize" - * is not defined). - * - * However, if applications want more stronger strength, setting - * system property "jdk.tls.ephemeralDHKeySize" to "matched" - * is a workaround to use ephemeral DH key which size matches the - * corresponding authentication key. For example, if the public key - * size of an authentication certificate is 2048 bits, then the - * ephemeral DH key size should be 2048 bits accordingly unless - * the cipher suite is exportable. This key sizing scheme keeps - * the cryptographic strength consistent between authentication - * keys and key-exchange keys. - * - * Applications may also want to customize the ephemeral DH key size - * to a fixed length for non-exportable cipher suites. This can be - * approached by setting system property "jdk.tls.ephemeralDHKeySize" - * to a valid positive integer between 1024 and 8192 bits, inclusive. - * - * Note that the minimum acceptable key size is 1024 bits except - * exportable cipher suites or legacy mode. - * - * Note that per RFC 2246, the key size limit of DH is 512 bits for - * exportable cipher suites. Because of the weakness, exportable - * cipher suites are deprecated since TLS v1.1 and they are not - * enabled by default in Oracle provider. The legacy behavior is - * reserved and 512 bits DH key is always used for exportable - * cipher suites. - */ - int keySize = export ? 512 : 1024; // default mode - if (!export) { - if (useLegacyEphemeralDHKeys) { // legacy mode - keySize = 768; - } else if (useSmartEphemeralDHKeys) { // matched mode - if (key != null) { - int ks = KeyUtil.getKeySize(key); - - // DH parameter generation can be extremely slow, make - // sure to use one of the supported pre-computed DH - // parameters (see DHCrypt class). - // - // Old deployed applications may not be ready to support - // DH key sizes bigger than 2048 bits. Please DON'T use - // value other than 1024 and 2048 at present. May improve - // the underlying providers and key size limit in the - // future when the compatibility and interoperability - // impact is limited. - // - // keySize = ks <= 1024 ? 1024 : (ks >= 2048 ? 2048 : ks); - keySize = ks <= 1024 ? 1024 : 2048; - } // Otherwise, anonymous cipher suites, 1024-bit is used. - } else if (customizedDHKeySize > 0) { // customized mode - keySize = customizedDHKeySize; - } - } - - dh = new DHCrypt(keySize, sslContext.getSecureRandom()); - } - - // Setup the ephemeral ECDH parameters. - // If we cannot continue because we do not support any of the curves that - // the client requested, return false. Otherwise (all is well), return true. - private boolean setupEphemeralECDHKeys() { - int index = (requestedCurves != null) ? - requestedCurves.getPreferredCurve(algorithmConstraints) : - EllipticCurvesExtension.getActiveCurves(algorithmConstraints); - if (index < 0) { - // no match found, cannot use this ciphersuite - return false; - } - - ecdh = new ECDHCrypt(index, sslContext.getSecureRandom()); - return true; - } - - private void setupStaticECDHKeys() { - // don't need to check whether the curve is supported, already done - // in setupPrivateKeyAndChain(). - ecdh = new ECDHCrypt(privateKey, certs[0].getPublicKey()); - } - - /** - * Retrieve the server key and certificate for the specified algorithm - * from the KeyManager and set the instance variables. - * - * @return true if successful, false if not available or invalid - */ - private boolean setupPrivateKeyAndChain(String algorithm) { - X509ExtendedKeyManager km = sslContext.getX509KeyManager(); - String alias; - if (conn != null) { - alias = km.chooseServerAlias(algorithm, null, conn); - } else { - alias = km.chooseEngineServerAlias(algorithm, null, engine); - } - if (alias == null) { - return false; - } - PrivateKey tempPrivateKey = km.getPrivateKey(alias); - if (tempPrivateKey == null) { - return false; - } - X509Certificate[] tempCerts = km.getCertificateChain(alias); - if ((tempCerts == null) || (tempCerts.length == 0)) { - return false; - } - String keyAlgorithm = algorithm.split("_")[0]; - PublicKey publicKey = tempCerts[0].getPublicKey(); - if ((tempPrivateKey.getAlgorithm().equals(keyAlgorithm) == false) - || (publicKey.getAlgorithm().equals(keyAlgorithm) == false)) { - return false; - } - // For ECC certs, check whether we support the EC domain parameters. - // If the client sent a SupportedEllipticCurves ClientHello extension, - // check against that too. - if (keyAlgorithm.equals("EC")) { - if (publicKey instanceof ECPublicKey == false) { - return false; - } - ECParameterSpec params = ((ECPublicKey)publicKey).getParams(); - int id = EllipticCurvesExtension.getCurveIndex(params); - if ((id <= 0) || !EllipticCurvesExtension.isSupported(id) || - ((requestedCurves != null) && !requestedCurves.contains(id))) { - return false; - } - } - this.privateKey = tempPrivateKey; - this.certs = tempCerts; - return true; - } - - /** - * Retrieve the Kerberos key for the specified server principal - * from the JAAS configuration file. - * - * @return true if successful, false if not available or invalid - */ - private boolean setupKerberosKeys() { - if (serviceCreds != null) { - return true; - } - try { - final AccessControlContext acc = getAccSE(); - serviceCreds = AccessController.doPrivileged( - // Eliminate dependency on KerberosKey - new PrivilegedExceptionAction<Object>() { - @Override - public Object run() throws Exception { - // get kerberos key for the default principal - return Krb5Helper.getServiceCreds(acc); - }}); - - // check permission to access and use the secret key of the - // Kerberized "host" service - if (serviceCreds != null) { - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Using Kerberos creds"); - } - String serverPrincipal = - Krb5Helper.getServerPrincipalName(serviceCreds); - if (serverPrincipal != null) { - // When service is bound, we check ASAP. Otherwise, - // will check after client request is received - // in in Kerberos ClientKeyExchange - SecurityManager sm = System.getSecurityManager(); - try { - if (sm != null) { - // Eliminate dependency on ServicePermission - sm.checkPermission(Krb5Helper.getServicePermission( - serverPrincipal, "accept"), acc); - } - } catch (SecurityException se) { - serviceCreds = null; - // Do not destroy keys. Will affect Subject - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Permission to access Kerberos" - + " secret key denied"); - } - return false; - } - } - } - return serviceCreds != null; - } catch (PrivilegedActionException e) { - // Likely exception here is LoginExceptin - if (debug != null && Debug.isOn("handshake")) { - System.out.println("Attempt to obtain Kerberos key failed: " - + e.toString()); - } - return false; - } - } - - /* - * For Kerberos ciphers, the premaster secret is encrypted using - * the session key. See RFC 2712. - */ - private SecretKey clientKeyExchange(KerberosClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - // Record the principals involved in exchange - session.setPeerPrincipal(mesg.getPeerPrincipal()); - session.setLocalPrincipal(mesg.getLocalPrincipal()); - - byte[] b = mesg.getUnencryptedPreMasterSecret(); - return new SecretKeySpec(b, "TlsPremasterSecret"); - } - - /* - * Diffie Hellman key exchange is used when the server presented - * D-H parameters in its certificate (signed using RSA or DSS/DSA), - * or else the server presented no certificate but sent D-H params - * in a ServerKeyExchange message. Use of D-H is specified by the - * cipher suite chosen. - * - * The message optionally contains the client's D-H public key (if - * it wasn't not sent in a client certificate). As always with D-H, - * if a client and a server have each other's D-H public keys and - * they use common algorithm parameters, they have a shared key - * that's derived via the D-H calculation. That key becomes the - * pre-master secret. - */ - private SecretKey clientKeyExchange(DHClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - BigInteger publicKeyValue = mesg.getClientPublicKey(); - - // check algorithm constraints - dh.checkConstraints(algorithmConstraints, publicKeyValue); - - return dh.getAgreedSecret(publicKeyValue, false); - } - - private SecretKey clientKeyExchange(ECDHClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - byte[] publicPoint = mesg.getEncodedPoint(); - - // check algorithm constraints - ecdh.checkConstraints(algorithmConstraints, publicPoint); - - return ecdh.getAgreedSecret(publicPoint); - } - - /* - * Client wrote a message to verify the certificate it sent earlier. - * - * Note that this certificate isn't involved in key exchange. Client - * authentication messages are included in the checksums used to - * validate the handshake (e.g. Finished messages). Other than that, - * the _exact_ identity of the client is less fundamental to protocol - * security than its role in selecting keys via the pre-master secret. - */ - private void clientCertificateVerify(CertificateVerify mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - SignatureAndHashAlgorithm signAlg = - mesg.getPreferableSignatureAlgorithm(); - if (signAlg == null) { - throw new SSLHandshakeException( - "Illegal CertificateVerify message"); - } - - String hashAlg = - SignatureAndHashAlgorithm.getHashAlgorithmName(signAlg); - if (hashAlg == null || hashAlg.length() == 0) { - throw new SSLHandshakeException( - "No supported hash algorithm"); - } - } - - try { - PublicKey publicKey = - session.getPeerCertificates()[0].getPublicKey(); - - boolean valid = mesg.verify(protocolVersion, handshakeHash, - publicKey, session.getMasterSecret()); - if (valid == false) { - fatalSE(Alerts.alert_bad_certificate, - "certificate verify message signature error"); - } - } catch (GeneralSecurityException e) { - fatalSE(Alerts.alert_bad_certificate, - "certificate verify format error", e); - } - - // reset the flag for clientCertificateVerify message - needClientVerify = false; - } - - - /* - * Client writes "finished" at the end of its handshake, after cipher - * spec is changed. We verify it and then send ours. - * - * When we're resuming a session, we'll have already sent our own - * Finished message so just the verification is needed. - */ - private void clientFinished(Finished mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - /* - * Verify if client did send the certificate when client - * authentication was required, otherwise server should not proceed - */ - if (doClientAuth == SSLEngineImpl.clauth_required) { - // get X500Principal of the end-entity certificate for X509-based - // ciphersuites, or Kerberos principal for Kerberos ciphersuites - session.getPeerPrincipal(); - } - - /* - * Verify if client did send clientCertificateVerify message following - * the client Certificate, otherwise server should not proceed - */ - if (needClientVerify) { - fatalSE(Alerts.alert_handshake_failure, - "client did not send certificate verify message"); - } - - /* - * Verify the client's message with the "before" digest of messages, - * and forget about continuing to use that digest. - */ - boolean verified = mesg.verify(handshakeHash, Finished.CLIENT, - session.getMasterSecret()); - - if (!verified) { - fatalSE(Alerts.alert_handshake_failure, - "client 'finished' message doesn't verify"); - // NOTREACHED - } - - /* - * save client verify data for secure renegotiation - */ - if (secureRenegotiation) { - clientVerifyData = mesg.getVerifyData(); - } - - /* - * OK, it verified. If we're doing the full handshake, add that - * "Finished" message to the hash of handshake messages, then send - * the change_cipher_spec and Finished message. - */ - if (!resumingSession) { - input.digestNow(); - sendChangeCipherAndFinish(true); - } else { - handshakeFinished = true; - } - - /* - * Update the session cache only after the handshake completed, else - * we're open to an attack against a partially completed handshake. - */ - session.setLastAccessedTime(System.currentTimeMillis()); - if (!resumingSession && session.isRejoinable()) { - ((SSLSessionContextImpl)sslContext.engineGetServerSessionContext()) - .put(session); - if (debug != null && Debug.isOn("session")) { - System.out.println( - "%% Cached server session: " + session); - } - } else if (!resumingSession && - debug != null && Debug.isOn("session")) { - System.out.println( - "%% Didn't cache non-resumable server session: " - + session); - } - } - - /* - * Compute finished message with the "server" digest (and then forget - * about that digest, it can't be used again). - */ - private void sendChangeCipherAndFinish(boolean finishedTag) - throws IOException { - - output.flush(); - - Finished mesg = new Finished(protocolVersion, handshakeHash, - Finished.SERVER, session.getMasterSecret(), cipherSuite); - - /* - * Send the change_cipher_spec record; then our Finished handshake - * message will be the last handshake message. Flush, and now we - * are ready for application data!! - */ - sendChangeCipherSpec(mesg, finishedTag); - - /* - * save server verify data for secure renegotiation - */ - if (secureRenegotiation) { - serverVerifyData = mesg.getVerifyData(); - } - } - - - /* - * Returns a HelloRequest message to kickstart renegotiations - */ - @Override - HandshakeMessage getKickstartMessage() { - return new HelloRequest(); - } - - - /* - * Fault detected during handshake. - */ - @Override - void handshakeAlert(byte description) throws SSLProtocolException { - - String message = Alerts.alertDescription(description); - - if (debug != null && Debug.isOn("handshake")) { - System.out.println("SSL -- handshake alert: " - + message); - } - - /* - * It's ok to get a no_certificate alert from a client of which - * we *requested* authentication information. - * However, if we *required* it, then this is not acceptable. - * - * Anyone calling getPeerCertificates() on the - * session will get an SSLPeerUnverifiedException. - */ - if ((description == Alerts.alert_no_certificate) && - (doClientAuth == SSLEngineImpl.clauth_requested)) { - return; - } - - throw new SSLProtocolException("handshake alert: " + message); - } - - /* - * RSA key exchange is normally used. The client encrypts a "pre-master - * secret" with the server's public key, from the Certificate (or else - * ServerKeyExchange) message that was sent to it by the server. That's - * decrypted using the private key before we get here. - */ - private SecretKey clientKeyExchange(RSAClientKeyExchange mesg) - throws IOException { - - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - return mesg.preMaster; - } - - /* - * Verify the certificate sent by the client. We'll only get one if we - * sent a CertificateRequest to request client authentication. If we - * are in TLS mode, the client may send a message with no certificates - * to indicate it does not have an appropriate chain. (In SSLv3 mode, - * it would send a no certificate alert). - */ - private void clientCertificate(CertificateMsg mesg) throws IOException { - if (debug != null && Debug.isOn("handshake")) { - mesg.print(System.out); - } - - X509Certificate[] peerCerts = mesg.getCertificateChain(); - - if (peerCerts.length == 0) { - /* - * If the client authentication is only *REQUESTED* (e.g. - * not *REQUIRED*, this is an acceptable condition.) - */ - if (doClientAuth == SSLEngineImpl.clauth_requested) { - return; - } else { - fatalSE(Alerts.alert_bad_certificate, - "null cert chain"); - } - } - - // ask the trust manager to verify the chain - X509TrustManager tm = sslContext.getX509TrustManager(); - - try { - // find out the types of client authentication used - PublicKey key = peerCerts[0].getPublicKey(); - String keyAlgorithm = key.getAlgorithm(); - String authType; - if (keyAlgorithm.equals("RSA")) { - authType = "RSA"; - } else if (keyAlgorithm.equals("DSA")) { - authType = "DSA"; - } else if (keyAlgorithm.equals("EC")) { - authType = "EC"; - } else { - // unknown public key type - authType = "UNKNOWN"; - } - - if (tm instanceof X509ExtendedTrustManager) { - if (conn != null) { - ((X509ExtendedTrustManager)tm).checkClientTrusted( - peerCerts.clone(), - authType, - conn); - } else { - ((X509ExtendedTrustManager)tm).checkClientTrusted( - peerCerts.clone(), - authType, - engine); - } - } else { - // Unlikely to happen, because we have wrapped the old - // X509TrustManager with the new X509ExtendedTrustManager. - throw new CertificateException( - "Improper X509TrustManager implementation"); - } - } catch (CertificateException e) { - // This will throw an exception, so include the original error. - fatalSE(Alerts.alert_certificate_unknown, e); - } - // set the flag for clientCertificateVerify message - needClientVerify = true; - - session.setPeerCertificates(peerCerts); - } -}
--- a/src/share/classes/sun/security/ssl/ServerNameExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.LinkedHashMap; -import java.util.Map; - -import javax.net.ssl.SNIHostName; -import javax.net.ssl.SNIMatcher; -import javax.net.ssl.SNIServerName; -import javax.net.ssl.SSLProtocolException; -import javax.net.ssl.StandardConstants; - -/* - * [RFC 4366/6066] To facilitate secure connections to servers that host - * multiple 'virtual' servers at a single underlying network address, clients - * MAY include an extension of type "server_name" in the (extended) client - * hello. The "extension_data" field of this extension SHALL contain - * "ServerNameList" where: - * - * struct { - * NameType name_type; - * select (name_type) { - * case host_name: HostName; - * } name; - * } ServerName; - * - * enum { - * host_name(0), (255) - * } NameType; - * - * opaque HostName<1..2^16-1>; - * - * struct { - * ServerName server_name_list<1..2^16-1> - * } ServerNameList; - */ -final class ServerNameExtension extends HelloExtension { - - // For backward compatibility, all future data structures associated with - // new NameTypes MUST begin with a 16-bit length field. - final static int NAME_HEADER_LENGTH = 3; // NameType: 1 byte - // Name length: 2 bytes - private Map<Integer, SNIServerName> sniMap; - private int listLength; // ServerNameList length - - // constructor for ServerHello - ServerNameExtension() throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - listLength = 0; - sniMap = Collections.<Integer, SNIServerName>emptyMap(); - } - - // constructor for ClientHello - ServerNameExtension(List<SNIServerName> serverNames) - throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - listLength = 0; - sniMap = new LinkedHashMap<>(); - for (SNIServerName serverName : serverNames) { - // check for duplicated server name type - if (sniMap.put(serverName.getType(), serverName) != null) { - // unlikely to happen, but in case ... - throw new RuntimeException( - "Duplicated server name of type " + serverName.getType()); - } - - listLength += serverName.getEncoded().length + NAME_HEADER_LENGTH; - } - - // This constructor is used for ClientHello only. Empty list is - // not allowed in client mode. - if (listLength == 0) { - throw new RuntimeException("The ServerNameList cannot be empty"); - } - } - - // constructor for ServerHello for parsing SNI extension - ServerNameExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_SERVER_NAME); - - int remains = len; - if (len >= 2) { // "server_name" extension in ClientHello - listLength = s.getInt16(); // ServerNameList length - if (listLength == 0 || listLength + 2 != len) { - throw new SSLProtocolException( - "Invalid " + type + " extension"); - } - - remains -= 2; - sniMap = new LinkedHashMap<>(); - while (remains > 0) { - int code = s.getInt8(); // NameType - - // HostName (length read in getBytes16); - byte[] encoded = s.getBytes16(); - SNIServerName serverName; - switch (code) { - case StandardConstants.SNI_HOST_NAME: - if (encoded.length == 0) { - throw new SSLProtocolException( - "Empty HostName in server name indication"); - } - try { - serverName = new SNIHostName(encoded); - } catch (IllegalArgumentException iae) { - SSLProtocolException spe = new SSLProtocolException( - "Illegal server name, type=host_name(" + - code + "), name=" + - (new String(encoded, StandardCharsets.UTF_8)) + - ", value=" + Debug.toString(encoded)); - spe.initCause(iae); - throw spe; - } - break; - default: - try { - serverName = new UnknownServerName(code, encoded); - } catch (IllegalArgumentException iae) { - SSLProtocolException spe = new SSLProtocolException( - "Illegal server name, type=(" + code + - "), value=" + Debug.toString(encoded)); - spe.initCause(iae); - throw spe; - } - } - // check for duplicated server name type - if (sniMap.put(serverName.getType(), serverName) != null) { - throw new SSLProtocolException( - "Duplicated server name of type " + - serverName.getType()); - } - - remains -= encoded.length + NAME_HEADER_LENGTH; - } - } else if (len == 0) { // "server_name" extension in ServerHello - listLength = 0; - sniMap = Collections.<Integer, SNIServerName>emptyMap(); - } - - if (remains != 0) { - throw new SSLProtocolException("Invalid server_name extension"); - } - } - - List<SNIServerName> getServerNames() { - if (sniMap != null && !sniMap.isEmpty()) { - return Collections.<SNIServerName>unmodifiableList( - new ArrayList<>(sniMap.values())); - } - - return Collections.<SNIServerName>emptyList(); - } - - /* - * Is the extension recognized by the corresponding matcher? - * - * This method is used to check whether the server name indication can - * be recognized by the server name matchers. - * - * Per RFC 6066, if the server understood the ClientHello extension but - * does not recognize the server name, the server SHOULD take one of two - * actions: either abort the handshake by sending a fatal-level - * unrecognized_name(112) alert or continue the handshake. - * - * If there is an instance of SNIMatcher defined for a particular name - * type, it must be used to perform match operations on the server name. - */ - boolean isMatched(Collection<SNIMatcher> matchers) { - if (sniMap != null && !sniMap.isEmpty()) { - for (SNIMatcher matcher : matchers) { - SNIServerName sniName = sniMap.get(matcher.getType()); - if (sniName != null && (!matcher.matches(sniName))) { - return false; - } - } - } - - return true; - } - - /* - * Is the extension is identical to a server name list? - * - * This method is used to check the server name indication during session - * resumption. - * - * Per RFC 6066, when the server is deciding whether or not to accept a - * request to resume a session, the contents of a server_name extension - * MAY be used in the lookup of the session in the session cache. The - * client SHOULD include the same server_name extension in the session - * resumption request as it did in the full handshake that established - * the session. A server that implements this extension MUST NOT accept - * the request to resume the session if the server_name extension contains - * a different name. Instead, it proceeds with a full handshake to - * establish a new session. When resuming a session, the server MUST NOT - * include a server_name extension in the server hello. - */ - boolean isIdentical(List<SNIServerName> other) { - if (other.size() == sniMap.size()) { - for(SNIServerName sniInOther : other) { - SNIServerName sniName = sniMap.get(sniInOther.getType()); - if (sniName == null || !sniInOther.equals(sniName)) { - return false; - } - } - - return true; - } - - return false; - } - - @Override - int length() { - return listLength == 0 ? 4 : 6 + listLength; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - if (listLength == 0) { - s.putInt16(listLength); // in ServerHello, empty extension_data - } else { - s.putInt16(listLength + 2); // length of extension_data - s.putInt16(listLength); // length of ServerNameList - - for (SNIServerName sniName : sniMap.values()) { - s.putInt8(sniName.getType()); // server name type - s.putBytes16(sniName.getEncoded()); // server name value - } - } - } - - @Override - public String toString() { - StringBuffer buffer = new StringBuffer(); - for (SNIServerName sniName : sniMap.values()) { - buffer.append("[" + sniName + "]"); - } - - return "Extension " + type + ", server_name: " + buffer; - } - - private static class UnknownServerName extends SNIServerName { - UnknownServerName(int code, byte[] encoded) { - super(code, encoded); - } - } - -}
--- a/src/share/classes/sun/security/ssl/SessionId.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.SecureRandom; -import java.util.Arrays; -import javax.net.ssl.SSLProtocolException; - -/** - * Encapsulates an SSL session ID. SSL Session IDs are not reused by - * servers during the lifetime of any sessions it created. Sessions may - * be used by many connections, either concurrently (for example, two - * connections to a web server at the same time) or sequentially (over as - * long a time period as is allowed by a given server). - * - * @author Satish Dharmaraj - * @author David Brownell - */ -final -class SessionId -{ - static int MAX_LENGTH = 32; - private byte sessionId []; // max 32 bytes - - /** Constructs a new session ID ... perhaps for a rejoinable session */ - SessionId (boolean isRejoinable, SecureRandom generator) - { - if (isRejoinable) - // this will be unique, it's a timestamp plus much randomness - sessionId = new RandomCookie (generator).random_bytes; - else - sessionId = new byte [0]; - } - - /** Constructs a session ID from a byte array (max size 32 bytes) */ - SessionId (byte sessionId []) - { this.sessionId = sessionId; } - - /** Returns the length of the ID, in bytes */ - int length () - { return sessionId.length; } - - /** Returns the bytes in the ID. May be an empty array. */ - byte [] getId () - { - return sessionId.clone (); - } - - /** Returns the ID as a string */ - @Override - public String toString () - { - int len = sessionId.length; - StringBuffer s = new StringBuffer (10 + 2 * len); - - s.append ("{"); - for (int i = 0; i < len; i++) { - s.append (0x0ff & sessionId [i]); - if (i != (len - 1)) - s.append (", "); - } - s.append ("}"); - return s.toString (); - } - - - /** Returns a value which is the same for session IDs which are equal */ - @Override - public int hashCode () - { - return Arrays.hashCode(sessionId); - } - - /** Returns true if the parameter is the same session ID */ - @Override - public boolean equals (Object obj) - { - if (!(obj instanceof SessionId)) - return false; - - SessionId s = (SessionId) obj; - byte b [] = s.getId (); - - if (b.length != sessionId.length) - return false; - for (int i = 0; i < sessionId.length; i++) { - if (b [i] != sessionId [i]) - return false; - } - return true; - } - - /** - * Checks the length of the session ID to make sure it sits within - * the range called out in the specification - */ - void checkLength(ProtocolVersion pv) throws SSLProtocolException { - // As of today all versions of TLS have a 32-byte maximum length. - // In the future we can do more here to support protocol versions - // that may have longer max lengths. - if (sessionId.length > MAX_LENGTH) { - throw new SSLProtocolException("Invalid session ID length (" + - sessionId.length + " bytes)"); - } - } - -}
--- a/src/share/classes/sun/security/ssl/SignatureAlgorithmsExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.Collection; - -import javax.net.ssl.SSLProtocolException; - -/* - * [RFC5246] The client uses the "signature_algorithms" extension to - * indicate to the server which signature/hash algorithm pairs may be - * used in digital signatures. The "extension_data" field of this - * extension contains a "supported_signature_algorithms" value. - * - * enum { - * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), - * sha512(6), (255) - * } HashAlgorithm; - * - * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } - * SignatureAlgorithm; - * - * struct { - * HashAlgorithm hash; - * SignatureAlgorithm signature; - * } SignatureAndHashAlgorithm; - * - * SignatureAndHashAlgorithm - * supported_signature_algorithms<2..2^16-2>; - */ -final class SignatureAlgorithmsExtension extends HelloExtension { - - private Collection<SignatureAndHashAlgorithm> algorithms; - private int algorithmsLen; // length of supported_signature_algorithms - - SignatureAlgorithmsExtension( - Collection<SignatureAndHashAlgorithm> signAlgs) { - - super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); - - algorithms = new ArrayList<SignatureAndHashAlgorithm>(signAlgs); - algorithmsLen = - SignatureAndHashAlgorithm.sizeInRecord() * algorithms.size(); - } - - SignatureAlgorithmsExtension(HandshakeInStream s, int len) - throws IOException { - super(ExtensionType.EXT_SIGNATURE_ALGORITHMS); - - algorithmsLen = s.getInt16(); - if (algorithmsLen == 0 || algorithmsLen + 2 != len) { - throw new SSLProtocolException("Invalid " + type + " extension"); - } - - algorithms = new ArrayList<SignatureAndHashAlgorithm>(); - int remains = algorithmsLen; - int sequence = 0; - while (remains > 1) { // needs at least two bytes - int hash = s.getInt8(); // hash algorithm - int signature = s.getInt8(); // signature algorithm - - SignatureAndHashAlgorithm algorithm = - SignatureAndHashAlgorithm.valueOf(hash, signature, ++sequence); - algorithms.add(algorithm); - remains -= 2; // one byte for hash, one byte for signature - } - - if (remains != 0) { - throw new SSLProtocolException("Invalid server_name extension"); - } - } - - Collection<SignatureAndHashAlgorithm> getSignAlgorithms() { - return algorithms; - } - - @Override - int length() { - return 6 + algorithmsLen; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putInt16(algorithmsLen + 2); - s.putInt16(algorithmsLen); - - for (SignatureAndHashAlgorithm algorithm : algorithms) { - s.putInt8(algorithm.getHashValue()); // HashAlgorithm - s.putInt8(algorithm.getSignatureValue()); // SignatureAlgorithm - } - } - - @Override - public String toString() { - StringBuffer buffer = new StringBuffer(); - boolean opened = false; - for (SignatureAndHashAlgorithm signAlg : algorithms) { - if (opened) { - buffer.append(", " + signAlg.getAlgorithmName()); - } else { - buffer.append(signAlg.getAlgorithmName()); - opened = true; - } - } - - return "Extension " + type + ", signature_algorithms: " + buffer; - } -} -
--- a/src/share/classes/sun/security/ssl/SignatureAndHashAlgorithm.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,441 +0,0 @@ -/* - * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.security.AlgorithmConstraints; -import java.security.CryptoPrimitive; -import java.security.PrivateKey; -import java.security.Security; - -import java.util.Set; -import java.util.HashSet; -import java.util.Map; -import java.util.EnumSet; -import java.util.TreeMap; -import java.util.Collection; -import java.util.Collections; -import java.util.ArrayList; - -import sun.security.util.KeyUtil; - -/** - * Signature and hash algorithm. - * - * [RFC5246] The client uses the "signature_algorithms" extension to - * indicate to the server which signature/hash algorithm pairs may be - * used in digital signatures. The "extension_data" field of this - * extension contains a "supported_signature_algorithms" value. - * - * enum { - * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), - * sha512(6), (255) - * } HashAlgorithm; - * - * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } - * SignatureAlgorithm; - * - * struct { - * HashAlgorithm hash; - * SignatureAlgorithm signature; - * } SignatureAndHashAlgorithm; - */ -final class SignatureAndHashAlgorithm { - - // minimum priority for default enabled algorithms - final static int SUPPORTED_ALG_PRIORITY_MAX_NUM = 0x00F0; - - // performance optimization - private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET = - Collections.unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE)); - - // supported pairs of signature and hash algorithm - private final static Map<Integer, SignatureAndHashAlgorithm> supportedMap; - private final static Map<Integer, SignatureAndHashAlgorithm> priorityMap; - - // the hash algorithm - private HashAlgorithm hash; - - // id in 16 bit MSB format, i.e. 0x0603 for SHA512withECDSA - private int id; - - // the standard algorithm name, for example "SHA512withECDSA" - private String algorithm; - - // Priority for the preference order. The lower the better. - // - // If the algorithm is unsupported, its priority should be bigger - // than SUPPORTED_ALG_PRIORITY_MAX_NUM. - private int priority; - - // constructor for supported algorithm - private SignatureAndHashAlgorithm(HashAlgorithm hash, - SignatureAlgorithm signature, String algorithm, int priority) { - this.hash = hash; - this.algorithm = algorithm; - this.id = ((hash.value & 0xFF) << 8) | (signature.value & 0xFF); - this.priority = priority; - } - - // constructor for unsupported algorithm - private SignatureAndHashAlgorithm(String algorithm, int id, int sequence) { - this.hash = HashAlgorithm.valueOf((id >> 8) & 0xFF); - this.algorithm = algorithm; - this.id = id; - - // add one more to the sequence number, in case that the number is zero - this.priority = SUPPORTED_ALG_PRIORITY_MAX_NUM + sequence + 1; - } - - // Note that we do not use the sequence argument for supported algorithms, - // so please don't sort by comparing the objects read from handshake - // messages. - static SignatureAndHashAlgorithm valueOf(int hash, - int signature, int sequence) { - hash &= 0xFF; - signature &= 0xFF; - - int id = (hash << 8) | signature; - SignatureAndHashAlgorithm signAlg = supportedMap.get(id); - if (signAlg == null) { - // unsupported algorithm - signAlg = new SignatureAndHashAlgorithm( - "Unknown (hash:0x" + Integer.toString(hash, 16) + - ", signature:0x" + Integer.toString(signature, 16) + ")", - id, sequence); - } - - return signAlg; - } - - int getHashValue() { - return (id >> 8) & 0xFF; - } - - int getSignatureValue() { - return id & 0xFF; - } - - String getAlgorithmName() { - return algorithm; - } - - // return the size of a SignatureAndHashAlgorithm structure in TLS record - static int sizeInRecord() { - return 2; - } - - // Get local supported algorithm collection complying to - // algorithm constraints - static Collection<SignatureAndHashAlgorithm> - getSupportedAlgorithms(AlgorithmConstraints constraints) { - - Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>(); - for (SignatureAndHashAlgorithm sigAlg : priorityMap.values()) { - if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - sigAlg.algorithm, null)) { - supported.add(sigAlg); - } - } - - return supported; - } - - // Get supported algorithm collection from an untrusted collection - static Collection<SignatureAndHashAlgorithm> getSupportedAlgorithms( - AlgorithmConstraints constraints, - Collection<SignatureAndHashAlgorithm> algorithms ) { - Collection<SignatureAndHashAlgorithm> supported = new ArrayList<>(); - for (SignatureAndHashAlgorithm sigAlg : algorithms) { - if (sigAlg.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && - constraints.permits(SIGNATURE_PRIMITIVE_SET, - sigAlg.algorithm, null)) { - supported.add(sigAlg); - } - } - - return supported; - } - - static String[] getAlgorithmNames( - Collection<SignatureAndHashAlgorithm> algorithms) { - ArrayList<String> algorithmNames = new ArrayList<>(); - if (algorithms != null) { - for (SignatureAndHashAlgorithm sigAlg : algorithms) { - algorithmNames.add(sigAlg.algorithm); - } - } - - String[] array = new String[algorithmNames.size()]; - return algorithmNames.toArray(array); - } - - static Set<String> getHashAlgorithmNames( - Collection<SignatureAndHashAlgorithm> algorithms) { - Set<String> algorithmNames = new HashSet<>(); - if (algorithms != null) { - for (SignatureAndHashAlgorithm sigAlg : algorithms) { - if (sigAlg.hash.value > 0) { - algorithmNames.add(sigAlg.hash.standardName); - } - } - } - - return algorithmNames; - } - - static String getHashAlgorithmName(SignatureAndHashAlgorithm algorithm) { - return algorithm.hash.standardName; - } - - private static void supports(HashAlgorithm hash, - SignatureAlgorithm signature, String algorithm, int priority) { - - SignatureAndHashAlgorithm pair = - new SignatureAndHashAlgorithm(hash, signature, algorithm, priority); - if (supportedMap.put(pair.id, pair) != null) { - throw new RuntimeException( - "Duplicate SignatureAndHashAlgorithm definition, id: " + - pair.id); - } - if (priorityMap.put(pair.priority, pair) != null) { - throw new RuntimeException( - "Duplicate SignatureAndHashAlgorithm definition, priority: " + - pair.priority); - } - } - - static SignatureAndHashAlgorithm getPreferableAlgorithm( - Collection<SignatureAndHashAlgorithm> algorithms, String expected) { - - return SignatureAndHashAlgorithm.getPreferableAlgorithm( - algorithms, expected, null); - } - - static SignatureAndHashAlgorithm getPreferableAlgorithm( - Collection<SignatureAndHashAlgorithm> algorithms, - String expected, PrivateKey signingKey) { - - int maxDigestLength = getMaxDigestLength(signingKey); - for (SignatureAndHashAlgorithm algorithm : algorithms) { - int signValue = algorithm.id & 0xFF; - if ((expected == null) || - (expected.equalsIgnoreCase("rsa") && - signValue == SignatureAlgorithm.RSA.value) || - (expected.equalsIgnoreCase("dsa") && - signValue == SignatureAlgorithm.DSA.value) || - (expected.equalsIgnoreCase("ecdsa") && - signValue == SignatureAlgorithm.ECDSA.value) || - (expected.equalsIgnoreCase("ec") && - signValue == SignatureAlgorithm.ECDSA.value)) { - - if (algorithm.priority <= SUPPORTED_ALG_PRIORITY_MAX_NUM && - algorithm.hash.length <= maxDigestLength) { - - return algorithm; - } - } - } - - return null; - } - - /* - * Need to check key length to match the length of hash value - */ - private static int getMaxDigestLength(PrivateKey signingKey) { - int maxDigestLength = Integer.MAX_VALUE; - - // only need to check RSA algorithm at present. - if (signingKey != null && - "rsa".equalsIgnoreCase(signingKey.getAlgorithm())) { - /* - * RSA keys of 512 bits have been shown to be practically - * breakable, it does not make much sense to use the strong - * hash algorithm for keys whose key size less than 512 bits. - * So it is not necessary to caculate the required max digest - * length exactly. - * - * If key size is greater than or equals to 768, there is no max - * digest length limitation in currect implementation. - * - * If key size is greater than or equals to 512, but less than - * 768, the digest length should be less than or equal to 32 bytes. - * - * If key size is less than 512, the digest length should be - * less than or equal to 20 bytes. - */ - int keySize = KeyUtil.getKeySize(signingKey); - if (keySize >= 768) { - maxDigestLength = HashAlgorithm.SHA512.length; - } else if ((keySize >= 512) && (keySize < 768)) { - maxDigestLength = HashAlgorithm.SHA256.length; - } else if ((keySize > 0) && (keySize < 512)) { - maxDigestLength = HashAlgorithm.SHA1.length; - } // Otherwise, cannot determine the key size, prefer the most - // preferable hash algorithm. - } - - return maxDigestLength; - } - - static enum HashAlgorithm { - UNDEFINED("undefined", "", -1, -1), - NONE( "none", "NONE", 0, -1), - MD5( "md5", "MD5", 1, 16), - SHA1( "sha1", "SHA-1", 2, 20), - SHA224( "sha224", "SHA-224", 3, 28), - SHA256( "sha256", "SHA-256", 4, 32), - SHA384( "sha384", "SHA-384", 5, 48), - SHA512( "sha512", "SHA-512", 6, 64); - - final String name; // not the standard signature algorithm name - // except the UNDEFINED, other names are defined - // by TLS 1.2 protocol - final String standardName; // the standard MessageDigest algorithm name - final int value; - final int length; // digest length in bytes, -1 means not applicable - - private HashAlgorithm(String name, String standardName, - int value, int length) { - this.name = name; - this.standardName = standardName; - this.value = value; - this.length = length; - } - - static HashAlgorithm valueOf(int value) { - HashAlgorithm algorithm = UNDEFINED; - switch (value) { - case 0: - algorithm = NONE; - break; - case 1: - algorithm = MD5; - break; - case 2: - algorithm = SHA1; - break; - case 3: - algorithm = SHA224; - break; - case 4: - algorithm = SHA256; - break; - case 5: - algorithm = SHA384; - break; - case 6: - algorithm = SHA512; - break; - } - - return algorithm; - } - } - - static enum SignatureAlgorithm { - UNDEFINED("undefined", -1), - ANONYMOUS("anonymous", 0), - RSA( "rsa", 1), - DSA( "dsa", 2), - ECDSA( "ecdsa", 3); - - final String name; // not the standard signature algorithm name - // except the UNDEFINED, other names are defined - // by TLS 1.2 protocol - final int value; - - private SignatureAlgorithm(String name, int value) { - this.name = name; - this.value = value; - } - - static SignatureAlgorithm valueOf(int value) { - SignatureAlgorithm algorithm = UNDEFINED; - switch (value) { - case 0: - algorithm = ANONYMOUS; - break; - case 1: - algorithm = RSA; - break; - case 2: - algorithm = DSA; - break; - case 3: - algorithm = ECDSA; - break; - } - - return algorithm; - } - } - - static { - supportedMap = Collections.synchronizedSortedMap( - new TreeMap<Integer, SignatureAndHashAlgorithm>()); - priorityMap = Collections.synchronizedSortedMap( - new TreeMap<Integer, SignatureAndHashAlgorithm>()); - - synchronized (supportedMap) { - int p = SUPPORTED_ALG_PRIORITY_MAX_NUM; - supports(HashAlgorithm.MD5, SignatureAlgorithm.RSA, - "MD5withRSA", --p); - supports(HashAlgorithm.SHA1, SignatureAlgorithm.DSA, - "SHA1withDSA", --p); - supports(HashAlgorithm.SHA1, SignatureAlgorithm.RSA, - "SHA1withRSA", --p); - supports(HashAlgorithm.SHA1, SignatureAlgorithm.ECDSA, - "SHA1withECDSA", --p); - - if (Security.getProvider("SunMSCAPI") == null) { - supports(HashAlgorithm.SHA224, SignatureAlgorithm.DSA, - "SHA224withDSA", --p); - supports(HashAlgorithm.SHA224, SignatureAlgorithm.RSA, - "SHA224withRSA", --p); - supports(HashAlgorithm.SHA224, SignatureAlgorithm.ECDSA, - "SHA224withECDSA", --p); - } - - supports(HashAlgorithm.SHA256, SignatureAlgorithm.DSA, - "SHA256withDSA", --p); - supports(HashAlgorithm.SHA256, SignatureAlgorithm.RSA, - "SHA256withRSA", --p); - supports(HashAlgorithm.SHA256, SignatureAlgorithm.ECDSA, - "SHA256withECDSA", --p); - supports(HashAlgorithm.SHA384, SignatureAlgorithm.RSA, - "SHA384withRSA", --p); - supports(HashAlgorithm.SHA384, SignatureAlgorithm.ECDSA, - "SHA384withECDSA", --p); - supports(HashAlgorithm.SHA512, SignatureAlgorithm.RSA, - "SHA512withRSA", --p); - supports(HashAlgorithm.SHA512, SignatureAlgorithm.ECDSA, - "SHA512withECDSA", --p); - } - } -} -
--- a/src/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,427 +0,0 @@ -/* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.net.ssl.*; -import java.security.*; -import java.security.cert.*; -import java.security.cert.Certificate; -import java.util.*; -import java.net.Socket; - -import javax.security.auth.x500.X500Principal; - - -/** - * An implementation of X509KeyManager backed by a KeyStore. - * - * The backing KeyStore is inspected when this object is constructed. - * All key entries containing a PrivateKey and a non-empty chain of - * X509Certificate are then copied into an internal store. This means - * that subsequent modifications of the KeyStore have no effect on the - * X509KeyManagerImpl object. - * - * Note that this class assumes that all keys are protected by the same - * password. - * - * The JSSE handshake code currently calls into this class via - * chooseClientAlias() and chooseServerAlias() to find the certificates to - * use. As implemented here, both always return the first alias returned by - * getClientAliases() and getServerAliases(). In turn, these methods are - * implemented by calling getAliases(), which performs the actual lookup. - * - * Note that this class currently implements no checking of the local - * certificates. In particular, it is *not* guaranteed that: - * . the certificates are within their validity period and not revoked - * . the signatures verify - * . they form a PKIX compliant chain. - * . the certificate extensions allow the certificate to be used for - * the desired purpose. - * - * Chains that fail any of these criteria will probably be rejected by - * the remote peer. - * - */ -final class SunX509KeyManagerImpl extends X509ExtendedKeyManager { - - private static final Debug debug = Debug.getInstance("ssl"); - - private static final String[] STRING0 = new String[0]; - - /* - * The credentials from the KeyStore as - * Map: String(alias) -> X509Credentials(credentials) - */ - private Map<String,X509Credentials> credentialsMap; - - /* - * Cached server aliases for the case issuers == null. - * (in the current JSSE implementation, issuers are always null for - * server certs). See chooseServerAlias() for details. - * - * Map: String(keyType) -> String[](alias) - */ - private final Map<String,String[]> serverAliasCache; - - /* - * Basic container for credentials implemented as an inner class. - */ - private static class X509Credentials { - PrivateKey privateKey; - X509Certificate[] certificates; - private Set<X500Principal> issuerX500Principals; - - X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) { - // assert privateKey and certificates != null - this.privateKey = privateKey; - this.certificates = certificates; - } - - synchronized Set<X500Principal> getIssuerX500Principals() { - // lazy initialization - if (issuerX500Principals == null) { - issuerX500Principals = new HashSet<X500Principal>(); - for (int i = 0; i < certificates.length; i++) { - issuerX500Principals.add( - certificates[i].getIssuerX500Principal()); - } - } - return issuerX500Principals; - } - } - - SunX509KeyManagerImpl(KeyStore ks, char[] password) - throws KeyStoreException, - NoSuchAlgorithmException, UnrecoverableKeyException { - - credentialsMap = new HashMap<String,X509Credentials>(); - serverAliasCache = Collections.synchronizedMap( - new HashMap<String,String[]>()); - if (ks == null) { - return; - } - - for (Enumeration<String> aliases = ks.aliases(); - aliases.hasMoreElements(); ) { - String alias = aliases.nextElement(); - if (!ks.isKeyEntry(alias)) { - continue; - } - Key key = ks.getKey(alias, password); - if (key instanceof PrivateKey == false) { - continue; - } - Certificate[] certs = ks.getCertificateChain(alias); - if ((certs == null) || (certs.length == 0) || - !(certs[0] instanceof X509Certificate)) { - continue; - } - if (!(certs instanceof X509Certificate[])) { - Certificate[] tmp = new X509Certificate[certs.length]; - System.arraycopy(certs, 0, tmp, 0, certs.length); - certs = tmp; - } - - X509Credentials cred = new X509Credentials((PrivateKey)key, - (X509Certificate[])certs); - credentialsMap.put(alias, cred); - if (debug != null && Debug.isOn("keymanager")) { - System.out.println("***"); - System.out.println("found key for : " + alias); - for (int i = 0; i < certs.length; i++) { - System.out.println("chain [" + i + "] = " - + certs[i]); - } - System.out.println("***"); - } - } - } - - /* - * Returns the certificate chain associated with the given alias. - * - * @return the certificate chain (ordered with the user's certificate first - * and the root certificate authority last) - */ - @Override - public X509Certificate[] getCertificateChain(String alias) { - if (alias == null) { - return null; - } - X509Credentials cred = credentialsMap.get(alias); - if (cred == null) { - return null; - } else { - return cred.certificates.clone(); - } - } - - /* - * Returns the key associated with the given alias - */ - @Override - public PrivateKey getPrivateKey(String alias) { - if (alias == null) { - return null; - } - X509Credentials cred = credentialsMap.get(alias); - if (cred == null) { - return null; - } else { - return cred.privateKey; - } - } - - /* - * Choose an alias to authenticate the client side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseClientAlias(String[] keyTypes, Principal[] issuers, - Socket socket) { - /* - * We currently don't do anything with socket, but - * someday we might. It might be a useful hint for - * selecting one of the aliases we get back from - * getClientAliases(). - */ - - if (keyTypes == null) { - return null; - } - - for (int i = 0; i < keyTypes.length; i++) { - String[] aliases = getClientAliases(keyTypes[i], issuers); - if ((aliases != null) && (aliases.length > 0)) { - return aliases[0]; - } - } - return null; - } - - /* - * Choose an alias to authenticate the client side of an - * <code>SSLEngine</code> connection given the public key type - * and the list of certificate issuer authorities recognized by - * the peer (if any). - * - * @since 1.5 - */ - @Override - public String chooseEngineClientAlias(String[] keyType, - Principal[] issuers, SSLEngine engine) { - /* - * If we ever start using socket as a selection criteria, - * we'll need to adjust this. - */ - return chooseClientAlias(keyType, issuers, null); - } - - /* - * Choose an alias to authenticate the server side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String chooseServerAlias(String keyType, - Principal[] issuers, Socket socket) { - /* - * We currently don't do anything with socket, but - * someday we might. It might be a useful hint for - * selecting one of the aliases we get back from - * getServerAliases(). - */ - if (keyType == null) { - return null; - } - - String[] aliases; - - if (issuers == null || issuers.length == 0) { - aliases = serverAliasCache.get(keyType); - if (aliases == null) { - aliases = getServerAliases(keyType, issuers); - // Cache the result (positive and negative lookups) - if (aliases == null) { - aliases = STRING0; - } - serverAliasCache.put(keyType, aliases); - } - } else { - aliases = getServerAliases(keyType, issuers); - } - if ((aliases != null) && (aliases.length > 0)) { - return aliases[0]; - } - return null; - } - - /* - * Choose an alias to authenticate the server side of an - * <code>SSLEngine</code> connection given the public key type - * and the list of certificate issuer authorities recognized by - * the peer (if any). - * - * @since 1.5 - */ - @Override - public String chooseEngineServerAlias(String keyType, - Principal[] issuers, SSLEngine engine) { - /* - * If we ever start using socket as a selection criteria, - * we'll need to adjust this. - */ - return chooseServerAlias(keyType, issuers, null); - } - - /* - * Get the matching aliases for authenticating the client side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return getAliases(keyType, issuers); - } - - /* - * Get the matching aliases for authenticating the server side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - */ - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return getAliases(keyType, issuers); - } - - /* - * Get the matching aliases for authenticating the either side of a secure - * socket given the public key type and the list of - * certificate issuer authorities recognized by the peer (if any). - * - * Issuers comes to us in the form of X500Principal[]. - */ - private String[] getAliases(String keyType, Principal[] issuers) { - if (keyType == null) { - return null; - } - if (issuers == null) { - issuers = new X500Principal[0]; - } - if (issuers instanceof X500Principal[] == false) { - // normally, this will never happen but try to recover if it does - issuers = convertPrincipals(issuers); - } - String sigType; - if (keyType.contains("_")) { - int k = keyType.indexOf("_"); - sigType = keyType.substring(k + 1); - keyType = keyType.substring(0, k); - } else { - sigType = null; - } - - X500Principal[] x500Issuers = (X500Principal[])issuers; - // the algorithm below does not produce duplicates, so avoid Set - List<String> aliases = new ArrayList<>(); - - for (Map.Entry<String,X509Credentials> entry : - credentialsMap.entrySet()) { - - String alias = entry.getKey(); - X509Credentials credentials = entry.getValue(); - X509Certificate[] certs = credentials.certificates; - - if (!keyType.equals(certs[0].getPublicKey().getAlgorithm())) { - continue; - } - if (sigType != null) { - if (certs.length > 1) { - // if possible, check the public key in the issuer cert - if (!sigType.equals( - certs[1].getPublicKey().getAlgorithm())) { - continue; - } - } else { - // Check the signature algorithm of the certificate itself. - // Look for the "withRSA" in "SHA1withRSA", etc. - String sigAlgName = - certs[0].getSigAlgName().toUpperCase(Locale.ENGLISH); - String pattern = "WITH" + - sigType.toUpperCase(Locale.ENGLISH); - if (sigAlgName.contains(pattern) == false) { - continue; - } - } - } - - if (issuers.length == 0) { - // no issuer specified, match all - aliases.add(alias); - if (debug != null && Debug.isOn("keymanager")) { - System.out.println("matching alias: " + alias); - } - } else { - Set<X500Principal> certIssuers = - credentials.getIssuerX500Principals(); - for (int i = 0; i < x500Issuers.length; i++) { - if (certIssuers.contains(issuers[i])) { - aliases.add(alias); - if (debug != null && Debug.isOn("keymanager")) { - System.out.println("matching alias: " + alias); - } - break; - } - } - } - } - - String[] aliasStrings = aliases.toArray(STRING0); - return ((aliasStrings.length == 0) ? null : aliasStrings); - } - - /* - * Convert an array of Principals to an array of X500Principals, if - * possible. Principals that cannot be converted are ignored. - */ - private static X500Principal[] convertPrincipals(Principal[] principals) { - List<X500Principal> list = new ArrayList<>(principals.length); - for (int i = 0; i < principals.length; i++) { - Principal p = principals[i]; - if (p instanceof X500Principal) { - list.add((X500Principal)p); - } else { - try { - list.add(new X500Principal(p.getName())); - } catch (IllegalArgumentException e) { - // ignore - } - } - } - return list.toArray(new X500Principal[list.size()]); - } -}
--- a/src/share/classes/sun/security/ssl/TrustManagerFactoryImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,174 +0,0 @@ -/* - * Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.util.*; -import java.io.*; -import java.security.*; -import java.security.cert.*; -import javax.net.ssl.*; - -import sun.security.validator.Validator; -import sun.security.validator.TrustStoreUtil; - -abstract class TrustManagerFactoryImpl extends TrustManagerFactorySpi { - - private static final Debug debug = Debug.getInstance("ssl"); - private X509TrustManager trustManager = null; - private boolean isInitialized = false; - - TrustManagerFactoryImpl() { - // empty - } - - @Override - protected void engineInit(KeyStore ks) throws KeyStoreException { - if (ks == null) { - try { - trustManager = getInstance(TrustStoreManager.getTrustedCerts()); - } catch (SecurityException se) { - // eat security exceptions but report other throwables - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "SunX509: skip default keystore: " + se); - } - } catch (Error err) { - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "SunX509: skip default keystore: " + err); - } - throw err; - } catch (RuntimeException re) { - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "SunX509: skip default keystore: " + re); - } - throw re; - } catch (Exception e) { - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "SunX509: skip default keystore: " + e); - } - throw new KeyStoreException( - "problem accessing trust store", e); - } - } else { - trustManager = getInstance(TrustStoreUtil.getTrustedCerts(ks)); - } - - isInitialized = true; - } - - abstract X509TrustManager getInstance( - Collection<X509Certificate> trustedCerts); - - abstract X509TrustManager getInstance(ManagerFactoryParameters spec) - throws InvalidAlgorithmParameterException; - - @Override - protected void engineInit(ManagerFactoryParameters spec) throws - InvalidAlgorithmParameterException { - trustManager = getInstance(spec); - isInitialized = true; - } - - /** - * Returns one trust manager for each type of trust material. - */ - @Override - protected TrustManager[] engineGetTrustManagers() { - if (!isInitialized) { - throw new IllegalStateException( - "TrustManagerFactoryImpl is not initialized"); - } - return new TrustManager[] { trustManager }; - } - - /* - * Try to get an InputStream based on the file we pass in. - */ - private static FileInputStream getFileInputStream(final File file) - throws Exception { - return AccessController.doPrivileged( - new PrivilegedExceptionAction<FileInputStream>() { - @Override - public FileInputStream run() throws Exception { - try { - if (file.exists()) { - return new FileInputStream(file); - } else { - return null; - } - } catch (FileNotFoundException e) { - // couldn't find it, oh well. - return null; - } - } - }); - } - - public static final class SimpleFactory extends TrustManagerFactoryImpl { - @Override - X509TrustManager getInstance( - Collection<X509Certificate> trustedCerts) { - return new X509TrustManagerImpl( - Validator.TYPE_SIMPLE, trustedCerts); - } - - @Override - X509TrustManager getInstance(ManagerFactoryParameters spec) - throws InvalidAlgorithmParameterException { - throw new InvalidAlgorithmParameterException - ("SunX509 TrustManagerFactory does not use " - + "ManagerFactoryParameters"); - } - } - - public static final class PKIXFactory extends TrustManagerFactoryImpl { - @Override - X509TrustManager getInstance( - Collection<X509Certificate> trustedCerts) { - return new X509TrustManagerImpl(Validator.TYPE_PKIX, trustedCerts); - } - - @Override - X509TrustManager getInstance(ManagerFactoryParameters spec) - throws InvalidAlgorithmParameterException { - if (spec instanceof CertPathTrustManagerParameters == false) { - throw new InvalidAlgorithmParameterException - ("Parameters must be CertPathTrustManagerParameters"); - } - CertPathParameters params = - ((CertPathTrustManagerParameters)spec).getParameters(); - if (params instanceof PKIXBuilderParameters == false) { - throw new InvalidAlgorithmParameterException - ("Encapsulated parameters must be PKIXBuilderParameters"); - } - PKIXBuilderParameters pkixParams = (PKIXBuilderParameters)params; - return new X509TrustManagerImpl(Validator.TYPE_PKIX, pkixParams); - } - } -}
--- a/src/share/classes/sun/security/ssl/TrustStoreManager.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.lang.ref.WeakReference; -import java.io.*; -import java.util.*; - -import java.security.*; -import java.security.cert.*; -import java.security.cert.Certificate; - -import sun.security.action.*; -import sun.security.validator.TrustStoreUtil; - -/** - * Collection of static utility methods to manage the default trusted KeyStores - * effectively. - */ -final class TrustStoreManager { - private static final Debug debug = Debug.getInstance("ssl"); - - // A singleton service to manage the default trusted KeyStores effectively. - private static final TrustAnchorManager tam = new TrustAnchorManager(); - - // Restrict instantiation of this class. - private TrustStoreManager() { - // empty - } - - /** - * Return an unmodifiable set of all trusted X509Certificates contained - * in the default trusted KeyStore. - */ - public static Set<X509Certificate> getTrustedCerts() throws Exception { - return tam.getTrustedCerts(TrustStoreDescriptor.createInstance()); - } - - /** - * Return an instance of the default trusted KeyStore. - */ - public static KeyStore getTrustedKeyStore() throws Exception { - return tam.getKeyStore(TrustStoreDescriptor.createInstance()); - } - - /** - * A descriptor of the default trusted KeyStore. - * - * The preference of the default trusted KeyStore is: - * javax.net.ssl.trustStore - * jssecacerts - * cacerts - */ - private static final class TrustStoreDescriptor { - private static final String fileSep = File.separator; - private static final String defaultStorePath = - GetPropertyAction.privilegedGetProperty("java.home") + - fileSep + "lib" + fileSep + "security"; - private static final String defaultStore = - defaultStorePath + fileSep + "cacerts"; - private static final String jsseDefaultStore = - defaultStorePath + fileSep + "jssecacerts"; - - // the trust store name - private final String storeName; - - // the trust store type, JKS/PKCS12 - private final String storeType; - - // the provider of the trust store - private final String storeProvider; - - // the password used for the trust store - private final String storePassword; - - // the File object of the trust store - private final File storeFile; - - // the last modified time of the store - private final long lastModified; - - private TrustStoreDescriptor(String storeName, String storeType, - String storeProvider, String storePassword, - File storeFile, long lastModified) { - this.storeName = storeName; - this.storeType = storeType; - this.storeProvider = storeProvider; - this.storePassword = storePassword; - this.storeFile = storeFile; - this.lastModified = lastModified; - - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "trustStore is: " + storeName + "\n" + - "trustStore type is: " + storeType + "\n" + - "trustStore provider is: " + storeProvider + "\n" + - "the last modified time is: " + (new Date(lastModified))); - } - } - - /** - * Create an instance of TrustStoreDescriptor for the default - * trusted KeyStore. - */ - static TrustStoreDescriptor createInstance() { - return AccessController.doPrivileged(new PrivilegedAction<TrustStoreDescriptor>() { - - @Override - public TrustStoreDescriptor run() { - // Get the system properties for trust store. - String storePropName = System.getProperty( - "javax.net.ssl.trustStore", jsseDefaultStore); - String storePropType = System.getProperty( - "javax.net.ssl.trustStoreType", - KeyStore.getDefaultType()); - String storePropProvider = System.getProperty( - "javax.net.ssl.trustStoreProvider", ""); - String storePropPassword = System.getProperty( - "javax.net.ssl.trustStorePassword", ""); - - String temporaryName = ""; - File temporaryFile = null; - long temporaryTime = 0L; - if (!"NONE".equals(storePropName)) { - String[] fileNames = - new String[] {storePropName, defaultStore}; - for (String fileName : fileNames) { - File f = new File(fileName); - if (f.isFile() && f.canRead()) { - temporaryName = fileName;; - temporaryFile = f; - temporaryTime = f.lastModified(); - - break; - } - - // Not break, the file is inaccessible. - if (debug != null && - Debug.isOn("trustmanager")) { - System.out.println( - "Inaccessible trust store: " + - storePropName); - } - } - } else { - temporaryName = storePropName; - } - - return new TrustStoreDescriptor( - temporaryName, storePropType, storePropProvider, - storePropPassword, temporaryFile, temporaryTime); - } - }); - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - - if (obj instanceof TrustStoreDescriptor) { - TrustStoreDescriptor that = (TrustStoreDescriptor)obj; - return ((this.lastModified == that.lastModified) && - Objects.equals(this.storeName, that.storeName) && - Objects.equals(this.storeType, that.storeType) && - Objects.equals(this.storeProvider, that.storeProvider)); - } - - return false; - } - - - // Please be careful if computing security-sensitive attributes' - // hash code. For example the storePassword should not be computed. - @Override - public int hashCode() { - int result = 17; - - if (storeName != null && !storeName.isEmpty()) { - result = 31 * result + storeName.hashCode(); - } - - if (storeType != null && !storeType.isEmpty()) { - result = 31 * result + storeType.hashCode(); - } - - if (storeProvider != null && !storeProvider.isEmpty()) { - result = 31 * result + storeProvider.hashCode(); - } - - if (storeFile != null) { - result = 31 * result + storeFile.hashCode(); - } - - if (lastModified != 0L) { - result = (int)(31 * result + lastModified); - } - - return result; - } - } - - /** - * The trust anchors manager used to expedite the performance. - * - * This class can be used to provide singleton services to access default - * trust KeyStore more effectively. - */ - private static final class TrustAnchorManager { - // Last trust store descriptor. - private TrustStoreDescriptor descriptor; - - // The key store used for the trust anchors. - // - // Use weak reference so that the heavy loaded KeyStore object can - // be atomically cleared, and reloaded if needed. - private WeakReference<KeyStore> ksRef; - - // The trusted X.509 certificates in the key store. - // - // Use weak reference so that the heavy loaded certificates collection - // objects can be atomically cleared, and reloaded if needed. - private WeakReference<Set<X509Certificate>> csRef; - - private TrustAnchorManager() { - this.descriptor = null; - this.ksRef = new WeakReference<>(null); - this.csRef = new WeakReference<>(null); - } - - /** - * Get the default trusted KeyStore with the specified descriptor. - * - * @return null if the underlying KeyStore is not available. - */ - synchronized KeyStore getKeyStore( - TrustStoreDescriptor descriptor) throws Exception { - - TrustStoreDescriptor temporaryDesc = this.descriptor; - KeyStore ks = ksRef.get(); - if ((ks != null) && descriptor.equals(temporaryDesc)) { - return ks; - } - - // Reload a new key store. - if ((debug != null) && Debug.isOn("trustmanager")) { - System.out.println("Reload the trust store"); - } - - ks = loadKeyStore(descriptor); - this.descriptor = descriptor; - this.ksRef = new WeakReference<>(ks); - - return ks; - } - - /** - * Get trusted certificates in the default trusted KeyStore with - * the specified descriptor. - * - * @return empty collection if the underlying KeyStore is not available. - */ - synchronized Set<X509Certificate> getTrustedCerts( - TrustStoreDescriptor descriptor) throws Exception { - - KeyStore ks = null; - TrustStoreDescriptor temporaryDesc = this.descriptor; - Set<X509Certificate> certs = csRef.get(); - if (certs != null) { - if (descriptor.equals(temporaryDesc)) { - return certs; - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } - } else { - // Try to use the cached store at first. - if (descriptor.equals(temporaryDesc)) { - ks = ksRef.get(); - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } - } - - // Reload the trust store if needed. - if (ks == null) { - if ((debug != null) && Debug.isOn("trustmanager")) { - System.out.println("Reload the trust store"); - } - ks = loadKeyStore(descriptor); - } - - // Reload trust certs from the key store. - if ((debug != null) && Debug.isOn("trustmanager")) { - System.out.println("Reload trust certs"); - } - - certs = loadTrustedCerts(ks); - if ((debug != null) && Debug.isOn("trustmanager")) { - System.out.println("Reloaded " + certs.size() + " trust certs"); - } - - // Note that as ks is a local variable, it is not - // necessary to add it to the ksRef weak reference. - this.csRef = new WeakReference<>(certs); - - return certs; - } - - /** - * Load the the KeyStore as described in the specified descriptor. - */ - private static KeyStore loadKeyStore( - TrustStoreDescriptor descriptor) throws Exception { - if (!"NONE".equals(descriptor.storeName) && - descriptor.storeFile == null) { - - // No file available, no KeyStore available. - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println("No available key store"); - } - - return null; - } - - KeyStore ks; - if (descriptor.storeProvider.isEmpty()) { - ks = KeyStore.getInstance(descriptor.storeType); - } else { - ks = KeyStore.getInstance( - descriptor.storeType, descriptor.storeProvider); - } - - char[] password = null; - if (!descriptor.storePassword.isEmpty()) { - password = descriptor.storePassword.toCharArray(); - } - - if (!"NONE".equals(descriptor.storeName)) { - try (FileInputStream fis = AccessController.doPrivileged( - new OpenFileInputStreamAction(descriptor.storeFile))) { - ks.load(fis, password); - } catch (FileNotFoundException fnfe) { - // No file available, no KeyStore available. - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println( - "Not available key store: " + descriptor.storeName); - } - - return null; - } - } else { - ks.load(null, password); - } - - return ks; - } - - /** - * Load trusted certificates from the specified KeyStore. - */ - private static Set<X509Certificate> loadTrustedCerts(KeyStore ks) { - if (ks == null) { - return Collections.<X509Certificate>emptySet(); - } - - return TrustStoreUtil.getTrustedCerts(ks); - } - } -}
--- a/src/share/classes/sun/security/ssl/UnknownExtension.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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; - -final class UnknownExtension extends HelloExtension { - - private final byte[] data; - - UnknownExtension(HandshakeInStream s, int len, ExtensionType type) - throws IOException { - super(type); - data = new byte[len]; - // s.read() does not handle 0-length arrays. - if (len != 0) { - s.read(data); - } - } - - @Override - int length() { - return 4 + data.length; - } - - @Override - void send(HandshakeOutStream s) throws IOException { - s.putInt16(type.id); - s.putBytes16(data); - } - - @Override - public String toString() { - return "Unsupported extension " + type + ", data: " + - Debug.toString(data); - } -}
--- a/src/share/classes/sun/security/ssl/Utilities.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 javax.net.ssl.*; -import java.util.*; -import sun.net.util.IPAddressUtil; - -/** - * A utility class to share the static methods. - */ -final class Utilities { - /** - * Puts {@code hostname} into the {@code serverNames} list. - * <P> - * If the {@code serverNames} does not look like a legal FQDN, it will - * not be put into the returned list. - * <P> - * Note that the returned list does not allow duplicated name type. - * - * @return a list of {@link SNIServerName} - */ - static List<SNIServerName> addToSNIServerNameList( - List<SNIServerName> serverNames, String hostname) { - - SNIHostName sniHostName = rawToSNIHostName(hostname); - if (sniHostName == null) { - return serverNames; - } - - int size = serverNames.size(); - List<SNIServerName> sniList = (size != 0) ? - new ArrayList<SNIServerName>(serverNames) : - new ArrayList<SNIServerName>(1); - - boolean reset = false; - for (int i = 0; i < size; i++) { - SNIServerName serverName = sniList.get(i); - if (serverName.getType() == StandardConstants.SNI_HOST_NAME) { - sniList.set(i, sniHostName); - if (Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", the previous server name in SNI (" + serverName + - ") was replaced with (" + sniHostName + ")"); - } - reset = true; - break; - } - } - - if (!reset) { - sniList.add(sniHostName); - } - - return Collections.<SNIServerName>unmodifiableList(sniList); - } - - /** - * Converts string hostname to {@code SNIHostName}. - * <P> - * Note that to check whether a hostname is a valid domain name, we cannot - * use the hostname resolved from name services. For virtual hosting, - * multiple hostnames may be bound to the same IP address, so the hostname - * resolved from name services is not always reliable. - * - * @param hostname - * the raw hostname - * @return an instance of {@link SNIHostName}, or null if the hostname does - * not look like a FQDN - */ - private static SNIHostName rawToSNIHostName(String hostname) { - SNIHostName sniHostName = null; - if (hostname != null && hostname.indexOf('.') > 0 && - !hostname.endsWith(".") && - !IPAddressUtil.isIPv4LiteralAddress(hostname) && - !IPAddressUtil.isIPv6LiteralAddress(hostname)) { - - try { - sniHostName = new SNIHostName(hostname); - } catch (IllegalArgumentException iae) { - // don't bother to handle illegal host_name - if (Debug.isOn("ssl")) { - System.out.println(Thread.currentThread().getName() + - ", \"" + hostname + "\" " + - "is not a legal HostName for server name indication"); - } - } - } - - return sniHostName; - } -}
--- a/src/share/classes/sun/security/ssl/X509KeyManagerImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,860 +0,0 @@ -/* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.lang.ref.*; -import java.util.*; -import static java.util.Locale.ENGLISH; -import java.util.concurrent.atomic.AtomicLong; -import java.net.Socket; - -import java.security.*; -import java.security.KeyStore.*; -import java.security.cert.*; -import java.security.cert.Certificate; - -import javax.net.ssl.*; - -import sun.security.provider.certpath.AlgorithmChecker; -import sun.security.validator.Validator; - -/** - * The new X509 key manager implementation. The main differences to the - * old SunX509 key manager are: - * . it is based around the KeyStore.Builder API. This allows it to use - * other forms of KeyStore protection or password input (e.g. a - * CallbackHandler) or to have keys within one KeyStore protected by - * different keys. - * . it can use multiple KeyStores at the same time. - * . it is explicitly designed to accommodate KeyStores that change over - * the lifetime of the process. - * . it makes an effort to choose the key that matches best, i.e. one that - * is not expired and has the appropriate certificate extensions. - * - * Note that this code is not explicitly performance optimzied yet. - * - * @author Andreas Sterbenz - */ -final class X509KeyManagerImpl extends X509ExtendedKeyManager - implements X509KeyManager { - - private static final Debug debug = Debug.getInstance("ssl"); - - private static final boolean useDebug = - (debug != null) && Debug.isOn("keymanager"); - - // for unit testing only, set via privileged reflection - private static Date verificationDate; - - // list of the builders - private final List<Builder> builders; - - // counter to generate unique ids for the aliases - private final AtomicLong uidCounter; - - // cached entries - private final Map<String,Reference<PrivateKeyEntry>> entryCacheMap; - - X509KeyManagerImpl(Builder builder) { - this(Collections.singletonList(builder)); - } - - X509KeyManagerImpl(List<Builder> builders) { - this.builders = builders; - uidCounter = new AtomicLong(); - entryCacheMap = Collections.synchronizedMap - (new SizedMap<String,Reference<PrivateKeyEntry>>()); - } - - // LinkedHashMap with a max size of 10 - // see LinkedHashMap JavaDocs - private static class SizedMap<K,V> extends LinkedHashMap<K,V> { - private static final long serialVersionUID = -8211222668790986062L; - - @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { - return size() > 10; - } - } - - // - // public methods - // - - @Override - public X509Certificate[] getCertificateChain(String alias) { - PrivateKeyEntry entry = getEntry(alias); - return entry == null ? null : - (X509Certificate[])entry.getCertificateChain(); - } - - @Override - public PrivateKey getPrivateKey(String alias) { - PrivateKeyEntry entry = getEntry(alias); - return entry == null ? null : entry.getPrivateKey(); - } - - @Override - public String chooseClientAlias(String[] keyTypes, Principal[] issuers, - Socket socket) { - return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT, - getAlgorithmConstraints(socket)); - } - - @Override - public String chooseEngineClientAlias(String[] keyTypes, - Principal[] issuers, SSLEngine engine) { - return chooseAlias(getKeyTypes(keyTypes), issuers, CheckType.CLIENT, - getAlgorithmConstraints(engine)); - } - - @Override - public String chooseServerAlias(String keyType, - Principal[] issuers, Socket socket) { - return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER, - getAlgorithmConstraints(socket), - X509TrustManagerImpl.getRequestedServerNames(socket), - "HTTPS"); // The SNI HostName is a fully qualified domain name. - // The certificate selection scheme for SNI HostName - // is similar to HTTPS endpoint identification scheme - // implemented in this provider. - // - // Using HTTPS endpoint identification scheme to guide - // the selection of an appropriate authentication - // certificate according to requested SNI extension. - // - // It is not a really HTTPS endpoint identification. - } - - @Override - public String chooseEngineServerAlias(String keyType, - Principal[] issuers, SSLEngine engine) { - return chooseAlias(getKeyTypes(keyType), issuers, CheckType.SERVER, - getAlgorithmConstraints(engine), - X509TrustManagerImpl.getRequestedServerNames(engine), - "HTTPS"); // The SNI HostName is a fully qualified domain name. - // The certificate selection scheme for SNI HostName - // is similar to HTTPS endpoint identification scheme - // implemented in this provider. - // - // Using HTTPS endpoint identification scheme to guide - // the selection of an appropriate authentication - // certificate according to requested SNI extension. - // - // It is not a really HTTPS endpoint identification. - } - - @Override - public String[] getClientAliases(String keyType, Principal[] issuers) { - return getAliases(keyType, issuers, CheckType.CLIENT, null); - } - - @Override - public String[] getServerAliases(String keyType, Principal[] issuers) { - return getAliases(keyType, issuers, CheckType.SERVER, null); - } - - // - // implementation private methods - // - - // Gets algorithm constraints of the socket. - private AlgorithmConstraints getAlgorithmConstraints(Socket socket) { - if (socket != null && socket.isConnected() && - socket instanceof SSLSocket) { - - SSLSocket sslSocket = (SSLSocket)socket; - SSLSession session = sslSocket.getHandshakeSession(); - - if (session != null) { - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - String[] peerSupportedSignAlgs = null; - - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return new SSLAlgorithmConstraints( - sslSocket, peerSupportedSignAlgs, true); - } - } - - return new SSLAlgorithmConstraints(sslSocket, true); - } - - return new SSLAlgorithmConstraints((SSLSocket)null, true); - } - - // Gets algorithm constraints of the engine. - private AlgorithmConstraints getAlgorithmConstraints(SSLEngine engine) { - if (engine != null) { - SSLSession session = engine.getHandshakeSession(); - if (session != null) { - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - String[] peerSupportedSignAlgs = null; - - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - peerSupportedSignAlgs = - extSession.getPeerSupportedSignatureAlgorithms(); - } - - return new SSLAlgorithmConstraints( - engine, peerSupportedSignAlgs, true); - } - } - } - - return new SSLAlgorithmConstraints(engine, true); - } - - // we construct the alias we return to JSSE as seen in the code below - // a unique id is included to allow us to reliably cache entries - // between the calls to getCertificateChain() and getPrivateKey() - // even if tokens are inserted or removed - private String makeAlias(EntryStatus entry) { - return uidCounter.incrementAndGet() + "." + entry.builderIndex + "." - + entry.alias; - } - - private PrivateKeyEntry getEntry(String alias) { - // if the alias is null, return immediately - if (alias == null) { - return null; - } - - // try to get the entry from cache - Reference<PrivateKeyEntry> ref = entryCacheMap.get(alias); - PrivateKeyEntry entry = (ref != null) ? ref.get() : null; - if (entry != null) { - return entry; - } - - // parse the alias - int firstDot = alias.indexOf('.'); - int secondDot = alias.indexOf('.', firstDot + 1); - if ((firstDot == -1) || (secondDot == firstDot)) { - // invalid alias - return null; - } - try { - int builderIndex = Integer.parseInt - (alias.substring(firstDot + 1, secondDot)); - String keyStoreAlias = alias.substring(secondDot + 1); - Builder builder = builders.get(builderIndex); - KeyStore ks = builder.getKeyStore(); - Entry newEntry = ks.getEntry - (keyStoreAlias, builder.getProtectionParameter(alias)); - if (newEntry instanceof PrivateKeyEntry == false) { - // unexpected type of entry - return null; - } - entry = (PrivateKeyEntry)newEntry; - entryCacheMap.put(alias, new SoftReference<PrivateKeyEntry>(entry)); - return entry; - } catch (Exception e) { - // ignore - return null; - } - } - - // Class to help verify that the public key algorithm (and optionally - // the signature algorithm) of a certificate matches what we need. - private static class KeyType { - - final String keyAlgorithm; - - // In TLS 1.2, the signature algorithm has been obsoleted by the - // supported_signature_algorithms, and the certificate type no longer - // restricts the algorithm used to sign the certificate. - // However, because we don't support certificate type checking other - // than rsa_sign, dss_sign and ecdsa_sign, we don't have to check the - // protocol version here. - final String sigKeyAlgorithm; - - KeyType(String algorithm) { - int k = algorithm.indexOf("_"); - if (k == -1) { - keyAlgorithm = algorithm; - sigKeyAlgorithm = null; - } else { - keyAlgorithm = algorithm.substring(0, k); - sigKeyAlgorithm = algorithm.substring(k + 1); - } - } - - boolean matches(Certificate[] chain) { - if (!chain[0].getPublicKey().getAlgorithm().equals(keyAlgorithm)) { - return false; - } - if (sigKeyAlgorithm == null) { - return true; - } - if (chain.length > 1) { - // if possible, check the public key in the issuer cert - return sigKeyAlgorithm.equals( - chain[1].getPublicKey().getAlgorithm()); - } else { - // Check the signature algorithm of the certificate itself. - // Look for the "withRSA" in "SHA1withRSA", etc. - X509Certificate issuer = (X509Certificate)chain[0]; - String sigAlgName = issuer.getSigAlgName().toUpperCase(ENGLISH); - String pattern = "WITH" + sigKeyAlgorithm.toUpperCase(ENGLISH); - return sigAlgName.contains(pattern); - } - } - } - - private static List<KeyType> getKeyTypes(String ... keyTypes) { - if ((keyTypes == null) || - (keyTypes.length == 0) || (keyTypes[0] == null)) { - return null; - } - List<KeyType> list = new ArrayList<>(keyTypes.length); - for (String keyType : keyTypes) { - list.add(new KeyType(keyType)); - } - return list; - } - - /* - * Return the best alias that fits the given parameters. - * The algorithm we use is: - * . scan through all the aliases in all builders in order - * . as soon as we find a perfect match, return - * (i.e. a match with a cert that has appropriate key usage, - * qualified endpoint identity, and is not expired). - * . if we do not find a perfect match, keep looping and remember - * the imperfect matches - * . at the end, sort the imperfect matches. we prefer expired certs - * with appropriate key usage to certs with the wrong key usage. - * return the first one of them. - */ - private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers, - CheckType checkType, AlgorithmConstraints constraints) { - - return chooseAlias(keyTypeList, issuers, - checkType, constraints, null, null); - } - - private String chooseAlias(List<KeyType> keyTypeList, Principal[] issuers, - CheckType checkType, AlgorithmConstraints constraints, - List<SNIServerName> requestedServerNames, String idAlgorithm) { - - if (keyTypeList == null || keyTypeList.isEmpty()) { - return null; - } - - Set<Principal> issuerSet = getIssuerSet(issuers); - List<EntryStatus> allResults = null; - for (int i = 0, n = builders.size(); i < n; i++) { - try { - List<EntryStatus> results = getAliases(i, keyTypeList, - issuerSet, false, checkType, constraints, - requestedServerNames, idAlgorithm); - if (results != null) { - // the results will either be a single perfect match - // or 1 or more imperfect matches - // if it's a perfect match, return immediately - EntryStatus status = results.get(0); - if (status.checkResult == CheckResult.OK) { - if (useDebug) { - debug.println("KeyMgr: choosing key: " + status); - } - return makeAlias(status); - } - if (allResults == null) { - allResults = new ArrayList<EntryStatus>(); - } - allResults.addAll(results); - } - } catch (Exception e) { - // ignore - } - } - if (allResults == null) { - if (useDebug) { - debug.println("KeyMgr: no matching key found"); - } - return null; - } - Collections.sort(allResults); - if (useDebug) { - debug.println("KeyMgr: no good matching key found, " - + "returning best match out of:"); - debug.println(allResults.toString()); - } - return makeAlias(allResults.get(0)); - } - - /* - * Return all aliases that (approximately) fit the parameters. - * These are perfect matches plus imperfect matches (expired certificates - * and certificates with the wrong extensions). - * The perfect matches will be first in the array. - */ - public String[] getAliases(String keyType, Principal[] issuers, - CheckType checkType, AlgorithmConstraints constraints) { - if (keyType == null) { - return null; - } - - Set<Principal> issuerSet = getIssuerSet(issuers); - List<KeyType> keyTypeList = getKeyTypes(keyType); - List<EntryStatus> allResults = null; - for (int i = 0, n = builders.size(); i < n; i++) { - try { - List<EntryStatus> results = getAliases(i, keyTypeList, - issuerSet, true, checkType, constraints, - null, null); - if (results != null) { - if (allResults == null) { - allResults = new ArrayList<EntryStatus>(); - } - allResults.addAll(results); - } - } catch (Exception e) { - // ignore - } - } - if (allResults == null || allResults.isEmpty()) { - if (useDebug) { - debug.println("KeyMgr: no matching alias found"); - } - return null; - } - Collections.sort(allResults); - if (useDebug) { - debug.println("KeyMgr: getting aliases: " + allResults); - } - return toAliases(allResults); - } - - // turn candidate entries into unique aliases we can return to JSSE - private String[] toAliases(List<EntryStatus> results) { - String[] s = new String[results.size()]; - int i = 0; - for (EntryStatus result : results) { - s[i++] = makeAlias(result); - } - return s; - } - - // make a Set out of the array - private Set<Principal> getIssuerSet(Principal[] issuers) { - if ((issuers != null) && (issuers.length != 0)) { - return new HashSet<>(Arrays.asList(issuers)); - } else { - return null; - } - } - - // a candidate match - // identifies the entry by builder and alias - // and includes the result of the certificate check - private static class EntryStatus implements Comparable<EntryStatus> { - - final int builderIndex; - final int keyIndex; - final String alias; - final CheckResult checkResult; - - EntryStatus(int builderIndex, int keyIndex, String alias, - Certificate[] chain, CheckResult checkResult) { - this.builderIndex = builderIndex; - this.keyIndex = keyIndex; - this.alias = alias; - this.checkResult = checkResult; - } - - @Override - public int compareTo(EntryStatus other) { - int result = this.checkResult.compareTo(other.checkResult); - return (result == 0) ? (this.keyIndex - other.keyIndex) : result; - } - - @Override - public String toString() { - String s = alias + " (verified: " + checkResult + ")"; - if (builderIndex == 0) { - return s; - } else { - return "Builder #" + builderIndex + ", alias: " + s; - } - } - } - - // enum for the type of certificate check we want to perform - // (client or server) - // also includes the check code itself - private static enum CheckType { - - // enum constant for "no check" (currently not used) - NONE(Collections.<String>emptySet()), - - // enum constant for "tls client" check - // valid EKU for TLS client: any, tls_client - CLIENT(new HashSet<String>(Arrays.asList(new String[] { - "2.5.29.37.0", "1.3.6.1.5.5.7.3.2" }))), - - // enum constant for "tls server" check - // valid EKU for TLS server: any, tls_server, ns_sgc, ms_sgc - SERVER(new HashSet<String>(Arrays.asList(new String[] { - "2.5.29.37.0", "1.3.6.1.5.5.7.3.1", "2.16.840.1.113730.4.1", - "1.3.6.1.4.1.311.10.3.3" }))); - - // set of valid EKU values for this type - final Set<String> validEku; - - CheckType(Set<String> validEku) { - this.validEku = validEku; - } - - private static boolean getBit(boolean[] keyUsage, int bit) { - return (bit < keyUsage.length) && keyUsage[bit]; - } - - // check if this certificate is appropriate for this type of use - // first check extensions, if they match, check expiration - // note: we may want to move this code into the sun.security.validator - // package - CheckResult check(X509Certificate cert, Date date, - List<SNIServerName> serverNames, String idAlgorithm) { - - if (this == NONE) { - return CheckResult.OK; - } - - // check extensions - try { - // check extended key usage - List<String> certEku = cert.getExtendedKeyUsage(); - if ((certEku != null) && - Collections.disjoint(validEku, certEku)) { - // if extension present and it does not contain any of - // the valid EKU OIDs, return extension_mismatch - return CheckResult.EXTENSION_MISMATCH; - } - - // check key usage - boolean[] ku = cert.getKeyUsage(); - if (ku != null) { - String algorithm = cert.getPublicKey().getAlgorithm(); - boolean kuSignature = getBit(ku, 0); - switch (algorithm) { - case "RSA": - // require either signature bit - // or if server also allow key encipherment bit - if (kuSignature == false) { - if ((this == CLIENT) || (getBit(ku, 2) == false)) { - return CheckResult.EXTENSION_MISMATCH; - } - } - break; - case "DSA": - // require signature bit - if (kuSignature == false) { - return CheckResult.EXTENSION_MISMATCH; - } - break; - case "DH": - // require keyagreement bit - if (getBit(ku, 4) == false) { - return CheckResult.EXTENSION_MISMATCH; - } - break; - case "EC": - // require signature bit - if (kuSignature == false) { - return CheckResult.EXTENSION_MISMATCH; - } - // For servers, also require key agreement. - // This is not totally accurate as the keyAgreement - // bit is only necessary for static ECDH key - // exchange and not ephemeral ECDH. We leave it in - // for now until there are signs that this check - // causes problems for real world EC certificates. - if ((this == SERVER) && (getBit(ku, 4) == false)) { - return CheckResult.EXTENSION_MISMATCH; - } - break; - } - } - } catch (CertificateException e) { - // extensions unparseable, return failure - return CheckResult.EXTENSION_MISMATCH; - } - - try { - cert.checkValidity(date); - } catch (CertificateException e) { - return CheckResult.EXPIRED; - } - - if (serverNames != null && !serverNames.isEmpty()) { - for (SNIServerName serverName : serverNames) { - if (serverName.getType() == - StandardConstants.SNI_HOST_NAME) { - if (!(serverName instanceof SNIHostName)) { - try { - serverName = - new SNIHostName(serverName.getEncoded()); - } catch (IllegalArgumentException iae) { - // unlikely to happen, just in case ... - if (useDebug) { - debug.println( - "Illegal server name: " + serverName); - } - - return CheckResult.INSENSITIVE; - } - } - String hostname = - ((SNIHostName)serverName).getAsciiName(); - - try { - X509TrustManagerImpl.checkIdentity(hostname, - cert, idAlgorithm); - } catch (CertificateException e) { - if (useDebug) { - debug.println( - "Certificate identity does not match " + - "Server Name Inidication (SNI): " + - hostname); - } - return CheckResult.INSENSITIVE; - } - - break; - } - } - } - - return CheckResult.OK; - } - - public String getValidator() { - if (this == CLIENT) { - return Validator.VAR_TLS_CLIENT; - } else if (this == SERVER) { - return Validator.VAR_TLS_SERVER; - } - return Validator.VAR_GENERIC; - } - } - - // enum for the result of the extension check - // NOTE: the order of the constants is important as they are used - // for sorting, i.e. OK is best, followed by EXPIRED and EXTENSION_MISMATCH - private static enum CheckResult { - OK, // ok or not checked - INSENSITIVE, // server name indication insensitive - EXPIRED, // extensions valid but cert expired - EXTENSION_MISMATCH, // extensions invalid (expiration not checked) - } - - /* - * Return a List of all candidate matches in the specified builder - * that fit the parameters. - * We exclude entries in the KeyStore if they are not: - * . private key entries - * . the certificates are not X509 certificates - * . the algorithm of the key in the EE cert doesn't match one of keyTypes - * . none of the certs is issued by a Principal in issuerSet - * Using those entries would not be possible or they would almost - * certainly be rejected by the peer. - * - * In addition to those checks, we also check the extensions in the EE - * cert and its expiration. Even if there is a mismatch, we include - * such certificates because they technically work and might be accepted - * by the peer. This leads to more graceful failure and better error - * messages if the cert expires from one day to the next. - * - * The return values are: - * . null, if there are no matching entries at all - * . if 'findAll' is 'false' and there is a perfect match, a List - * with a single element (early return) - * . if 'findAll' is 'false' and there is NO perfect match, a List - * with all the imperfect matches (expired, wrong extensions) - * . if 'findAll' is 'true', a List with all perfect and imperfect - * matches - */ - private List<EntryStatus> getAliases(int builderIndex, - List<KeyType> keyTypes, Set<Principal> issuerSet, - boolean findAll, CheckType checkType, - AlgorithmConstraints constraints, - List<SNIServerName> requestedServerNames, - String idAlgorithm) throws Exception { - - Builder builder = builders.get(builderIndex); - KeyStore ks = builder.getKeyStore(); - List<EntryStatus> results = null; - Date date = verificationDate; - boolean preferred = false; - for (Enumeration<String> e = ks.aliases(); e.hasMoreElements(); ) { - String alias = e.nextElement(); - // check if it is a key entry (private key or secret key) - if (ks.isKeyEntry(alias) == false) { - continue; - } - - Certificate[] chain = ks.getCertificateChain(alias); - if ((chain == null) || (chain.length == 0)) { - // must be secret key entry, ignore - continue; - } - - boolean incompatible = false; - for (Certificate cert : chain) { - if (cert instanceof X509Certificate == false) { - // not an X509Certificate, ignore this alias - incompatible = true; - break; - } - } - if (incompatible) { - continue; - } - - // check keytype - int keyIndex = -1; - int j = 0; - for (KeyType keyType : keyTypes) { - if (keyType.matches(chain)) { - keyIndex = j; - break; - } - j++; - } - if (keyIndex == -1) { - if (useDebug) { - debug.println("Ignoring alias " + alias - + ": key algorithm does not match"); - } - continue; - } - // check issuers - if (issuerSet != null) { - boolean found = false; - for (Certificate cert : chain) { - X509Certificate xcert = (X509Certificate)cert; - if (issuerSet.contains(xcert.getIssuerX500Principal())) { - found = true; - break; - } - } - if (found == false) { - if (useDebug) { - debug.println("Ignoring alias " + alias - + ": issuers do not match"); - } - continue; - } - } - - // check the algorithm constraints - if (constraints != null && - !conformsToAlgorithmConstraints(constraints, chain, - checkType.getValidator())) { - - if (useDebug) { - debug.println("Ignoring alias " + alias + - ": certificate list does not conform to " + - "algorithm constraints"); - } - continue; - } - - if (date == null) { - date = new Date(); - } - CheckResult checkResult = - checkType.check((X509Certificate)chain[0], date, - requestedServerNames, idAlgorithm); - EntryStatus status = - new EntryStatus(builderIndex, keyIndex, - alias, chain, checkResult); - if (!preferred && checkResult == CheckResult.OK && keyIndex == 0) { - preferred = true; - } - if (preferred && (findAll == false)) { - // if we have a good match and do not need all matches, - // return immediately - return Collections.singletonList(status); - } else { - if (results == null) { - results = new ArrayList<EntryStatus>(); - } - results.add(status); - } - } - return results; - } - - private static boolean conformsToAlgorithmConstraints( - AlgorithmConstraints constraints, Certificate[] chain, - String variant) { - - AlgorithmChecker checker = new AlgorithmChecker(constraints, null, variant); - try { - checker.init(false); - } catch (CertPathValidatorException cpve) { - // unlikely to happen - if (useDebug) { - debug.println( - "Cannot initialize algorithm constraints checker: " + cpve); - } - - return false; - } - - // It is a forward checker, so we need to check from trust to target. - for (int i = chain.length - 1; i >= 0; i--) { - Certificate cert = chain[i]; - try { - // We don't care about the unresolved critical extensions. - checker.check(cert, Collections.<String>emptySet()); - } catch (CertPathValidatorException cpve) { - if (useDebug) { - debug.println("Certificate (" + cert + - ") does not conform to algorithm constraints: " + cpve); - } - - return false; - } - } - - return true; - } - -}
--- a/src/share/classes/sun/security/ssl/X509TrustManagerImpl.java Sat Aug 01 03:20:01 2020 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,474 +0,0 @@ -/* - * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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.net.Socket; -import javax.net.ssl.SSLSession; - -import java.util.*; -import java.security.*; -import java.security.cert.*; -import javax.net.ssl.*; - -import sun.security.validator.*; -import sun.security.util.HostnameChecker; - -/** - * This class implements the SunJSSE X.509 trust manager using the internal - * validator API in J2SE core. The logic in this class is minimal.<p> - * <p> - * This class supports both the Simple validation algorithm from previous - * JSSE versions and PKIX validation. Currently, it is not possible for the - * application to specify PKIX parameters other than trust anchors. This will - * be fixed in a future release using new APIs. When that happens, it may also - * make sense to separate the Simple and PKIX trust managers into separate - * classes. - * - * @author Andreas Sterbenz - */ -final class X509TrustManagerImpl extends X509ExtendedTrustManager - implements X509TrustManager { - - private final String validatorType; - - /** - * The Set of trusted X509Certificates. - */ - private final Collection<X509Certificate> trustedCerts; - - private final PKIXBuilderParameters pkixParams; - - // note that we need separate validator for client and server due to - // the different extension checks. They are initialized lazily on demand. - private volatile Validator clientValidator, serverValidator; - - private static final Debug debug = Debug.getInstance("ssl"); - - X509TrustManagerImpl(String validatorType, - Collection<X509Certificate> trustedCerts) { - - this.validatorType = validatorType; - this.pkixParams = null; - - if (trustedCerts == null) { - trustedCerts = Collections.<X509Certificate>emptySet(); - } - - this.trustedCerts = trustedCerts; - - if (debug != null && Debug.isOn("trustmanager")) { - showTrustedCerts(); - } - } - - X509TrustManagerImpl(String validatorType, PKIXBuilderParameters params) { - this.validatorType = validatorType; - this.pkixParams = params; - // create server validator eagerly so that we can conveniently - // get the trusted certificates - // clients need it anyway eventually, and servers will not mind - // the little extra footprint - Validator v = getValidator(Validator.VAR_TLS_SERVER); - trustedCerts = v.getTrustedCertificates(); - serverValidator = v; - - if (debug != null && Debug.isOn("trustmanager")) { - showTrustedCerts(); - } - } - - @Override - public void checkClientTrusted(X509Certificate chain[], String authType) - throws CertificateException { - checkTrusted(chain, authType, (Socket)null, true); - } - - @Override - public void checkServerTrusted(X509Certificate chain[], String authType) - throws CertificateException { - checkTrusted(chain, authType, (Socket)null, false); - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()]; - trustedCerts.toArray(certsArray); - return certsArray; - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - checkTrusted(chain, authType, socket, true); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - Socket socket) throws CertificateException { - checkTrusted(chain, authType, socket, false); - } - - @Override - public void checkClientTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - checkTrusted(chain, authType, engine, true); - } - - @Override - public void checkServerTrusted(X509Certificate[] chain, String authType, - SSLEngine engine) throws CertificateException { - checkTrusted(chain, authType, engine, false); - } - - private Validator checkTrustedInit(X509Certificate[] chain, - String authType, boolean checkClientTrusted) { - if (chain == null || chain.length == 0) { - throw new IllegalArgumentException( - "null or zero-length certificate chain"); - } - - if (authType == null || authType.length() == 0) { - throw new IllegalArgumentException( - "null or zero-length authentication type"); - } - - Validator v = null; - if (checkClientTrusted) { - v = clientValidator; - if (v == null) { - synchronized (this) { - v = clientValidator; - if (v == null) { - v = getValidator(Validator.VAR_TLS_CLIENT); - clientValidator = v; - } - } - } - } else { - // assume double checked locking with a volatile flag works - // (guaranteed under the new Tiger memory model) - v = serverValidator; - if (v == null) { - synchronized (this) { - v = serverValidator; - if (v == null) { - v = getValidator(Validator.VAR_TLS_SERVER); - serverValidator = v; - } - } - } - } - - return v; - } - - - private void checkTrusted(X509Certificate[] chain, - String authType, Socket socket, - boolean checkClientTrusted) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, checkClientTrusted); - - AlgorithmConstraints constraints = null; - if ((socket != null) && socket.isConnected() && - (socket instanceof SSLSocket)) { - - SSLSocket sslSocket = (SSLSocket)socket; - SSLSession session = sslSocket.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - // check endpoint identity - String identityAlg = sslSocket.getSSLParameters(). - getEndpointIdentificationAlgorithm(); - if (identityAlg != null && identityAlg.length() != 0) { - checkIdentity(session, chain, identityAlg, checkClientTrusted); - } - - // create the algorithm constraints - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - String[] localSupportedSignAlgs = - extSession.getLocalSupportedSignatureAlgorithms(); - - constraints = new SSLAlgorithmConstraints( - sslSocket, localSupportedSignAlgs, false); - } else { - constraints = - new SSLAlgorithmConstraints(sslSocket, false); - } - } else { - constraints = new SSLAlgorithmConstraints(sslSocket, false); - } - } - - X509Certificate[] trustedChain = null; - if (checkClientTrusted) { - trustedChain = validate(v, chain, constraints, null); - } else { - trustedChain = validate(v, chain, constraints, authType); - } - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println("Found trusted certificate:"); - System.out.println(trustedChain[trustedChain.length - 1]); - } - } - - private void checkTrusted(X509Certificate[] chain, - String authType, SSLEngine engine, - boolean checkClientTrusted) throws CertificateException { - Validator v = checkTrustedInit(chain, authType, checkClientTrusted); - - AlgorithmConstraints constraints = null; - if (engine != null) { - SSLSession session = engine.getHandshakeSession(); - if (session == null) { - throw new CertificateException("No handshake session"); - } - - // check endpoint identity - String identityAlg = engine.getSSLParameters(). - getEndpointIdentificationAlgorithm(); - if (identityAlg != null && identityAlg.length() != 0) { - checkIdentity(session, chain, identityAlg, checkClientTrusted); - } - - // create the algorithm constraints - ProtocolVersion protocolVersion = - ProtocolVersion.valueOf(session.getProtocol()); - if (protocolVersion.v >= ProtocolVersion.TLS12.v) { - if (session instanceof ExtendedSSLSession) { - ExtendedSSLSession extSession = - (ExtendedSSLSession)session; - String[] localSupportedSignAlgs = - extSession.getLocalSupportedSignatureAlgorithms(); - - constraints = new SSLAlgorithmConstraints( - engine, localSupportedSignAlgs, false); - } else { - constraints = - new SSLAlgorithmConstraints(engine, false); - } - } else { - constraints = new SSLAlgorithmConstraints(engine, false); - } - } - - X509Certificate[] trustedChain = null; - if (checkClientTrusted) { - trustedChain = validate(v, chain, constraints, null); - } else { - trustedChain = validate(v, chain, constraints, authType); - } - if (debug != null && Debug.isOn("trustmanager")) { - System.out.println("Found trusted certificate:"); - System.out.println(trustedChain[trustedChain.length - 1]); - } - } - - private void showTrustedCerts() { - for (X509Certificate cert : trustedCerts) { - System.out.println("adding as trusted cert:"); - System.out.println(" Subject: " - + cert.getSubjectX500Principal()); - System.out.println(" Issuer: " - + cert.getIssuerX500Principal()); - System.out.println(" Algorithm: " - + cert.getPublicKey().getAlgorithm() - + "; Serial number: 0x" - + cert.getSerialNumber().toString(16)); - System.out.println(" Valid from " - + cert.getNotBefore() + " until " - + cert.getNotAfter()); - System.out.println(); - } - } - - private Validator getValidator(String variant) { - Validator v; - if (pkixParams == null) { - v = Validator.getInstance(validatorType, variant, trustedCerts); - } else { - v = Validator.getInstance(validatorType, variant, pkixParams); - } - return v; - } - - private static X509Certificate[] validate(Validator v, - X509Certificate[] chain, AlgorithmConstraints constraints, - String authType) throws CertificateException { - Object o = JsseJce.beginFipsProvider(); - try { - return v.validate(chain, null, constraints, authType); - } finally { - JsseJce.endFipsProvider(o); - } - } - - // Get string representation of HostName from a list of server names. - // - // We are only accepting host_name name type in the list. - private static String getHostNameInSNI(List<SNIServerName> sniNames) { - - SNIHostName hostname = null; - for (SNIServerName sniName : sniNames) { - if (sniName.getType() != StandardConstants.SNI_HOST_NAME) { - continue; - } - - if (sniName instanceof SNIHostName) { - hostname = (SNIHostName)sniName; - } else { - try { - hostname = new SNIHostName(sniName.getEncoded()); - } catch (IllegalArgumentException iae) { - // unlikely to happen, just in case ... - if ((debug != null) && Debug.isOn("trustmanager")) { - System.out.println("Illegal server name: " + sniName); - } - } - } - - // no more than server name of the same name type - break; - } - - if (hostname != null) { - return hostname.getAsciiName(); - } - - return null; - } - - // Also used by X509KeyManagerImpl - static List<SNIServerName> getRequestedServerNames(Socket socket) { - if (socket != null && socket.isConnected() && - socket instanceof SSLSocket) { - - return getRequestedServerNames( - ((SSLSocket)socket).getHandshakeSession()); - } - - return Collections.<SNIServerName>emptyList(); - } - - // Also used by X509KeyManagerImpl - static List<SNIServerName> getRequestedServerNames(SSLEngine engine) { - if (engine != null) { - return getRequestedServerNames(engine.getHandshakeSession()); - } - - return Collections.<SNIServerName>emptyList(); - } - - private static List<SNIServerName> getRequestedServerNames( - SSLSession session) { - if (session != null && (session instanceof ExtendedSSLSession)) { - return ((ExtendedSSLSession)session).getRequestedServerNames(); - } - - return Collections.<SNIServerName>emptyList(); - } - - /* - * Per RFC 6066, if an application negotiates a server name using an - * application protocol and then upgrades to TLS, and if a server_name - * extension is sent, then the extension SHOULD contain the same name - * that was negotiated in the application protocol. If the server_name - * is established in the TLS session handshake, the client SHOULD NOT - * attempt to request a different server name at the application layer. - * - * According to the above spec, we only need to check either the identity - * in server_name extension or the peer host of the connection. Peer host - * is not always a reliable fully qualified domain name. The HostName in - * server_name extension is more reliable than peer host. So we prefer - * the identity checking aginst the server_name extension if present, and - * may failove to peer host checking. - */ - static void checkIdentity(SSLSession session, - X509Certificate [] trustedChain, - String algorithm, - boolean checkClientTrusted) throws CertificateException { - - boolean identifiable = false; - String peerHost = session.getPeerHost(); - if (!checkClientTrusted) { - List<SNIServerName> sniNames = getRequestedServerNames(session); - String sniHostName = getHostNameInSNI(sniNames); - if (sniHostName != null) { - try { - checkIdentity(sniHostName, - trustedChain[0], algorithm); - identifiable = true; - } catch (CertificateException ce) { - if (sniHostName.equalsIgnoreCase(peerHost)) { - throw ce; - } - - // otherwisw, failover to check peer host - } - } - } - - if (!identifiable) { - checkIdentity(peerHost, - trustedChain[0], algorithm); - } - } - - /* - * Identify the peer by its certificate and hostname. - * - * Lifted from sun.net.www.protocol.https.HttpsClient. - */ - static void checkIdentity(String hostname, X509Certificate cert, - String algorithm) throws CertificateException { - if (algorithm != null && algorithm.length() != 0) { - // if IPv6 strip off the "[]" - if ((hostname != null) && hostname.startsWith("[") && - hostname.endsWith("]")) { - hostname = hostname.substring(1, hostname.length() - 1); - } - - if (algorithm.equalsIgnoreCase("HTTPS")) { - HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match( - hostname, cert); - } else if (algorithm.equalsIgnoreCase("LDAP") || - algorithm.equalsIgnoreCase("LDAPS")) { - HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match( - hostname, cert); - } else { - throw new CertificateException( - "Unknown identification algorithm: " + algorithm); - } - } - } -}