aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@chromium.org>2015-02-05 16:49:47 -0500
committerAdam Langley <agl@chromium.org>2015-02-09 17:31:28 -0800
commit65226257c1c49eac4a739b9d57409b52dfbb5d45 (patch)
tree801023b8443b97e73a8c948399b297704338e354
parent722696b39e6a707b06e16d43edbd26197949a01e (diff)
downloadboringssl-65226257c1c49eac4a739b9d57409b52dfbb5d45.zip
boringssl-65226257c1c49eac4a739b9d57409b52dfbb5d45.tar.gz
boringssl-65226257c1c49eac4a739b9d57409b52dfbb5d45.tar.bz2
Add SSL_CIPHER_get_rfc_name.
OpenSSL's internal names for the ciphers are not the standard ones and are not easy to consistently map to the standard ones. Add an API to get the real names out. (WebRTC wants an API to get the standard names out.) Also change some incorrect flags on SHA-256 TLS 1.2 ciphers; SSL_HANDSHAKE_MAC_DEFAULT and SSL_HANDSHAKE_MAC_SHA256 are the same after TLS 1.2. A TLS 1.2 cipher should be tagged explicitly with SHA-256. (This avoids tripping a check in SSL_CIPHER_get_rfc_name which asserts that default-hash ciphers only ever use SHA-1 or MD5 for the bulk cipher MAC.) Change-Id: Iaec2fd4aa97df29883094d3c2ae60f0ba003bf07
-rw-r--r--include/openssl/ssl.h9
-rw-r--r--ssl/s3_lib.c12
-rw-r--r--ssl/ssl_ciph.c97
-rw-r--r--ssl/ssl_test.c92
4 files changed, 193 insertions, 17 deletions
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 19f9f00..0e75011 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -1811,9 +1811,16 @@ OPENSSL_EXPORT const SSL_CIPHER *SSL_get_current_cipher(const SSL *s);
OPENSSL_EXPORT int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits);
OPENSSL_EXPORT const char *SSL_CIPHER_get_version(const SSL_CIPHER *c);
OPENSSL_EXPORT const char *SSL_CIPHER_get_name(const SSL_CIPHER *c);
+
/* SSL_CIPHER_get_kx_name returns a string that describes the key-exchange
- * method used by |c|. For example, "ECDHE-ECDSA". */
+ * method used by |cipher|. For example, "ECDHE-ECDSA". */
OPENSSL_EXPORT const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher);
+
+/* SSL_CIPHER_get_rfc_name returns a newly-allocated string with the standard
+ * name for |cipher|. For example, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256". The
+ * caller is responsible for calling |OPENSSL_free| on the result. */
+OPENSSL_EXPORT char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher);
+
OPENSSL_EXPORT unsigned long SSL_CIPHER_get_id(const SSL_CIPHER *c);
OPENSSL_EXPORT int SSL_get_fd(const SSL *s);
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index c230427..8ed2be9 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -246,14 +246,14 @@ const SSL_CIPHER ssl3_ciphers[] = {
{
1, TLS1_TXT_RSA_WITH_AES_128_SHA256, TLS1_CK_RSA_WITH_AES_128_SHA256,
SSL_kRSA, SSL_aRSA, SSL_AES128, SSL_SHA256, SSL_TLSV1_2,
- SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128,
+ SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128,
},
/* Cipher 3D */
{
1, TLS1_TXT_RSA_WITH_AES_256_SHA256, TLS1_CK_RSA_WITH_AES_256_SHA256,
SSL_kRSA, SSL_aRSA, SSL_AES256, SSL_SHA256, SSL_TLSV1_2,
- SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256,
+ SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256,
},
/* Cipher 67 */
@@ -261,7 +261,7 @@ const SSL_CIPHER ssl3_ciphers[] = {
1, TLS1_TXT_DHE_RSA_WITH_AES_128_SHA256,
TLS1_CK_DHE_RSA_WITH_AES_128_SHA256, SSL_kEDH, SSL_aRSA, SSL_AES128,
SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128,
+ SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128,
},
/* Cipher 6B */
@@ -269,21 +269,21 @@ const SSL_CIPHER ssl3_ciphers[] = {
1, TLS1_TXT_DHE_RSA_WITH_AES_256_SHA256,
TLS1_CK_DHE_RSA_WITH_AES_256_SHA256, SSL_kEDH, SSL_aRSA, SSL_AES256,
SSL_SHA256, SSL_TLSV1_2, SSL_HIGH | SSL_FIPS,
- SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256,
+ SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256,
},
/* Cipher 6C */
{
1, TLS1_TXT_ADH_WITH_AES_128_SHA256, TLS1_CK_ADH_WITH_AES_128_SHA256,
SSL_kEDH, SSL_aNULL, SSL_AES128, SSL_SHA256, SSL_TLSV1_2,
- SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 128, 128,
+ SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 128, 128,
},
/* Cipher 6D */
{
1, TLS1_TXT_ADH_WITH_AES_256_SHA256, TLS1_CK_ADH_WITH_AES_256_SHA256,
SSL_kEDH, SSL_aNULL, SSL_AES256, SSL_SHA256, SSL_TLSV1_2,
- SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_DEFAULT | TLS1_PRF, 256, 256,
+ SSL_HIGH | SSL_FIPS, SSL_HANDSHAKE_MAC_SHA256 | TLS1_PRF_SHA256, 256, 256,
},
/* Cipher 8A */
diff --git a/ssl/ssl_ciph.c b/ssl/ssl_ciph.c
index e792533..ad2e301 100644
--- a/ssl/ssl_ciph.c
+++ b/ssl/ssl_ciph.c
@@ -1322,35 +1322,120 @@ const char *SSL_CIPHER_get_kx_name(const SSL_CIPHER *cipher) {
switch (cipher->algorithm_mkey) {
case SSL_kRSA:
- return SSL_TXT_RSA;
+ return "RSA";
case SSL_kEDH:
switch (cipher->algorithm_auth) {
case SSL_aRSA:
- return "DHE_" SSL_TXT_RSA;
+ return "DHE_RSA";
case SSL_aNULL:
- return SSL_TXT_DH "_anon";
+ return "DH_anon";
default:
+ assert(0);
return "UNKNOWN";
}
case SSL_kEECDH:
switch (cipher->algorithm_auth) {
case SSL_aECDSA:
- return "ECDHE_" SSL_TXT_ECDSA;
+ return "ECDHE_ECDSA";
case SSL_aRSA:
- return "ECDHE_" SSL_TXT_RSA;
+ return "ECDHE_RSA";
+ case SSL_aPSK:
+ return "ECDHE_PSK";
case SSL_aNULL:
- return SSL_TXT_ECDH "_anon";
+ return "ECDH_anon";
default:
+ assert(0);
return "UNKNOWN";
}
+ case SSL_kPSK:
+ assert(cipher->algorithm_auth == SSL_aPSK);
+ return "PSK";
+
default:
+ assert(0);
return "UNKNOWN";
}
}
+static const char *ssl_cipher_get_enc_name(const SSL_CIPHER *cipher) {
+ switch (cipher->algorithm_enc) {
+ case SSL_3DES:
+ return "3DES_EDE_CBC";
+ case SSL_RC4:
+ return "RC4";
+ case SSL_AES128:
+ return "AES_128_CBC";
+ case SSL_AES256:
+ return "AES_256_CBC";
+ case SSL_AES128GCM:
+ return "AES_128_GCM";
+ case SSL_AES256GCM:
+ return "AES_256_GCM";
+ case SSL_CHACHA20POLY1305:
+ return "CHACHA20_POLY1305";
+ break;
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+}
+
+static const char *ssl_cipher_get_prf_name(const SSL_CIPHER *cipher) {
+ if ((cipher->algorithm2 & TLS1_PRF) == TLS1_PRF) {
+ /* Before TLS 1.2, the PRF component is the hash used in the HMAC, which is
+ * only ever MD5 or SHA-1. */
+ switch (cipher->algorithm_mac) {
+ case SSL_MD5:
+ return "MD5";
+ case SSL_SHA1:
+ return "SHA";
+ default:
+ assert(0);
+ return "UNKNOWN";
+ }
+ } else if (cipher->algorithm2 & TLS1_PRF_SHA256) {
+ return "SHA256";
+ } else if (cipher->algorithm2 & TLS1_PRF_SHA384) {
+ return "SHA384";
+ } else {
+ assert(0);
+ return "UNKNOWN";
+ }
+}
+
+char *SSL_CIPHER_get_rfc_name(const SSL_CIPHER *cipher) {
+ if (cipher == NULL) {
+ return NULL;
+ }
+
+ const char *kx_name = SSL_CIPHER_get_kx_name(cipher);
+ const char *enc_name = ssl_cipher_get_enc_name(cipher);
+ const char *prf_name = ssl_cipher_get_prf_name(cipher);
+
+ /* The final name is TLS_{kx_name}_WITH_{enc_name}_{prf_name}. */
+ size_t len = 4 + strlen(kx_name) + 6 + strlen(enc_name) + 1 +
+ strlen(prf_name) + 1;
+ char *ret = OPENSSL_malloc(len);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (BUF_strlcpy(ret, "TLS_", len) >= len ||
+ BUF_strlcat(ret, kx_name, len) >= len ||
+ BUF_strlcat(ret, "_WITH_", len) >= len ||
+ BUF_strlcat(ret, enc_name, len) >= len ||
+ BUF_strlcat(ret, "_", len) >= len ||
+ BUF_strlcat(ret, prf_name, len) >= len) {
+ assert(0);
+ OPENSSL_free(ret);
+ return NULL;
+ }
+ assert(strlen(ret) + 1 == len);
+ return ret;
+}
+
/* number of bits for symmetric cipher */
int SSL_CIPHER_get_bits(const SSL_CIPHER *c, int *alg_bits) {
int ret = 0;
diff --git a/ssl/ssl_test.c b/ssl/ssl_test.c
index 70291a2..de0f8ed 100644
--- a/ssl/ssl_test.c
+++ b/ssl/ssl_test.c
@@ -214,9 +214,13 @@ static void print_cipher_preference_list(
static int test_cipher_rule(CIPHER_TEST *t) {
int ret = 0;
- SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
+ SSL_CTX *ctx = SSL_CTX_new(TLS_method());
size_t i;
+ if (ctx == NULL) {
+ goto done;
+ }
+
if (!SSL_CTX_set_cipher_list(ctx, t->rule)) {
fprintf(stderr, "Error testing cipher rule '%s'\n", t->rule);
BIO_print_errors_fp(stderr);
@@ -243,7 +247,9 @@ static int test_cipher_rule(CIPHER_TEST *t) {
ret = 1;
done:
- SSL_CTX_free(ctx);
+ if (ctx != NULL) {
+ SSL_CTX_free(ctx);
+ }
return ret;
}
@@ -257,8 +263,12 @@ static int test_cipher_rules(void) {
for (i = 0; kBadRules[i] != NULL; i++) {
SSL_CTX *ctx = SSL_CTX_new(SSLv23_server_method());
+ if (ctx == NULL) {
+ return 0;
+ }
if (SSL_CTX_set_cipher_list(ctx, kBadRules[i])) {
fprintf(stderr, "Cipher rule '%s' unexpectedly succeeded\n", kBadRules[i]);
+ SSL_CTX_free(ctx);
return 0;
}
ERR_clear_error();
@@ -420,7 +430,8 @@ static int test_ssl_session_asn1(const char *input_b64) {
return ret;
}
-int test_default_version(uint16_t version, const SSL_METHOD *(*method)(void)) {
+static int test_default_version(uint16_t version,
+ const SSL_METHOD *(*method)(void)) {
SSL_CTX *ctx;
int ret;
@@ -434,6 +445,78 @@ int test_default_version(uint16_t version, const SSL_METHOD *(*method)(void)) {
return ret;
}
+static char *cipher_get_rfc_name(const char *name) {
+ SSL_CTX *ctx = SSL_CTX_new(TLS_method());
+ char *ret = NULL;
+
+ if (ctx == NULL) {
+ goto done;
+ }
+
+ if (!SSL_CTX_set_cipher_list(ctx, name) ||
+ sk_SSL_CIPHER_num(ctx->cipher_list->ciphers) != 1) {
+ fprintf(stderr, "Error finding cipher '%s'\n", name);
+ BIO_print_errors_fp(stderr);
+ goto done;
+ }
+
+ const SSL_CIPHER *cipher = sk_SSL_CIPHER_value(ctx->cipher_list->ciphers, 0);
+ ret = SSL_CIPHER_get_rfc_name(cipher);
+
+done:
+ if (ctx != NULL) {
+ SSL_CTX_free(ctx);
+ }
+ return ret;
+}
+
+typedef struct {
+ const char *name;
+ const char *rfc_name;
+} CIPHER_RFC_NAME_TEST;
+
+static const CIPHER_RFC_NAME_TEST kCipherRFCNameTests[] = {
+ { "DES-CBC3-SHA", "TLS_RSA_WITH_3DES_EDE_CBC_SHA" },
+ { "RC4-MD5", "TLS_RSA_WITH_RC4_MD5" },
+ { "AES128-SHA", "TLS_RSA_WITH_AES_128_CBC_SHA" },
+ { "ADH-AES128-SHA", "TLS_DH_anon_WITH_AES_128_CBC_SHA" },
+ { "DHE-RSA-AES256-SHA", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA" },
+ { "DHE-RSA-AES256-SHA256", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256" },
+ { "AECDH-AES128-SHA", "TLS_ECDH_anon_WITH_AES_128_CBC_SHA" },
+ { "ECDHE-RSA-AES128-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256" },
+ { "ECDHE-RSA-AES256-SHA384", "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384" },
+ { "ECDHE-RSA-AES128-GCM-SHA256", "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" },
+ { "ECDHE-ECDSA-AES128-GCM-SHA256", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" },
+ { "ECDHE-ECDSA-AES256-GCM-SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" },
+ { "PSK-RC4-SHA", "TLS_PSK_WITH_RC4_SHA" },
+ /* These names are non-standard: */
+ { "ECDHE-RSA-CHACHA20-POLY1305", "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" },
+ { "ECDHE-ECDSA-CHACHA20-POLY1305", "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" },
+ { "ECDHE-PSK-WITH-AES-128-GCM-SHA256", "TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256" },
+};
+
+static int test_cipher_get_rfc_name() {
+ size_t i;
+
+ for (i = 0; i < sizeof(kCipherRFCNameTests) / sizeof(kCipherRFCNameTests[0]);
+ i++) {
+ const CIPHER_RFC_NAME_TEST *test = &kCipherRFCNameTests[i];
+ char *rfc_name = cipher_get_rfc_name(test->name);
+ if (rfc_name == NULL) {
+ fprintf(stderr, "cipher_get_rfc_name failed on '%s'\n", test->name);
+ return 0;
+ }
+ if (strcmp(rfc_name, test->rfc_name) != 0) {
+ fprintf(stderr, "SSL_CIPHER_get_rfc_name: got '%s', wanted '%s'\n",
+ rfc_name, test->rfc_name);
+ OPENSSL_free(rfc_name);
+ return 0;
+ }
+ OPENSSL_free(rfc_name);
+ }
+ return 1;
+}
+
int main(void) {
SSL_library_init();
@@ -447,7 +530,8 @@ int main(void) {
!test_default_version(TLS1_2_VERSION, &TLSv1_2_method) ||
!test_default_version(0, &DTLS_method) ||
!test_default_version(DTLS1_VERSION, &DTLSv1_method) ||
- !test_default_version(DTLS1_2_VERSION, &DTLSv1_2_method)) {
+ !test_default_version(DTLS1_2_VERSION, &DTLSv1_2_method) ||
+ !test_cipher_get_rfc_name()) {
return 1;
}