Add a helper function for parsing extensions blocks.
TLS 1.3 adds a number of places with extensions blocks that don't easily
fit into our ClientHello/EncryptedExtensions callbacks. Between
HelloRetryRequest, ServerHello, draft 18 going nuts with Certificate,
and NewSessionTicket when we do 0-RTT, this passes the "abstract things
that are repeated three times" sniff test.
For now, it rejects unknown extensions, but it will probably grow an
allow_unknown parameter for NewSessionTicket.
This involves disabling some MSVC warnings, but they're invalid as of
C99 which we otherwise require. See
https://connect.microsoft.com/VisualStudio/feedback/details/1230248/remove-c99-related-warnings-or-make-them-off-by-default
Change-Id: Iea8bf8ab216270c081dd63e79aaad9ec73b3b550
Reviewed-on: https://boringssl-review.googlesource.com/12233
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index e540b77..ebe7703 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -24,6 +24,7 @@
#include <openssl/stack.h>
#include <openssl/x509.h>
+#include "../crypto/internal.h"
#include "internal.h"
@@ -67,97 +68,73 @@
return ssl_hs_error;
}
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
+ int have_cookie, have_key_share;
+ CBS cookie, key_share;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_cookie, &have_cookie, &cookie},
+ };
+
+ uint8_t alert;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
+ }
+
+ if (have_cookie) {
+ CBS cookie_value;
+ if (!CBS_get_u16_length_prefixed(&cookie, &cookie_value) ||
+ CBS_len(&cookie_value) == 0 ||
+ CBS_len(&cookie) != 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
return ssl_hs_error;
}
- switch (type) {
- case TLSEXT_TYPE_cookie: {
- if (hs->cookie != NULL) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
- /* Cookies may be requested whether or not advertised, so no need to
- * check. */
-
- CBS cookie;
- if (!CBS_get_u16_length_prefixed(&extension, &cookie) ||
- CBS_len(&cookie) == 0 ||
- CBS_len(&extension) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- if (!CBS_stow(&cookie, &hs->cookie, &hs->cookie_len)) {
- return ssl_hs_error;
- }
- break;
- }
-
- case TLSEXT_TYPE_key_share: {
- if (hs->retry_group != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
-
- /* key_share is always advertised, so no need to check. */
-
- uint16_t group_id;
- if (!CBS_get_u16(&extension, &group_id) ||
- CBS_len(&extension) != 0) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
-
- /* The group must be supported. */
- const uint16_t *groups;
- size_t groups_len;
- tls1_get_grouplist(ssl, &groups, &groups_len);
- int found = 0;
- for (size_t i = 0; i < groups_len; i++) {
- if (groups[i] == group_id) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
- return ssl_hs_error;
- }
-
- /* Check that the HelloRetryRequest does not request the key share that
- * was provided in the initial ClientHello. */
- if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
- return ssl_hs_error;
- }
-
- SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
- hs->retry_group = group_id;
- break;
- }
-
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
+ if (!CBS_stow(&cookie_value, &hs->cookie, &hs->cookie_len)) {
+ return ssl_hs_error;
}
}
+ if (have_key_share) {
+ uint16_t group_id;
+ if (!CBS_get_u16(&key_share, &group_id) || CBS_len(&key_share) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return ssl_hs_error;
+ }
+
+ /* The group must be supported. */
+ const uint16_t *groups;
+ size_t groups_len;
+ tls1_get_grouplist(ssl, &groups, &groups_len);
+ int found = 0;
+ for (size_t i = 0; i < groups_len; i++) {
+ if (groups[i] == group_id) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
+ }
+
+ /* Check that the HelloRetryRequest does not request the key share that
+ * was provided in the initial ClientHello. */
+ if (SSL_ECDH_CTX_get_id(&hs->ecdh_ctx) == group_id) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
+ OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
+ return ssl_hs_error;
+ }
+
+ SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ hs->retry_group = group_id;
+ }
+
hs->received_hello_retry_request = 1;
hs->state = state_send_second_client_hello;
return ssl_hs_ok;
@@ -225,40 +202,16 @@
/* Parse out the extensions. */
int have_key_share = 0, have_pre_shared_key = 0;
CBS key_share, pre_shared_key;
- while (CBS_len(&extensions) != 0) {
- uint16_t type;
- CBS extension;
- if (!CBS_get_u16(&extensions, &type) ||
- !CBS_get_u16_length_prefixed(&extensions, &extension)) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_PARSE_TLSEXT);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- return ssl_hs_error;
- }
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_key_share, &have_key_share, &key_share},
+ {TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+ };
- switch (type) {
- case TLSEXT_TYPE_key_share:
- if (have_key_share) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
- key_share = extension;
- have_key_share = 1;
- break;
- case TLSEXT_TYPE_pre_shared_key:
- if (have_pre_shared_key) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DUPLICATE_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER);
- return ssl_hs_error;
- }
- pre_shared_key = extension;
- have_pre_shared_key = 1;
- break;
- default:
- OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
- ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
- return ssl_hs_error;
- }
+ uint8_t alert;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types))) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return ssl_hs_error;
}
/* We only support PSK_DHE_KE. */
@@ -268,7 +221,7 @@
return ssl_hs_error;
}
- uint8_t alert = SSL_AD_DECODE_ERROR;
+ alert = SSL_AD_DECODE_ERROR;
if (have_pre_shared_key) {
if (ssl->session == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);