io.netty
diff --git a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientByteArrayOutputStream.java b/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientByteArrayOutputStream.java
deleted file mode 100644
index cc85ffb4840d..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientByteArrayOutputStream.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2014 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.netty.handler.ssl;
-
-import java.io.ByteArrayOutputStream;
-
-import javax.net.ssl.SSLEngine;
-
-/**
- * Super hacky class that allows the client and server hello message to be modified and the corresponding hash generated
- * at runtime.
- *
- *
- * @author Stuart Douglas
- */
-class ALPNHackClientByteArrayOutputStream extends ByteArrayOutputStream {
-
- private final SSLEngine sslEngine;
- private boolean ready = true;
- /**
- * the server hello that was sent over the wire, before we messed with it
- */
- private byte[] receivedServerHello;
- private byte[] sentClientHello;
-
- ALPNHackClientByteArrayOutputStream(SSLEngine sslEngine) {
- this.sslEngine = sslEngine;
- }
-
- @Override
- public void write(byte[] b, int off, int len) {
- if(ready) {
- if(b[off] == 2) { // server hello
- ready = false; //we are done processing
- byte[] newData;
- if(receivedServerHello != null) {
- int b1 = b[off + 1];
- int b2 = b[off + 2];
- int b3 = b[off + 3];
- int length = (b1 & 0xFF) << 16 | (b2 & 0xFF) << 8 | b3 & 0xFF;
- if(length + 4 == len) {
- newData = receivedServerHello;
- } else {
- newData = new byte[receivedServerHello.length + len - 4 - length];
- System.arraycopy(receivedServerHello, 0, newData, 0, receivedServerHello.length);
- System.arraycopy(b, length + 4, newData, receivedServerHello.length, len - 4 -length);
- }
- } else {
- newData = new byte[len];
- System.arraycopy(b, off, newData, 0, len);
- }
- ALPNHackSSLEngine.regenerateHashes(sslEngine, this, sentClientHello, newData);
- return;
- }
- }
- super.write(b, off, len);
- }
-
- byte[] getSentClientHello() {
- return sentClientHello;
- }
-
- void setSentClientHello(byte[] sentClientHello) {
- this.sentClientHello = sentClientHello;
- }
-
- byte[] getReceivedServerHello() {
- return receivedServerHello;
- }
-
- void setReceivedServerHello(byte[] receivedServerHello) {
- this.receivedServerHello = receivedServerHello;
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientHelloExplorer.java b/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientHelloExplorer.java
deleted file mode 100644
index 536f2df74df2..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackClientHelloExplorer.java
+++ /dev/null
@@ -1,436 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2014 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.netty.handler.ssl;
-
-import javax.net.ssl.SSLException;
-import java.io.ByteArrayOutputStream;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * This class is used to both read and write the ALPN protocol names in the ClientHello SSL message.
- *
- * If the out parameter is not null then the read function is being used, while if it present then it is rewriting
- * the hello message to include ALPN.
- *
- * Even though this dual approach is not particularly clean it does remove the need to have two versions of each function,
- * that do almost exactly the same thing.
- *
- */
-final class ALPNHackClientHelloExplorer {
-
- // Private constructor prevents construction outside this class.
- private ALPNHackClientHelloExplorer() {
- }
-
- /**
- * The header size of TLS/SSL records.
- *
- * The value of this constant is {@value}.
- */
- public static final int RECORD_HEADER_SIZE = 0x05;
-
- /**
- *
- *
- */
- static List exploreClientHello(ByteBuffer source)
- throws SSLException {
-
- ByteBuffer input = source.duplicate();
-
- // Do we have a complete header?
- if (input.remaining() < RECORD_HEADER_SIZE) {
- throw new BufferUnderflowException();
- }
- List alpnProtocols = new ArrayList<>();
- // Is it a handshake message?
- byte firstByte = input.get();
- byte secondByte = input.get();
- byte thirdByte = input.get();
-
- if ((firstByte & 0x80) != 0 && thirdByte == 0x01) {
- // looks like a V2ClientHello, we ignore it.
- return null;
- } else if (firstByte == 22) { // 22: handshake record
- if(secondByte == 3 && thirdByte >= 1 && thirdByte <= 3) {
- exploreTLSRecord(input,
- firstByte, secondByte, thirdByte, alpnProtocols, null);
- return alpnProtocols;
- }
- return null;
- } else {
- throw new SSLException("No handshake record");
- }
- }
-
- static byte[] rewriteClientHello(byte[] source, List alpnProtocols) throws SSLException {
- ByteBuffer input = ByteBuffer.wrap(source);
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- // Do we have a complete header?
- if (input.remaining() < RECORD_HEADER_SIZE) {
- throw new BufferUnderflowException();
- }
- try {
-
- // Is it a handshake message?
- byte firstByte = input.get();
- byte secondByte = input.get();
- byte thirdByte = input.get();
- out.write(firstByte & 0xFF);
- out.write(secondByte & 0xFF);
- out.write(thirdByte & 0xFF);
- if ((firstByte & 0x80) != 0 && thirdByte == 0x01) {
- // looks like a V2ClientHello, we ignore it.
- return null;
- } else if (firstByte == 22) { // 22: handshake record
- if (secondByte == 3 && thirdByte == 3) {
- //TLS1.2 is the only one we care about. Previous versions can't use HTTP/2, newer versions won't be backported to JDK8
- exploreTLSRecord(input,
- firstByte, secondByte, thirdByte, alpnProtocols, out);
- //we need to adjust the record length;
- int clientHelloLength = out.size() - 9;
- byte[] data = out.toByteArray();
- int newLength = data.length - 5;
- data[3] = (byte) ((newLength >> 8) & 0xFF);
- data[4] = (byte) (newLength & 0xFF);
-
- //now we need to adjust the handshake frame length
- data[6] = (byte) ((clientHelloLength >> 16) & 0xFF);
- data[7] = (byte) ((clientHelloLength >> 8) & 0xFF);
- data[8] = (byte) (clientHelloLength & 0xFF);
-
- return data;
- }
- return null;
- } else {
- throw new SSLException("No handshake record");
- }
- } catch (ALPNPresentException e) {
- return null;
- }
- }
-
- /*
- * struct {
- * uint8 major;
- * uint8 minor;
- * } ProtocolVersion;
- *
- * enum {
- * change_cipher_spec(20), alert(21), handshake(22),
- * application_data(23), (255)
- * } ContentType;
- *
- * struct {
- * ContentType type;
- * ProtocolVersion version;
- * uint16 length;
- * opaque fragment[TLSPlaintext.length];
- * } TLSPlaintext;
- */
- private static void exploreTLSRecord(
- ByteBuffer input, byte firstByte, byte secondByte,
- byte thirdByte, List alpnProtocols, ByteArrayOutputStream out) throws SSLException {
-
- // Is it a handshake message?
- if (firstByte != 22) { // 22: handshake record
- throw new SSLException("No handshake record");
- }
-
- // Is there enough data for a full record?
- int recordLength = getInt16(input);
- if (recordLength > input.remaining()) {
- throw new BufferUnderflowException();
- }
- if(out != null) {
- out.write(0);
- out.write(0);
- }
-
- // We have already had enough source bytes.
- try {
- exploreHandshake(input,
- secondByte, thirdByte, recordLength, alpnProtocols, out);
- } catch (BufferUnderflowException ignored) {
- throw new SSLException("No handshake record");
- }
- }
-
- /*
- * enum {
- * hello_request(0), client_hello(1), server_hello(2),
- * certificate(11), server_key_exchange (12),
- * certificate_request(13), server_hello_done(14),
- * certificate_verify(15), client_key_exchange(16),
- * finished(20)
- * (255)
- * } HandshakeType;
- *
- * struct {
- * HandshakeType msg_type;
- * uint24 length;
- * select (HandshakeType) {
- * case hello_request: HelloRequest;
- * case client_hello: ClientHello;
- * case server_hello: ServerHello;
- * case certificate: Certificate;
- * case server_key_exchange: ServerKeyExchange;
- * case certificate_request: CertificateRequest;
- * case server_hello_done: ServerHelloDone;
- * case certificate_verify: CertificateVerify;
- * case client_key_exchange: ClientKeyExchange;
- * case finished: Finished;
- * } body;
- * } Handshake;
- */
- private static void exploreHandshake(
- ByteBuffer input, byte recordMajorVersion,
- byte recordMinorVersion, int recordLength, List alpnProtocols, ByteArrayOutputStream out) throws SSLException {
-
- // What is the handshake type?
- byte handshakeType = input.get();
- if (handshakeType != 0x01) { // 0x01: client_hello message
- throw new SSLException("Expected client hello");
- }
- if(out != null) {
- out.write(handshakeType & 0xFF);
- }
-
- // What is the handshake body length?
- int handshakeLength = getInt24(input);
- if(out != null) {
- //placeholder
- out.write(0);
- out.write(0);
- out.write(0);
- }
-
- // Theoretically, a single handshake message might span multiple
- // records, but in practice this does not occur.
- if (handshakeLength > recordLength - 4) { // 4: handshake header size
- throw new SSLException("Multi record handshake");
- }
-
- input = input.duplicate();
- input.limit(handshakeLength + input.position());
- exploreClientHello(input, alpnProtocols, out);
- }
-
- /*
- * struct {
- * uint32 gmt_unix_time;
- * opaque random_bytes[28];
- * } Random;
- *
- * opaque SessionID<0..32>;
- *
- * uint8 CipherSuite[2];
- *
- * enum { null(0), (255) } CompressionMethod;
- *
- * struct {
- * ProtocolVersion client_version;
- * Random random;
- * SessionID session_id;
- * CipherSuite cipher_suites<2..2^16-2>;
- * CompressionMethod compression_methods<1..2^8-1>;
- * select (extensions_present) {
- * case false:
- * struct {};
- * case true:
- * Extension extensions<0..2^16-1>;
- * };
- * } ClientHello;
- */
- private static void exploreClientHello(
- ByteBuffer input,
- List alpnProtocols,
- ByteArrayOutputStream out) throws SSLException {
-
- // client version
- byte helloMajorVersion = input.get();
- byte helloMinorVersion = input.get();
- if(out != null) {
- out.write(helloMajorVersion & 0xFF);
- out.write(helloMinorVersion & 0xFF);
- }
- if(helloMajorVersion != 3 && helloMinorVersion != 3) {
- //we only care about TLS 1.2
- return;
- }
-
-
- // ignore random
- for(int i = 0; i < 32; ++i) {// 32: the length of Random
- byte d = input.get();
- if(out != null) {
- out.write(d & 0xFF);
- }
- }
-
- // session id
- processByteVector8(input, out);
-
- // cipher_suites
- processByteVector16(input, out);
-
- // compression methods
- processByteVector8(input, out);
- if (input.remaining() > 0) {
- exploreExtensions(input, alpnProtocols, out);
- } else if(out != null) {
- byte[] data = generateAlpnExtension(alpnProtocols);
- writeInt16(out, data.length);
- out.write(data, 0, data.length);
- }
- }
-
- private static void writeInt16(ByteArrayOutputStream out, int l) {
- if(out == null) return;
- out.write((l >> 8) & 0xFF);
- out.write(l & 0xFF);
- }
-
- private static byte[] generateAlpnExtension(List alpnProtocols) {
- ByteArrayOutputStream alpnBits = new ByteArrayOutputStream();
- alpnBits.write(0);
- alpnBits.write(16); //ALPN type
- int length = 2;
- for(String p : alpnProtocols) {
- length++;
- length += p.length();
- }
- writeInt16(alpnBits, length);
- length -= 2;
- writeInt16(alpnBits, length);
- for(String p : alpnProtocols) {
- alpnBits.write(p.length() & 0xFF);
- for (int i = 0; i < p.length(); ++i) {
- alpnBits.write(p.charAt(i) & 0xFF);
- }
- }
- return alpnBits.toByteArray();
- }
-
- /*
- * struct {
- * ExtensionType extension_type;
- * opaque extension_data<0..2^16-1>;
- * } Extension;
- *
- * enum {
- * server_name(0), max_fragment_length(1),
- * client_certificate_url(2), trusted_ca_keys(3),
- * truncated_hmac(4), status_request(5), (65535)
- * } ExtensionType;
- */
- private static void exploreExtensions(ByteBuffer input, List alpnProtocols, ByteArrayOutputStream out)
- throws SSLException {
- ByteArrayOutputStream extensionOut = out == null ? null : new ByteArrayOutputStream();
- int length = getInt16(input); // length of extensions
- writeInt16(extensionOut, 0); //placeholder
- while (length > 0) {
- int extType = getInt16(input); // extenson type
- writeInt16(extensionOut, extType);
- int extLen = getInt16(input); // length of extension data
- writeInt16(extensionOut, extLen);
- if (extType == 16) { // 0x00: ty
- if(out == null) {
- exploreALPNExt(input, alpnProtocols);
- } else {
- throw new ALPNPresentException();
- }
- } else { // ignore other extensions
- processByteVector(input, extLen, extensionOut);
- }
-
- length -= extLen + 4;
- }
- if(out != null) {
- byte[] alpnBits = generateAlpnExtension(alpnProtocols);
- extensionOut.write(alpnBits,0 ,alpnBits.length);
- byte[] extensionsData = extensionOut.toByteArray();
- int newLength = extensionsData.length - 2;
- extensionsData[0] = (byte) ((newLength >> 8) & 0xFF);
- extensionsData[1] = (byte) (newLength & 0xFF);
- out.write(extensionsData, 0, extensionsData.length);
- }
-
- }
-
- private static void exploreALPNExt(ByteBuffer input, List alpnProtocols) {
- int length = getInt16(input);
- int end = input.position() + length;
- while (input.position() < end) {
- alpnProtocols.add(readByteVector8(input));
- }
- }
-
- private static int getInt8(ByteBuffer input) {
- return input.get();
- }
-
- private static int getInt16(ByteBuffer input) {
- return (input.get() & 0xFF) << 8 | input.get() & 0xFF;
- }
-
- private static int getInt24(ByteBuffer input) {
- return (input.get() & 0xFF) << 16 | (input.get() & 0xFF) << 8 |
- input.get() & 0xFF;
- }
-
- private static void processByteVector8(ByteBuffer input, ByteArrayOutputStream out) {
- int int8 = getInt8(input);
- if(out != null) {
- out.write(int8 & 0xFF);
- }
- processByteVector(input, int8, out);
- }
-
-
- private static void processByteVector(ByteBuffer input, int length, ByteArrayOutputStream out) {
- for (int i = 0; i < length; ++i) {
- byte b = input.get();
- if(out != null) {
- out.write(b & 0xFF);
- }
- }
- }
- private static String readByteVector8(ByteBuffer input) {
- int length = getInt8(input);
- byte[] data = new byte[length];
- input.get(data);
- return new String(data, StandardCharsets.US_ASCII);
- }
-
- private static void processByteVector16(ByteBuffer input, ByteArrayOutputStream out) {
- int int16 = getInt16(input);
- writeInt16(out, int16);
- processByteVector(input, int16, out);
- }
-
- private static final class ALPNPresentException extends RuntimeException {
-
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackSSLEngine.java b/server/core/src/main/java/io/netty/handler/ssl/ALPNHackSSLEngine.java
deleted file mode 100644
index 4be5b9427c7b..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackSSLEngine.java
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2014 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.netty.handler.ssl;
-
-import java.io.ByteArrayOutputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.security.MessageDigest;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLSession;
-
-import org.infinispan.commons.logging.LogFactory;
-
-/**
- * SSLEngine wrapper that provides some super hacky ALPN support on JDK8.
- *
- * Even though this is a nasty hack that relies on JDK internals it is still preferable to modifying the boot class path.
- *
- * It is expected to work with all JDK8 versions, however this cannot be guaranteed if the SSL internals are changed
- * in an incompatible way.
- *
- * This class will go away once JDK8 is no longer in use.
- *
- * @author Stuart Douglas
- */
-public class ALPNHackSSLEngine extends SSLEngine {
-
- private static final org.infinispan.commons.logging.Log log = LogFactory.getLog(ALPNHackSSLEngine.class);
-
- public static final boolean ENABLED;
-
- private static final Field HANDSHAKER;
- private static final Field HANDSHAKER_PROTOCOL_VERSION;
- private static final Field HANDSHAKE_HASH;
- private static final Field HANDSHAKE_HASH_VERSION;
- private static final Method HANDSHAKE_HASH_UPDATE;
- private static final Method HANDSHAKE_HASH_PROTOCOL_DETERMINED;
- private static final Field HANDSHAKE_HASH_DATA;
- private static final Field HANDSHAKE_HASH_FIN_MD;
-
- private static final Class> SSL_ENGINE_IMPL_CLASS;
-
- static {
-
- boolean enabled = true;
- Field handshaker;
- Field handshakeHash;
- Field handshakeHashVersion;
- Field handshakeHashData;
- Field handshakeHashFinMd;
- Field protocolVersion;
- Method handshakeHashUpdate;
- Method handshakeHashProtocolDetermined;
- Class> sslEngineImpleClass;
- try {
- Class> protocolVersionClass = Class.forName("sun.security.ssl.ProtocolVersion", true, ClassLoader.getSystemClassLoader());
- sslEngineImpleClass = Class.forName("sun.security.ssl.SSLEngineImpl", true, ClassLoader.getSystemClassLoader());
- handshaker = sslEngineImpleClass.getDeclaredField("handshaker");
- handshaker.setAccessible(true);
- handshakeHash = handshaker.getType().getDeclaredField("handshakeHash");
- handshakeHash.setAccessible(true);
- protocolVersion = handshaker.getType().getDeclaredField("protocolVersion");
- protocolVersion.setAccessible(true);
- handshakeHashVersion = handshakeHash.getType().getDeclaredField("version");
- handshakeHashVersion.setAccessible(true);
- handshakeHashUpdate = handshakeHash.getType().getDeclaredMethod("update", byte[].class, int.class, int.class);
- handshakeHashUpdate.setAccessible(true);
- handshakeHashProtocolDetermined = handshakeHash.getType().getDeclaredMethod("protocolDetermined", protocolVersionClass);
- handshakeHashProtocolDetermined.setAccessible(true);
- handshakeHashData = handshakeHash.getType().getDeclaredField("data");
- handshakeHashData.setAccessible(true);
- handshakeHashFinMd = handshakeHash.getType().getDeclaredField("finMD");
- handshakeHashFinMd.setAccessible(true);
-
- } catch (Exception e) {
- log.debug("JDK8 ALPN Hack failed ", e);
- enabled = false;
- handshaker = null;
- handshakeHash = null;
- handshakeHashVersion = null;
- handshakeHashUpdate = null;
- handshakeHashProtocolDetermined = null;
- handshakeHashData = null;
- handshakeHashFinMd = null;
- protocolVersion = null;
- sslEngineImpleClass = null;
- }
- ENABLED = enabled && !Boolean.getBoolean("io.undertow.disable-jdk8-alpn");
- HANDSHAKER = handshaker;
- HANDSHAKE_HASH = handshakeHash;
- HANDSHAKE_HASH_PROTOCOL_DETERMINED = handshakeHashProtocolDetermined;
- HANDSHAKE_HASH_VERSION = handshakeHashVersion;
- HANDSHAKE_HASH_UPDATE = handshakeHashUpdate;
- HANDSHAKE_HASH_DATA = handshakeHashData;
- HANDSHAKE_HASH_FIN_MD = handshakeHashFinMd;
- HANDSHAKER_PROTOCOL_VERSION = protocolVersion;
- SSL_ENGINE_IMPL_CLASS = sslEngineImpleClass;
- }
-
- private final SSLEngine delegate;
-
- //ALPN Hack specific variables
- private boolean unwrapHelloSeen = false;
- private boolean ourHelloSent = false;
- private ALPNHackServerByteArrayOutputStream alpnHackServerByteArrayOutputStream;
- private ALPNHackClientByteArrayOutputStream ALPNHackClientByteArrayOutputStream;
- private List applicationProtocols;
- private String selectedApplicationProtocol;
- private ByteBuffer bufferedWrapData;
-
- public ALPNHackSSLEngine(SSLEngine delegate) {
- this.delegate = delegate;
- }
-
- public static boolean isEnabled(SSLEngine engine) {
- if(!ENABLED) {
- return false;
- }
- return SSL_ENGINE_IMPL_CLASS.isAssignableFrom(engine.getClass());
- }
-
- @Override
- public SSLEngineResult wrap(ByteBuffer[] byteBuffers, int i, int i1, ByteBuffer byteBuffer) throws SSLException {
- if(bufferedWrapData != null) {
- int prod = bufferedWrapData.remaining();
- byteBuffer.put(bufferedWrapData);
- bufferedWrapData = null;
- return new SSLEngineResult(SSLEngineResult.Status.OK, SSLEngineResult.HandshakeStatus.NEED_WRAP, 0, prod);
- }
- int pos = byteBuffer.position();
- int limit = byteBuffer.limit();
- SSLEngineResult res = delegate.wrap(byteBuffers, i, i1, byteBuffer);
- if(!ourHelloSent && res.bytesProduced() > 0) {
- if(delegate.getUseClientMode() && applicationProtocols != null && !applicationProtocols.isEmpty()) {
- ourHelloSent = true;
- ALPNHackClientByteArrayOutputStream = replaceClientByteOutput(delegate);
- ByteBuffer newBuf = byteBuffer.duplicate();
- newBuf.flip();
- byte[] data = new byte[newBuf.remaining()];
- newBuf.get(data);
- byte[] newData = ALPNHackClientHelloExplorer.rewriteClientHello(data, applicationProtocols);
- if(newData != null) {
- byte[] clientHelloMesage = new byte[newData.length - 5];
- System.arraycopy(newData, 5, clientHelloMesage, 0 , clientHelloMesage.length);
- ALPNHackClientByteArrayOutputStream.setSentClientHello(clientHelloMesage);
- byteBuffer.clear();
- byteBuffer.put(newData);
- }
- } else if (!getUseClientMode()) {
- if(selectedApplicationProtocol != null && alpnHackServerByteArrayOutputStream != null) {
- byte[] newServerHello = alpnHackServerByteArrayOutputStream.getServerHello(); //this is the new server hello, it will be part of the first TLS plaintext record
- if (newServerHello != null) {
- byteBuffer.flip();
- List records = ALPNHackServerHelloExplorer.extractRecords(byteBuffer);
- ByteBuffer newData = ALPNHackServerHelloExplorer.createNewOutputRecords(newServerHello, records);
- byteBuffer.position(pos); //erase the data
- byteBuffer.limit(limit);
- if (newData.remaining() > byteBuffer.remaining()) {
- int old = newData.limit();
- newData.limit(newData.position() + byteBuffer.remaining());
- res = new SSLEngineResult(res.getStatus(), res.getHandshakeStatus(), res.bytesConsumed(), newData.remaining());
- byteBuffer.put(newData);
- newData.limit(old);
- bufferedWrapData = newData;
- } else {
- res = new SSLEngineResult(res.getStatus(), res.getHandshakeStatus(), res.bytesConsumed(), newData.remaining());
- byteBuffer.put(newData);
- }
- }
- }
- }
- }
- if(res.bytesProduced() > 0) {
- ourHelloSent = true;
- }
- return res;
- }
-
- @Override
- public SSLEngineResult unwrap(ByteBuffer dataToUnwrap, ByteBuffer[] byteBuffers, int i, int i1) throws SSLException {
- if(!unwrapHelloSeen) {
- if(!delegate.getUseClientMode() && applicationProtocols != null) {
- try {
- List result = ALPNHackClientHelloExplorer.exploreClientHello(dataToUnwrap.duplicate());
- if(result != null) {
- for(String protocol : applicationProtocols) {
- if(result.contains(protocol)) {
- selectedApplicationProtocol = protocol;
- break;
- }
- }
- }
- unwrapHelloSeen = true;
- } catch (BufferUnderflowException e) {
- return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, SSLEngineResult.HandshakeStatus.NEED_UNWRAP, 0, 0);
- }
- } else if(delegate.getUseClientMode() && ALPNHackClientByteArrayOutputStream != null) {
- if(!dataToUnwrap.hasRemaining()) {
- return delegate.unwrap(dataToUnwrap, byteBuffers, i, i1);
- }
- try {
- ByteBuffer dup = dataToUnwrap.duplicate();
- int type = dup.get();
- int major = dup.get();
- int minor = dup.get();
- if(type == 22 && major == 3 && minor == 3) {
- //we only care about TLS 1.2
- //split up the records, there may be multiple when doing a fast session resume
- List records = ALPNHackServerHelloExplorer.extractRecords(dataToUnwrap.duplicate());
-
- ByteBuffer firstRecord = records.get(0); //this will be the handshake record
-
- final AtomicReference alpnResult = new AtomicReference<>();
- ByteBuffer dupFirst = firstRecord.duplicate();
- dupFirst.position(firstRecord.position() + 5);
- ByteBuffer firstLessFraming = dupFirst.duplicate();
-
- byte[] result = ALPNHackServerHelloExplorer.removeAlpnExtensionsFromServerHello(dupFirst, alpnResult);
- firstLessFraming.limit(dupFirst.position());
- unwrapHelloSeen = true;
- if (result != null) {
- selectedApplicationProtocol = alpnResult.get();
- int newFirstRecordLength = result.length + dupFirst.remaining();
- byte[] newFirstRecord = new byte[newFirstRecordLength];
- System.arraycopy(result, 0, newFirstRecord, 0, result.length);
- dupFirst.get(newFirstRecord, result.length, dupFirst.remaining());
- dataToUnwrap.position(dataToUnwrap.limit());
-
- byte[] originalFirstRecord = new byte[firstLessFraming.remaining()];
- firstLessFraming.get(originalFirstRecord);
-
- ByteBuffer newData = ALPNHackServerHelloExplorer.createNewOutputRecords(newFirstRecord, records);
- dataToUnwrap.clear();
- dataToUnwrap.put(newData);
- dataToUnwrap.flip();
- ALPNHackClientByteArrayOutputStream.setReceivedServerHello(originalFirstRecord);
- }
- }
- } catch (BufferUnderflowException e) {
- return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, SSLEngineResult.HandshakeStatus.NEED_UNWRAP, 0, 0);
- }
- }
- }
- SSLEngineResult res = delegate.unwrap(dataToUnwrap, byteBuffers, i, i1);
- if(!delegate.getUseClientMode() && selectedApplicationProtocol != null && alpnHackServerByteArrayOutputStream == null) {
- alpnHackServerByteArrayOutputStream = replaceServerByteOutput(delegate, selectedApplicationProtocol);
- }
- return res;
- }
-
- @Override
- public Runnable getDelegatedTask() {
- return delegate.getDelegatedTask();
- }
-
- @Override
- public void closeInbound() throws SSLException {
- delegate.closeInbound();
- }
-
- @Override
- public boolean isInboundDone() {
- return delegate.isInboundDone();
- }
-
- @Override
- public void closeOutbound() {
- delegate.closeOutbound();
- }
-
- @Override
- public boolean isOutboundDone() {
- return delegate.isOutboundDone();
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return delegate.getSupportedCipherSuites();
- }
-
- @Override
- public String[] getEnabledCipherSuites() {
- return delegate.getEnabledCipherSuites();
- }
-
- @Override
- public void setEnabledCipherSuites(String[] strings) {
- delegate.setEnabledCipherSuites(strings);
- }
-
- @Override
- public String[] getSupportedProtocols() {
- return delegate.getSupportedProtocols();
- }
-
- @Override
- public String[] getEnabledProtocols() {
- return delegate.getEnabledProtocols();
- }
-
- @Override
- public void setEnabledProtocols(String[] strings) {
- delegate.setEnabledProtocols(strings);
- }
-
- @Override
- public SSLSession getSession() {
- return delegate.getSession();
- }
-
- @Override
- public void beginHandshake() throws SSLException {
- delegate.beginHandshake();
- }
-
- @Override
- public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
- return delegate.getHandshakeStatus();
- }
-
- @Override
- public void setUseClientMode(boolean b) {
- delegate.setUseClientMode(b);
- }
-
- @Override
- public boolean getUseClientMode() {
- return delegate.getUseClientMode();
- }
-
- @Override
- public void setNeedClientAuth(boolean b) {
- delegate.setNeedClientAuth(b);
- }
-
- @Override
- public boolean getNeedClientAuth() {
- return delegate.getNeedClientAuth();
- }
-
- @Override
- public void setWantClientAuth(boolean b) {
- delegate.setWantClientAuth(b);
- }
-
- @Override
- public boolean getWantClientAuth() {
- return delegate.getWantClientAuth();
- }
-
- @Override
- public void setEnableSessionCreation(boolean b) {
- delegate.setEnableSessionCreation(b);
- }
-
- @Override
- public boolean getEnableSessionCreation() {
- return delegate.getEnableSessionCreation();
- }
-
- /**
- * JDK8 ALPN hack support method.
- *
- * These methods will be removed once JDK8 ALPN support is no longer required
- * @param applicationProtocols
- */
- public void setApplicationProtocols(List applicationProtocols) {
- this.applicationProtocols = applicationProtocols;
- }
-
- /**
- * JDK8 ALPN hack support method.
- *
- * These methods will be removed once JDK8 ALPN support is no longer required
- */
- public List getApplicationProtocols() {
- return applicationProtocols;
- }
-
- /**
- * JDK8 ALPN hack support method.
- *
- * These methods will be removed once JDK8 ALPN support is no longer required
- */
- public String getSelectedApplicationProtocol() {
- return selectedApplicationProtocol;
- }
-
-
- static ALPNHackServerByteArrayOutputStream replaceServerByteOutput(SSLEngine sslEngine, String selectedAlpnProtocol) {
- try {
- Object handshaker = HANDSHAKER.get(sslEngine);
- Object hash = HANDSHAKE_HASH.get(handshaker);
- ByteArrayOutputStream existing = (ByteArrayOutputStream) HANDSHAKE_HASH_DATA.get(hash);
-
- ALPNHackServerByteArrayOutputStream out = new ALPNHackServerByteArrayOutputStream(sslEngine, existing.toByteArray(), selectedAlpnProtocol);
- HANDSHAKE_HASH_DATA.set(hash, out);
- return out;
- } catch (Exception e) {
- log.debug("Failed to replace hash output stream ", e);
- return null;
- }
- }
-
- static ALPNHackClientByteArrayOutputStream replaceClientByteOutput(SSLEngine sslEngine) {
- try {
- Object handshaker = HANDSHAKER.get(sslEngine);
- Object hash = HANDSHAKE_HASH.get(handshaker);
-
- ALPNHackClientByteArrayOutputStream out = new ALPNHackClientByteArrayOutputStream(sslEngine);
- HANDSHAKE_HASH_DATA.set(hash, out);
- return out;
- } catch (Exception e) {
- log.debug("Failed to replace hash output stream ", e);
- return null;
- }
- }
- static void regenerateHashes(SSLEngine sslEngineToHack, ByteArrayOutputStream data, byte[]... hashBytes) {
- //hack up the SSL engine internal state
- try {
- Object handshaker = HANDSHAKER.get(sslEngineToHack);
- Object hash = HANDSHAKE_HASH.get(handshaker);
- data.reset();
- Object protocolVersion = HANDSHAKER_PROTOCOL_VERSION.get(handshaker);
- HANDSHAKE_HASH_VERSION.set(hash, -1);
- HANDSHAKE_HASH_PROTOCOL_DETERMINED.invoke(hash, protocolVersion);
- MessageDigest digest = (MessageDigest) HANDSHAKE_HASH_FIN_MD.get(hash);
- digest.reset();
- for (byte[] b : hashBytes) {
- HANDSHAKE_HASH_UPDATE.invoke(hash, b, 0, b.length);
- }
- } catch (Exception e) {
- e.printStackTrace(); //TODO: remove
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerByteArrayOutputStream.java b/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerByteArrayOutputStream.java
deleted file mode 100644
index 7dbc127f56e9..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerByteArrayOutputStream.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2014 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.netty.handler.ssl;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLException;
-
-/**
- * Super hacky class that allows the ServerHello message to be modified and the corresponding hash generated at runtime.
- *
- *
- * @author Stuart Douglas
- */
-class ALPNHackServerByteArrayOutputStream extends ByteArrayOutputStream {
-
- private final SSLEngine sslEngine;
-
- private byte[] serverHello;
- private final String alpnProtocol;
- private boolean ready = false;
-
-
- ALPNHackServerByteArrayOutputStream(SSLEngine sslEngine, byte[] bytes, String alpnProtocol) {
- this.sslEngine = sslEngine;
- this.alpnProtocol = alpnProtocol;
- try {
- write(bytes);
- } catch (IOException e) {
- throw new RuntimeException(e); //never happen
- }
- ready = true;
- }
-
- @Override
- public void write(byte[] b, int off, int len) {
- if(ready) {
- if(b[off] == 2) { // server hello
- ready = false; //we are done processing
-
- serverHello = new byte[len]; //TODO: actual ALPN
- System.arraycopy(b, off, serverHello, 0, len);
- try {
- serverHello = ALPNHackServerHelloExplorer.addAlpnExtensionsToServerHello(serverHello, alpnProtocol);
- } catch (SSLException e) {
- throw new RuntimeException(e);
- }
- ALPNHackSSLEngine.regenerateHashes(sslEngine, this, toByteArray(), serverHello);
- return;
- }
- }
- super.write(b, off, len);
- }
-
- byte[] getServerHello() {
- return serverHello;
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerHelloExplorer.java b/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerHelloExplorer.java
deleted file mode 100644
index b5cea62a9771..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/ALPNHackServerHelloExplorer.java
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2014 Red Hat, Inc., and individual contributors
- * as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package io.netty.handler.ssl;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
-
-import javax.net.ssl.SSLException;
-
-/**
- * Hacks up ALPN support into the server hello message
- *
- * This has two different usage modes, one is adding a selected protocol into the extensions, the other is removing
- * all mention of ALPN and retuning the selected protocol. This dual mode does not make for the cleanest code
- * but removes the need to have duplicate nearly identical methods.
- *
- * The if the selected protocol is set then this will be added. If the selected protocol is null then ALPN will be
- * parsed and removed.
- *
- *
- * We only care about TLS 1.2, as TLS 1.1 is not allowed to use ALPN.
- *
- * Super hacky, but slightly less hacky than modifying the boot class path
- */
-final class ALPNHackServerHelloExplorer {
-
- // Private constructor prevents construction outside this class.
- private ALPNHackServerHelloExplorer() {
- }
-
- static byte[] addAlpnExtensionsToServerHello(byte[] source, String selectedAlpnProtocol)
- throws SSLException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- ByteBuffer input = ByteBuffer.wrap(source);
- try {
-
- exploreHandshake(input, source.length, new AtomicReference<>(selectedAlpnProtocol), out);
- //we need to adjust the record length;
- int serverHelloLength = out.size() - 4;
- out.write(source, input.position(), input.remaining()); //there may be more messages (cert etc), so we append them
- byte[] data = out.toByteArray();
-
- //now we need to adjust the handshake frame length
- data[1] = (byte) ((serverHelloLength >> 16) & 0xFF);
- data[2] = (byte) ((serverHelloLength >> 8) & 0xFF);
- data[3] = (byte) (serverHelloLength & 0xFF);
- return data;
- } catch (AlpnProcessingException e) {
- return source;
- }
- }
-
- /**
- * removes the ALPN extensions from the server hello
- * @param source
- * @return
- * @throws SSLException
- */
- static byte[] removeAlpnExtensionsFromServerHello(ByteBuffer source, final AtomicReference selectedAlpnProtocol)
- throws SSLException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
-
- try {
-
- exploreHandshake(source, source.remaining(), selectedAlpnProtocol, out);
- //we need to adjust the record length;
- int serverHelloLength = out.size() - 4;
- byte[] data = out.toByteArray();
-
- //now we need to adjust the handshake frame length
- data[1] = (byte) ((serverHelloLength >> 16) & 0xFF);
- data[2] = (byte) ((serverHelloLength >> 8) & 0xFF);
- data[3] = (byte) (serverHelloLength & 0xFF);
- return data;
- } catch (AlpnProcessingException e) {
- return null;
- }
- }
- private static void exploreHandshake(ByteBuffer input, int recordLength, AtomicReference selectedAlpnProtocol, ByteArrayOutputStream out) throws SSLException {
-
- // What is the handshake type?
- byte handshakeType = input.get();
- if (handshakeType != 0x02) { // 0x01: server_hello message
- throw new SSLException("Expected server hello");
- }
- out.write(handshakeType);
-
- // What is the handshake body length?
- int handshakeLength = getInt24(input);
- out.write(0); //placeholders
- out.write(0);
- out.write(0);
-
- // Theoretically, a single handshake message might span multiple
- // records, but in practice this does not occur.
- if (handshakeLength > recordLength - 4) { // 4: handshake header size
- throw new SSLException("Multi record handshake");
- }
- int old = input.limit();
- input.limit(handshakeLength + input.position());
- exploreServerHello(input, selectedAlpnProtocol, out);
- input.limit(old);
- }
-
- private static void exploreServerHello( ByteBuffer input, AtomicReference alpnProtocolReference, ByteArrayOutputStream out) throws SSLException {
-
- // server version
- byte helloMajorVersion = input.get();
- byte helloMinorVersion = input.get();
- out.write(helloMajorVersion);
- out.write(helloMinorVersion);
-
- for (int i = 0; i < 32; ++i) { //the Random is 32 bytes
- out.write(input.get() & 0xFF);
- }
-
- // ignore session id
- processByteVector8(input, out);
-
- // ignore cipher_suite
- out.write(input.get() & 0xFF);
- out.write(input.get() & 0xFF);
-
- // ignore compression methods
- out.write(input.get() & 0xFF);
-
- String existingAlpn = null;
- ByteArrayOutputStream extensionsOutput = null;
- if (input.remaining() > 0) {
- extensionsOutput = new ByteArrayOutputStream();
- existingAlpn = exploreExtensions(input, extensionsOutput, alpnProtocolReference.get() == null);
- }
-
- if (existingAlpn != null) {
- if(alpnProtocolReference.get() != null) {
- throw new AlpnProcessingException();
- }
- alpnProtocolReference.set(existingAlpn);
- byte[] existing = extensionsOutput.toByteArray();
- out.write(existing, 0, existing.length);
-
- } else if(alpnProtocolReference.get() != null) {
- String selectedAlpnProtocol = alpnProtocolReference.get();
- ByteArrayOutputStream alpnBits = new ByteArrayOutputStream();
- alpnBits.write(0);
- alpnBits.write(16); //ALPN type
- int length = 3 + selectedAlpnProtocol.length(); //length of extension data
- alpnBits.write((length >> 8) & 0xFF);
- alpnBits.write(length & 0xFF);
- length -= 2;
- alpnBits.write((length >> 8) & 0xFF);
- alpnBits.write(length & 0xFF);
- alpnBits.write(selectedAlpnProtocol.length() & 0xFF);
- for (int i = 0; i < selectedAlpnProtocol.length(); ++i) {
- alpnBits.write(selectedAlpnProtocol.charAt(i) & 0xFF);
- }
-
- if (extensionsOutput != null) {
- byte[] existing = extensionsOutput.toByteArray();
- int newLength = existing.length - 2 + alpnBits.size();
- existing[0] = (byte) ((newLength >> 8) & 0xFF);
- existing[1] = (byte) (newLength & 0xFF);
- try {
- out.write(existing);
- out.write(alpnBits.toByteArray());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- } else {
- int al = alpnBits.size();
- out.write((al >> 8) & 0xFF);
- out.write(al & 0xFF);
- try {
- out.write(alpnBits.toByteArray());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- } else if(extensionsOutput != null){
- byte[] existing = extensionsOutput.toByteArray();
- out.write(existing, 0, existing.length);
- }
- }
-
- static List extractRecords(ByteBuffer data) {
- List ret = new ArrayList<>();
- while (data.hasRemaining()) {
- byte d1 = data.get();
- byte d2 = data.get();
- byte d3 = data.get();
- byte d4 = data.get();
- byte d5 = data.get();
- int length = (d4 & 0xFF) << 8 | d5 & 0xFF;
- byte[] b = new byte[length + 5];
- b[0] = d1;
- b[1] = d2;
- b[2] = d3;
- b[3] = d4;
- b[4] = d5;
- data.get(b, 5, length);
- ret.add(ByteBuffer.wrap(b));
- }
- return ret;
- }
-
- private static String exploreExtensions(ByteBuffer input, ByteArrayOutputStream extensionOut, boolean removeAlpn)
- throws SSLException {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- String ret = null;
- int length = getInt16(input); // length of extensions
- out.write((length >> 8) & 0xFF);
- out.write(length & 0xFF);
- int originalLength = length;
- while (length > 0) {
- int extType = getInt16(input); // extenson type
- int extLen = getInt16(input); // length of extension data
- if(extType == 16) {
- int vlen = getInt16(input);
- ret = readByteVector8(input);
- if(!removeAlpn) {
- //we write the extension data back to the output stream
- out.write((extType >> 8) & 0xFF);
- out.write(extType & 0xFF);
- out.write((extLen >> 8) & 0xFF);
- out.write(extLen & 0xFF);
- out.write((vlen >> 8) & 0xFF);
- out.write(vlen & 0xFF);
- out.write(ret.length() & 0xFF);
- for(int i = 0; i < ret.length(); ++i) {
- out.write(ret.charAt(i) & 0xFF);
- }
- } else {
- originalLength -= 6;
- originalLength -= vlen;
- }
- } else {
- out.write((extType >> 8) & 0xFF);
- out.write(extType & 0xFF);
- out.write((extLen >> 8) & 0xFF);
- out.write(extLen & 0xFF);
- processByteVector(input, extLen, out);
- }
- length -= extLen + 4;
- }
- if(removeAlpn && ret == null) {
- //there was not ALPN to remove, so this whole thing is unnecessary, throw an exception to abort
- throw new AlpnProcessingException();
- }
- byte[] data = out.toByteArray();
- data[0] = (byte) ((originalLength >> 8) & 0xFF);
- data[1] = (byte) (originalLength & 0xFF);
- extensionOut.write(data, 0, data.length);
- return ret;
- }
-
- private static String readByteVector8(ByteBuffer input) {
- int length = getInt8(input);
- byte[] data = new byte[length];
- input.get(data);
- return new String(data, StandardCharsets.US_ASCII);
- }
- private static int getInt8(ByteBuffer input) {
- return input.get();
- }
-
- private static int getInt16(ByteBuffer input) {
- return (input.get() & 0xFF) << 8 | input.get() & 0xFF;
- }
-
- private static int getInt24(ByteBuffer input) {
- return (input.get() & 0xFF) << 16 | (input.get() & 0xFF) << 8 |
- input.get() & 0xFF;
- }
- private static void processByteVector8(ByteBuffer input, ByteArrayOutputStream out) {
- int int8 = getInt8(input);
- out.write(int8 & 0xFF);
- processByteVector(input, int8, out);
- }
-
-
- private static void processByteVector(ByteBuffer input, int length, ByteArrayOutputStream out) {
- for (int i = 0; i < length; ++i) {
- out.write(input.get() & 0xFF);
- }
- }
-
- static ByteBuffer createNewOutputRecords(byte[] newFirstMessage, List records) {
- int length = newFirstMessage.length;
- length += 5; //Framing layer
- for (int i = 1; i < records.size(); ++i) {
- //the first record is the old server hello, so we start at 1 rather than zero
- ByteBuffer rec = records.get(i);
- length += rec.remaining();
- }
- byte[] newData = new byte[length];
- ByteBuffer ret = ByteBuffer.wrap(newData);
- ByteBuffer oldHello = records.get(0);
- ret.put(oldHello.get()); //type
- ret.put(oldHello.get()); //major
- ret.put(oldHello.get()); //minor
- ret.put((byte) ((newFirstMessage.length >> 8) & 0xFF));
- ret.put((byte) (newFirstMessage.length & 0xFF));
- ret.put(newFirstMessage);
- for (int i = 1; i < records.size(); ++i) {
- ByteBuffer rec = records.get(i);
- ret.put(rec);
- }
- ret.flip();
- return ret;
- }
-
- private static final class AlpnProcessingException extends RuntimeException {
-
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkApplicationProtocolNegotiator.java b/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkApplicationProtocolNegotiator.java
deleted file mode 100644
index 241bad2bd966..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkApplicationProtocolNegotiator.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package io.netty.handler.ssl;
-
-
-import java.util.List;
-
-import javax.net.ssl.SSLEngine;
-
-/**
- * Netty's negotiator for Hacked ALPN SSL Engine.
- *
- * @author Sebastian Łaskawiec
- */
-public class AlpnHackedJdkApplicationProtocolNegotiator extends JdkBaseApplicationProtocolNegotiator {
-
- private static final SslEngineWrapperFactory ALPN_WRAPPER = new SslEngineWrapperFactory() {
- @Override
- public SSLEngine wrapSslEngine(SSLEngine engine, JdkApplicationProtocolNegotiator applicationNegotiator,
- boolean isServer) {
- ALPNHackSSLEngine wrappedEngine = new ALPNHackSSLEngine(engine);
- wrappedEngine.setApplicationProtocols(applicationNegotiator.protocols());
- return new AlpnHackedJdkSslEngine(wrappedEngine);
- }
- };
-
- public AlpnHackedJdkApplicationProtocolNegotiator(boolean failIfNoCommonProtocols, List protocols) {
- super(ALPN_WRAPPER
- , failIfNoCommonProtocols ? FAIL_SELECTOR_FACTORY : NO_FAIL_SELECTOR_FACTORY
- , failIfNoCommonProtocols ? FAIL_SELECTION_LISTENER_FACTORY : NO_FAIL_SELECTION_LISTENER_FACTORY
- , protocols);
- }
-
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslContext.java b/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslContext.java
deleted file mode 100644
index c120558a6b4d..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslContext.java
+++ /dev/null
@@ -1,22 +0,0 @@
-package io.netty.handler.ssl;
-
-import javax.net.ssl.SSLContext;
-
-/**
- * Hacked ALPN SSL Context for Netty.
- *
- * @author Sebastian Łaskawiec
- */
-public class AlpnHackedJdkSslContext extends JdkSslContext {
-
- public AlpnHackedJdkSslContext(SSLContext sslContext, boolean isClient, Iterable ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, ClientAuth clientAuth) {
- super(sslContext, isClient, ciphers, cipherFilter, createNegotiator(apn), clientAuth, null, false);
- }
-
- private final static JdkApplicationProtocolNegotiator createNegotiator(ApplicationProtocolConfig apn) {
- if (apn == null) {
- return JdkDefaultApplicationProtocolNegotiator.INSTANCE;
- }
- return new AlpnHackedJdkApplicationProtocolNegotiator(apn.selectorFailureBehavior() == ApplicationProtocolConfig.SelectorFailureBehavior.FATAL_ALERT, apn.supportedProtocols());
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslEngine.java b/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslEngine.java
deleted file mode 100644
index c70727092e94..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedJdkSslEngine.java
+++ /dev/null
@@ -1,190 +0,0 @@
-package io.netty.handler.ssl;
-
-import java.nio.ByteBuffer;
-
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLSession;
-
-public class AlpnHackedJdkSslEngine extends SSLEngine implements ApplicationProtocolAccessor {
-
- private final ALPNHackSSLEngine engine;
- private final AlpnHackedSslSession session;
-
- AlpnHackedJdkSslEngine(ALPNHackSSLEngine engine) {
- this.engine = engine;
- session = new AlpnHackedSslSession(engine);
- }
-
- @Override
- public AlpnHackedSslSession getSession() {
- return session;
- }
-
- @Override
- public void closeInbound() throws SSLException {
- engine.closeInbound();
- }
-
- @Override
- public void closeOutbound() {
- engine.closeOutbound();
- }
-
- @Override
- public String getPeerHost() {
- return engine.getPeerHost();
- }
-
- @Override
- public int getPeerPort() {
- return engine.getPeerPort();
- }
-
- @Override
- public SSLEngineResult wrap(ByteBuffer byteBuffer, ByteBuffer byteBuffer2) throws SSLException {
- return engine.wrap(byteBuffer, byteBuffer2);
- }
-
- @Override
- public SSLEngineResult wrap(ByteBuffer[] byteBuffers, ByteBuffer byteBuffer) throws SSLException {
- return engine.wrap(byteBuffers, byteBuffer);
- }
-
- @Override
- public SSLEngineResult wrap(ByteBuffer[] byteBuffers, int i, int i2, ByteBuffer byteBuffer) throws SSLException {
- return engine.wrap(byteBuffers, i, i2, byteBuffer);
- }
-
- @Override
- public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer byteBuffer2) throws SSLException {
- return engine.unwrap(byteBuffer, byteBuffer2);
- }
-
- @Override
- public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers) throws SSLException {
- return engine.unwrap(byteBuffer, byteBuffers);
- }
-
- @Override
- public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers, int i, int i2) throws SSLException {
- return engine.unwrap(byteBuffer, byteBuffers, i, i2);
- }
-
- @Override
- public Runnable getDelegatedTask() {
- return engine.getDelegatedTask();
- }
-
- @Override
- public boolean isInboundDone() {
- return engine.isInboundDone();
- }
-
- @Override
- public boolean isOutboundDone() {
- return engine.isOutboundDone();
- }
-
- @Override
- public String[] getSupportedCipherSuites() {
- return engine.getSupportedCipherSuites();
- }
-
- @Override
- public String[] getEnabledCipherSuites() {
- return engine.getEnabledCipherSuites();
- }
-
- @Override
- public void setEnabledCipherSuites(String[] strings) {
- engine.setEnabledCipherSuites(strings);
- }
-
- @Override
- public String[] getSupportedProtocols() {
- return engine.getSupportedProtocols();
- }
-
- @Override
- public String[] getEnabledProtocols() {
- return engine.getEnabledProtocols();
- }
-
- @Override
- public void setEnabledProtocols(String[] strings) {
- engine.setEnabledProtocols(strings);
- }
-
- @Override
- public SSLSession getHandshakeSession() {
- return engine.getHandshakeSession();
- }
-
- @Override
- public void beginHandshake() throws SSLException {
- engine.beginHandshake();
- }
-
- @Override
- public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
- return engine.getHandshakeStatus();
- }
-
- @Override
- public void setUseClientMode(boolean b) {
- engine.setUseClientMode(b);
- }
-
- @Override
- public boolean getUseClientMode() {
- return engine.getUseClientMode();
- }
-
- @Override
- public void setNeedClientAuth(boolean b) {
- engine.setNeedClientAuth(b);
- }
-
- @Override
- public boolean getNeedClientAuth() {
- return engine.getNeedClientAuth();
- }
-
- @Override
- public void setWantClientAuth(boolean b) {
- engine.setWantClientAuth(b);
- }
-
- @Override
- public boolean getWantClientAuth() {
- return engine.getWantClientAuth();
- }
-
- @Override
- public void setEnableSessionCreation(boolean b) {
- engine.setEnableSessionCreation(b);
- }
-
- @Override
- public boolean getEnableSessionCreation() {
- return engine.getEnableSessionCreation();
- }
-
- @Override
- public SSLParameters getSSLParameters() {
- return engine.getSSLParameters();
- }
-
- @Override
- public void setSSLParameters(SSLParameters sslParameters) {
- engine.setSSLParameters(sslParameters);
- }
-
- @Override
- public String getNegotiatedApplicationProtocol() {
- return engine.getSelectedApplicationProtocol();
- }
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedSslSession.java b/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedSslSession.java
deleted file mode 100644
index b049aada784f..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/AlpnHackedSslSession.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package io.netty.handler.ssl;
-
-
-import java.security.Principal;
-import java.security.cert.Certificate;
-
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSessionContext;
-import javax.security.cert.X509Certificate;
-
-/**
- * Hacked ALPN SSL Session for Netty. This class allows to grab negotiated protocols out of Hacked ALPN SSL Engine.
- *
- * @author Sebastian Łaskawiec
- */
-public class AlpnHackedSslSession implements SSLSession {
-
- private final ALPNHackSSLEngine engine;
-
- AlpnHackedSslSession(ALPNHackSSLEngine engine) {
- this.engine = engine;
- }
-
- private SSLSession unwrap() {
- return engine.getSession();
- }
-
- @Override
- public String getProtocol() {
- return unwrap().getProtocol();
- }
-
- @Override
- public byte[] getId() {
- return unwrap().getId();
- }
-
- @Override
- public SSLSessionContext getSessionContext() {
- return unwrap().getSessionContext();
- }
-
- @Override
- public long getCreationTime() {
- return unwrap().getCreationTime();
- }
-
- @Override
- public long getLastAccessedTime() {
- return unwrap().getLastAccessedTime();
- }
-
- @Override
- public void invalidate() {
- unwrap().invalidate();
- }
-
- @Override
- public boolean isValid() {
- return unwrap().isValid();
- }
-
- @Override
- public void putValue(String s, Object o) {
- unwrap().putValue(s, o);
- }
-
- @Override
- public Object getValue(String s) {
- return unwrap().getValue(s);
- }
-
- @Override
- public void removeValue(String s) {
- unwrap().removeValue(s);
- }
-
- @Override
- public String[] getValueNames() {
- return unwrap().getValueNames();
- }
-
- @Override
- public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
- return unwrap().getPeerCertificates();
- }
-
- @Override
- public Certificate[] getLocalCertificates() {
- return unwrap().getLocalCertificates();
- }
-
- @Override
- public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
- return unwrap().getPeerCertificateChain();
- }
-
- @Override
- public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
- return unwrap().getPeerPrincipal();
- }
-
- @Override
- public Principal getLocalPrincipal() {
- return unwrap().getLocalPrincipal();
- }
-
- @Override
- public String getCipherSuite() {
- return unwrap().getCipherSuite();
- }
-
- @Override
- public String getPeerHost() {
- return unwrap().getPeerHost();
- }
-
- @Override
- public int getPeerPort() {
- return unwrap().getPeerPort();
- }
-
- @Override
- public int getPacketBufferSize() {
- return unwrap().getPacketBufferSize();
- }
-
- @Override
- public int getApplicationBufferSize() {
- return unwrap().getApplicationBufferSize();
- }
-
-}
diff --git a/server/core/src/main/java/io/netty/handler/ssl/package-info.java b/server/core/src/main/java/io/netty/handler/ssl/package-info.java
deleted file mode 100644
index 5621aa2381f6..000000000000
--- a/server/core/src/main/java/io/netty/handler/ssl/package-info.java
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * This package contains hacked SSL Engine for handling ALPN.
- *
- *
- * Unfortunately JDK 8 doesn't have support handling TLS/ALPN for negotiating protocols. Using OpenSSL doesn't
- * improve the situation neither since we obtain an initialized {@link javax.net.ssl.SSLContext} from WildFly.
- * There's also 3rd element of the puzzle - Netty, which contains its own class hierarchy for handling TLS.
- *
- * So in order to support TLS/ALPN without Jetty's agent (which requires specific version per JVM version), we need
- * to wrap original {@link javax.net.ssl.SSLEngine} with {@link io.netty.handler.ssl.ALPNHackSSLEngine} (that
- * supports ALPN) and then wrap it again in {@link io.netty.handler.ssl.AlpnHackedJdkSslEngine} (and friends) to
- * pass it to Netty.
- *
- * All classes in this package can be removed once we are baselined on JDK9.
- *
- */
-package io.netty.handler.ssl;
diff --git a/server/core/src/main/java/org/infinispan/server/core/utils/SslUtils.java b/server/core/src/main/java/org/infinispan/server/core/utils/SslUtils.java
index a158473d3cca..44f9f26d3bc5 100644
--- a/server/core/src/main/java/org/infinispan/server/core/utils/SslUtils.java
+++ b/server/core/src/main/java/org/infinispan/server/core/utils/SslUtils.java
@@ -8,7 +8,6 @@
import org.infinispan.server.core.configuration.SslConfiguration;
import org.infinispan.server.core.configuration.SslEngineConfiguration;
-import io.netty.handler.ssl.AlpnHackedJdkSslContext;
import io.netty.handler.ssl.ApplicationProtocolConfig;
import io.netty.handler.ssl.ClientAuth;
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
@@ -23,23 +22,24 @@
public class SslUtils {
public static JdkSslContext createNettySslContext(SslConfiguration sslConfiguration, SslEngineConfiguration sslEngineConfiguration, ApplicationProtocolConfig alpnConfig) {
- return createSslContext(createJdkSslContext(sslConfiguration, sslEngineConfiguration), requireClientAuth(sslConfiguration), alpnConfig);
+ return createSslContext(createJdkSslContext(sslEngineConfiguration), requireClientAuth(sslConfiguration), alpnConfig);
}
- public static SSLContext createJdkSslContext(SslConfiguration sslConfiguration, SslEngineConfiguration sslEngineConfiguration) {
+ public static SSLContext createJdkSslContext(SslEngineConfiguration sslEngineConfiguration) {
if (sslEngineConfiguration.sslContext() != null) {
return sslEngineConfiguration.sslContext();
}
- return SslContextFactory.getContext(
- sslEngineConfiguration.keyStoreFileName(),
- sslEngineConfiguration.keyStoreType(),
- sslEngineConfiguration.keyStorePassword(),
- sslEngineConfiguration.keyStoreCertificatePassword(),
- sslEngineConfiguration.keyAlias(),
- sslEngineConfiguration.trustStoreFileName(),
- sslEngineConfiguration.trustStoreType(),
- sslEngineConfiguration.trustStorePassword(),
- sslEngineConfiguration.protocol(), null);
+ return new SslContextFactory()
+ .keyStoreFileName(sslEngineConfiguration.keyStoreFileName())
+ .keyStoreType(sslEngineConfiguration.keyStoreType())
+ .keyStorePassword(sslEngineConfiguration.keyStorePassword())
+ .keyStoreCertificatePassword(sslEngineConfiguration.keyStoreCertificatePassword())
+ .keyAlias(sslEngineConfiguration.keyAlias())
+ .trustStoreFileName(sslEngineConfiguration.trustStoreFileName())
+ .trustStoreType(sslEngineConfiguration.trustStoreType())
+ .trustStorePassword(sslEngineConfiguration.trustStorePassword())
+ .sslProtocol(sslEngineConfiguration.protocol())
+ .getContext();
}
private static JdkSslContext createSslContext(SSLContext sslContext, ClientAuth clientAuth, ApplicationProtocolConfig alpnConfig) {
@@ -47,19 +47,10 @@ private static JdkSslContext createSslContext(SSLContext sslContext, ClientAuth
//If we won't, JdkSslContext will use common ciphers from DEFAULT and SUPPORTED, which gives us 5 out of ~50 available ciphers
//Of course, we don't need to any specific engine configuration here... just a list of ciphers
String[] ciphers = SslContextFactory.getEngine(sslContext, false, clientAuth == ClientAuth.REQUIRE).getSupportedCipherSuites();
- if (alpnConfig != null && !isJdkAlpn()) {
- //we want to minimize the impact of possibly bugs in hacked SSL Context.
- return new AlpnHackedJdkSslContext(sslContext, false, Arrays.asList(ciphers), IdentityCipherSuiteFilter.INSTANCE, alpnConfig, clientAuth);
- } else {
- return new JdkSslContext(sslContext, false, Arrays.asList(ciphers), IdentityCipherSuiteFilter.INSTANCE, alpnConfig, clientAuth, null, false);
- }
+ return new JdkSslContext(sslContext, false, Arrays.asList(ciphers), IdentityCipherSuiteFilter.INSTANCE, alpnConfig, clientAuth, null, false);
}
private static ClientAuth requireClientAuth(SslConfiguration sslConfig) {
return sslConfig.requireClientAuth() ? ClientAuth.REQUIRE : ClientAuth.NONE;
}
-
- private static boolean isJdkAlpn() {
- return !SecurityActions.getSystemProperty("java.version").startsWith("1.8");
- }
}
diff --git a/server/hotrod/pom.xml b/server/hotrod/pom.xml
index 952863148b71..cd36ca52212a 100644
--- a/server/hotrod/pom.xml
+++ b/server/hotrod/pom.xml
@@ -68,6 +68,16 @@
wildfly-elytron
test
+