From: Benjamin Saunders Date: Mon, 26 Feb 2018 02:39:11 +0000 (-0800) Subject: Introduce SSL_CTX_set_stateless_cookie_{generate,verify}_cb X-Git-Tag: OpenSSL_1_1_1-pre3~119 X-Git-Url: https://git.openssl.org/?p=openssl.git;a=commitdiff_plain;h=3fa2812f32bdb922d47b84ab7b5a98a807d838c0 Introduce SSL_CTX_set_stateless_cookie_{generate,verify}_cb These functions are similar to SSL_CTX_set_cookie_{generate,verify}_cb, but used for the application-controlled portion of TLS1.3 stateless handshake cookies rather than entire DTLSv1 cookies. Reviewed-by: Ben Kaduk Reviewed-by: Matt Caswell (Merged from https://github.com/openssl/openssl/pull/5463) --- diff --git a/apps/s_apps.h b/apps/s_apps.h index 614aab8036..1ca8ff95c7 100644 --- a/apps/s_apps.h +++ b/apps/s_apps.h @@ -58,6 +58,11 @@ int generate_cookie_callback(SSL *ssl, unsigned char *cookie, int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len); +int generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie, + size_t *cookie_len); +int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie, + size_t cookie_len); + typedef struct ssl_excert_st SSL_EXCERT; void ssl_ctx_set_excert(SSL_CTX *ctx, SSL_EXCERT *exc); diff --git a/apps/s_cb.c b/apps/s_cb.c index 412442db23..820491a037 100644 --- a/apps/s_cb.c +++ b/apps/s_cb.c @@ -755,6 +755,22 @@ int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, return 0; } + +int generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie, + size_t *cookie_len) +{ + unsigned int temp; + int res = generate_cookie_callback(ssl, cookie, &temp); + *cookie_len = temp; + return res; +} + +int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie, + size_t cookie_len) +{ + return verify_cookie_callback(ssl, cookie, cookie_len); +} + #endif /* diff --git a/apps/s_server.c b/apps/s_server.c index bc1d1e5608..d21631e8e6 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -2038,6 +2038,10 @@ int s_server_main(int argc, char *argv[]) SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie_callback); SSL_CTX_set_cookie_verify_cb(ctx, verify_cookie_callback); + /* Set TLS1.3 cookie generation and verification callbacks */ + SSL_CTX_set_stateless_cookie_generate_cb(ctx, generate_stateless_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(ctx, verify_stateless_cookie_callback); + if (ctx2 != NULL) { SSL_CTX_set_verify(ctx2, s_server_verify, verify_callback); if (!SSL_CTX_set_session_id_context(ctx2, diff --git a/doc/man3/DTLSv1_listen.pod b/doc/man3/DTLSv1_listen.pod index 70f6a25cde..858e393161 100644 --- a/doc/man3/DTLSv1_listen.pod +++ b/doc/man3/DTLSv1_listen.pod @@ -64,10 +64,11 @@ does not support this), then B<*peer> will be cleared and the family set to AF_UNSPEC. Typically user code is expected to "connect" the underlying socket to the peer and continue the handshake in a connected state. -Prior to calling these functions user code must ensure that cookie generation +Prior to calling DTLSv1_listen() user code must ensure that cookie generation and verification callbacks have been set up using SSL_CTX_set_cookie_generate_cb() and SSL_CTX_set_cookie_verify_cb() -respectively. +respectively. For SSL_stateless(), SSL_CTX_set_stateless_cookie_generate_cb() +and SSL_CTX_set_stateless_cookie_verify_cb() must be used instead. Since DTLSv1_listen() operates entirely statelessly whilst processing incoming ClientHellos it is unable to process fragmented messages (since this would diff --git a/doc/man3/SSL_CTX_set_stateless_cookie_generate_cb.pod b/doc/man3/SSL_CTX_set_stateless_cookie_generate_cb.pod new file mode 100644 index 0000000000..f29153ed25 --- /dev/null +++ b/doc/man3/SSL_CTX_set_stateless_cookie_generate_cb.pod @@ -0,0 +1,58 @@ +=pod + +=head1 NAME + +SSL_CTX_set_stateless_cookie_generate_cb, +SSL_CTX_set_stateless_cookie_verify_cb +- Callback functions for stateless TLS1.3 cookies + +=head1 SYNOPSIS + + #include + + void SSL_CTX_set_stateless_cookie_generate_cb( + SSL_CTX *ctx, + int (*gen_stateless_cookie_cb) (SSL *ssl, + unsigned char *cookie, + size_t *cookie_len)); + void SSL_CTX_set_stateless_cookie_verify_cb( + SSL_CTX *ctx, + int (*verify_stateless_cookie_cb) (SSL *ssl, + const unsigned char *cookie, + size_t cookie_len)); + +=head1 DESCRIPTION + +SSL_CTX_set_cookie_generate_cb() sets the callback used by L +to generate the application-controlled portion of the cookie provided to clients +in the HelloRetryRequest transmitted as a response to a ClientHello with a +missing or invalid cookie. gen_stateless_cookie_cb() must write at most +SSL_COOKIE_LENGTH bytes into B, and must write the number of bytes +written to B. If a cookie cannot be generated, a zero return value +can be used to abort the handshake. + +SSL_CTX_set_cookie_verify_cb() sets the callback used by L to +determine whether the application-controlled portion of a ClientHello cookie is +valid. A nonzero return value from app_verify_cookie_cb() communicates that the +cookie is valid. The integrity of the entire cookie, including the +application-controlled portion, is automatically verified by HMAC before +verify_stateless_cookie_cb() is called. + +=head1 RETURN VALUES + +Neither function returns a value. + +=head1 SEE ALSO + +L + +=head1 COPYRIGHT + +Copyright 2018 The OpenSSL Project Authors. All Rights Reserved. + +Licensed under the OpenSSL license (the "License"). You may not use +this file except in compliance with the License. You can obtain a copy +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index a47975d355..ec29405c50 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -546,8 +546,8 @@ typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx); # define SSL_CONF_TYPE_DIR 0x3 # define SSL_CONF_TYPE_NONE 0x4 -/* Length of a TLSv1.3 cookie */ -# define SSL_COOKIE_LENGTH 255 +/* Maximum length of the application-controlled segment of a a TLSv1.3 cookie */ +# define SSL_COOKIE_LENGTH 4096 /* * Note: SSL[_CTX]_set_{options,mode} use |= op on the previous value, they @@ -726,6 +726,17 @@ void SSL_CTX_set_cookie_verify_cb(SSL_CTX *ctx, *cookie, unsigned int cookie_len)); + +void SSL_CTX_set_stateless_cookie_generate_cb( + SSL_CTX *ctx, + int (*gen_stateless_cookie_cb) (SSL *ssl, + unsigned char *cookie, + size_t *cookie_len)); +void SSL_CTX_set_stateless_cookie_verify_cb( + SSL_CTX *ctx, + int (*verify_stateless_cookie_cb) (SSL *ssl, + const unsigned char *cookie, + size_t cookie_len)); # ifndef OPENSSL_NO_NEXTPROTONEG typedef int (*SSL_CTX_npn_advertised_cb_func)(SSL *ssl, diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 9eb58342a8..246605c81e 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -820,6 +820,14 @@ struct ssl_ctx_st { int (*app_verify_cookie_cb) (SSL *ssl, const unsigned char *cookie, unsigned int cookie_len); + /* TLS1.3 app-controlled cookie generate callback */ + int (*gen_stateless_cookie_cb) (SSL *ssl, unsigned char *cookie, + size_t *cookie_len); + + /* TLS1.3 verify app-controlled cookie callback */ + int (*verify_stateless_cookie_cb) (SSL *ssl, const unsigned char *cookie, + size_t cookie_len); + CRYPTO_EX_DATA ex_data; const EVP_MD *md5; /* For SSLv3/TLSv1 'ssl3-md5' */ diff --git a/ssl/ssl_sess.c b/ssl/ssl_sess.c index f78c9cde5f..1873237c70 100644 --- a/ssl/ssl_sess.c +++ b/ssl/ssl_sess.c @@ -1301,4 +1301,22 @@ int SSL_SESSION_get0_ticket_appdata(SSL_SESSION *ss, void **data, size_t *len) return 1; } +void SSL_CTX_set_stateless_cookie_generate_cb( + SSL_CTX *ctx, + int (*cb) (SSL *ssl, + unsigned char *cookie, + size_t *cookie_len)) +{ + ctx->gen_stateless_cookie_cb = cb; +} + +void SSL_CTX_set_stateless_cookie_verify_cb( + SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char *cookie, + size_t cookie_len)) +{ + ctx->verify_stateless_cookie_cb = cb; +} + IMPLEMENT_PEM_rw(SSL_SESSION, SSL_SESSION, PEM_STRING_SSL_SESSION, SSL_SESSION) diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 74acdb2d21..425cd80efe 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -729,7 +729,7 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, unsigned long tm, now; /* Ignore any cookie if we're not set up to verify it */ - if (s->ctx->app_verify_cookie_cb == NULL + if (s->ctx->verify_stateless_cookie_cb == NULL || (s->s3->flags & TLS1_FLAGS_STATELESS) == 0) return 1; @@ -852,7 +852,7 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x, } /* Verify the app cookie */ - if (s->ctx->app_verify_cookie_cb(s, PACKET_data(&appcookie), + if (s->ctx->verify_stateless_cookie_cb(s, PACKET_data(&appcookie), PACKET_remaining(&appcookie)) == 0) { SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_CTOS_COOKIE, SSL_R_COOKIE_MISMATCH); @@ -1676,8 +1676,7 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, { unsigned char *hashval1, *hashval2, *appcookie1, *appcookie2, *cookie; unsigned char *hmac, *hmac2; - size_t startlen, ciphlen, totcookielen, hashlen, hmaclen; - unsigned int appcookielen; + size_t startlen, ciphlen, totcookielen, hashlen, hmaclen, appcookielen; EVP_MD_CTX *hctx; EVP_PKEY *pkey; int ret = EXT_RETURN_FAIL; @@ -1685,7 +1684,7 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, if ((s->s3->flags & TLS1_FLAGS_STATELESS) == 0) return EXT_RETURN_NOT_SENT; - if (s->ctx->app_gen_cookie_cb == NULL) { + if (s->ctx->gen_stateless_cookie_cb == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE, SSL_R_NO_COOKIE_CALLBACK_SET); return EXT_RETURN_FAIL; @@ -1733,7 +1732,7 @@ EXT_RETURN tls_construct_stoc_cookie(SSL *s, WPACKET *pkt, unsigned int context, } /* Generate the application cookie */ - if (s->ctx->app_gen_cookie_cb(s, appcookie1, &appcookielen) == 0) { + if (s->ctx->gen_stateless_cookie_cb(s, appcookie1, &appcookielen) == 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_COOKIE, SSL_R_COOKIE_GEN_CALLBACK_FAILURE); return EXT_RETURN_FAIL; diff --git a/test/sslapitest.c b/test/sslapitest.c index ce903646c1..32f60e56e8 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -2723,6 +2723,21 @@ static int verify_cookie_callback(SSL *ssl, const unsigned char *cookie, return 0; } +static int generate_stateless_cookie_callback(SSL *ssl, unsigned char *cookie, + size_t *cookie_len) +{ + unsigned int temp; + int res = generate_cookie_callback(ssl, cookie, &temp); + *cookie_len = temp; + return res; +} + +static int verify_stateless_cookie_callback(SSL *ssl, const unsigned char *cookie, + size_t cookie_len) +{ + return verify_cookie_callback(ssl, cookie, cookie_len); +} + static int test_stateless(void) { SSL_CTX *sctx = NULL, *cctx = NULL; @@ -2754,8 +2769,8 @@ static int test_stateless(void) clientssl = NULL; /* Set up the cookie generation and verification callbacks */ - SSL_CTX_set_cookie_generate_cb(sctx, generate_cookie_callback); - SSL_CTX_set_cookie_verify_cb(sctx, verify_cookie_callback); + SSL_CTX_set_stateless_cookie_generate_cb(sctx, generate_stateless_cookie_callback); + SSL_CTX_set_stateless_cookie_verify_cb(sctx, verify_stateless_cookie_callback); /* * Create a new connection from the client (we can reuse the server SSL diff --git a/util/libssl.num b/util/libssl.num index 6c02a9b154..db844e33cf 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -482,3 +482,5 @@ SSL_use_cert_and_key 482 1_1_1 EXIST::FUNCTION: SSL_SESSION_get0_ticket_appdata 483 1_1_1 EXIST::FUNCTION: SSL_SESSION_set1_ticket_appdata 484 1_1_1 EXIST::FUNCTION: SSL_CTX_set_session_ticket_cb 485 1_1_1 EXIST::FUNCTION: +SSL_CTX_set_stateless_cookie_generate_cb 486 1_1_1 EXIST::FUNCTION: +SSL_CTX_set_stateless_cookie_verify_cb 487 1_1_1 EXIST::FUNCTION: