mirror of
https://github.com/openssl/openssl.git
synced 2024-12-13 12:03:48 +08:00
Promote SSL_get_negotiated_group() for non-TLSv1.3
It can be useful to know what group was used for the handshake's key exchange process even on non-TLS 1.3 connections. Allow this API, new in OpenSSL 3.0.0, to be used on other TLS versions as well. Since pre-TLS-1.3 key exchange occurs only on full handshakes, this necessitates adding a field to the SSL_SESSION object to carry the group information across resumptions. The key exchange group in the SSL_SESSION can also be relevant in TLS 1.3 when the resumption handshake uses the "psk_ke" key-exchange mode, so also track whether a fresh key exchange was done for TLS 1.3. Since the new field is optional in the ASN.1 sense, there is no need to increment SSL_SESSION_ASN1_VERSION (which incurs strong incompatibility churn). Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/14750)
This commit is contained in:
parent
a8457b4c3d
commit
aa6bd216dd
@ -77,10 +77,15 @@ NID_undef is returned. If the NID for the shared group is unknown then the value
|
||||
is set to the bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the
|
||||
group.
|
||||
|
||||
SSL_get_negotiated_group() returns the NID of the negotiated group on a TLSv1.3
|
||||
connection for key exchange. This can be called by either client or server. If
|
||||
the NID for the shared group is unknown then the value is set to the bitwise OR
|
||||
of TLSEXT_nid_unknown (0x1000000) and the id of the group.
|
||||
SSL_get_negotiated_group() returns the NID of the negotiated group used for
|
||||
the handshake key exchange process. For TLSv1.3 connections this typically
|
||||
reflects the state of the current connection, though in the case of PSK-only
|
||||
resumption, the returned value will be from a previous connection. For earlier
|
||||
TLS versions, when a session has been resumed, it always reflects the group
|
||||
used for key exchange during the initial handshake (otherwise it is from the
|
||||
current, non-resumption, connection). This can be called by either client or
|
||||
server. If the NID for the shared group is unknown then the value is set to the
|
||||
bitwise OR of TLSEXT_nid_unknown (0x1000000) and the id of the group.
|
||||
|
||||
All these functions are implemented as macros.
|
||||
|
||||
@ -110,9 +115,8 @@ is -1.
|
||||
When called on a client B<ssl>, SSL_get_shared_group() has no meaning and
|
||||
returns -1.
|
||||
|
||||
SSL_get_negotiated_group() returns the NID of the negotiated group on a
|
||||
TLSv1.3 connection for key exchange. Or it returns NID_undef if no negotiated
|
||||
group.
|
||||
SSL_get_negotiated_group() returns the NID of the negotiated group used for
|
||||
key exchange, or NID_undef if there was no negotiated group.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
|
11
ssl/s3_lib.c
11
ssl/s3_lib.c
@ -3636,9 +3636,16 @@ long ssl3_ctrl(SSL *s, int cmd, long larg, void *parg)
|
||||
return id;
|
||||
}
|
||||
case SSL_CTRL_GET_NEGOTIATED_GROUP:
|
||||
ret = tls1_group_id2nid(s->s3.group_id, 1);
|
||||
break;
|
||||
{
|
||||
unsigned int id;
|
||||
|
||||
if (SSL_IS_TLS13(s) && s->s3.did_kex)
|
||||
id = s->s3.group_id;
|
||||
else
|
||||
id = s->session->kex_group;
|
||||
ret = tls1_group_id2nid(id, 1);
|
||||
break;
|
||||
}
|
||||
case SSL_CTRL_SET_SIGALGS:
|
||||
return tls1_set_sigalgs(s->cert, parg, larg, 0);
|
||||
|
||||
|
@ -43,6 +43,7 @@ typedef struct {
|
||||
ASN1_OCTET_STRING *alpn_selected;
|
||||
uint32_t tlsext_max_fragment_len_mode;
|
||||
ASN1_OCTET_STRING *ticket_appdata;
|
||||
uint32_t kex_group;
|
||||
} SSL_SESSION_ASN1;
|
||||
|
||||
ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
|
||||
@ -73,7 +74,8 @@ ASN1_SEQUENCE(SSL_SESSION_ASN1) = {
|
||||
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, max_early_data, ZUINT32, 15),
|
||||
ASN1_EXP_OPT(SSL_SESSION_ASN1, alpn_selected, ASN1_OCTET_STRING, 16),
|
||||
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, tlsext_max_fragment_len_mode, ZUINT32, 17),
|
||||
ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18)
|
||||
ASN1_EXP_OPT(SSL_SESSION_ASN1, ticket_appdata, ASN1_OCTET_STRING, 18),
|
||||
ASN1_EXP_OPT_EMBED(SSL_SESSION_ASN1, kex_group, UINT32, 19)
|
||||
} static_ASN1_SEQUENCE_END(SSL_SESSION_ASN1)
|
||||
|
||||
IMPLEMENT_STATIC_ASN1_ENCODE_FUNCTIONS(SSL_SESSION_ASN1)
|
||||
@ -134,6 +136,8 @@ int i2d_SSL_SESSION(const SSL_SESSION *in, unsigned char **pp)
|
||||
as.version = SSL_SESSION_ASN1_VERSION;
|
||||
as.ssl_version = in->ssl_version;
|
||||
|
||||
as.kex_group = in->kex_group;
|
||||
|
||||
if (in->cipher == NULL)
|
||||
l = in->cipher_id;
|
||||
else
|
||||
@ -272,6 +276,8 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const unsigned char **pp,
|
||||
|
||||
ret->ssl_version = (int)as->ssl_version;
|
||||
|
||||
ret->kex_group = as->kex_group;
|
||||
|
||||
if (as->cipher->length != 2) {
|
||||
ERR_raise(ERR_LIB_SSL, SSL_R_CIPHER_CODE_WRONG_LENGTH);
|
||||
goto err;
|
||||
|
@ -599,6 +599,7 @@ struct ssl_session_st {
|
||||
const SSL_CIPHER *cipher;
|
||||
unsigned long cipher_id; /* when ASN.1 loaded, this needs to be used to
|
||||
* load the 'cipher' structure */
|
||||
unsigned int kex_group; /* TLS group from key exchange */
|
||||
CRYPTO_EX_DATA ex_data; /* application specific data */
|
||||
/*
|
||||
* These are used to make removal of session-ids more efficient and to
|
||||
@ -1412,6 +1413,12 @@ struct ssl_st {
|
||||
*/
|
||||
char is_probably_safari;
|
||||
|
||||
/*
|
||||
* Track whether we did a key exchange this handshake or not, so
|
||||
* SSL_get_negotiated_group() knows whether to fall back to the
|
||||
* value in the SSL_SESSION.
|
||||
*/
|
||||
char did_kex;
|
||||
/* For clients: peer temporary key */
|
||||
/* The group_id for the key exchange key */
|
||||
uint16_t group_id;
|
||||
|
@ -1793,6 +1793,28 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
|
||||
return 0;
|
||||
}
|
||||
/* Retain this group in the SSL_SESSION */
|
||||
if (!s->hit) {
|
||||
s->session->kex_group = group_id;
|
||||
} else if (group_id != s->session->kex_group) {
|
||||
/*
|
||||
* If this is a resumption but changed what group was used, we need
|
||||
* to record the new group in the session, but the session is not
|
||||
* a new session and could be in use by other threads. So, make
|
||||
* a copy of the session to record the new information so that it's
|
||||
* useful for any sessions resumed from tickets issued on this
|
||||
* connection.
|
||||
*/
|
||||
SSL_SESSION *new_sess;
|
||||
|
||||
if ((new_sess = ssl_session_dup(s->session, 0)) == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_MALLOC_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
SSL_SESSION_free(s->session);
|
||||
s->session = new_sess;
|
||||
s->session->kex_group = group_id;
|
||||
}
|
||||
|
||||
if ((ginf = tls1_group_id_lookup(s->ctx, group_id)) == NULL) {
|
||||
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_R_BAD_KEY_SHARE);
|
||||
@ -1836,6 +1858,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
s->s3.did_kex = 1;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
|
@ -669,6 +669,8 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
|
||||
}
|
||||
|
||||
s->s3.group_id = group_id;
|
||||
/* Cache the selected group ID in the SSL_SESSION */
|
||||
s->session->kex_group = group_id;
|
||||
|
||||
if (EVP_PKEY_set1_encoded_public_key(s->s3.peer_tmp,
|
||||
PACKET_data(&encoded_pt),
|
||||
@ -1705,6 +1707,7 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
|
||||
return EXT_RETURN_FAIL;
|
||||
}
|
||||
}
|
||||
s->s3.did_kex = 1;
|
||||
return EXT_RETURN_SENT;
|
||||
#else
|
||||
return EXT_RETURN_FAIL;
|
||||
|
@ -2167,6 +2167,8 @@ static int tls_process_ske_ecdhe(SSL *s, PACKET *pkt, EVP_PKEY **pkey)
|
||||
*pkey = X509_get0_pubkey(s->session->peer);
|
||||
/* else anonymous ECDH, so no certificate or pkey. */
|
||||
|
||||
/* Cache the agreed upon group in the SSL_SESSION */
|
||||
s->session->kex_group = curve_id;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2519,8 +2519,10 @@ int tls_construct_server_key_exchange(SSL *s, WPACKET *pkt)
|
||||
SSL_R_UNSUPPORTED_ELLIPTIC_CURVE);
|
||||
goto err;
|
||||
}
|
||||
s->s3.tmp.pkey = ssl_generate_pkey_group(s, curve_id);
|
||||
/* Cache the group used in the SSL_SESSION */
|
||||
s->session->kex_group = curve_id;
|
||||
/* Generate a new key for this curve */
|
||||
s->s3.tmp.pkey = ssl_generate_pkey_group(s, curve_id);
|
||||
if (s->s3.tmp.pkey == NULL) {
|
||||
/* SSLfatal() already called */
|
||||
goto err;
|
||||
|
Loading…
Reference in New Issue
Block a user