Make EVP_PKEY_[get1|set1]_tls_encodedpoint work with provided keys
authorMatt Caswell <matt@openssl.org>
Wed, 20 May 2020 15:20:27 +0000 (16:20 +0100)
committerMatt Caswell <matt@openssl.org>
Fri, 5 Jun 2020 10:04:11 +0000 (11:04 +0100)
EVP_PKEY_[get1|set1]_tls_encodedpoint() only worked if an ameth was present
which isn't the case for provided keys. Support has been added to dh,
ec and ecx keys.

Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/11898)

12 files changed:
crypto/dh/dh_ameth.c
crypto/dh/dh_key.c
crypto/dh/dh_local.h
crypto/evp/p_lib.c
doc/man7/EVP_PKEY-DH.pod
doc/man7/EVP_PKEY-EC.pod
doc/man7/EVP_PKEY-X25519.pod
include/crypto/dh.h
include/openssl/core_names.h
providers/implementations/keymgmt/dh_kmgmt.c
providers/implementations/keymgmt/ec_kmgmt.c
providers/implementations/keymgmt/ecx_kmgmt.c

index d93d519..d5e5f72 100644 (file)
@@ -438,7 +438,7 @@ static int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
     case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
         return dh_buf2key(EVP_PKEY_get0_DH(pkey), arg2, arg1);
     case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
-        return dh_key2buf(EVP_PKEY_get0_DH(pkey), arg2);
+        return dh_key2buf(EVP_PKEY_get0_DH(pkey), arg2, 0, 1);
     default:
         return -2;
     }
index 1893b48..5d2acca 100644 (file)
@@ -351,10 +351,10 @@ err:
     return 0;
 }
 
-size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out)
+size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out, size_t size, int alloc)
 {
     const BIGNUM *pubkey;
-    unsigned char *pbuf;
+    unsigned char *pbuf = NULL;
     const BIGNUM *p;
     int p_size;
 
@@ -366,19 +366,29 @@ size_t dh_key2buf(const DH *dh, unsigned char **pbuf_out)
         DHerr(DH_F_DH_KEY2BUF, DH_R_INVALID_PUBKEY);
         return 0;
     }
-    if ((pbuf = OPENSSL_malloc(p_size)) == NULL) {
-        DHerr(DH_F_DH_KEY2BUF, ERR_R_MALLOC_FAILURE);
-        return 0;
-    }
-    /*
-     * As per Section 4.2.8.1 of RFC 8446 left pad public
-     * key with zeros to the size of p
-     */
-    if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) {
-        OPENSSL_free(pbuf);
-        DHerr(DH_F_DH_KEY2BUF, DH_R_BN_ERROR);
-        return 0;
+    if (pbuf_out != NULL && (alloc || *pbuf_out != NULL)) {
+        if (!alloc) {
+            if (size >= (size_t)p_size)
+                pbuf = *pbuf_out;
+        } else {
+            pbuf = OPENSSL_malloc(p_size);
+        }
+
+        if (pbuf == NULL) {
+            DHerr(DH_F_DH_KEY2BUF, ERR_R_MALLOC_FAILURE);
+            return 0;
+        }
+        /*
+         * As per Section 4.2.8.1 of RFC 8446 left pad public
+         * key with zeros to the size of p
+         */
+        if (BN_bn2binpad(pubkey, pbuf, p_size) < 0) {
+            if (alloc)
+                OPENSSL_free(pbuf);
+            DHerr(DH_F_DH_KEY2BUF, DH_R_BN_ERROR);
+            return 0;
+        }
+        *pbuf_out = pbuf;
     }
-    *pbuf_out = pbuf;
     return p_size;
 }
index a54d25f..51c3f97 100644 (file)
@@ -58,6 +58,3 @@ struct dh_method {
     int (*generate_params) (DH *dh, int prime_len, int generator,
                             BN_GENCB *cb);
 };
