Fix migration guide mappings for i2o/o2i_ECPublicKey
[openssl.git] / providers / implementations / exchange / ecdh_exch.c
index 7293e0b9fe1e0cf3c11e25b144646e4789dc206d..5b8412aba16dfb9f07a6495056bfab0d9df81ee5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
 #include <string.h>
 #include <openssl/crypto.h>
 #include <openssl/evp.h>
-#include <openssl/core_numbers.h>
+#include <openssl/core_dispatch.h>
 #include <openssl/core_names.h>
 #include <openssl/ec.h>
 #include <openssl/params.h>
 #include <openssl/err.h>
+#include <openssl/proverr.h>
 #include "prov/provider_ctx.h"
+#include "prov/providercommon.h"
 #include "prov/implementations.h"
-#include "crypto/ec.h" /* ecdh_KDF_X9_63() */
-
-static OSSL_OP_keyexch_newctx_fn ecdh_newctx;
-static OSSL_OP_keyexch_init_fn ecdh_init;
-static OSSL_OP_keyexch_set_peer_fn ecdh_set_peer;
-static OSSL_OP_keyexch_derive_fn ecdh_derive;
-static OSSL_OP_keyexch_freectx_fn ecdh_freectx;
-static OSSL_OP_keyexch_dupctx_fn ecdh_dupctx;
-static OSSL_OP_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
-static OSSL_OP_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
-static OSSL_OP_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
-static OSSL_OP_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
+#include "prov/securitycheck.h"
+#include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */
+
+static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
+static OSSL_FUNC_keyexch_init_fn ecdh_init;
+static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
+static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
+static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
+static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
+static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
+static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
+static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
+static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
 
 enum kdf_type {
     PROV_ECDH_KDF_NONE = 0,
@@ -48,7 +51,7 @@ enum kdf_type {
  */
 
 typedef struct {
-    OPENSSL_CTX *libctx;
+    OSSL_LIB_CTX *libctx;
 
     EC_KEY *k;
     EC_KEY *peerk;
@@ -79,12 +82,16 @@ typedef struct {
 static
 void *ecdh_newctx(void *provctx)
 {
-    PROV_ECDH_CTX *pectx = OPENSSL_zalloc(sizeof(*pectx));
+    PROV_ECDH_CTX *pectx;
 
+    if (!ossl_prov_is_running())
+        return NULL;
+
+    pectx = OPENSSL_zalloc(sizeof(*pectx));
     if (pectx == NULL)
         return NULL;
 
-    pectx->libctx = PROV_LIBRARY_CONTEXT_OF(provctx);
+    pectx->libctx = PROV_LIBCTX_OF(provctx);
     pectx->cofactor_mode = -1;
     pectx->kdf_type = PROV_ECDH_KDF_NONE;
 
@@ -92,17 +99,43 @@ void *ecdh_newctx(void *provctx)
 }
 
 static
-int ecdh_init(void *vpecdhctx, void *vecdh)
+int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
 {
     PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
 
-    if (pecdhctx == NULL || vecdh == NULL || !EC_KEY_up_ref(vecdh))
+    if (!ossl_prov_is_running()
+            || pecdhctx == NULL
+            || vecdh == NULL
+            || !EC_KEY_up_ref(vecdh))
         return 0;
     EC_KEY_free(pecdhctx->k);
     pecdhctx->k = vecdh;
     pecdhctx->cofactor_mode = -1;
     pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
-    return 1;
+    return ecdh_set_ctx_params(pecdhctx, params)
+           && ossl_ec_check_key(pecdhctx->libctx, vecdh, 1);
+}
+
+static
+int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer)
+{
+    int ret;
+    BN_CTX *ctx = NULL;
+    const EC_GROUP *group_priv = EC_KEY_get0_group(priv);
+    const EC_GROUP *group_peer = EC_KEY_get0_group(peer);
+
+    ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv));
+    if (ctx == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_BN_LIB);
+        return 0;
+    }
+    ret = group_priv != NULL
+          && group_peer != NULL
+          && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0;
+    if (!ret)
+        ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
+    BN_CTX_free(ctx);
+    return ret;
 }
 
 static
