summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorNicola Tuveri <nic.tuv@gmail.com>2020-09-28 03:45:30 +0300
committerNicola Tuveri <nic.tuv@gmail.com>2020-10-14 18:42:59 +0300
commita011b5861b545b40df3c6f111df4fbde74cd7c82 (patch)
tree12dc48963f2cd0a88563cc9658dbfa9ea202be48 /ssl
parentc1a74f59ac799087c511d641cb086722817b805b (diff)
[ssl] Support ssl_decapsulate on client side
Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/13018)
Diffstat (limited to 'ssl')
-rw-r--r--ssl/s3_lib.c99
-rw-r--r--ssl/ssl_local.h3
-rw-r--r--ssl/statem/extensions_clnt.c55
3 files changed, 123 insertions, 34 deletions
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;