Allow to enable/disable protocols on the OpenSslEngine

Motivation:

To be compatible with SSLEngine we need to support enable / disable procols on the OpenSslEngine

Modifications:

Implement OpenSslEngine.getSupportedProtocols() , getEnabledProtocols() and setEnabledProtocols(...)

Result:

Better compability with SSLEngine
This commit is contained in:
Norman Maurer 2014-11-07 11:05:07 +01:00 committed by Norman Maurer
parent 6bfc68c785
commit eabfb91686
2 changed files with 95 additions and 6 deletions

View File

@ -313,12 +313,12 @@ public abstract class OpenSslContext extends SslContext {
return OpenSslDefaultApplicationProtocolNegotiator.INSTANCE; return OpenSslDefaultApplicationProtocolNegotiator.INSTANCE;
} }
switch(config.protocol()) { switch (config.protocol()) {
case NONE: case NONE:
return OpenSslDefaultApplicationProtocolNegotiator.INSTANCE; return OpenSslDefaultApplicationProtocolNegotiator.INSTANCE;
case NPN: case NPN:
if (isServer) { if (isServer) {
switch(config.selectedListenerFailureBehavior()) { switch (config.selectedListenerFailureBehavior()) {
case CHOOSE_MY_LAST_PROTOCOL: case CHOOSE_MY_LAST_PROTOCOL:
return new OpenSslNpnApplicationProtocolNegotiator(config.supportedProtocols()); return new OpenSslNpnApplicationProtocolNegotiator(config.supportedProtocols());
default: default:

View File

@ -38,8 +38,13 @@ import java.nio.ByteBuffer;
import java.nio.ReadOnlyBufferException; import java.nio.ReadOnlyBufferException;
import java.security.Principal; import java.security.Principal;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -82,6 +87,24 @@ public final class OpenSslEngine extends SSLEngine {
private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024; private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024; private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
// Protocols
private static final String PROTOCOL_SSL_V2_HELLO = "SSLv2Hello";
private static final String PROTOCOL_SSL_V2 = "SSLv2";
private static final String PROTOCOL_SSL_V3 = "SSLv3";
private static final String PROTOCOL_TLS_V1 = "TLSv1";
private static final String PROTOCOL_TLS_V1_1 = "TLSv1.1";
private static final String PROTOCOL_TLS_V1_2 = "TLSv1.2";
private static final String[] SUPPORTED_PROTOCOLS = {
PROTOCOL_SSL_V2_HELLO,
PROTOCOL_SSL_V2,
PROTOCOL_SSL_V3,
PROTOCOL_TLS_V1,
PROTOCOL_TLS_V1_1,
PROTOCOL_TLS_V1_2
};
private static final Set<String> SUPPORTED_PROTOCOLS_SET = new HashSet<String>(Arrays.asList(SUPPORTED_PROTOCOLS));
// Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256) // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256; static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
@ -644,17 +667,83 @@ public final class OpenSslEngine extends SSLEngine {
@Override @Override
public String[] getSupportedProtocols() { public String[] getSupportedProtocols() {
return EmptyArrays.EMPTY_STRINGS; return SUPPORTED_PROTOCOLS.clone();
} }
@Override @Override
public String[] getEnabledProtocols() { public String[] getEnabledProtocols() {
return EmptyArrays.EMPTY_STRINGS; List<String> enabled = new ArrayList<String>();
// Seems like there is no way to explict disable SSLv2Hello in openssl so it is always enabled
enabled.add(PROTOCOL_SSL_V2_HELLO);
int opts = SSL.getOptions(ssl);
if ((opts & SSL.SSL_OP_NO_TLSv1) == 0) {
enabled.add(PROTOCOL_TLS_V1);
}
if ((opts & SSL.SSL_OP_NO_TLSv1_1) == 0) {
enabled.add(PROTOCOL_TLS_V1_1);
}
if ((opts & SSL.SSL_OP_NO_TLSv1_2) == 0) {
enabled.add(PROTOCOL_TLS_V1_2);
}
if ((opts & SSL.SSL_OP_NO_SSLv2) == 0) {
enabled.add(PROTOCOL_SSL_V2);
}
if ((opts & SSL.SSL_OP_NO_SSLv3) == 0) {
enabled.add(PROTOCOL_SSL_V3);
}
int size = enabled.size();
if (size == 0) {
return EmptyArrays.EMPTY_STRINGS;
} else {
return enabled.toArray(new String[size]);
}
} }
@Override @Override
public void setEnabledProtocols(String[] strings) { public void setEnabledProtocols(String[] protocols) {
throw new UnsupportedOperationException(); if (protocols == null) {
// This is correct from the API docs
throw new IllegalArgumentException();
}
boolean sslv2 = false;
boolean sslv3 = false;
boolean tlsv1 = false;
boolean tlsv1_1 = false;
boolean tlsv1_2 = false;
for (String p: protocols) {
if (!SUPPORTED_PROTOCOLS_SET.contains(p)) {
throw new IllegalArgumentException("Protocol " + p + " is not supported.");
}
if (p.equals(PROTOCOL_SSL_V2)) {
sslv2 = true;
} else if (p.equals(PROTOCOL_SSL_V3)) {
sslv3 = true;
} else if (p.equals(PROTOCOL_TLS_V1)) {
tlsv1 = true;
} else if (p.equals(PROTOCOL_TLS_V1_1)) {
tlsv1_1 = true;
} else if (p.equals(PROTOCOL_TLS_V1_2)) {
tlsv1_2 = true;
}
}
// Enable all and then disable what we not want
SSL.setOptions(ssl, SSL.SSL_OP_ALL);
if (!sslv2) {
SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv2);
}
if (!sslv3) {
SSL.setOptions(ssl, SSL.SSL_OP_NO_SSLv3);
}
if (!tlsv1) {
SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1);
}
if (!tlsv1_1) {
SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_1);
}
if (!tlsv1_2) {
SSL.setOptions(ssl, SSL.SSL_OP_NO_TLSv1_2);
}
} }
private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException { private Certificate[] initPeerCertChain() throws SSLPeerUnverifiedException {