-
-int dh_buf2key(DH *key, const unsigned char *buf, size_t len);
-size_t dh_key2buf(const DH *dh, unsigned char **pbuf);
index 4670912..1d57a22 100644 (file)
@@ -1215,6 +1215,18 @@ int EVP_PKEY_supports_digest_nid(EVP_PKEY *pkey, int nid)
 int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
                                const unsigned char *pt, size_t ptlen)
 {
+    if (pkey->ameth == NULL) {
+        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+        if (pkey->keymgmt == NULL || pkey->keydata == NULL)
+            return 0;
+
+        params[0] =
+            OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT,
+                                              (unsigned char *)pt, ptlen);
+        return evp_keymgmt_set_params(pkey->keymgmt, pkey->keydata, params);
+    }
+
     if (ptlen > INT_MAX)
         return 0;
     if (evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_SET1_TLS_ENCPT, ptlen,
@@ -1226,6 +1238,33 @@ int EVP_PKEY_set1_tls_encodedpoint(EVP_PKEY *pkey,
 size_t EVP_PKEY_get1_tls_encodedpoint(EVP_PKEY *pkey, unsigned char **ppt)
 {
     int rv;
+
+    if (pkey->ameth == NULL) {
+        OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
+
+        if (pkey->keymgmt == NULL || pkey->keydata == NULL)
+            return 0;
+
+        params[0] =
+            OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT,
+                                              NULL, 0);
+        if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+            return 0;
+
+        *ppt = OPENSSL_malloc(params[0].return_size);
+        if (*ppt == NULL)
+            return 0;
+
+        params[0] =
+            OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT,
+                                              *ppt, params[0].return_size);
+        if (!evp_keymgmt_get_params(pkey->keymgmt, pkey->keydata, params))
+            return 0;
+
+        return params[0].return_size;
+    }
+
+
     rv = evp_pkey_asn1_ctrl(pkey, ASN1_PKEY_CTRL_GET1_TLS_ENCPT, 0, ppt);
     if (rv <= 0)
         return 0;
index 33b19a7..d2a49b7 100644 (file)
@@ -54,6 +54,11 @@ validation is required. The default value is 2.
 These are not named safe prime groups so setting this value for the OpenSSL FIPS
 provider will instead choose a named safe prime group based on the size of I<p>.
 
+=item "tls-encoded-pt" (B<OSSL_PKEY_PARAM_TLS_ENCODED_PT>) <octet string>
+
+Used for getting and setting the encoding of the DH public key used in a key
+exchange message for the TLS protocol.
+
 =back
 
 =head2 DH domain parameter / key generation parameters
index 1995cf7..85e633c 100644 (file)
@@ -39,6 +39,11 @@ The public key value in EC point format.
 
 The private key value.
 
+=item "tls-encoded-pt" (B<OSSL_PKEY_PARAM_TLS_ENCODED_PT>) <octet string>
+
+Used for getting and setting the encoding of the EC public key used in key
+exchange message for the TLS protocol.
+
 =back
 
 =head1 EXAMPLES
index fa8c868..ebeda8d 100644 (file)
@@ -34,6 +34,11 @@ The public key value.
 
 The private key value.
 
+=item "tls-encoded-pt" (B<OSSL_PKEY_PARAM_TLS_ENCODED_PT>) <octet string>
+
+Used for getting and setting the encoding of the public key used in a key exchange
+message for the TLS protocol.
+
 =back
 
 =head2 ED25519 and ED448 parameters
index 1ae2c2f..f67b4e0 100644 (file)
@@ -32,3 +32,6 @@ int dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret);
 int dh_check_pairwise(DH *dh);
 
 const DH_METHOD *dh_get_method(const DH *dh);
+
+int dh_buf2key(DH *key, const unsigned char *buf, size_t len);
+size_t dh_key2buf(const DH *dh, unsigned char **pbuf, size_t size, int alloc);
index 8bafc1b..f04168e 100644 (file)
@@ -194,6 +194,7 @@ extern "C" {
 #define OSSL_PKEY_PARAM_MASKGENFUNC         "mgf"
 #define OSSL_PKEY_PARAM_MGF1_DIGEST         "mgf1-digest"
 #define OSSL_PKEY_PARAM_MGF1_PROPERTIES     "mgf1-properties"
+#define OSSL_PKEY_PARAM_TLS_ENCODED_PT      "tls-encoded-pt"
 
 /* Diffie-Hellman/DSA public/private key */
 #define OSSL_PKEY_PARAM_PUB_KEY             "pub"
index 1e344bd..0dd1796 100644 (file)
@@ -36,6 +36,8 @@ static OSSL_OP_keymgmt_gen_fn dh_gen;
 static OSSL_OP_keymgmt_gen_cleanup_fn dh_gen_cleanup;
 static OSSL_OP_keymgmt_get_params_fn dh_get_params;
 static OSSL_OP_keymgmt_gettable_params_fn dh_gettable_params;
+static OSSL_OP_keymgmt_set_params_fn dh_set_params;
+static OSSL_OP_keymgmt_settable_params_fn dh_settable_params;
 static OSSL_OP_keymgmt_has_fn dh_has;
 static OSSL_OP_keymgmt_match_fn dh_match;
 static OSSL_OP_keymgmt_validate_fn dh_validate;
@@ -298,6 +300,15 @@ static ossl_inline int dh_get_params(void *key, OSSL_PARAM params[])
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
         && !OSSL_PARAM_set_int(p, DH_size(dh)))
         return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL) {
+        if (p->data_type != OSSL_PARAM_OCTET_STRING)
+            return 0;
+        p->return_size = dh_key2buf(dh, (unsigned char **)&p->data,
+                                    p->data_size, 0);
+        if (p->return_size == 0)
+            return 0;
+    }
+
     return ffc_params_todata(dh_get0_params(dh), NULL, params)
            && dh_key_todata(dh, NULL, params);
 }
