From 63eb1f4c6ef8c1bb68afbfc5fba8762d50c1a0a8 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 17 Jun 2015 11:12:40 -0400 Subject: [PATCH] Fix logical AND support in OpenSSL cipher compatibility The + operator didn't perform properly at all. It is supposed to be used either for logical AND to combine two cipher suites or to move ciphers to the end of the list. Given that NSS doesn't support cipher ordering + is a no-op in this case. Also add in a slew of missing aliases: kRSA, aRSA, EDH, ECDH, kECDHe, kECDHr, kEECDH, aECDH, aNULL, AESGCM, AES128, AES256, CAMELLIA, CAMELLIA128, CAMELLIA256. Fix the definition of TLSv1.2. Define some ciphers as unimplemented in NSS. Renumber the mask/protocol/strength values to ensure uniqueness. Replace the existing cipher test to one that compares the output of the NSS-generated cipher string with the openssl generated string. There are a lot of restrictions on the openssl string since so much isn't either implemented or needed for mod_nss. Add a new openssl-compatible cipher request test to the server tests. --- nss_engine_cipher.c | 196 +++++++++++++++++++++++++++++++------- nss_engine_cipher.h | 61 ++++++------ test/createinstance.sh | 1 + test/suite1.tmpl | 6 ++ test/test.py | 6 ++ test/test_cipher.py | 254 ++++++++++++++++++++++++++++++++----------------- test_cipher.c | 32 +++++-- 7 files changed, 401 insertions(+), 155 deletions(-) diff --git a/nss_engine_cipher.c b/nss_engine_cipher.c index 9110d57..37ef338 100644 --- a/nss_engine_cipher.c +++ b/nss_engine_cipher.c @@ -29,10 +29,11 @@ cipher_properties ciphers_def[ciphernum] = {"rsa_rc4_128_md5", TLS_RSA_WITH_RC4_128_MD5, "RC4-MD5", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_MD5, SSLV3, SSL_MEDIUM, 128, 128}, {"rsa_rc4_128_sha", TLS_RSA_WITH_RC4_128_SHA, "RC4-SHA", SSL_kRSA|SSL_aRSA|SSL_RC4|SSL_SHA1, SSLV3, SSL_MEDIUM, 128, 128}, {"rsa_rc2_40_md5", TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "EXP-RC2-CBC-MD5", SSL_kRSA|SSL_aRSA|SSL_RC2|SSL_MD5, SSLV3, SSL_EXPORT40, 40, 128}, + /* TLS_RSA_EXPORT_WITH_DES40_CBC_SHA not implemented 0x0008 */ {"rsa_des_sha", TLS_RSA_WITH_DES_CBC_SHA, "DES-CBC-SHA", SSL_kRSA|SSL_aRSA|SSL_DES|SSL_SHA1, SSLV3, SSL_LOW, 56, 56}, - {"rsa_3des_sha", TLS_RSA_WITH_3DES_EDE_CBC_SHA, "DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_HIGH, 112, 168}, + {"rsa_3des_sha", TLS_RSA_WITH_3DES_EDE_CBC_SHA, "DES-CBC3-SHA", SSL_kRSA|SSL_aRSA|SSL_3DES|SSL_SHA1, SSLV3, SSL_HIGH, 168, 168}, {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, "AES128-SHA", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA1, TLSV1, SSL_HIGH, 128, 128}, - {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, "AES256-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, + {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, "AES256-SHA", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA1, TLSV1, SSL_HIGH, 256, 256}, {"null_sha_256", TLS_RSA_WITH_NULL_SHA256, "NULL-SHA256", SSL_kRSA|SSL_aRSA|SSL_eNULL|SSL_SHA256, TLSV1_2, SSL_STRONG_NONE, 0, 0}, {"aes_128_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256, "AES128-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128}, {"aes_256_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256, "AES256-SHA256", SSL_kRSA|SSL_aRSA|SSL_AES256|SSL_SHA256, TLSV1_2, SSL_HIGH, 256, 256}, @@ -73,9 +74,25 @@ cipher_properties ciphers_def[ciphernum] = {"ecdhe_rsa_aes_128_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "ECDHE-RSA-AES128-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128|SSL_SHA256, TLSV1_2, SSL_HIGH, 128, 128}, {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "ECDHE-ECDSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aECDSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128}, {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "ECDHE-RSA-AES128-GCM-SHA256", SSL_kEECDH|SSL_aRSA|SSL_AES128GCM|SSL_AEAD, TLSV1_2, SSL_HIGH, 128, 128}, + /* TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 is not implemented */ + /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 is not implemented */ + /* TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 is not implemented */ + /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 is not implemented */ #endif }; + +/* Some ciphers are optionally enabled in OpenSSL. For safety sake assume + * they are not available. + */ +static int skip_ciphers = 4; +static int ciphers_not_in_openssl[] = { + SSL_RSA_FIPS_WITH_DES_CBC_SHA, + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, +}; + static int parse_nss_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]); static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]); @@ -107,19 +124,48 @@ int nss_parse_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum rv = parse_nss_ciphers(s, ciphers, cipher_list); } else { rv = parse_openssl_ciphers(s, ciphers, cipher_list); - if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { + if (rv == 0 && 0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { rv = parse_nss_ciphers(s, ciphers, cipher_list); } } + if (0 == countciphers(cipher_list, SSLV3|TLSV1|TLSV1_2)) { + ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, + "no cipher match"); + } return rv; } +/* Given a set of ciphers perform a given action on the indexed value. + * + * This is needed because the + action doesn't do anything in the NSS + * context. In OpenSSL it will re-order the cipher list. + */ +static int set_cipher_value(PRBool cipher_list[ciphernum], int index, int action) +{ + int i; + + for (i = 0; i < skip_ciphers; i++) { + if (ciphers_def[index].num == ciphers_not_in_openssl[i]) { + cipher_list[index] = -1; + return; + } + } + + if (cipher_list[index] == -1) /* cipher is disabled */ + return; + else + cipher_list[index] = action; +} + + static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_list[ciphernum]) { char * cipher; int i, action; + PRBool merge = PR_FALSE; + PRBool found = PR_FALSE; cipher = ciphers; while (ciphers && (strlen(ciphers))) @@ -127,12 +173,12 @@ static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_lis while ((*cipher) && (isspace(*cipher))) ++cipher; - action = 1; + action = 1; /* default to enable */ switch(*cipher) { case '+': /* Add something */ - action = 1; - cipher++; + /* Cipher ordering is not supported in NSS */ + return 0; break; case '-': /* Subtract something */ action = 0; @@ -149,34 +195,58 @@ static int parse_openssl_ciphers(server_rec *s, char *ciphers, PRBool cipher_lis if ((ciphers = strchr(cipher, ':'))) { *ciphers++ = '\0'; + merge = PR_FALSE; + found = PR_FALSE; } if (!strcmp(cipher, "ALL")) { + found = PR_TRUE; for (i=0; i + + # In openssl equivalent of AES:-ECDH:-ADH:-PSK:-DH + # In NSS equivalent of AES:-ECDH + NSSCipherSuite AES+RSA + + NSSOptions +StdEnvVars +CompatEnvVars +ExportCertData NSSVerifyClient require diff --git a/test/test.py b/test/test.py index ee8d95b..23e093c 100644 --- a/test/test.py +++ b/test/test.py @@ -69,6 +69,12 @@ class test_suite1(Declarative): ), dict( + desc='server-side OpenSSL-style AES cipher check', + request=('/openssl_aes_cipher/', {'ciphers': 'AES128-SHA'}), + expected=200, + ), + + dict( desc='Basic client auth, no certificate', request=('/acl/aclS01.html', {}), expected=requests.exceptions.SSLError(), diff --git a/test/test_cipher.py b/test/test_cipher.py index 55989bd..a91f411 100644 --- a/test/test_cipher.py +++ b/test/test_cipher.py @@ -10,9 +10,50 @@ WITH_ECC=47 cwd = os.getcwd() srcdir = os.path.dirname(cwd) exe = "%s/test_cipher" % srcdir +openssl = "/usr/bin/openssl" ciphernum = 0 +CIPHERS_NOT_IN_NSS = ['ECDH-RSA-AES128-SHA256', + 'ECDH-ECDSA-AES128-GCM-SHA256', + 'ECDH-ECDSA-AES128-SHA256', + 'ECDH-RSA-AES128-GCM-SHA256', + 'EXP-DES-CBC-SHA', +] + +def assert_equal_openssl(nss_ciphers, ossl_ciphers): + (nss, err, rc) = run([exe, "--o", nss_ciphers]) + assert rc == 0 + (ossl, err, rc) = run([openssl, "ciphers", ossl_ciphers]) + assert rc == 0 + + nss_list = nss.strip().split(':') + nss_list.sort() + + ossl_list = ossl.strip().split(':') + ossl_list = list(set(ossl_list)) + ossl_list.sort() + + # NSS doesn't support the SHA-384 ciphers, remove them from the OpenSSL + # output. + t = list() + for o in ossl_list: + if 'SHA384' in o: + continue + if o in CIPHERS_NOT_IN_NSS: + continue + t.append(o) + ossl_list = t + + if len(nss_list) > len(ossl_list): + diff = set(nss_list) - set(ossl_list) + elif len(ossl_list) > len(nss_list): + diff = set(ossl_list) - set(nss_list) + else: + diff = '' + + assert nss_list == ossl_list, '%r != %r. Difference %r' % (':'.join(nss_list), ':'.join(ossl_list), diff) + class test_ciphers(object): @classmethod def setUpClass(cls): @@ -20,131 +61,172 @@ class test_ciphers(object): assert rc == 0 cls.ciphernum = int(out) + def test_RSA(self): + assert_equal_openssl("RSA", "RSA:-SSLv2:-SEED:-IDEA") + + def test_kRSA(self): + assert_equal_openssl("kRSA", "kRSA:-SSLv2:-SEED:-IDEA") + + def test_aRSA(self): + assert_equal_openssl("aRSA", "aRSA:-SSLv2:-SEED:-IDEA:-DH") + + def test_EDH(self): + # No DH ciphers supported yet + (out, err, rc) = run([exe, "EDH"]) + assert rc == 1 + def test_RC4(self): - (out, err, rc) = run([exe, "RC4"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc4_56_sha') - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc4_56_sha, ecdh_ecdsa_rc4_128_sha, ecdhe_ecdsa_rc4_128_sha, ecdh_rsa_128_sha, ecdhe_rsa_rc4_128_sha, ecdh_anon_rc4_128sha') + assert_equal_openssl("RC4", "RC4:-KRB5:-PSK:-ADH") + + def test_RC2(self): + assert_equal_openssl("RC2", "RC2:-SSLv2:-KRB5") def test_AES(self): - (out, err, rc) = run([exe, "AES"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_aes_128_sha, rsa_aes_256_sha, aes_128_sha_256, aes_256_sha_256, rsa_aes_128_gcm_sha_256') - else: - assert_equal(out, 'rsa_aes_128_sha, rsa_aes_256_sha, aes_128_sha_256, aes_256_sha_256, rsa_aes_128_gcm_sha_256, ecdh_ecdsa_rc4_128_sha, ecdh_ecdsa_3des_sha, ecdh_ecdsa_aes_128_sha, ecdh_ecdsa_aes_256_sha, ecdhe_ecdsa_rc4_128_sha, ecdhe_ecdsa_3des_sha, ecdhe_ecdsa_aes_128_sha, ecdhe_ecdsa_aes_256_sha, ecdh_rsa_128_sha, ecdh_rsa_3des_sha, ecdh_rsa_aes_128_sha, ecdh_rsa_aes_256_sha, ecdhe_rsa_aes_128_sha, ecdhe_rsa_aes_256_sha, ecdh_anon_aes_128_sha, ecdh_anon_aes_256_sha, ecdhe_ecdsa_aes_128_sha_256, ecdhe_rsa_aes_128_sha_256, ecdhe_ecdsa_aes_128_gcm_sha_256, ecdhe_rsa_aes_128_gcm_sha_256') + assert_equal_openssl("AES", "AES:-PSK:-ADH:-DSS:-DH") + def test_AESGCM(self): + assert_equal_openssl("AESGCM", "AESGCM:-PSK:-ADH:-DSS:-DH") + + def test_AES128(self): + assert_equal_openssl("AES128", "AES128:-PSK:-ADH:-DSS:-DH") + + def test_AES256(self): + assert_equal_openssl("AES256", "AES256:-PSK:-ADH:-DSS:-DH") + + def test_CAMELLIA(self): + assert_equal_openssl("CAMELLIA", "CAMELLIA:-DH") + + def test_CAMELLIA128(self): + assert_equal_openssl("CAMELLIA128", "CAMELLIA128:-DH") + + def test_CAMELLIA256(self): + assert_equal_openssl("CAMELLIA256", "CAMELLIA256:-DH") + + def test_3DES(self): + assert_equal_openssl("3DES", "3DES:-SSLv2:-PSK:-KRB5:-DH") + + def test_DES(self): + assert_equal_openssl("DES", "DES:-SSLv2:-KRB5:-DH") def test_ALL(self): - (out, err, rc) = run([exe, "ALL"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, aes_128_sha_256, aes_256_sha_256, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, rsa_aes_128_gcm_sha_256' - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, aes_128_sha_256, aes_256_sha_256, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, rsa_aes_128_gcm_sha_256, fips_3des_sha, fips_des_sha, ecdh_ecdsa_rc4_128_sha, ecdh_ecdsa_3des_sha, ecdh_ecdsa_aes_128_sha, ecdh_ecdsa_aes_256_sha, ecdhe_ecdsa_rc4_128_sha, ecdhe_ecdsa_3des_sha, ecdhe_ecdsa_aes_128_sha, ecdhe_ecdsa_aes_256_sha, ecdh_rsa_128_sha, ecdh_rsa_3des_sha, ecdh_rsa_aes_128_sha, ecdh_rsa_aes_256_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdhe_rsa_aes_128_sha, ecdhe_rsa_aes_256_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha, ecdh_anon_aes_128_sha, ecdh_anon_aes_256_sha, ecdhe_ecdsa_aes_128_sha_256, ecdhe_rsa_aes_128_sha_256, ecdhe_ecdsa_aes_128_gcm_sha_256, ecdhe_rsa_aes_128_gcm_sha_256') + assert_equal_openssl("ALL", "ALL:-SSLv2:-KRB5:-ADH:-DH:-DSS:-PSK:-SEED:-IDEA") def test_ALL_no_AES(self): - (out, err, rc) = run([exe, "ALL:-AES"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha') - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha') + assert_equal_openssl("ALL:-AES", "ALL:-AES:-SSLv2:-KRB5:-ADH:-DH:-DSS:-PSK:-SEED:-IDEA") + + def test_COMPLEMENTOFALL(self): + assert_equal_openssl("COMPLEMENTOFALL", "COMPLEMENTOFALL") + + # skipping DEFAULT as we use the NSS defaults + # skipping COMPLEMENTOFDEFAULT as these are all ADH ciphers def test_SSLv3(self): - (out, err, rc) = run([exe, "SSLv3"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha') - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha, ecdh_ecdsa_rc4_128_sha, ecdh_ecdsa_3des_sha, ecdh_ecdsa_aes_128_sha, ecdh_ecdsa_aes_256_sha, ecdhe_ecdsa_rc4_128_sha, ecdhe_ecdsa_3des_sha, ecdhe_ecdsa_aes_128_sha, ecdhe_ecdsa_aes_256_sha, ecdh_rsa_128_sha, ecdh_rsa_3des_sha, ecdh_rsa_aes_128_sha, ecdh_rsa_aes_256_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdhe_rsa_aes_128_sha, ecdhe_rsa_aes_256_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha, ecdh_anon_aes_128_sha, ecdh_anon_aes_256_sha') + assert_equal_openssl("SSLv3", "SSLv3:-KRB5:-PSK:-ADH:-EDH:-SEED:-IDEA") def test_SSLv3_equals_TLSv1(self): - (out, err, rc) = run([exe, "SSLv3"]) - (out2, err2, rc2) = run([exe, "TLSv1"]) + (nss, err, rc) = run([exe, "--o", "SSLv3"]) + (nss2, err, rc2) = run([exe, "--o", "TLSv1"]) assert rc == 0 assert rc2 == 0 - assert_equal(out, out2) + assert_equal(nss, nss2) def test_TLSv12(self): - if self.ciphernum < WITH_ECC: - raise nose.SkipTest('ECC disabled') - (out, err, rc) = run([exe, "TLSv12"]) - assert rc == 0 - assert_equal(out, 'aes_128_sha_256, aes_256_sha_256, rsa_aes_128_gcm_sha_256, ecdhe_ecdsa_aes_128_sha_256, ecdhe_rsa_aes_128_sha_256, ecdhe_ecdsa_aes_128_gcm_sha_256, ecdhe_rsa_aes_128_gcm_sha_256') + assert_equal_openssl("TLSv1.2", "TLSv1.2:TLSv1.2:-ADH:-DH:-DSS") def test_NULL(self): - (out, err, rc) = run([exe, "NULL"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_null_md5, rsa_null_sha, null_sha_256') - else: - assert_equal(out, 'rsa_null_md5, rsa_null_sha, null_sha_256, ecdh_ecdsa_null_sha, ecdhe_ecdsa_null_sha, ecdh_rsa_null_sha, ecdhe_rsa_null, ecdh_anon_null_sha') + assert_equal_openssl("NULL", "NULL") def test_nss_rsa_rc4_128(self): + # Test NSS cipher parsing (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+rsa_rc4_128_sha"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_md5, rsa_rc4_128_sha') - def test_openssl_cipher(self): - (out, err, rc) = run([exe, "DES-CBC3-SHA"]) - assert rc == 0 - assert_equal(out, 'rsa_3des_sha') + def test_EXP(self): + assert_equal_openssl("EXP", "EXP:-SSLv2:-DH:-KRB5") - def test_openssl_cipherlist(self): - (out, err, rc) = run([exe, "DES-CBC3-SHA:RC4-SHA"]) - assert rc == 0 - assert_equal(out, 'rsa_rc4_128_sha, rsa_3des_sha') + def test_EXPORT(self): + assert_equal_openssl("EXPORT", "EXPORT:-SSLv2:-DH:-KRB5") - def test_EXP(self): - (out, err, rc) = run([exe, "EXP"]) - assert rc == 0 - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc2_40_md5, rsa_des_56_sha, rsa_rc4_56_sha') + def test_EXPORT40(self): + assert_equal_openssl("EXPORT40", "EXPORT40:-SSLv2:-ADH:-DH:-KRB5") def test_MD5(self): - (out, err, rc) = run([exe, "MD5"]) - assert rc == 0 - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc2_40_md5') + assert_equal_openssl("MD5", "MD5:-SSLv2:-DH:-KRB5") def test_SHA(self): - (out, err, rc) = run([exe, "SHA"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_128_sha, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha') - else: - assert_equal(out, 'rsa_rc4_128_sha, rsa_des_sha, rsa_3des_sha, rsa_aes_128_sha, rsa_aes_256_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha, ecdh_ecdsa_rc4_128_sha, ecdh_ecdsa_3des_sha, ecdh_ecdsa_aes_128_sha, ecdh_ecdsa_aes_256_sha, ecdhe_ecdsa_rc4_128_sha, ecdhe_ecdsa_3des_sha, ecdhe_ecdsa_aes_128_sha, ecdhe_ecdsa_aes_256_sha, ecdh_rsa_128_sha, ecdh_rsa_3des_sha, ecdh_rsa_aes_128_sha, ecdh_rsa_aes_256_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdhe_rsa_aes_128_sha, ecdhe_rsa_aes_256_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha, ecdh_anon_aes_128_sha, ecdh_anon_aes_256_sha') + assert_equal_openssl("SHA", "SHA:-SSLv2:-DH:-KRB5:-PSK:-IDEA:-SEED") + + def test_HIGH(self): + assert_equal_openssl("HIGH", "HIGH:-SSLv2:-DH:-ADH:-KRB5:-PSK") + + def test_MEDIUM(self): + assert_equal_openssl("MEDIUM", "MEDIUM:-SSLv2:-ADH:-KRB5:-PSK:-SEED:-IDEA") + + def test_LOW(self): + assert_equal_openssl("LOW", "LOW:-SSLv2:-DH:-ADH:-KRB5") def test_SHA256(self): - (out, err, rc) = run([exe, "SHA256"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'aes_128_sha_256, aes_256_sha_256') - else: - assert_equal(out, 'aes_128_sha_256, aes_256_sha_256, ecdhe_ecdsa_aes_128_sha_256, ecdhe_rsa_aes_128_sha_256') + assert_equal_openssl("SHA256", "SHA256:-ADH:-DSS:-DH") def test_SHA_MD5_minus_AES(self): - (out, err, rc) = run([exe, "SHA:MD5:-AES"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha') - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha') + assert_equal_openssl("SHA:MD5:-AES", "SHA:MD5:-AES:-SSLv2:-DH:-DSS:-KRB5:-SEED:-PSK:-IDEA") - def test_SHA_MD5_not_AES_HIGH(self): - (out, err, rc) = run([exe, "!AES:SHA:MD5"]) - assert rc == 0 - if self.ciphernum < WITH_ECC: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha') - else: - assert_equal(out, 'rsa_rc4_40_md5, rsa_rc4_128_md5, rsa_rc4_128_sha, rsa_rc2_40_md5, rsa_des_sha, rsa_3des_sha, camelia_128_sha, rsa_des_56_sha, rsa_rc4_56_sha, camelia_256_sha, fips_3des_sha, fips_des_sha, ecdhe_rsa_rc4_128_sha, ecdhe_rsa_3des_sha, ecdh_anon_rc4_128sha, ecdh_anon_3des_sha') + def test_SHA_MD5_not_AES(self): + assert_equal_openssl("!AES:SHA:MD5", "!AES:SHA:MD5:-SSLv2:-DH:-KRB5:-DSS:-SEED:-PSK:-IDEA") + + def test_aECDH(self): + assert_equal_openssl("aECDH", "aECDH") + + def test_kECDHe(self): + assert_equal_openssl("kECDHe", "kECDHe") + + def test_kECDHr(self): + assert_equal_openssl("kECDHr", "kECDHr") + + def test_kEECDH(self): + assert_equal_openssl("kEECDH", "kEECDH") + + def test_ECDH(self): + assert_equal_openssl("ECDH", "ECDH") + + def test_AES_no_ECDH(self): + assert_equal_openssl("AES:-ECDH", "AES:-ECDH:-ADH:-PSK:-DH") + assert_equal_openssl("AES+RSA", "AES+RSA") + + def test_logical_and_3DES_RSA(self): + assert_equal_openssl("3DES+RSA", "3DES+RSA:-SSLv2") + + def test_logical_and_RSA_RC4(self): + assert_equal_openssl("RSA+RC4", "RSA+RC4:-SSLv2") + + def test_logical_and_ECDH_SHA(self): + assert_equal_openssl("ECDH+SHA", "ECDH+SHA") + + def test_logical_and_RSA_RC4_no_SHA(self): + assert_equal_openssl("RSA+RC4:!SHA", "RSA+RC4:-SSLv2:!SHA") + + def test_additive_RSA_RC4(self): + assert_equal_openssl("RSA:+RC4", "RSA:+RC4:-SSLv2:-SEED:-IDEA") + + def test_negative_plus_RSA_MD5(self): + assert_equal_openssl("-RC2:RSA+MD5", "-RC2:RSA+MD5:-SSLv2") def test_nss_subtraction(self): (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+rsa_rc4_128_sha,-rsa_rc4_128_md5"]) assert rc == 0 assert_equal(out, 'rsa_rc4_128_sha') + def test_openssl_cipher(self): + (out, err, rc) = run([exe, "DES-CBC3-SHA"]) + assert rc == 0 + assert_equal(out, 'rsa_3des_sha') + + def test_openssl_cipherlist(self): + (out, err, rc) = run([exe, "DES-CBC3-SHA:RC4-SHA"]) + assert rc == 0 + assert_equal(out, 'rsa_rc4_128_sha, rsa_3des_sha') + # As long as at least one is valid, things are ok def test_nss_unknown(self): (out, err, rc) = run([exe, "+rsa_rc4_128_md5,+unknown"]) @@ -156,7 +238,9 @@ class test_ciphers(object): assert rc == 0 assert_equal(out, 'aes_128_sha_256') + def test_openssl_single_cipher(self): + assert_equal_openssl("RC4-SHA", "RC4-SHA") + def test_invalid_format(self): (out, err, rc) = run([exe, "none"]) assert rc == 1 - assert_equal(err, 'nss_engine_cipher.c:292, invalid cipher string none. Format is +cipher1,-cipher2...Unable to parse cipher list') diff --git a/test_cipher.c b/test_cipher.c index 91d112b..86a88d6 100644 --- a/test_cipher.c +++ b/test_cipher.c @@ -40,7 +40,7 @@ int ap_log_error_(const char *fn, int line, int module_index, va_start(args, fmt); vsprintf(out, fmt, args); - fprintf(stderr,"%s:%d, %s", fn, line, out); + fprintf(stderr,"%s:%d, %s\n", fn, line, out); va_end(args); return 0; @@ -53,10 +53,11 @@ int main(int argc, char ** argv) int rv=0; int i; char *ciphers; + PRBool openssl_output = PR_FALSE; PRBool ciphers_list[ciphernum]; - if (argc != 2) { - fprintf(stderr, "Usage: test_cipher [--count] \n"); + if (argc != 2 && argc != 3) { + fprintf(stderr, "Usage: test_cipher [--count] [--o] \n"); exit(1); } @@ -70,9 +71,14 @@ int main(int argc, char ** argv) ciphers_list[i] = PR_FALSE; } - ciphers = strdup(argv[1]); + i = 1; /* index of ciphers */ + if (!strcmp(argv[1], "--o")) { + openssl_output = PR_TRUE; + i = 2; + } + + ciphers = strdup(argv[i]); if (nss_parse_ciphers(NULL, ciphers, ciphers_list) < 0) { - fprintf(stderr, "Unable to parse cipher list\n"); rv = 1; } free(ciphers); @@ -85,12 +91,22 @@ int main(int argc, char ** argv) for (i = 0; i < ciphernum; i++) { if (ciphers_list[i] == 1) { - strncat(output, ciphers_def[i].name, sizeof(output)); - strncat(output, ", ", sizeof(output)); + if (openssl_output) { + strncat(output, ciphers_def[i].openssl_name, sizeof(output)); + strncat(output, ":", sizeof(output)); + } else { + strncat(output, ciphers_def[i].name, sizeof(output)); + strncat(output, ", ", sizeof(output)); + } } } - output[strlen(output) - 2] = '\0'; + if (openssl_output) + output[strlen(output) - 1] = '\0'; + else + output[strlen(output) - 2] = '\0'; fprintf(stdout, "%s\n", output); + } else { + fprintf(stdout, "Unable to parse cipher list\n"); } return rv; -- 1.9.3