Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 24 additions & 10 deletions src/main/java/org/jruby/ext/openssl/CipherStrings.java
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,7 @@ static final class Def implements Comparable<Def>, Cloneable {
private final long mask;
private final long algStrengthMask;
private final long requiredAlgorithms;
private final int requiredStrengthBits; // 0 matches any

// OpenSSL 1.1.1
private long algorithm_mkey;
Expand All @@ -518,9 +519,14 @@ static final class Def implements Comparable<Def>, Cloneable {
this.mask = mask;
this.algStrengthMask = maskStrength;
this.requiredAlgorithms = 0;
this.requiredStrengthBits = 0;
}

Def(String name, long algorithms, long mask, long requiredAlgorithms) {
this(name, algorithms, mask, requiredAlgorithms, 0);
}

Def(String name, long algorithms, long mask, long requiredAlgorithms, int requiredStrengthBits) {
this.valid = false;
this.name = name;
this.id = 0;
Expand All @@ -531,6 +537,7 @@ static final class Def implements Comparable<Def>, Cloneable {
this.mask = mask;
this.algStrengthMask = 0;
this.requiredAlgorithms = requiredAlgorithms;
this.requiredStrengthBits = requiredStrengthBits;
}

Def(String name, long algorithms, long algo_strength, int strength_bits, int alg_bits, long mask, long maskStrength) {
Expand All @@ -544,6 +551,7 @@ static final class Def implements Comparable<Def>, Cloneable {
this.mask = mask;
this.algStrengthMask = maskStrength;
this.requiredAlgorithms = 0;
this.requiredStrengthBits = 0;
}

Def(int valid, String name, String stdname, /* RFC name */
Expand Down Expand Up @@ -578,6 +586,7 @@ static final class Def implements Comparable<Def>, Cloneable {
this.mask = 0;
this.algStrengthMask = 0;
this.requiredAlgorithms = 0;
this.requiredStrengthBits = 0;
}


Expand Down Expand Up @@ -636,6 +645,7 @@ public String toString() {
// from ssl_cipher_apply_rule
public boolean matches(Def current) {
if ( (current.algorithms & requiredAlgorithms) != requiredAlgorithms ) return false;
if ( requiredStrengthBits != 0 && current.algStrengthBits != requiredStrengthBits ) return false;
Comment thread
kares marked this conversation as resolved.
// ma = mask & cp->algorithms;
// ma_s = mask_strength & cp->algo_strength;
//
Expand Down Expand Up @@ -740,11 +750,13 @@ private static Collection<Def> matchingExact(final String name, final String[] a
return matchingPattern(pattern, all, true, setSuite);
}

final Def def = CipherNames.get(name);
// an OpenSSL cipher name, or an RFC (Java) suite name
final String ossl = CipherNames.containsKey(name) ? name : SuiteToOSSL.get(name);
final Def def = ossl == null ? null : CipherNames.get(ossl);
if (def != null) {
if (setSuite) {
for (final String entry : all) {
if (name.equals(SuiteToOSSL.get(entry))) {
if (ossl.equals(SuiteToOSSL.get(entry))) {
return Collections.singleton(def.setCipherSuite(entry));
}
}
Expand All @@ -759,14 +771,13 @@ private static Collection<Def> matching(final String[] defs, final String[] all,
final boolean setSuite) {
Collection<Def> matching = null;
for ( final String name : defs ) {
final Def pattern = Definitions.get(name);
if ( pattern != null ) {
if ( matching == null ) {
matching = matchingPattern(pattern, all, true, setSuite);
}
else {
matching.retainAll( matchingPattern(pattern, all, false, setSuite) );
}
final Collection<Def> found = matchingExact(name, all, setSuite);
if ( found == null ) return null; // unknown name drops the rule (libssl ssl_cipher_process_rulestr)
if ( matching == null ) {
matching = new LinkedHashSet<Def>(found);
}
else {
matching.retainAll(found);
}
}
return matching;
Expand Down Expand Up @@ -847,6 +858,9 @@ static Def suiteToDef(final String cipherSuite) {
Definitions.put(SSL_TXT_eNULL,new Def(0,SSL_TXT_eNULL,0,SSL_eNULL,0,0,0,0,SSL_ENC_MASK,0));
Definitions.put(SSL_TXT_eFZA,new Def(0,SSL_TXT_eFZA,0,SSL_eFZA, 0,0,0,0,SSL_ENC_MASK,0));
Definitions.put(SSL_TXT_AES,new Def(0,SSL_TXT_AES, 0,SSL_AES, 0,0,0,0,SSL_ENC_MASK,0));
Definitions.put(SSL_TXT_AES128,new Def(SSL_TXT_AES128,SSL_AES,SSL_ENC_MASK,SSL_AES,128));
Definitions.put(SSL_TXT_AES256,new Def(SSL_TXT_AES256,SSL_AES,SSL_ENC_MASK,SSL_AES,256));
Definitions.put(SSL_TXT_CHACHA20,new Def(0,SSL_TXT_CHACHA20,0,SSL_CHACHA20,0,0,0,0,SSL_ENC_MASK,0));
Definitions.put(SSL_TXT_MD5,new Def(0,SSL_TXT_MD5, 0,SSL_MD5, 0,0,0,0,SSL_MAC_MASK,0));
Definitions.put(SSL_TXT_SHA1,new Def(0,SSL_TXT_SHA1,0,SSL_SHA1, 0,0,0,0,SSL_MAC_MASK,0));
Definitions.put(SSL_TXT_SHA,new Def(0,SSL_TXT_SHA, 0,SSL_SHA, 0,0,0,0,SSL_MAC_MASK,0));
Expand Down
43 changes: 42 additions & 1 deletion src/test/java/org/jruby/ext/openssl/CipherStringsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,49 @@ public void ecdheSelectorsMatchOpenSSLAuthenticationRules() {
), javaNames);
}

private static final String[] ENC_SUITES = {
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256"
};

@Test
public void encryptionSelectorsMatchKeySize() {
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256", "DHE-RSA-AES128-SHA"), names("AES128", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-AES256-GCM-SHA384"), names("AES256", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-CHACHA20-POLY1305", "DHE-RSA-CHACHA20-POLY1305"), names("CHACHA20", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-CHACHA20-POLY1305"), names("EECDH+CHACHA20", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256"), names("EECDH+AES128", ENC_SUITES));
}

@Test
public void unknownAliasVoidsCombinedRule() {
assertEquals(Arrays.asList(), names("EECDH+FOO", ENC_SUITES));
assertEquals(Arrays.asList(), names("FOO+EECDH", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-AES256-GCM-SHA384"), names("EECDH+FOO:EECDH+AES256", ENC_SUITES));
}

@Test
public void combinedRuleAcceptsCipherNames() {
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256"), names("AES128+ECDHE-RSA-AES128-GCM-SHA256", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256"), names("ECDHE-RSA-AES128-GCM-SHA256+AES128", ENC_SUITES));
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256"), names("AES128+TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ENC_SUITES));
assertEquals(Arrays.asList(), names("AES256+ECDHE-RSA-AES128-GCM-SHA256", ENC_SUITES));
}

@Test
public void rfcCipherName() {
assertEquals(Arrays.asList("ECDHE-RSA-AES128-GCM-SHA256"), names("TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", ENC_SUITES));
}

private static List<String> names(final String selector) {
final Collection<CipherStrings.Def> ciphers = CipherStrings.matchingCiphers(selector, SUITES, false);
return names(selector, SUITES);
}

private static List<String> names(final String selector, final String[] suites) {
final Collection<CipherStrings.Def> ciphers = CipherStrings.matchingCiphers(selector, suites, false);
final List<String> names = new ArrayList<>(ciphers.size());
for (final CipherStrings.Def cipher : ciphers) names.add(cipher.name);
return names;
Expand Down
33 changes: 33 additions & 0 deletions test/ssl/test_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,39 @@ def test_set_ciphers_by_ecdh_group_name
end
end

def test_set_ciphers_by_encryption_alias
context = OpenSSL::SSL::SSLContext.new
context.ciphers = 'EECDH+CHACHA20:EECDH+AES128'
selected = context.ciphers.map(&:first)
assert_include selected, 'ECDHE-RSA-CHACHA20-POLY1305'
assert_include selected, 'ECDHE-RSA-AES128-GCM-SHA256'
assert_not_include selected, 'ECDHE-RSA-AES256-GCM-SHA384'

context.ciphers = 'AES256'
selected = context.ciphers.map(&:first)
assert_include selected, 'ECDHE-RSA-AES256-GCM-SHA384'
assert_not_include selected, 'ECDHE-RSA-AES128-GCM-SHA256'

assert_raise(OpenSSL::SSL::SSLError) { context.ciphers = 'EECDH+FOO' }
end

def test_set_ciphers_by_cipher_name_in_combined_rule
context = OpenSSL::SSL::SSLContext.new
['AES128+ECDHE-RSA-AES128-GCM-SHA256', 'AES128+TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'].each do |rule|
context.ciphers = rule
selected = context.ciphers.reject { |_, version, *| version == 'TLSv1.3' }.map(&:first)
assert_equal ['ECDHE-RSA-AES128-GCM-SHA256'], selected, rule
end

assert_raise(OpenSSL::SSL::SSLError) { context.ciphers = 'AES256+ECDHE-RSA-AES128-GCM-SHA256' }
end

def test_set_ciphers_by_rfc_name
context = OpenSSL::SSL::SSLContext.new
context.ciphers = 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256'
assert_equal ['ECDHE-RSA-AES128-GCM-SHA256'], context.ciphers.reject { |_, version, *| version == 'TLSv1.3' }.map(&:first)
end

def test_set_ciphers_by_cipher_name
context = OpenSSL::SSL::SSLContext.new
context.ciphers = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384"
Expand Down
Loading