@@ -306,6 +317,7 @@ static const OSSL_PARAM dh_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
     DH_IMEXPORTABLE_PARAMETERS,
     DH_IMEXPORTABLE_PUBLIC_KEY,
     DH_IMEXPORTABLE_PRIVATE_KEY,
@@ -317,6 +329,30 @@ static const OSSL_PARAM *dh_gettable_params(void)
     return dh_params;
 }
 
+static const OSSL_PARAM dh_known_settable_params[] = {
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *dh_settable_params(void)
+{
+    return dh_known_settable_params;
+}
+
+static int dh_set_params(void *key, const OSSL_PARAM params[])
+{
+    DH *dh = key;
+    const OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT);
+    if (p != NULL
+            && (p->data_type != OSSL_PARAM_OCTET_STRING
+                || !dh_buf2key(dh, p->data, p->data_size)))
+        return 0;
+
+    return 1;
+}
+
 static int dh_validate_public(DH *dh)
 {
     const BIGNUM *pub_key = NULL;
@@ -621,6 +657,8 @@ const OSSL_DISPATCH dh_keymgmt_functions[] = {
     { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))dh_freedata },
     { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))dh_get_params },
     { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))dh_gettable_params },
+    { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))dh_set_params },
+    { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))dh_settable_params },
     { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))dh_has },
     { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))dh_match },
     { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))dh_validate },
index 8e7b9f3..7e32207 100644 (file)
@@ -504,6 +504,20 @@ int ec_get_params(void *key, OSSL_PARAM params[])
         if (!OSSL_PARAM_set_int(p, ecdh_cofactor_mode))
             return 0;
     }
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL) {
+        BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(key));
+
+        if (ctx == NULL)
+            return 0;
+        p->return_size = EC_POINT_point2oct(EC_KEY_get0_group(key),
+                                            EC_KEY_get0_public_key(key),
+                                            POINT_CONVERSION_UNCOMPRESSED,
+                                            p->data, p->return_size, ctx);
+        BN_CTX_free(ctx);
+        if (p->return_size == 0)
+            return 0;
+    }
+
     ret = domparams_to_params(eck, NULL, params)
           && key_to_params(eck, NULL, params, 1, &pub_key)
           && otherparams_to_params(eck, NULL, params);
@@ -515,6 +529,7 @@ static const OSSL_PARAM ec_known_gettable_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
     EC_IMEXPORTABLE_DOM_PARAMETERS,
     EC_IMEXPORTABLE_PUBLIC_KEY,
     EC_IMEXPORTABLE_PRIVATE_KEY,
@@ -530,6 +545,7 @@ const OSSL_PARAM *ec_gettable_params(void)
 
 static const OSSL_PARAM ec_known_settable_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_USE_COFACTOR_ECDH, NULL),
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
     OSSL_PARAM_END
 };
 
@@ -543,6 +559,21 @@ static
 int ec_set_params(void *key, const OSSL_PARAM params[])
 {
     EC_KEY *eck = key;
+    const OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT);
+    if (p != NULL) {
+        BN_CTX *ctx = BN_CTX_new_ex(ec_key_get_libctx(key));
+        int ret = 1;
+
+        if (ctx == NULL
+                || p->data_type != OSSL_PARAM_OCTET_STRING
+                || !EC_KEY_oct2key(key, p->data, p->data_size, ctx))
+            ret = 0;
+        BN_CTX_free(ctx);
+        if (!ret)
+            return 0;
+    }
 
     return ec_key_otherparams_fromdata(eck, params);
 }
index e2b613e..c7a9054 100644 (file)
@@ -46,6 +46,14 @@ static OSSL_OP_keymgmt_gettable_params_fn x25519_gettable_params;
 static OSSL_OP_keymgmt_gettable_params_fn x448_gettable_params;
 static OSSL_OP_keymgmt_gettable_params_fn ed25519_gettable_params;
 static OSSL_OP_keymgmt_gettable_params_fn ed448_gettable_params;
