diff options
-rw-r--r-- | lib/libssl/ssl.h | 8 | ||||
-rw-r--r-- | lib/libssl/ssl_ciph.c | 17 | ||||
-rw-r--r-- | lib/libssl/ssl_ciphers.c | 129 | ||||
-rw-r--r-- | lib/libssl/ssl_lib.c | 57 | ||||
-rw-r--r-- | lib/libssl/ssl_locl.h | 13 |
5 files changed, 211 insertions, 13 deletions
diff --git a/lib/libssl/ssl.h b/lib/libssl/ssl.h index 4370c84cd76..eb288699b1c 100644 --- a/lib/libssl/ssl.h +++ b/lib/libssl/ssl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl.h,v 1.171 2020/03/16 15:25:13 tb Exp $ */ +/* $OpenBSD: ssl.h,v 1.172 2020/09/13 16:49:05 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1275,6 +1275,9 @@ void BIO_ssl_shutdown(BIO *ssl_bio); STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx); int SSL_CTX_set_cipher_list(SSL_CTX *, const char *str); +#if defined(LIBRESSL_HAS_TLS1_3) || defined(LIBRESSL_INTERNAL) +int SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str); +#endif SSL_CTX *SSL_CTX_new(const SSL_METHOD *meth); void SSL_CTX_free(SSL_CTX *); int SSL_CTX_up_ref(SSL_CTX *ctx); @@ -1316,6 +1319,9 @@ void SSL_set_bio(SSL *s, BIO *rbio, BIO *wbio); BIO * SSL_get_rbio(const SSL *s); BIO * SSL_get_wbio(const SSL *s); int SSL_set_cipher_list(SSL *s, const char *str); +#if defined(LIBRESSL_HAS_TLS1_3) || defined(LIBRESSL_INTERNAL) +int SSL_set_ciphersuites(SSL *s, const char *str); +#endif void SSL_set_read_ahead(SSL *s, int yes); int SSL_get_verify_mode(const SSL *s); int SSL_get_verify_depth(const SSL *s); diff --git a/lib/libssl/ssl_ciph.c b/lib/libssl/ssl_ciph.c index 4afbcf98963..fd576cee7b1 100644 --- a/lib/libssl/ssl_ciph.c +++ b/lib/libssl/ssl_ciph.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_ciph.c,v 1.118 2020/09/11 17:36:27 jsing Exp $ */ +/* $OpenBSD: ssl_ciph.c,v 1.119 2020/09/13 16:49:05 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -1184,6 +1184,7 @@ ssl_aes_is_accelerated(void) STACK_OF(SSL_CIPHER) * ssl_create_cipher_list(const SSL_METHOD *ssl_method, STACK_OF(SSL_CIPHER) **cipher_list, + STACK_OF(SSL_CIPHER) *cipher_list_tls13, const char *rule_str) { int ok, num_of_ciphers, num_of_alias_max, num_of_group_aliases; @@ -1192,8 +1193,10 @@ ssl_create_cipher_list(const SSL_METHOD *ssl_method, const char *rule_p; CIPHER_ORDER *co_list = NULL, *head = NULL, *tail = NULL, *curr; const SSL_CIPHER **ca_list = NULL; + const SSL_CIPHER *cipher; int tls13_seen = 0; int any_active; + int i; /* * Return with error if nothing to do. @@ -1335,11 +1338,21 @@ ssl_create_cipher_list(const SSL_METHOD *ssl_method, return (NULL); } + /* Prefer TLSv1.3 cipher suites. */ + if (cipher_list_tls13 != NULL) { + for (i = 0; i < sk_SSL_CIPHER_num(cipher_list_tls13); i++) { + cipher = sk_SSL_CIPHER_value(cipher_list_tls13, i); + sk_SSL_CIPHER_push(cipherstack, cipher); + } + tls13_seen = 1; + } + /* * The cipher selection for the list is done. The ciphers are added * to the resulting precedence to the STACK_OF(SSL_CIPHER). * - * If the rule string did not contain any references to TLSv1.3, + * If the rule string did not contain any references to TLSv1.3 and + * TLSv1.3 cipher suites have not been configured separately, * include inactive TLSv1.3 cipher suites. This avoids attempts to * use TLSv1.3 with an older rule string that does not include * TLSv1.3 cipher suites. If the rule string resulted in no active diff --git a/lib/libssl/ssl_ciphers.c b/lib/libssl/ssl_ciphers.c index 478238bd103..d84e4c6154c 100644 --- a/lib/libssl/ssl_ciphers.c +++ b/lib/libssl/ssl_ciphers.c @@ -1,7 +1,7 @@ -/* $OpenBSD: ssl_ciphers.c,v 1.6 2020/09/11 17:36:27 jsing Exp $ */ +/* $OpenBSD: ssl_ciphers.c,v 1.7 2020/09/13 16:49:05 jsing Exp $ */ /* * Copyright (c) 2015-2017 Doug Hogan <doug@openbsd.org> - * Copyright (c) 2015-2018 Joel Sing <jsing@openbsd.org> + * Copyright (c) 2015-2018, 2020 Joel Sing <jsing@openbsd.org> * Copyright (c) 2019 Theo Buehler <tb@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any @@ -171,3 +171,128 @@ ssl_bytes_to_cipher_list(SSL *s, CBS *cbs) return (NULL); } + +struct ssl_tls13_ciphersuite { + const char *name; + const char *alias; + unsigned long cid; +}; + +static const struct ssl_tls13_ciphersuite ssl_tls13_ciphersuites[] = { + { + .name = TLS1_3_TXT_AES_128_GCM_SHA256, + .alias = "TLS_AES_128_GCM_SHA256", + .cid = TLS1_3_CK_AES_128_GCM_SHA256, + }, + { + .name = TLS1_3_TXT_AES_256_GCM_SHA384, + .alias = "TLS_AES_256_GCM_SHA384", + .cid = TLS1_3_CK_AES_256_GCM_SHA384, + }, + { + .name = TLS1_3_TXT_CHACHA20_POLY1305_SHA256, + .alias = "TLS_CHACHA20_POLY1305_SHA256", + .cid = TLS1_3_CK_CHACHA20_POLY1305_SHA256, + }, + { + .name = TLS1_3_TXT_AES_128_CCM_SHA256, + .alias = "TLS_AES_128_CCM_SHA256", + .cid = TLS1_3_CK_AES_128_CCM_SHA256, + }, + { + .name = TLS1_3_TXT_AES_128_CCM_8_SHA256, + .alias = "TLS_AES_128_CCM_8_SHA256", + .cid = TLS1_3_CK_AES_128_CCM_8_SHA256, + }, + { + .name = NULL, + }, +}; + +int +ssl_parse_ciphersuites(STACK_OF(SSL_CIPHER) **out_ciphers, const char *str) +{ + const struct ssl_tls13_ciphersuite *ciphersuite; + STACK_OF(SSL_CIPHER) *ciphers; + const SSL_CIPHER *cipher; + char *s = NULL; + char *p, *q; + int i; + int ret = 0; + + sk_SSL_CIPHER_free(*out_ciphers); + *out_ciphers = NULL; + + if ((ciphers = sk_SSL_CIPHER_new_null()) == NULL) + goto err; + + /* An empty string is valid and means no ciphers. */ + if (strcmp(str, "") == 0) + goto done; + + if ((s = strdup(str)) == NULL) + goto err; + + q = s; + while ((p = strsep(&q, ":")) != NULL) { + ciphersuite = &ssl_tls13_ciphersuites[0]; + for (i = 0; ciphersuite->name != NULL; i++) { + ciphersuite = &ssl_tls13_ciphersuites[i]; + if (strcmp(p, ciphersuite->name) == 0) + break; + if (strcmp(p, ciphersuite->alias) == 0) + break; + } + if (ciphersuite->name == NULL) + goto err; + + /* We know about the cipher suite, but it is not supported. */ + if ((cipher = ssl3_get_cipher_by_id(ciphersuite->cid)) == NULL) + continue; + + if (!sk_SSL_CIPHER_push(ciphers, cipher)) + goto err; + } + + done: + *out_ciphers = ciphers; + ciphers = NULL; + ret = 1; + + err: + sk_SSL_CIPHER_free(ciphers); + free(s); + + return ret; +} + +int +ssl_merge_cipherlists(STACK_OF(SSL_CIPHER) *cipherlist, + STACK_OF(SSL_CIPHER) *cipherlist_tls13, + STACK_OF(SSL_CIPHER) **out_cipherlist) +{ + STACK_OF(SSL_CIPHER) *ciphers = NULL; + const SSL_CIPHER *cipher; + int i, ret = 0; + + if ((ciphers = sk_SSL_CIPHER_dup(cipherlist_tls13)) == NULL) + goto err; + for (i = 0; i < sk_SSL_CIPHER_num(cipherlist); i++) { + cipher = sk_SSL_CIPHER_value(cipherlist, i); + if (cipher->algorithm_ssl == SSL_TLSV1_3) + continue; + if (!sk_SSL_CIPHER_push(ciphers, cipher)) + goto err; + } + + sk_SSL_CIPHER_free(*out_cipherlist); + *out_cipherlist = ciphers; + ciphers = NULL; + + ret = 1; + + err: + sk_SSL_CIPHER_free(ciphers); + + return ret; +} diff --git a/lib/libssl/ssl_lib.c b/lib/libssl/ssl_lib.c index 5bc759d483c..a194e5639a7 100644 --- a/lib/libssl/ssl_lib.c +++ b/lib/libssl/ssl_lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_lib.c,v 1.225 2020/09/11 17:36:27 jsing Exp $ */ +/* $OpenBSD: ssl_lib.c,v 1.226 2020/09/13 16:49:05 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -230,7 +230,7 @@ SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) ctx->method = meth; ciphers = ssl_create_cipher_list(ctx->method, &ctx->cipher_list, - SSL_DEFAULT_CIPHER_LIST); + ctx->internal->cipher_list_tls13, SSL_DEFAULT_CIPHER_LIST); if (ciphers == NULL || sk_SSL_CIPHER_num(ciphers) <= 0) { SSLerrorx(SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS); return (0); @@ -530,6 +530,7 @@ SSL_free(SSL *s) BUF_MEM_free(s->internal->init_buf); sk_SSL_CIPHER_free(s->cipher_list); + sk_SSL_CIPHER_free(s->internal->cipher_list_tls13); /* Make the next call work :-) */ if (s->session != NULL) { @@ -1353,7 +1354,8 @@ SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) * an error as far as ssl_create_cipher_list is concerned, and hence * ctx->cipher_list has been updated. */ - ciphers = ssl_create_cipher_list(ctx->method, &ctx->cipher_list, str); + ciphers = ssl_create_cipher_list(ctx->method, &ctx->cipher_list, + ctx->internal->cipher_list_tls13, str); if (ciphers == NULL) { return (0); } else if (sk_SSL_CIPHER_num(ciphers) == 0) { @@ -1363,14 +1365,32 @@ SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str) return (1); } +int +SSL_CTX_set_ciphersuites(SSL_CTX *ctx, const char *str) +{ + if (!ssl_parse_ciphersuites(&ctx->internal->cipher_list_tls13, str)) { + SSLerrorx(SSL_R_NO_CIPHER_MATCH); + return 0; + } + if (!ssl_merge_cipherlists(ctx->cipher_list, + ctx->internal->cipher_list_tls13, &ctx->cipher_list)) + return 0; + + return 1; +} + /* Specify the ciphers to be used by the SSL. */ int SSL_set_cipher_list(SSL *s, const char *str) { - STACK_OF(SSL_CIPHER) *ciphers; + STACK_OF(SSL_CIPHER) *ciphers, *ciphers_tls13; + + if ((ciphers_tls13 = s->internal->cipher_list_tls13) == NULL) + ciphers_tls13 = s->ctx->internal->cipher_list_tls13; /* See comment in SSL_CTX_set_cipher_list. */ - ciphers = ssl_create_cipher_list(s->ctx->method, &s->cipher_list, str); + ciphers = ssl_create_cipher_list(s->ctx->method, &s->cipher_list, + ciphers_tls13, str); if (ciphers == NULL) { return (0); } else if (sk_SSL_CIPHER_num(ciphers) == 0) { @@ -1380,6 +1400,25 @@ SSL_set_cipher_list(SSL *s, const char *str) return (1); } +int +SSL_set_ciphersuites(SSL *s, const char *str) +{ + STACK_OF(SSL_CIPHER) *ciphers; + + if ((ciphers = s->cipher_list) == NULL) + ciphers = s->ctx->cipher_list; + + if (!ssl_parse_ciphersuites(&s->internal->cipher_list_tls13, str)) { + SSLerrorx(SSL_R_NO_CIPHER_MATCH); + return (0); + } + if (!ssl_merge_cipherlists(ciphers, s->internal->cipher_list_tls13, + &s->cipher_list)) + return 0; + + return 1; +} + char * SSL_get_shared_ciphers(const SSL *s, char *buf, int len) { @@ -1758,7 +1797,7 @@ SSL_CTX_new(const SSL_METHOD *meth) goto err; ssl_create_cipher_list(ret->method, &ret->cipher_list, - SSL_DEFAULT_CIPHER_LIST); + NULL, SSL_DEFAULT_CIPHER_LIST); if (ret->cipher_list == NULL || sk_SSL_CIPHER_num(ret->cipher_list) <= 0) { SSLerrorx(SSL_R_LIBRARY_HAS_NO_CIPHERS); @@ -1855,6 +1894,7 @@ SSL_CTX_free(SSL_CTX *ctx) X509_STORE_free(ctx->cert_store); sk_SSL_CIPHER_free(ctx->cipher_list); + sk_SSL_CIPHER_free(ctx->internal->cipher_list_tls13); ssl_cert_free(ctx->internal->cert); sk_X509_NAME_pop_free(ctx->internal->client_CA, X509_NAME_free); sk_X509_pop_free(ctx->extra_certs, X509_free); @@ -2451,6 +2491,11 @@ SSL_dup(SSL *s) sk_SSL_CIPHER_dup(s->cipher_list)) == NULL) goto err; } + if (s->internal->cipher_list_tls13 != NULL) { + if ((ret->internal->cipher_list_tls13 = + sk_SSL_CIPHER_dup(s->internal->cipher_list_tls13)) == NULL) + goto err; + } /* Dup the client_CA list */ if (s->internal->client_CA != NULL) { diff --git a/lib/libssl/ssl_locl.h b/lib/libssl/ssl_locl.h index df07ca68a67..540afee004f 100644 --- a/lib/libssl/ssl_locl.h +++ b/lib/libssl/ssl_locl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ssl_locl.h,v 1.290 2020/09/11 17:36:27 jsing Exp $ */ +/* $OpenBSD: ssl_locl.h,v 1.291 2020/09/13 16:49:05 jsing Exp $ */ /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * @@ -599,6 +599,8 @@ typedef struct ssl_ctx_internal_st { CRYPTO_EX_DATA ex_data; + STACK_OF(SSL_CIPHER) *cipher_list_tls13; + struct cert_st /* CERT */ *cert; /* Default values used when no per-SSL value is defined follow */ @@ -743,6 +745,8 @@ typedef struct ssl_internal_st { int hit; /* reusing a previous session */ + STACK_OF(SSL_CIPHER) *cipher_list_tls13; + /* These are the ones being used, the ones in SSL_SESSION are * the ones to be 'copied' into these ones */ int mac_flags; @@ -1164,7 +1168,12 @@ SSL_CIPHER *OBJ_bsearch_ssl_cipher_id(SSL_CIPHER *key, SSL_CIPHER const *base, int ssl_cipher_list_to_bytes(SSL *s, STACK_OF(SSL_CIPHER) *ciphers, CBB *cbb); STACK_OF(SSL_CIPHER) *ssl_bytes_to_cipher_list(SSL *s, CBS *cbs); STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth, - STACK_OF(SSL_CIPHER) **pref, const char *rule_str); + STACK_OF(SSL_CIPHER) **pref, STACK_OF(SSL_CIPHER) *tls13, + const char *rule_str); +int ssl_parse_ciphersuites(STACK_OF(SSL_CIPHER) **out_ciphers, const char *str); +int ssl_merge_cipherlists(STACK_OF(SSL_CIPHER) *cipherlist, + STACK_OF(SSL_CIPHER) *cipherlist_tls13, + STACK_OF(SSL_CIPHER) **out_cipherlist); void ssl_update_cache(SSL *s, int mode); int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, int *mac_pkey_type, int *mac_secret_size); |