diff options
-rw-r--r-- | doc/man3/SSL_get_ciphers.pod | 19 | ||||
-rw-r--r-- | include/openssl/ssl.h | 7 | ||||
-rw-r--r-- | ssl/ssl_err.c | 1 | ||||
-rw-r--r-- | ssl/ssl_lib.c | 139 | ||||
-rw-r--r-- | ssl/ssl_locl.h | 11 | ||||
-rw-r--r-- | ssl/statem/statem_srvr.c | 38 |
6 files changed, 124 insertions, 91 deletions
diff --git a/doc/man3/SSL_get_ciphers.pod b/doc/man3/SSL_get_ciphers.pod index 5933bf5..d1baafe 100644 --- a/doc/man3/SSL_get_ciphers.pod +++ b/doc/man3/SSL_get_ciphers.pod @@ -15,9 +15,9 @@ SSL_bytes_to_cipher_list, SSL_get_cipher_list STACK_OF(SSL_CIPHER) *SSL_CTX_get_ciphers(const SSL_CTX *ctx); STACK_OF(SSL_CIPHER) *SSL_get1_supported_ciphers(SSL *s); STACK_OF(SSL_CIPHER) *SSL_get_client_ciphers(const SSL *ssl); - STACK_OF(SSL_CIPHER) *SSL_bytes_to_cipher_list(SSL *s, - const unsigned char *bytes, - size_t len, int isv2format) + int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len, + int isv2format, STACK_OF(SSL_CIPHER) **sk, + STACK_OF(SSL_CIPHER) **scsvs); const char *SSL_get_cipher_list(const SSL *ssl, int priority); =head1 DESCRIPTION @@ -49,8 +49,9 @@ SSL_bytes_to_cipher_list() treats the supplied B<len> octets in B<bytes> as a wire-protocol cipher suite specification (in the three-octet-per-cipher SSLv2 wire format if B<isv2format> is nonzero; otherwise the two-octet SSLv3/TLS wire format), and parses the cipher suites supported by the library -into the returned stack of SSL_CIPHER objects. Unsupported cipher suites -are ignored, and NULL is returned on error. +into the returned stacks of SSL_CIPHER objects sk and Signalling Cipher-Suite +Values scsvs. Unsupported cipher suites are ignored. Returns 1 on success +and 0 on failure. SSL_get_cipher_list() returns a pointer to the name of the SSL_CIPHER listed for B<ssl> with B<priority>. If B<ssl> is NULL, no ciphers are @@ -74,19 +75,13 @@ free the return value itself. The stack returned by SSL_get1_supported_ciphers() should be freed using sk_SSL_CIPHER_free(). -The stack returned by SSL_bytes_to_cipher_list() should be freed using +The stacks returned by SSL_bytes_to_cipher_list() should be freed using sk_SSL_CIPHER_free(). =head1 RETURN VALUES See DESCRIPTION -=head1 BUGS - -The implementation of SSL_bytes_to_cipher_list() mutates state in the -supplied SSL object B<s>; SSL_bytes_to_cipher_list() should not be called -on a server SSL object after that server has processed the received ClientHello. - =head1 SEE ALSO L<ssl(7)>, L<SSL_CTX_set_cipher_list(3)>, diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 3716922..cb4dbff 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1820,9 +1820,9 @@ __owur int SSL_COMP_add_compression_method(int id, COMP_METHOD *cm); const SSL_CIPHER *SSL_CIPHER_find(SSL *ssl, const unsigned char *ptr); int SSL_CIPHER_get_cipher_nid(const SSL_CIPHER *c); int SSL_CIPHER_get_digest_nid(const SSL_CIPHER *c); -STACK_OF(SSL_CIPHER) *SSL_bytes_to_cipher_list(SSL *s, - const unsigned char *bytes, - size_t len, int isv2format); +int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len, + int isv2format, STACK_OF(SSL_CIPHER) **sk, + STACK_OF(SSL_CIPHER) **scsvs); /* TLS extensions functions */ __owur int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len); @@ -2164,6 +2164,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_BAD_METHOD 160 # define SSL_F_SSL_BUILD_CERT_CHAIN 332 # define SSL_F_SSL_BYTES_TO_CIPHER_LIST 161 +# define SSL_F_SSL_CACHE_CIPHERLIST 520 # define SSL_F_SSL_CERT_ADD0_CHAIN_CERT 346 # define SSL_F_SSL_CERT_DUP 221 # define SSL_F_SSL_CERT_NEW 162 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index 81b3a67..d937ba2 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -118,6 +118,7 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_SSL_BAD_METHOD), "ssl_bad_method"}, {ERR_FUNC(SSL_F_SSL_BUILD_CERT_CHAIN), "ssl_build_cert_chain"}, {ERR_FUNC(SSL_F_SSL_BYTES_TO_CIPHER_LIST), "SSL_bytes_to_cipher_list"}, + {ERR_FUNC(SSL_F_SSL_CACHE_CIPHERLIST), "ssl_cache_cipherlist"}, {ERR_FUNC(SSL_F_SSL_CERT_ADD0_CHAIN_CERT), "ssl_cert_add0_chain_cert"}, {ERR_FUNC(SSL_F_SSL_CERT_DUP), "ssl_cert_dup"}, {ERR_FUNC(SSL_F_SSL_CERT_NEW), "ssl_cert_new"}, diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 56c6a24..ff99c0f 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -4402,54 +4402,26 @@ int ssl_log_secret(SSL *ssl, secret_len); } - -STACK_OF(SSL_CIPHER) *SSL_bytes_to_cipher_list(SSL *s, - const unsigned char *bytes, - size_t len, int isv2format) -{ - int alert; - PACKET pkt; - - if (!PACKET_buf_init(&pkt, bytes, len)) - return 0; - return bytes_to_cipher_list(s, &pkt, NULL, isv2format, &alert); -} - #define SSLV2_CIPHER_LEN 3 -STACK_OF(SSL_CIPHER) *bytes_to_cipher_list(SSL *s, - PACKET *cipher_suites, - STACK_OF(SSL_CIPHER) **skp, - int sslv2format, int *al) +int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, int sslv2format, + int *al) { - const SSL_CIPHER *c; - STACK_OF(SSL_CIPHER) *sk; int n; - /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */ - unsigned char cipher[SSLV2_CIPHER_LEN]; - - s->s3->send_connection_binding = 0; n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN; if (PACKET_remaining(cipher_suites) == 0) { - SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED); + SSLerr(SSL_F_SSL_CACHE_CIPHERLIST, SSL_R_NO_CIPHERS_SPECIFIED); *al = SSL_AD_ILLEGAL_PARAMETER; - return NULL; + return 0; } if (PACKET_remaining(cipher_suites) % n != 0) { - SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, + SSLerr(SSL_F_SSL_CACHE_CIPHERLIST, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); *al = SSL_AD_DECODE_ERROR; - return NULL; - } - - sk = sk_SSL_CIPHER_new_null(); - if (sk == NULL) { - SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); - *al = SSL_AD_INTERNAL_ERROR; - return NULL; + return 0; } OPENSSL_free(s->s3->tmp.ciphers_raw); @@ -4498,6 +4470,57 @@ STACK_OF(SSL_CIPHER) *bytes_to_cipher_list(SSL *s, *al = SSL_AD_INTERNAL_ERROR; goto err; } + return 1; + err: + return 0; +} + +int SSL_bytes_to_cipher_list(SSL *s, const unsigned char *bytes, size_t len, + int isv2format, STACK_OF(SSL_CIPHER) **sk, + STACK_OF(SSL_CIPHER) **scsvs) +{ + int alert; + PACKET pkt; + + if (!PACKET_buf_init(&pkt, bytes, len)) + return 0; + return bytes_to_cipher_list(s, &pkt, sk, scsvs, isv2format, &alert); +} + +int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites, + STACK_OF(SSL_CIPHER) **skp, + STACK_OF(SSL_CIPHER) **scsvs_out, + int sslv2format, int *al) +{ + const SSL_CIPHER *c; + STACK_OF(SSL_CIPHER) *sk = NULL; + STACK_OF(SSL_CIPHER) *scsvs = NULL; + int n; + /* 3 = SSLV2_CIPHER_LEN > TLS_CIPHER_LEN = 2. */ + unsigned char cipher[SSLV2_CIPHER_LEN]; + + n = sslv2format ? SSLV2_CIPHER_LEN : TLS_CIPHER_LEN; + + if (PACKET_remaining(cipher_suites) == 0) { + SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, SSL_R_NO_CIPHERS_SPECIFIED); + *al = SSL_AD_ILLEGAL_PARAMETER; + return 0; + } + + if (PACKET_remaining(cipher_suites) % n != 0) { + SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, + SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST); + *al = SSL_AD_DECODE_ERROR; + return 0; + } + + sk = sk_SSL_CIPHER_new_null(); + scsvs = sk_SSL_CIPHER_new_null(); + if (sk == NULL || scsvs == NULL) { + SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); + *al = SSL_AD_INTERNAL_ERROR; + goto err; + } while (PACKET_copy_bytes(cipher_suites, cipher, n)) { /* @@ -4508,41 +4531,11 @@ STACK_OF(SSL_CIPHER) *bytes_to_cipher_list(SSL *s, if (sslv2format && cipher[0] != '\0') continue; - /* Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV */ - if ((cipher[n - 2] == ((SSL3_CK_SCSV >> 8) & 0xff)) && - (cipher[n - 1] == (SSL3_CK_SCSV & 0xff))) { - /* SCSV fatal if renegotiating */ - if (s->renegotiate) { - SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, - SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); - *al = SSL_AD_HANDSHAKE_FAILURE; - goto err; - } - s->s3->send_connection_binding = 1; - continue; - } - - /* Check for TLS_FALLBACK_SCSV */ - if ((cipher[n - 2] == ((SSL3_CK_FALLBACK_SCSV >> 8) & 0xff)) && - (cipher[n - 1] == (SSL3_CK_FALLBACK_SCSV & 0xff))) { - /* - * The SCSV indicates that the client previously tried a higher - * version. Fail if the current version is an unexpected - * downgrade. - */ - if (!ssl_check_version_downgrade(s)) { - SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, - SSL_R_INAPPROPRIATE_FALLBACK); - *al = SSL_AD_INAPPROPRIATE_FALLBACK; - goto err; - } - continue; - } - /* For SSLv2-compat, ignore leading 0-byte. */ c = ssl_get_cipher_by_char(s, sslv2format ? &cipher[1] : cipher, 1); if (c != NULL) { - if (!sk_SSL_CIPHER_push(sk, c)) { + if ((c->valid && !sk_SSL_CIPHER_push(sk, c)) || + (!c->valid && !sk_SSL_CIPHER_push(scsvs, c))) { SSLerr(SSL_F_BYTES_TO_CIPHER_LIST, ERR_R_MALLOC_FAILURE); *al = SSL_AD_INTERNAL_ERROR; goto err; @@ -4555,9 +4548,17 @@ STACK_OF(SSL_CIPHER) *bytes_to_cipher_list(SSL *s, goto err; } - *skp = sk; - return sk; + if (skp != NULL) + *skp = sk; + else + sk_SSL_CIPHER_free(sk); + if (scsvs_out != NULL) + *scsvs_out = scsvs; + else + sk_SSL_CIPHER_free(scsvs); + return 1; err: sk_SSL_CIPHER_free(sk); - return NULL; + sk_SSL_CIPHER_free(scsvs); + return 0; } diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 59605f5..40bcdd2 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -1991,11 +1991,12 @@ __owur STACK_OF(SSL_CIPHER) *ssl_create_cipher_list(const SSL_METHOD *meth, **sorted, const char *rule_str, CERT *c); -__owur STACK_OF(SSL_CIPHER) *bytes_to_cipher_list(SSL *s, - PACKET *cipher_suites, - STACK_OF(SSL_CIPHER) - **skp, int sslv2format, - int *al); +__owur int ssl_cache_cipherlist(SSL *s, PACKET *cipher_suites, + int sslv2format, int *al); +__owur int bytes_to_cipher_list(SSL *s, PACKET *cipher_suites, + STACK_OF(SSL_CIPHER) **skp, + STACK_OF(SSL_CIPHER) **scsvs, int sslv2format, + int *al); void ssl_update_cache(SSL *s, int mode); __owur int ssl_cipher_get_evp(const SSL_SESSION *s, const EVP_CIPHER **enc, const EVP_MD **md, int *mac_pkey_type, diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 00e69a6..880996b 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1226,6 +1226,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) SSL_COMP *comp = NULL; #endif STACK_OF(SSL_CIPHER) *ciphers = NULL; + STACK_OF(SSL_CIPHER) *scsvs = NULL; int protverr; /* |cookie| will only be initialized for DTLS. */ PACKET session_id, compression, extensions, cookie; @@ -1546,11 +1547,44 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt) } } - if (bytes_to_cipher_list(s, &clienthello.ciphersuites, &ciphers, - clienthello.isv2, &al) == NULL) { + if (!ssl_cache_cipherlist(s, &clienthello.ciphersuites, + clienthello.isv2, &al) || + !bytes_to_cipher_list(s, &clienthello.ciphersuites, &ciphers, &scsvs, + clienthello.isv2, &al)) { goto f_err; } + s->s3->send_connection_binding = 0; + /* Check what signalling cipher-suite values were received. */ + if (scsvs != NULL) { + for(i = 0; i < sk_SSL_CIPHER_num(scsvs); i++) { + c = sk_SSL_CIPHER_value(scsvs, i); + if (SSL_CIPHER_get_id(c) == SSL3_CK_SCSV) { + if (s->renegotiate) { + /* SCSV is fatal if renegotiating */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING); + al = SSL_AD_HANDSHAKE_FAILURE; + goto f_err; + } + s->s3->send_connection_binding = 1; + } else if (SSL_CIPHER_get_id(c) == SSL3_CK_FALLBACK_SCSV && + !ssl_check_version_downgrade(s)) { + /* + * This SCSV indicates that the client previously tried + * a higher version. We should fail if the current version + * is an unexpected downgrade, as that indicates that the first + * connection may have been tampered with in order to trigger + * an insecure downgrade. + */ + SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, + SSL_R_INAPPROPRIATE_FALLBACK); + al = SSL_AD_INAPPROPRIATE_FALLBACK; + goto f_err; + } + } + } + /* If it is a hit, check that the cipher is in the list */ if (s->hit) { j = 0; |