+static OSSL_OP_keymgmt_set_params_fn x25519_set_params;
+static OSSL_OP_keymgmt_set_params_fn x448_set_params;
+static OSSL_OP_keymgmt_set_params_fn ed25519_set_params;
+static OSSL_OP_keymgmt_set_params_fn ed448_set_params;
+static OSSL_OP_keymgmt_settable_params_fn x25519_settable_params;
+static OSSL_OP_keymgmt_settable_params_fn x448_settable_params;
+static OSSL_OP_keymgmt_settable_params_fn ed25519_settable_params;
+static OSSL_OP_keymgmt_settable_params_fn ed448_settable_params;
 static OSSL_OP_keymgmt_has_fn ecx_has;
 static OSSL_OP_keymgmt_match_fn ecx_match;
 static OSSL_OP_keymgmt_import_fn ecx_import;
@@ -233,6 +241,13 @@ static int ecx_get_params(void *key, OSSL_PARAM params[], int bits, int secbits,
     if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE)) != NULL
         && !OSSL_PARAM_set_int(p, size))
         return 0;
+    if ((p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT)) != NULL
+            && (ecx->type == ECX_KEY_TYPE_X25519
+                || ecx->type == ECX_KEY_TYPE_X448)) {
+        if (!OSSL_PARAM_set_octet_string(p, ecx->pubkey, ecx->keylen))
+            return 0;
+    }
+
     return key_to_params(ecx, NULL, params);
 }
 
@@ -273,16 +288,17 @@ static int ed448_get_params(void *key, OSSL_PARAM params[])
         && ed_get_params(key, params);
 }
 
-static const OSSL_PARAM ecx_params[] = {
+static const OSSL_PARAM ecx_gettable_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
     OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0),
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
     ECX_KEY_TYPES(),
     OSSL_PARAM_END
 };
 
-static const OSSL_PARAM ed_params[] = {
+static const OSSL_PARAM ed_gettable_params[] = {
     OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL),
     OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL),
@@ -292,22 +308,92 @@ static const OSSL_PARAM ed_params[] = {
 
 static const OSSL_PARAM *x25519_gettable_params(void)
 {
-    return ecx_params;
+    return ecx_gettable_params;
 }
 
 static const OSSL_PARAM *x448_gettable_params(void)
 {
-    return ecx_params;
+    return ecx_gettable_params;
 }
 
 static const OSSL_PARAM *ed25519_gettable_params(void)
 {
-    return ed_params;
+    return ed_gettable_params;
 }
 
 static const OSSL_PARAM *ed448_gettable_params(void)
 {
-    return ed_params;
+    return ed_gettable_params;
+}
+
+static int ecx_set_params(void *key, const OSSL_PARAM params[])
+{
+    ECX_KEY *ecxkey = key;
+    const OSSL_PARAM *p;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_TLS_ENCODED_PT);
+    if (p != NULL) {
+        void *buf = ecxkey->pubkey;
+
+        if (p->data_size != ecxkey->keylen
+                || !OSSL_PARAM_get_octet_string(p, &buf, sizeof(ecxkey->pubkey),
+                                                NULL))
+            return 0;
+        OPENSSL_clear_free(ecxkey->privkey, ecxkey->keylen);
+        ecxkey->privkey = NULL;
+        ecxkey->haspubkey = 1;
+    }
+
+    return 1;
+}
+
+static int x25519_set_params(void *key, const OSSL_PARAM params[])
+{
+    return ecx_set_params(key, params);
+}
+
+static int x448_set_params(void *key, const OSSL_PARAM params[])
+{
+    return ecx_set_params(key, params);
+}
+
+static int ed25519_set_params(void *key, const OSSL_PARAM params[])
+{
+    return 1;
+}
+
+static int ed448_set_params(void *key, const OSSL_PARAM params[])
+{
+    return 1;
+}
+
+static const OSSL_PARAM ecx_settable_params[] = {
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_TLS_ENCODED_PT, NULL, 0),
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM ed_settable_params[] = {
+    OSSL_PARAM_END
+};
+
+static const OSSL_PARAM *x25519_settable_params(void)
+{
+    return ecx_settable_params;
+}
+
+static const OSSL_PARAM *x448_settable_params(void)
+{
+    return ecx_settable_params;
+}
+
+static const OSSL_PARAM *ed25519_settable_params(void)
+{
+    return ed_settable_params;
+}
+
+static const OSSL_PARAM *ed448_settable_params(void)
+{
+    return ed_settable_params;
 }
 
 static void *ecx_gen_init(void *provctx, int selection, ECX_KEY_TYPE type)
@@ -450,6 +536,8 @@ static void ecx_gen_cleanup(void *genctx)
         { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))ecx_key_free }, \
         { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void (*) (void))alg##_get_params }, \
         { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void (*) (void))alg##_gettable_params }, \
+        { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void (*) (void))alg##_set_params }, \
+        { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void (*) (void))alg##_settable_params }, \
         { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))ecx_has }, \
         { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))ecx_match }, \
         { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))ecx_import }, \