summaryrefslogtreecommitdiffstats
path: root/ssl
diff options
context:
space:
mode:
authorNicola Tuveri <nic.tuv@gmail.com>2020-09-28 04:32:03 +0300
committerNicola Tuveri <nic.tuv@gmail.com>2020-10-14 18:42:59 +0300
commit8b17fbaf46ae8a1319be5975ad8da3e0f4932e77 (patch)
tree811bba9ea6a476e61615163eee67a1574848f589 /ssl
parenta011b5861b545b40df3c6f111df4fbde74cd7c82 (diff)
[ssl] Support ssl_encapsulate on server 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.c65
-rw-r--r--ssl/ssl_local.h4
-rw-r--r--ssl/statem/extensions_srvr.c106
3 files changed, 149 insertions, 26 deletions
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 96569ae0bd..1fd424a52e 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -4833,7 +4833,6 @@ EVP_PKEY *ssl_generate_param_group(SSL *s, uint16_t id)
}
/* Generate secrets from pms */
-__owur static
int ssl_gensecret(SSL *s, unsigned char *pms, size_t pmslen)
{
int rv = 0;
@@ -4973,6 +4972,70 @@ int ssl_decapsulate(SSL *s, EVP_PKEY *privkey,
return rv;
}
+int ssl_encapsulate(SSL *s, EVP_PKEY *pubkey,
+ unsigned char **ctp, size_t *ctlenp,
+ int gensecret)
+{
+ int rv = 0;
+ unsigned char *pms = NULL, *ct = NULL;
+ size_t pmslen = 0, ctlen = 0;
+ EVP_PKEY_CTX *pctx;
+
+ if (pubkey == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ pctx = EVP_PKEY_CTX_new_from_pkey(s->ctx->libctx, pubkey, s->ctx->propq);
+
+ if (EVP_PKEY_encapsulate_init(pctx) <= 0
+ || EVP_PKEY_encapsulate(pctx, NULL, &ctlen, NULL, &pmslen) <= 0
+ || pmslen == 0 || ctlen == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
+ pms = OPENSSL_malloc(pmslen);
+ ct = OPENSSL_malloc(ctlen);
+ if (pms == NULL || ct == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (EVP_PKEY_encapsulate(pctx, ct, &ctlen, pms, &pmslen) <= 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_SSL_ENCAPSULATE,
+ 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;
+ s->s3.tmp.pmslen = pmslen;
+ pms = NULL;
+ rv = 1;
+ }
+
+ if (rv > 0) {
+ /* Pass ownership of ct to caller */
+ *ctp = ct;
+ *ctlenp = ctlen;
+ ct = NULL;
+ }
+
+ err:
+ OPENSSL_clear_free(pms, pmslen);
+ OPENSSL_free(ct);
+ EVP_PKEY_CTX_free(pctx);
+ return rv;
+}
+
#ifndef OPENSSL_NO_DH
EVP_PKEY *ssl_dh_to_pkey(DH *dh)
{
diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h
index 3a4727f17a..66a84cf54e 100644
--- a/ssl/ssl_local.h
+++ b/ssl/ssl_local.h
@@ -2454,11 +2454,15 @@ __owur int ssl_fill_hello_random(SSL *s, int server, unsigned char *field,
__owur int ssl_generate_master_secret(SSL *s, unsigned char *pms, size_t pmslen,
int free_pms);
__owur EVP_PKEY *ssl_generate_pkey(SSL *s, EVP_PKEY *pm);
+__owur int ssl_gensecret(SSL *s, unsigned char *pms, size_t pmslen);
__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 int ssl_encapsulate(SSL *s, EVP_PKEY *pubkey,
+ unsigned char **ctp, size_t *ctlenp,
+ 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_srvr.c b/ssl/statem/extensions_srvr.c
index 9ec48ef56a..eb24d0a19e 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -1696,6 +1696,7 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
unsigned char *encodedPoint;
size_t encoded_pt_len = 0;
EVP_PKEY *ckey = s->s3.peer_tmp, *skey = NULL;
+ const TLS_GROUP_INFO *ginf = NULL;
if (s->hello_retry_request == SSL_HRR_PENDING) {
if (ckey != NULL) {
@@ -1733,37 +1734,92 @@ EXT_RETURN tls_construct_stoc_key_share(SSL *s, WPACKET *pkt,
return EXT_RETURN_FAIL;
}
- skey = ssl_generate_pkey(s, ckey);
- if (skey == NULL) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
- ERR_R_MALLOC_FAILURE);
+ if ((ginf = tls1_group_id_lookup(s->ctx, s->s3.group_id)) == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
- /* Generate encoding of server key */
- encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
- if (encoded_pt_len == 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
- ERR_R_EC_LIB);
- EVP_PKEY_free(skey);
- return EXT_RETURN_FAIL;
- }
+ if (!ginf->is_kem) {
+ /* Regular KEX */
+ skey = ssl_generate_pkey(s, ckey);
+ if (skey == NULL) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_MALLOC_FAILURE);
+ return EXT_RETURN_FAIL;
+ }
- if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
- || !WPACKET_close(pkt)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
- ERR_R_INTERNAL_ERROR);
- EVP_PKEY_free(skey);
+ /* Generate encoding of server key */
+ encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
+ if (encoded_pt_len == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_EC_LIB);
+ EVP_PKEY_free(skey);
+ return EXT_RETURN_FAIL;
+ }
+
+ if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ EVP_PKEY_free(skey);
+ OPENSSL_free(encodedPoint);
+ return EXT_RETURN_FAIL;
+ }
OPENSSL_free(encodedPoint);
- return EXT_RETURN_FAIL;
- }
- OPENSSL_free(encodedPoint);
- /* This causes the crypto state to be updated based on the derived keys */
- s->s3.tmp.pkey = skey;
- if (ssl_derive(s, skey, ckey, 1) == 0) {
- /* SSLfatal() already called */
- return EXT_RETURN_FAIL;
+ /*
+ * This causes the crypto state to be updated based on the derived keys
+ */
+ s->s3.tmp.pkey = skey;
+ if (ssl_derive(s, skey, ckey, 1) == 0) {
+ /* SSLfatal() already called */
+ return EXT_RETURN_FAIL;
+ }
+ } else {
+ /* KEM mode */
+ unsigned char *ct = NULL;
+ size_t ctlen = 0;
+
+ /*
+ * This does not update the crypto state.
+ *
+ * The generated pms is stored in `s->s3.tmp.pms` to be later used via
+ * ssl_gensecret().
+ */
+ if (ssl_encapsulate(s, ckey, &ct, &ctlen, 0) == 0) {
+ /* SSLfatal() already called */
+ return EXT_RETURN_FAIL;
+ }
+
+ if (ctlen == 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(ct);
+ return EXT_RETURN_FAIL;
+ }
+
+ if (!WPACKET_sub_memcpy_u16(pkt, ct, ctlen)
+ || !WPACKET_close(pkt)) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(ct);
+ return EXT_RETURN_FAIL;
+ }
+ OPENSSL_free(ct);
+
+ /*
+ * This causes the crypto state to be updated based on the generated pms
+ */
+ if (ssl_gensecret(s, s->s3.tmp.pms, s->s3.tmp.pmslen) == 0) {
+ /* SSLfatal() already called */
+ return EXT_RETURN_FAIL;
+ }
}
return EXT_RETURN_SENT;
#else