mirror of
https://github.com/QuasarApp/openssl.git
synced 2025-05-18 12:29:42 +00:00
Fix logic around when to send an HRR based on cookies
Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/4435)
This commit is contained in:
parent
042c57539b
commit
c36001c3a8
@ -5310,5 +5310,8 @@ int SSL_stateless(SSL *s)
|
|||||||
ret = SSL_accept(s);
|
ret = SSL_accept(s);
|
||||||
s->s3->flags &= ~TLS1_FLAGS_STATELESS;
|
s->s3->flags &= ~TLS1_FLAGS_STATELESS;
|
||||||
|
|
||||||
|
if (s->ext.cookieok)
|
||||||
|
return 1;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1276,6 +1276,9 @@ struct ssl_st {
|
|||||||
/* May be sent by a server in HRR. Must be echoed back in ClientHello */
|
/* May be sent by a server in HRR. Must be echoed back in ClientHello */
|
||||||
unsigned char *tls13_cookie;
|
unsigned char *tls13_cookie;
|
||||||
size_t tls13_cookie_len;
|
size_t tls13_cookie_len;
|
||||||
|
/* Have we received a cookie from the client? */
|
||||||
|
int cookieok;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Maximum Fragment Length as per RFC 4366.
|
* Maximum Fragment Length as per RFC 4366.
|
||||||
* If this member contains one of the allowed values (1-4)
|
* If this member contains one of the allowed values (1-4)
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "internal/cryptlib.h"
|
#include "internal/cryptlib.h"
|
||||||
#include "../ssl_locl.h"
|
#include "../ssl_locl.h"
|
||||||
#include "statem_locl.h"
|
#include "statem_locl.h"
|
||||||
|
#include "internal/cryptlib.h"
|
||||||
|
|
||||||
static int final_renegotiate(SSL *s, unsigned int context, int sent);
|
static int final_renegotiate(SSL *s, unsigned int context, int sent);
|
||||||
static int init_server_name(SSL *s, unsigned int context);
|
static int init_server_name(SSL *s, unsigned int context);
|
||||||
@ -1237,85 +1238,136 @@ static int final_key_share(SSL *s, unsigned int context, int sent)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* If
|
* IF
|
||||||
* we are a server
|
* we are a server
|
||||||
* AND
|
|
||||||
* we have no key_share
|
|
||||||
* THEN
|
* THEN
|
||||||
* If
|
* IF
|
||||||
* we didn't already send a HelloRetryRequest
|
* we have a suitable key_share
|
||||||
* AND
|
|
||||||
* the client sent a key_share extension
|
|
||||||
* AND
|
|
||||||
* (we are not resuming
|
|
||||||
* OR the kex_mode allows key_share resumes)
|
|
||||||
* AND
|
|
||||||
* a shared group exists
|
|
||||||
* THEN
|
* THEN
|
||||||
* send a HelloRetryRequest
|
* IF
|
||||||
* ELSE If
|
* we are stateless AND we have no cookie
|
||||||
* we are not resuming
|
* THEN
|
||||||
* OR
|
* send a HelloRetryRequest
|
||||||
* the kex_mode doesn't allow non key_share resumes
|
* ELSE
|
||||||
* THEN
|
* IF
|
||||||
* fail;
|
* we didn't already send a HelloRetryRequest
|
||||||
|
* AND
|
||||||
|
* the client sent a key_share extension
|
||||||
|
* AND
|
||||||
|
* (we are not resuming
|
||||||
|
* OR the kex_mode allows key_share resumes)
|
||||||
|
* AND
|
||||||
|
* a shared group exists
|
||||||
|
* THEN
|
||||||
|
* send a HelloRetryRequest
|
||||||
|
* ELSE IF
|
||||||
|
* we are not resuming
|
||||||
|
* OR
|
||||||
|
* the kex_mode doesn't allow non key_share resumes
|
||||||
|
* THEN
|
||||||
|
* fail
|
||||||
|
* ELSE IF
|
||||||
|
* we are stateless AND we have no cookie
|
||||||
|
* THEN
|
||||||
|
* send a HelloRetryRequest
|
||||||
*/
|
*/
|
||||||
if (s->server && s->s3->peer_tmp == NULL) {
|
if (s->server) {
|
||||||
/* No suitable share */
|
if (s->s3->peer_tmp != NULL) {
|
||||||
if (s->hello_retry_request == SSL_HRR_NONE && sent
|
/* We have a suitable key_share */
|
||||||
&& (!s->hit
|
if ((s->s3->flags & TLS1_FLAGS_STATELESS) != 0
|
||||||
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
|
&& !s->ext.cookieok) {
|
||||||
!= 0)) {
|
if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
|
||||||
const uint16_t *pgroups, *clntgroups;
|
/*
|
||||||
size_t num_groups, clnt_num_groups, i;
|
* If we are stateless then we wouldn't know about any
|
||||||
unsigned int group_id = 0;
|
* previously sent HRR - so how can this be anything other
|
||||||
|
* than 0?
|
||||||
|
*/
|
||||||
|
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
|
||||||
|
ERR_R_INTERNAL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s->hello_retry_request = SSL_HRR_PENDING;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* No suitable key_share */
|
||||||
|
if (s->hello_retry_request == SSL_HRR_NONE && sent
|
||||||
|
&& (!s->hit
|
||||||
|
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE)
|
||||||
|
!= 0)) {
|
||||||
|
const uint16_t *pgroups, *clntgroups;
|
||||||
|
size_t num_groups, clnt_num_groups, i;
|
||||||
|
unsigned int group_id = 0;
|
||||||
|
|
||||||
/* Check if a shared group exists */
|
/* Check if a shared group exists */
|
||||||
|
|
||||||
/* Get the clients list of supported groups. */
|
/* Get the clients list of supported groups. */
|
||||||
tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
|
tls1_get_peer_groups(s, &clntgroups, &clnt_num_groups);
|
||||||
tls1_get_supported_groups(s, &pgroups, &num_groups);
|
tls1_get_supported_groups(s, &pgroups, &num_groups);
|
||||||
|
|
||||||
/* Find the first group we allow that is also in client's list */
|
/*
|
||||||
for (i = 0; i < num_groups; i++) {
|
* Find the first group we allow that is also in client's list
|
||||||
group_id = pgroups[i];
|
*/
|
||||||
|
for (i = 0; i < num_groups; i++) {
|
||||||
|
group_id = pgroups[i];
|
||||||
|
|
||||||
if (check_in_list(s, group_id, clntgroups, clnt_num_groups, 1))
|
if (check_in_list(s, group_id, clntgroups, clnt_num_groups,
|
||||||
break;
|
1))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < num_groups) {
|
||||||
|
/* A shared group exists so send a HelloRetryRequest */
|
||||||
|
s->s3->group_id = group_id;
|
||||||
|
s->hello_retry_request = SSL_HRR_PENDING;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!s->hit
|
||||||
|
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
|
||||||
|
/* Nothing left we can do - just fail */
|
||||||
|
SSLfatal(s, sent ? SSL_AD_HANDSHAKE_FAILURE
|
||||||
|
: SSL_AD_MISSING_EXTENSION,
|
||||||
|
SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < num_groups) {
|
if ((s->s3->flags & TLS1_FLAGS_STATELESS) != 0
|
||||||
/* A shared group exists so send a HelloRetryRequest */
|
&& !s->ext.cookieok) {
|
||||||
s->s3->group_id = group_id;
|
if (!ossl_assert(s->hello_retry_request == SSL_HRR_NONE)) {
|
||||||
|
/*
|
||||||
|
* If we are stateless then we wouldn't know about any
|
||||||
|
* previously sent HRR - so how can this be anything other
|
||||||
|
* than 0?
|
||||||
|
*/
|
||||||
|
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
|
||||||
|
ERR_R_INTERNAL_ERROR);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
s->hello_retry_request = SSL_HRR_PENDING;
|
s->hello_retry_request = SSL_HRR_PENDING;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!s->hit
|
|
||||||
|| (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0) {
|
/*
|
||||||
/* Nothing left we can do - just fail */
|
* We have a key_share so don't send any more HelloRetryRequest
|
||||||
SSLfatal(s,
|
* messages
|
||||||
sent ? SSL_AD_HANDSHAKE_FAILURE : SSL_AD_MISSING_EXTENSION,
|
*/
|
||||||
SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
|
if (s->hello_retry_request == SSL_HRR_PENDING)
|
||||||
|
s->hello_retry_request = SSL_HRR_COMPLETE;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* For a client side resumption with no key_share we need to generate
|
||||||
|
* the handshake secret (otherwise this is done during key_share
|
||||||
|
* processing).
|
||||||
|
*/
|
||||||
|
if (!sent && !tls13_generate_handshake_secret(s, NULL, 0)) {
|
||||||
|
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
|
||||||
|
ERR_R_INTERNAL_ERROR);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have a key_share so don't send any more HelloRetryRequest messages */
|
|
||||||
if (s->server && s->hello_retry_request == SSL_HRR_PENDING)
|
|
||||||
s->hello_retry_request = SSL_HRR_COMPLETE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For a client side resumption with no key_share we need to generate
|
|
||||||
* the handshake secret (otherwise this is done during key_share
|
|
||||||
* processing).
|
|
||||||
*/
|
|
||||||
if (!sent && !s->server && !tls13_generate_handshake_secret(s, NULL, 0)) {
|
|
||||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_FINAL_KEY_SHARE,
|
|
||||||
ERR_R_INTERNAL_ERROR);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -895,6 +895,8 @@ int tls_parse_ctos_cookie(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
|||||||
/* Act as if this ClientHello came after a HelloRetryRequest */
|
/* Act as if this ClientHello came after a HelloRetryRequest */
|
||||||
s->hello_retry_request = 1;
|
s->hello_retry_request = 1;
|
||||||
|
|
||||||
|
s->ext.cookieok = 1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,7 +687,8 @@ WORK_STATE ossl_statem_server_pre_work(SSL *s, WORK_STATE wst)
|
|||||||
return WORK_FINISHED_CONTINUE;
|
return WORK_FINISHED_CONTINUE;
|
||||||
|
|
||||||
case TLS_ST_EARLY_DATA:
|
case TLS_ST_EARLY_DATA:
|
||||||
if (s->early_data_state != SSL_EARLY_DATA_ACCEPTING)
|
if (s->early_data_state != SSL_EARLY_DATA_ACCEPTING
|
||||||
|
&& (s->s3->flags & TLS1_FLAGS_STATELESS) == 0)
|
||||||
return WORK_FINISHED_CONTINUE;
|
return WORK_FINISHED_CONTINUE;
|
||||||
/* Fall through */
|
/* Fall through */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user