diff options
author | Nicola Tuveri <nic.tuv@gmail.com> | 2020-09-28 03:45:30 +0300 |
---|---|---|
committer | Nicola Tuveri <nic.tuv@gmail.com> | 2020-10-14 18:42:59 +0300 |
commit | a011b5861b545b40df3c6f111df4fbde74cd7c82 (patch) | |
tree | 12dc48963f2cd0a88563cc9658dbfa9ea202be48 | |
parent | c1a74f59ac799087c511d641cb086722817b805b (diff) | |
download | openssl-a011b5861b545b40df3c6f111df4fbde74cd7c82.tar.gz |
[ssl] Support ssl_decapsulate on client side
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/13018)
-rw-r--r-- | crypto/err/openssl.txt | 1 | ||||
-rw-r--r-- | include/openssl/sslerr.h | 1 | ||||
-rw-r--r-- | ssl/s3_lib.c | 99 | ||||
-rw-r--r-- | ssl/ssl_local.h | 3 | ||||
-rw-r--r-- | ssl/statem/extensions_clnt.c | 55 |
5 files changed, 125 insertions, 34 deletions
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 1724982709..2f22bc1d31 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1401,6 +1401,7 @@ SSL_F_SSL_CTX_USE_SERVERINFO_EX:543:SSL_CTX_use_serverinfo_ex SSL_F_SSL_CTX_USE_SERVERINFO_FILE:337:SSL_CTX_use_serverinfo_file SSL_F_SSL_DANE_DUP:403:ssl_dane_dup SSL_F_SSL_DANE_ENABLE:395:SSL_dane_enable +SSL_F_SSL_DECAPSULATE:643: SSL_F_SSL_DERIVE:590:ssl_derive SSL_F_SSL_DO_CONFIG:391:ssl_do_config SSL_F_SSL_DO_HANDSHAKE:180:SSL_do_handshake diff --git a/include/openssl/sslerr.h b/include/openssl/sslerr.h index d4ee837a1e..26c5ee1b39 100644 --- a/include/openssl/sslerr.h +++ b/include/openssl/sslerr.h @@ -183,6 +183,7 @@ int ERR_load_SSL_strings(void); # define SSL_F_SSL_CTX_USE_SERVERINFO_FILE 0 # define SSL_F_SSL_DANE_DUP 0 # define SSL_F_SSL_DANE_ENABLE 0 +# define SSL_F_SSL_DECAPSULATE 0 # define SSL_F_SSL_DERIVE 0 # define SSL_F_SSL_DO_CONFIG 0 # define SSL_F_SSL_DO_HANDSHAKE 0 diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c index 94c2d8c2ce..96569ae0bd 100644 --- a/ssl/s3_lib.c +++ b/ssl/s3_lib.c @@ -4832,6 +4832,33 @@ EVP_PKEY *ssl_generate_param_group(SSL *s, uint16_t id) return pkey; } +/* Generate secrets from pms */ +__owur static +int ssl_gensecret(SSL *s, unsigned char *pms, size_t pmslen) +{ + int rv = 0; + + /* SSLfatal() called as appropriate in the below functions */ + if (SSL_IS_TLS13(s)) { + /* + * If we are resuming then we already generated the early secret + * when we created the ClientHello, so don't recreate it. + */ + if (!s->hit) + rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL, + 0, + (unsigned char *)&s->early_secret); + else + rv = 1; + + rv = rv && tls13_generate_handshake_secret(s, pms, pmslen); + } else { + rv = ssl_generate_master_secret(s, pms, pmslen, 0); + } + + return rv; +} + /* Derive secrets for ECDH/DH */ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret) { @@ -4876,22 +4903,62 @@ int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int gensecret) if (gensecret) { /* SSLfatal() called as appropriate in the below functions */ - if (SSL_IS_TLS13(s)) { - /* - * If we are resuming then we already generated the early secret - * when we created the ClientHello, so don't recreate it. - */ - if (!s->hit) - rv = tls13_generate_secret(s, ssl_handshake_md(s), NULL, NULL, - 0, - (unsigned char *)&s->early_secret); - else - rv = 1; - - rv = rv && tls13_generate_handshake_secret(s, pms, pmslen); - } else { - rv = ssl_generate_master_secret(s, pms, pmslen, 0); - } + rv = ssl_gensecret(s, pms, pmslen); + } else { + /* Save premaster secret */ + s->s3.tmp.pms = pms; + s->s3.tmp.pmslen = pmslen; + pms = NULL; + rv = 1; + } + + err: + OPENSSL_clear_free(pms, pmslen); + EVP_PKEY_CTX_free(pctx); + return rv; +} + +/* Decapsulate secrets for KEM */ +int ssl_decapsulate(SSL *s, EVP_PKEY *privkey, + const unsigned char *ct, size_t ctlen, + int gensecret) +{ + int rv = 0; + unsigned char *pms = NULL; + size_t pmslen = 0; + EVP_PKEY_CTX *pctx; + + if (privkey == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + return 0; + } + + pctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, privkey, s->ctx->propq); + + if (EVP_PKEY_decapsulate_init(pctx) <= 0 + || EVP_PKEY_decapsulate(pctx, NULL, &pmslen, ct, ctlen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + pms = OPENSSL_malloc(pmslen); + if (pms == NULL) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (EVP_PKEY_decapsulate(pctx, pms, &pmslen, ct, ctlen) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_DECAPSULATE, + ERR_R_INTERNAL_ERROR); + goto err; + } + + if (gensecret) { + /* SSLfatal() called as appropriate in the below functions */ + rv = ssl_gensecret(s, pms, pmslen); } else { /* Save premaster secret */ s->s3.tmp.pms = pms; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h index e81470a82c..3a4727f17a 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -2456,6 +2456,9 @@ __owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen, __owur EVP_PKEY *ssl_generate_pkey(SSL *s, EVP_PKEY *pm); __owur int ssl_derive(SSL *s, EVP_PKEY *privkey, EVP_PKEY *pubkey, int genmaster); +__owur int ssl_decapsulate(SSL *s, EVP_PKEY *privkey, + const unsigned char *ct, size_t ctlen, + int gensecret); __owur EVP_PKEY *ssl_dh_to_pkey(DH *dh); __owur unsigned int ssl_get_max_send_fragment(const SSL *ssl); __owur unsigned int ssl_get_split_send_fragment(const SSL *ssl); diff --git a/ssl/statem/extensions_clnt.c b/ssl/statem/extensions_clnt.c index 189e2c9e5e..15cd622ed5 100644 --- a/ssl/statem/extensions_clnt.c +++ b/ssl/statem/extensions_clnt.c @@ -1830,6 +1830,7 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, unsigned int group_id; PACKET encoded_pt; EVP_PKEY *ckey = s->s3.tmp.pkey, *skey = NULL; + const TLS_GROUP_INFO *ginf = NULL; /* Sanity check */ if (ckey == NULL || s->s3.peer_tmp != NULL) { @@ -1893,6 +1894,12 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } + if ((ginf = tls1_group_id_lookup(s->ctx, group_id)) == NULL) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_BAD_KEY_SHARE); + return 0; + } + if (!PACKET_as_length_prefixed_2(pkt, &encoded_pt) || PACKET_remaining(&encoded_pt) == 0) { SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, @@ -1900,27 +1907,39 @@ int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, unsigned int context, X509 *x, return 0; } - skey = EVP_PKEY_new(); - if (skey == NULL || EVP_PKEY_copy_parameters(skey, ckey) <= 0) { - SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, - SSL_R_COPY_PARAMETERS_FAILED); - return 0; - } + if (!ginf->is_kem) { + /* Regular KEX */ + skey = EVP_PKEY_new(); + if (skey == NULL || EVP_PKEY_copy_parameters(skey, ckey) <= 0) { + SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_COPY_PARAMETERS_FAILED); + return 0; + } - if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), - PACKET_remaining(&encoded_pt))) { - SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, - SSL_R_BAD_ECPOINT); - EVP_PKEY_free(skey); - return 0; - } + if (!EVP_PKEY_set1_tls_encodedpoint(skey, PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_KEY_SHARE, + SSL_R_BAD_ECPOINT); + EVP_PKEY_free(skey); + return 0; + } - if (ssl_derive(s, ckey, skey, 1) == 0) { - /* SSLfatal() already called */ - EVP_PKEY_free(skey); - return 0; + if (ssl_derive(s, ckey, skey, 1) == 0) { + /* SSLfatal() already called */ + EVP_PKEY_free(skey); + return 0; + } + s->s3.peer_tmp = skey; + } else { + /* KEM Mode */ + const unsigned char *ct = PACKET_data(&encoded_pt); + size_t ctlen = PACKET_remaining(&encoded_pt); + + if (ssl_decapsulate(s, ckey, ct, ctlen, 1) == 0) { + /* SSLfatal() already called */ + return 0; + } } - s->s3.peer_tmp = skey; #endif return 1; |