ecdh_exch.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650
  1. /*
  2. * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. /*
  10. * ECDH low level APIs are deprecated for public use, but still ok for
  11. * internal use.
  12. */
  13. #include "internal/deprecated.h"
  14. #include <string.h>
  15. #include <openssl/crypto.h>
  16. #include <openssl/evp.h>
  17. #include <openssl/core_dispatch.h>
  18. #include <openssl/core_names.h>
  19. #include <openssl/ec.h>
  20. #include <openssl/params.h>
  21. #include <openssl/err.h>
  22. #include <openssl/proverr.h>
  23. #include "prov/provider_ctx.h"
  24. #include "prov/providercommon.h"
  25. #include "prov/implementations.h"
  26. #include "prov/securitycheck.h"
  27. #include "crypto/ec.h" /* ossl_ecdh_kdf_X9_63() */
  28. static OSSL_FUNC_keyexch_newctx_fn ecdh_newctx;
  29. static OSSL_FUNC_keyexch_init_fn ecdh_init;
  30. static OSSL_FUNC_keyexch_set_peer_fn ecdh_set_peer;
  31. static OSSL_FUNC_keyexch_derive_fn ecdh_derive;
  32. static OSSL_FUNC_keyexch_freectx_fn ecdh_freectx;
  33. static OSSL_FUNC_keyexch_dupctx_fn ecdh_dupctx;
  34. static OSSL_FUNC_keyexch_set_ctx_params_fn ecdh_set_ctx_params;
  35. static OSSL_FUNC_keyexch_settable_ctx_params_fn ecdh_settable_ctx_params;
  36. static OSSL_FUNC_keyexch_get_ctx_params_fn ecdh_get_ctx_params;
  37. static OSSL_FUNC_keyexch_gettable_ctx_params_fn ecdh_gettable_ctx_params;
  38. enum kdf_type {
  39. PROV_ECDH_KDF_NONE = 0,
  40. PROV_ECDH_KDF_X9_63
  41. };
  42. /*
  43. * What's passed as an actual key is defined by the KEYMGMT interface.
  44. * We happen to know that our KEYMGMT simply passes EC_KEY structures, so
  45. * we use that here too.
  46. */
  47. typedef struct {
  48. OSSL_LIB_CTX *libctx;
  49. EC_KEY *k;
  50. EC_KEY *peerk;
  51. /*
  52. * ECDH cofactor mode:
  53. *
  54. * . 0 disabled
  55. * . 1 enabled
  56. * . -1 use cofactor mode set for k
  57. */
  58. int cofactor_mode;
  59. /************
  60. * ECDH KDF *
  61. ************/
  62. /* KDF (if any) to use for ECDH */
  63. enum kdf_type kdf_type;
  64. /* Message digest to use for key derivation */
  65. EVP_MD *kdf_md;
  66. /* User key material */
  67. unsigned char *kdf_ukm;
  68. size_t kdf_ukmlen;
  69. /* KDF output length */
  70. size_t kdf_outlen;
  71. OSSL_FIPS_IND_DECLARE
  72. } PROV_ECDH_CTX;
  73. static
  74. void *ecdh_newctx(void *provctx)
  75. {
  76. PROV_ECDH_CTX *pectx;
  77. if (!ossl_prov_is_running())
  78. return NULL;
  79. pectx = OPENSSL_zalloc(sizeof(*pectx));
  80. if (pectx == NULL)
  81. return NULL;
  82. pectx->libctx = PROV_LIBCTX_OF(provctx);
  83. pectx->cofactor_mode = -1;
  84. pectx->kdf_type = PROV_ECDH_KDF_NONE;
  85. OSSL_FIPS_IND_INIT(pectx)
  86. return (void *)pectx;
  87. }
  88. static
  89. int ecdh_init(void *vpecdhctx, void *vecdh, const OSSL_PARAM params[])
  90. {
  91. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  92. if (!ossl_prov_is_running()
  93. || pecdhctx == NULL
  94. || vecdh == NULL
  95. || (EC_KEY_get0_group(vecdh) == NULL)
  96. || !EC_KEY_up_ref(vecdh))
  97. return 0;
  98. EC_KEY_free(pecdhctx->k);
  99. pecdhctx->k = vecdh;
  100. pecdhctx->cofactor_mode = -1;
  101. pecdhctx->kdf_type = PROV_ECDH_KDF_NONE;
  102. OSSL_FIPS_IND_SET_APPROVED(pecdhctx)
  103. if (!ecdh_set_ctx_params(pecdhctx, params))
  104. return 0;
  105. #ifdef FIPS_MODULE
  106. if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
  107. OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
  108. EC_KEY_get0_group(vecdh), "ECDH Init", 1))
  109. return 0;
  110. #endif
  111. return 1;
  112. }
  113. static
  114. int ecdh_match_params(const EC_KEY *priv, const EC_KEY *peer)
  115. {
  116. int ret;
  117. BN_CTX *ctx = NULL;
  118. const EC_GROUP *group_priv = EC_KEY_get0_group(priv);
  119. const EC_GROUP *group_peer = EC_KEY_get0_group(peer);
  120. ctx = BN_CTX_new_ex(ossl_ec_key_get_libctx(priv));
  121. if (ctx == NULL) {
  122. ERR_raise(ERR_LIB_PROV, ERR_R_BN_LIB);
  123. return 0;
  124. }
  125. ret = group_priv != NULL
  126. && group_peer != NULL
  127. && EC_GROUP_cmp(group_priv, group_peer, ctx) == 0;
  128. if (!ret)
  129. ERR_raise(ERR_LIB_PROV, PROV_R_MISMATCHING_DOMAIN_PARAMETERS);
  130. BN_CTX_free(ctx);
  131. return ret;
  132. }
  133. static
  134. int ecdh_set_peer(void *vpecdhctx, void *vecdh)
  135. {
  136. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  137. if (!ossl_prov_is_running()
  138. || pecdhctx == NULL
  139. || vecdh == NULL
  140. || !ecdh_match_params(pecdhctx->k, vecdh))
  141. return 0;
  142. #ifdef FIPS_MODULE
  143. if (!ossl_fips_ind_ec_key_check(OSSL_FIPS_IND_GET(pecdhctx),
  144. OSSL_FIPS_IND_SETTABLE0, pecdhctx->libctx,
  145. EC_KEY_get0_group(vecdh), "ECDH Set Peer",
  146. 1))
  147. return 0;
  148. #endif
  149. if (!EC_KEY_up_ref(vecdh))
  150. return 0;
  151. EC_KEY_free(pecdhctx->peerk);
  152. pecdhctx->peerk = vecdh;
  153. return 1;
  154. }
  155. static
  156. void ecdh_freectx(void *vpecdhctx)
  157. {
  158. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  159. EC_KEY_free(pecdhctx->k);
  160. EC_KEY_free(pecdhctx->peerk);
  161. EVP_MD_free(pecdhctx->kdf_md);
  162. OPENSSL_clear_free(pecdhctx->kdf_ukm, pecdhctx->kdf_ukmlen);
  163. OPENSSL_free(pecdhctx);
  164. }
  165. static
  166. void *ecdh_dupctx(void *vpecdhctx)
  167. {
  168. PROV_ECDH_CTX *srcctx = (PROV_ECDH_CTX *)vpecdhctx;
  169. PROV_ECDH_CTX *dstctx;
  170. if (!ossl_prov_is_running())
  171. return NULL;
  172. dstctx = OPENSSL_zalloc(sizeof(*srcctx));
  173. if (dstctx == NULL)
  174. return NULL;
  175. *dstctx = *srcctx;
  176. /* clear all pointers */
  177. dstctx->k= NULL;
  178. dstctx->peerk = NULL;
  179. dstctx->kdf_md = NULL;
  180. dstctx->kdf_ukm = NULL;
  181. /* up-ref all ref-counted objects referenced in dstctx */
  182. if (srcctx->k != NULL && !EC_KEY_up_ref(srcctx->k))
  183. goto err;
  184. else
  185. dstctx->k = srcctx->k;
  186. if (srcctx->peerk != NULL && !EC_KEY_up_ref(srcctx->peerk))
  187. goto err;
  188. else
  189. dstctx->peerk = srcctx->peerk;
  190. if (srcctx->kdf_md != NULL && !EVP_MD_up_ref(srcctx->kdf_md))
  191. goto err;
  192. else
  193. dstctx->kdf_md = srcctx->kdf_md;
  194. /* Duplicate UKM data if present */
  195. if (srcctx->kdf_ukm != NULL && srcctx->kdf_ukmlen > 0) {
  196. dstctx->kdf_ukm = OPENSSL_memdup(srcctx->kdf_ukm,
  197. srcctx->kdf_ukmlen);
  198. if (dstctx->kdf_ukm == NULL)
  199. goto err;
  200. }
  201. return dstctx;
  202. err:
  203. ecdh_freectx(dstctx);
  204. return NULL;
  205. }
  206. static
  207. int ecdh_set_ctx_params(void *vpecdhctx, const OSSL_PARAM params[])
  208. {
  209. char name[80] = { '\0' }; /* should be big enough */
  210. char *str = NULL;
  211. PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
  212. const OSSL_PARAM *p;
  213. if (pectx == NULL)
  214. return 0;
  215. if (ossl_param_is_empty(params))
  216. return 1;
  217. if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE0, params,
  218. OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK))
  219. return 0;
  220. if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE1, params,
  221. OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK))
  222. return 0;
  223. if (!OSSL_FIPS_IND_SET_CTX_PARAM(pectx, OSSL_FIPS_IND_SETTABLE2, params,
  224. OSSL_EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK))
  225. return 0;
  226. p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
  227. if (p != NULL) {
  228. int mode;
  229. if (!OSSL_PARAM_get_int(p, &mode))
  230. return 0;
  231. if (mode < -1 || mode > 1)
  232. return 0;
  233. pectx->cofactor_mode = mode;
  234. }
  235. p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
  236. if (p != NULL) {
  237. str = name;
  238. if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
  239. return 0;
  240. if (name[0] == '\0')
  241. pectx->kdf_type = PROV_ECDH_KDF_NONE;
  242. else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0)
  243. pectx->kdf_type = PROV_ECDH_KDF_X9_63;
  244. else
  245. return 0;
  246. }
  247. p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
  248. if (p != NULL) {
  249. char mdprops[80] = { '\0' }; /* should be big enough */
  250. str = name;
  251. if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(name)))
  252. return 0;
  253. str = mdprops;
  254. p = OSSL_PARAM_locate_const(params,
  255. OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS);
  256. if (p != NULL) {
  257. if (!OSSL_PARAM_get_utf8_string(p, &str, sizeof(mdprops)))
  258. return 0;
  259. }
  260. EVP_MD_free(pectx->kdf_md);
  261. pectx->kdf_md = EVP_MD_fetch(pectx->libctx, name, mdprops);
  262. if (pectx->kdf_md == NULL)
  263. return 0;
  264. /* XOF digests are not allowed */
  265. if (EVP_MD_xof(pectx->kdf_md)) {
  266. ERR_raise(ERR_LIB_PROV, PROV_R_XOF_DIGESTS_NOT_ALLOWED);
  267. return 0;
  268. }
  269. #ifdef FIPS_MODULE
  270. if (!ossl_fips_ind_digest_exch_check(OSSL_FIPS_IND_GET(pectx),
  271. OSSL_FIPS_IND_SETTABLE1, pectx->libctx,
  272. pectx->kdf_md, "ECDH Set Ctx")) {
  273. EVP_MD_free(pectx->kdf_md);
  274. pectx->kdf_md = NULL;
  275. return 0;
  276. }
  277. #endif
  278. }
  279. p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
  280. if (p != NULL) {
  281. size_t outlen;
  282. if (!OSSL_PARAM_get_size_t(p, &outlen))
  283. return 0;
  284. pectx->kdf_outlen = outlen;
  285. }
  286. p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
  287. if (p != NULL) {
  288. void *tmp_ukm = NULL;
  289. size_t tmp_ukmlen;
  290. if (!OSSL_PARAM_get_octet_string(p, &tmp_ukm, 0, &tmp_ukmlen))
  291. return 0;
  292. OPENSSL_free(pectx->kdf_ukm);
  293. pectx->kdf_ukm = tmp_ukm;
  294. pectx->kdf_ukmlen = tmp_ukmlen;
  295. }
  296. return 1;
  297. }
  298. static const OSSL_PARAM known_settable_ctx_params[] = {
  299. OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
  300. OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
  301. OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
  302. OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST_PROPS, NULL, 0),
  303. OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
  304. OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0),
  305. OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_KEY_CHECK)
  306. OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_DIGEST_CHECK)
  307. OSSL_FIPS_IND_SETTABLE_CTX_PARAM(OSSL_EXCHANGE_PARAM_FIPS_ECDH_COFACTOR_CHECK)
  308. OSSL_PARAM_END
  309. };
  310. static
  311. const OSSL_PARAM *ecdh_settable_ctx_params(ossl_unused void *vpecdhctx,
  312. ossl_unused void *provctx)
  313. {
  314. return known_settable_ctx_params;
  315. }
  316. static
  317. int ecdh_get_ctx_params(void *vpecdhctx, OSSL_PARAM params[])
  318. {
  319. PROV_ECDH_CTX *pectx = (PROV_ECDH_CTX *)vpecdhctx;
  320. OSSL_PARAM *p;
  321. if (pectx == NULL)
  322. return 0;
  323. p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE);
  324. if (p != NULL) {
  325. int mode = pectx->cofactor_mode;
  326. if (mode == -1) {
  327. /* check what is the default for pecdhctx->k */
  328. mode = EC_KEY_get_flags(pectx->k) & EC_FLAG_COFACTOR_ECDH ? 1 : 0;
  329. }
  330. if (!OSSL_PARAM_set_int(p, mode))
  331. return 0;
  332. }
  333. p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE);
  334. if (p != NULL) {
  335. const char *kdf_type = NULL;
  336. switch (pectx->kdf_type) {
  337. case PROV_ECDH_KDF_NONE:
  338. kdf_type = "";
  339. break;
  340. case PROV_ECDH_KDF_X9_63:
  341. kdf_type = OSSL_KDF_NAME_X963KDF;
  342. break;
  343. default:
  344. return 0;
  345. }
  346. if (!OSSL_PARAM_set_utf8_string(p, kdf_type))
  347. return 0;
  348. }
  349. p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST);
  350. if (p != NULL
  351. && !OSSL_PARAM_set_utf8_string(p, pectx->kdf_md == NULL
  352. ? ""
  353. : EVP_MD_get0_name(pectx->kdf_md))) {
  354. return 0;
  355. }
  356. p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN);
  357. if (p != NULL && !OSSL_PARAM_set_size_t(p, pectx->kdf_outlen))
  358. return 0;
  359. p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM);
  360. if (p != NULL &&
  361. !OSSL_PARAM_set_octet_ptr(p, pectx->kdf_ukm, pectx->kdf_ukmlen))
  362. return 0;
  363. if (!OSSL_FIPS_IND_GET_CTX_PARAM(pectx, params))
  364. return 0;
  365. return 1;
  366. }
  367. static const OSSL_PARAM known_gettable_ctx_params[] = {
  368. OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL),
  369. OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0),
  370. OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0),
  371. OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL),
  372. OSSL_PARAM_DEFN(OSSL_EXCHANGE_PARAM_KDF_UKM, OSSL_PARAM_OCTET_PTR,
  373. NULL, 0),
  374. OSSL_FIPS_IND_GETTABLE_CTX_PARAM()
  375. OSSL_PARAM_END
  376. };
  377. static
  378. const OSSL_PARAM *ecdh_gettable_ctx_params(ossl_unused void *vpecdhctx,
  379. ossl_unused void *provctx)
  380. {
  381. return known_gettable_ctx_params;
  382. }
  383. static ossl_inline
  384. size_t ecdh_size(const EC_KEY *k)
  385. {
  386. size_t degree = 0;
  387. const EC_GROUP *group;
  388. if (k == NULL
  389. || (group = EC_KEY_get0_group(k)) == NULL)
  390. return 0;
  391. degree = EC_GROUP_get_degree(group);
  392. return (degree + 7) / 8;
  393. }
  394. static ossl_inline
  395. int ecdh_plain_derive(void *vpecdhctx, unsigned char *secret,
  396. size_t *psecretlen, size_t outlen)
  397. {
  398. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  399. int retlen, ret = 0;
  400. size_t ecdhsize, size;
  401. const EC_POINT *ppubkey = NULL;
  402. EC_KEY *privk = NULL;
  403. const EC_GROUP *group;
  404. const BIGNUM *cofactor;
  405. int key_cofactor_mode;
  406. int has_cofactor;
  407. #ifdef FIPS_MODULE
  408. int cofactor_approved = 0;
  409. #endif
  410. if (pecdhctx->k == NULL || pecdhctx->peerk == NULL) {
  411. ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY);
  412. return 0;
  413. }
  414. ecdhsize = ecdh_size(pecdhctx->k);
  415. if (secret == NULL) {
  416. *psecretlen = ecdhsize;
  417. return 1;
  418. }
  419. if ((group = EC_KEY_get0_group(pecdhctx->k)) == NULL
  420. || (cofactor = EC_GROUP_get0_cofactor(group)) == NULL)
  421. return 0;
  422. has_cofactor = !BN_is_one(cofactor);
  423. /*
  424. * NB: unlike PKCS#3 DH, if outlen is less than maximum size this is not
  425. * an error, the result is truncated.
  426. */
  427. size = outlen < ecdhsize ? outlen : ecdhsize;
  428. /*
  429. * The ctx->cofactor_mode flag has precedence over the
  430. * cofactor_mode flag set on ctx->k.
  431. *
  432. * - if ctx->cofactor_mode == -1, use ctx->k directly
  433. * - if ctx->cofactor_mode == key_cofactor_mode, use ctx->k directly
  434. * - if ctx->cofactor_mode != key_cofactor_mode:
  435. * - if ctx->k->cofactor == 1, the cofactor_mode flag is irrelevant, use
  436. * ctx->k directly
  437. * - if ctx->k->cofactor != 1, use a duplicate of ctx->k with the flag
  438. * set to ctx->cofactor_mode
  439. */
  440. key_cofactor_mode =
  441. (EC_KEY_get_flags(pecdhctx->k) & EC_FLAG_COFACTOR_ECDH) ? 1 : 0;
  442. if (pecdhctx->cofactor_mode != -1
  443. && pecdhctx->cofactor_mode != key_cofactor_mode
  444. && has_cofactor) {
  445. if ((privk = EC_KEY_dup(pecdhctx->k)) == NULL)
  446. return 0;
  447. if (pecdhctx->cofactor_mode == 1) {
  448. EC_KEY_set_flags(privk, EC_FLAG_COFACTOR_ECDH);
  449. #ifdef FIPS_MODULE
  450. cofactor_approved = 1;
  451. #endif
  452. } else {
  453. EC_KEY_clear_flags(privk, EC_FLAG_COFACTOR_ECDH);
  454. }
  455. } else {
  456. privk = pecdhctx->k;
  457. #ifdef FIPS_MODULE
  458. cofactor_approved = key_cofactor_mode;
  459. #endif
  460. }
  461. #ifdef FIPS_MODULE
  462. /*
  463. * SP800-56A r3 Section 5.7.1.2 requires ECC Cofactor DH to be used.
  464. * This applies to the 'B' and 'K' curves that have cofactors that are not 1.
  465. */
  466. if (has_cofactor && !cofactor_approved) {
  467. if (!OSSL_FIPS_IND_ON_UNAPPROVED(pecdhctx, OSSL_FIPS_IND_SETTABLE2,
  468. pecdhctx->libctx, "ECDH", "Cofactor",
  469. ossl_fips_config_ecdh_cofactor_check)) {
  470. ERR_raise(ERR_LIB_PROV, PROV_R_COFACTOR_REQUIRED);
  471. goto end;
  472. }
  473. }
  474. #endif
  475. ppubkey = EC_KEY_get0_public_key(pecdhctx->peerk);
  476. retlen = ECDH_compute_key(secret, size, ppubkey, privk, NULL);
  477. if (retlen <= 0)
  478. goto end;
  479. *psecretlen = retlen;
  480. ret = 1;
  481. end:
  482. if (privk != pecdhctx->k)
  483. EC_KEY_free(privk);
  484. return ret;
  485. }
  486. static ossl_inline
  487. int ecdh_X9_63_kdf_derive(void *vpecdhctx, unsigned char *secret,
  488. size_t *psecretlen, size_t outlen)
  489. {
  490. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  491. unsigned char *stmp = NULL;
  492. size_t stmplen;
  493. int ret = 0;
  494. if (secret == NULL) {
  495. *psecretlen = pecdhctx->kdf_outlen;
  496. return 1;
  497. }
  498. if (pecdhctx->kdf_outlen > outlen) {
  499. ERR_raise(ERR_LIB_PROV, PROV_R_OUTPUT_BUFFER_TOO_SMALL);
  500. return 0;
  501. }
  502. if (!ecdh_plain_derive(vpecdhctx, NULL, &stmplen, 0))
  503. return 0;
  504. if ((stmp = OPENSSL_secure_malloc(stmplen)) == NULL)
  505. return 0;
  506. if (!ecdh_plain_derive(vpecdhctx, stmp, &stmplen, stmplen))
  507. goto err;
  508. /* Do KDF stuff */
  509. if (!ossl_ecdh_kdf_X9_63(secret, pecdhctx->kdf_outlen,
  510. stmp, stmplen,
  511. pecdhctx->kdf_ukm,
  512. pecdhctx->kdf_ukmlen,
  513. pecdhctx->kdf_md,
  514. pecdhctx->libctx, NULL))
  515. goto err;
  516. *psecretlen = pecdhctx->kdf_outlen;
  517. ret = 1;
  518. err:
  519. OPENSSL_secure_clear_free(stmp, stmplen);
  520. return ret;
  521. }
  522. static
  523. int ecdh_derive(void *vpecdhctx, unsigned char *secret,
  524. size_t *psecretlen, size_t outlen)
  525. {
  526. PROV_ECDH_CTX *pecdhctx = (PROV_ECDH_CTX *)vpecdhctx;
  527. switch (pecdhctx->kdf_type) {
  528. case PROV_ECDH_KDF_NONE:
  529. return ecdh_plain_derive(vpecdhctx, secret, psecretlen, outlen);
  530. case PROV_ECDH_KDF_X9_63:
  531. return ecdh_X9_63_kdf_derive(vpecdhctx, secret, psecretlen, outlen);
  532. default:
  533. break;
  534. }
  535. return 0;
  536. }
  537. const OSSL_DISPATCH ossl_ecdh_keyexch_functions[] = {
  538. { OSSL_FUNC_KEYEXCH_NEWCTX, (void (*)(void))ecdh_newctx },
  539. { OSSL_FUNC_KEYEXCH_INIT, (void (*)(void))ecdh_init },
  540. { OSSL_FUNC_KEYEXCH_DERIVE, (void (*)(void))ecdh_derive },
  541. { OSSL_FUNC_KEYEXCH_SET_PEER, (void (*)(void))ecdh_set_peer },
  542. { OSSL_FUNC_KEYEXCH_FREECTX, (void (*)(void))ecdh_freectx },
  543. { OSSL_FUNC_KEYEXCH_DUPCTX, (void (*)(void))ecdh_dupctx },
  544. { OSSL_FUNC_KEYEXCH_SET_CTX_PARAMS, (void (*)(void))ecdh_set_ctx_params },
  545. { OSSL_FUNC_KEYEXCH_SETTABLE_CTX_PARAMS,
  546. (void (*)(void))ecdh_settable_ctx_params },
  547. { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void (*)(void))ecdh_get_ctx_params },
  548. { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS,
  549. (void (*)(void))ecdh_gettable_ctx_params },
  550. OSSL_DISPATCH_END
  551. };