@@ -110,8 +143,14 @@ int ecdh_set_peer(void *vpecdhctx, void *vecdh)
 {
     PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
 
-    if (pecdhctx == NULL || vecdh == NULL || !EC_KEY_up_ref(vecdh))
+    if (!ossl_prov_is_running()
+            || pecdhctx == NULL
+            || vecdh == NULL
+            || !ecdh_match_params(pecdhctx->k, vecdh)
+            || !ossl_ec_check_key(pecdhctx->libctx, vecdh, 1)
+            || !EC_KEY_up_ref(vecdh))
         return 0;
+
     EC_KEY_free(pecdhctx->peerk);
     pecdhctx->peerk = vecdh;
     return 1;
@@ -137,6 +176,9 @@ void *ecdh_dupctx(void *vpecdhctx)
     PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
     PROV_ECDH_CTX *dstctx;
 
+    if (!ossl_prov_is_running())
+        return NULL;
+
     dstctx = OPENSSL_zalloc(sizeof(*srcctx));
     if (dstctx == NULL)
         return NULL;
@@ -190,8 +232,10 @@ int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
     PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
     const OSSL_PARAM *p;
 
-    if (pectx == NULL || params == NULL)
+    if (pectx == NULL)
         return 0;
+    if (params == NULL)
+        return 1;
 
     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
     if (p != NULL) {
@@ -239,9 +283,13 @@ int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
 
         EVP_MD_free(pectx->kdf_md);
         pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
-
         if (pectx->kdf_md == NULL)
             return 0;
+        if (!ossl_digest_is_allowed(pectx->libctx, pectx->kdf_md)) {
+            EVP_MD_free(pectx->kdf_md);
+            pectx->kdf_md = NULL;
+            return 0;
+        }
     }
 
     p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
@@ -279,7 +327,8 @@ static const OSSL_PARAM known_settable_ctx_params[] = {
 };
 
 static
-const OSSL_PARAM *ecdh_settable_ctx_params(void)
+const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
+                                           ossl_unused void *provctx)
 {
     return known_settable_ctx_params;
 }
@@ -290,7 +339,7 @@ int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
     PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
     OSSL_PARAM *p;
 
-    if (pectx == NULL || params == NULL)
+    if (pectx == NULL)
         return 0;
 
     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
@@ -329,7 +378,7 @@ int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
     if (p != NULL
             && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL
                                            ? ""
-                                           : EVP_MD_name(pectx->kdf_md))){
+                                           : EVP_MD_get0_name(pectx->kdf_md))) {
         return 0;
     }
 
@@ -338,11 +387,8 @@ int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
         return 0;
 
     p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
-    if (p != NULL && !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, 0))
-        return 0;
-
-    p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM_LEN);
-    if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_ukmlen))
+    if (p != NULL &&
+        !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen))
         return 0;
 
     return 1;
@@ -355,12 +401,12 @@ static const OSSL_PARAM known_gettable_ctx_params[] = {
     OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
     OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
                     NULL, 0),
-    OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_UKM_LEN, NULL),
     OSSL_PARAM_END
 };
 
 static
-const OSSL_PARAM *ecdh_gettable_ctx_params(void)
+const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
+                                           ossl_unused void *provctx)
 {
     return known_gettable_ctx_params;
 }
@@ -394,7 +440,7 @@ int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
     int key_cofactor_mode;
 
     if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
-        ERR_raise(ERR_LIB_PROV, EC_R_KEYS_NOT_SET);
+        ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
         return 0;
     }
 
@@ -405,7 +451,7 @@ int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
     }
 
     if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
-            || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL )
+            || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL)
         return 0;
 
     /*
@@ -458,7 +504,6 @@ int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
     return ret;
 }
 
-#ifndef FIPS_MODE
 static ossl_inline
 int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
                           size_t *psecretlen, size_t outlen)
@@ -473,23 +518,24 @@ int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
         return 1;
     }
 
-    if (pecdhctx->kdf_outlen > outlen)
+    if (pecdhctx->kdf_outlen > outlen) {
+        ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
         return 0;
+    }
     if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
         return 0;
-    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL) {
-        ERR_raise(ERR_LIB_PROV, ERR_R_MALLOC_FAILURE);
+    if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
         return 0;
-    }
     if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
         goto err;
 
     /* Do KDF stuff */
-    if (!ecdh_KDF_X9_63(secret, pecdhctx->kdf_outlen,
-                        stmp, stmplen,
-                        pecdhctx->kdf_ukm,
-                        pecdhctx->kdf_ukmlen,
-                        pecdhctx->kdf_md))
+    if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen,
+                             stmp, stmplen,
+                             pecdhctx->kdf_ukm,
+                             pecdhctx->kdf_ukmlen,
+                             pecdhctx->kdf_md,
+                             pecdhctx->libctx, NULL))
         goto err;
     *psecretlen = pecdhctx->kdf_outlen;
     ret = 1;
@@ -498,7 +544,6 @@ int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
     OPENSSL_secure_clear_free(stmp, stmplen);
     return ret;
 }
-#endif /* FIPS_MODE */
 
 static
 int ecdh_derive(void *vpecdhctx, unsigned char *secret,
@@ -509,21 +554,15 @@ int ecdh_derive(void *vpecdhctx, unsigned char *secret,
     switch (pecdhctx->kdf_type) {
         case PROV_ECDH_KDF_NONE:
             return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
-#ifndef FIPS_MODE
         case PROV_ECDH_KDF_X9_63:
             return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
-
-#endif /* FIPS_MODE */
         default:
             break;
     }
-
     return 0;
 }
 
-
-
-const OSSL_DISPATCH ecdh_keyexch_functions[] = {
+const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
     { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
     { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
     { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
@@ -536,5 +575,5 @@ const OSSL_DISPATCH ecdh_keyexch_functions[] = {
     { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
     { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
       (void (*)(void))ecdh_gettable_ctx_params },
-    { 0, NULL }
+    OSSL_DISPATCH_END
 };