xref: /freebsd/crypto/openssl/crypto/dh/dh_pmeth.c (revision b077aed3)
16f9291ceSJung-uk Kim /*
2*b077aed3SPierre Pronchery  * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
31f13597dSJung-uk Kim  *
4*b077aed3SPierre Pronchery  * Licensed under the Apache License 2.0 (the "License").  You may not use
5e71b7053SJung-uk Kim  * this file except in compliance with the License.  You can obtain a copy
6e71b7053SJung-uk Kim  * in the file LICENSE in the source distribution or at
7e71b7053SJung-uk Kim  * https://www.openssl.org/source/license.html
81f13597dSJung-uk Kim  */
91f13597dSJung-uk Kim 
10*b077aed3SPierre Pronchery /*
11*b077aed3SPierre Pronchery  * DH & DSA low level APIs are deprecated for public use, but still ok for
12*b077aed3SPierre Pronchery  * internal use.
13*b077aed3SPierre Pronchery  */
14*b077aed3SPierre Pronchery #include "internal/deprecated.h"
15*b077aed3SPierre Pronchery 
161f13597dSJung-uk Kim #include <stdio.h>
17e71b7053SJung-uk Kim #include "internal/cryptlib.h"
181f13597dSJung-uk Kim #include <openssl/asn1t.h>
191f13597dSJung-uk Kim #include <openssl/x509.h>
201f13597dSJung-uk Kim #include <openssl/evp.h>
2117f01e99SJung-uk Kim #include "dh_local.h"
221f13597dSJung-uk Kim #include <openssl/bn.h>
237bded2dbSJung-uk Kim #include <openssl/dsa.h>
247bded2dbSJung-uk Kim #include <openssl/objects.h>
2517f01e99SJung-uk Kim #include "crypto/evp.h"
261f13597dSJung-uk Kim 
271f13597dSJung-uk Kim /* DH pkey context structure */
281f13597dSJung-uk Kim 
296f9291ceSJung-uk Kim typedef struct {
301f13597dSJung-uk Kim     /* Parameter gen parameters */
311f13597dSJung-uk Kim     int prime_len;
321f13597dSJung-uk Kim     int generator;
33*b077aed3SPierre Pronchery     int paramgen_type;
347bded2dbSJung-uk Kim     int subprime_len;
35e71b7053SJung-uk Kim     int pad;
367bded2dbSJung-uk Kim     /* message digest used for parameter generation */
377bded2dbSJung-uk Kim     const EVP_MD *md;
38e71b7053SJung-uk Kim     int param_nid;
391f13597dSJung-uk Kim     /* Keygen callback info */
401f13597dSJung-uk Kim     int gentmp[2];
417bded2dbSJung-uk Kim     /* KDF (if any) to use for DH */
427bded2dbSJung-uk Kim     char kdf_type;
437bded2dbSJung-uk Kim     /* OID to use for KDF */
447bded2dbSJung-uk Kim     ASN1_OBJECT *kdf_oid;
457bded2dbSJung-uk Kim     /* Message digest to use for key derivation */
467bded2dbSJung-uk Kim     const EVP_MD *kdf_md;
477bded2dbSJung-uk Kim     /* User key material */
487bded2dbSJung-uk Kim     unsigned char *kdf_ukm;
497bded2dbSJung-uk Kim     size_t kdf_ukmlen;
507bded2dbSJung-uk Kim     /* KDF output length */
517bded2dbSJung-uk Kim     size_t kdf_outlen;
521f13597dSJung-uk Kim } DH_PKEY_CTX;
531f13597dSJung-uk Kim 
pkey_dh_init(EVP_PKEY_CTX * ctx)541f13597dSJung-uk Kim static int pkey_dh_init(EVP_PKEY_CTX *ctx)
551f13597dSJung-uk Kim {
561f13597dSJung-uk Kim     DH_PKEY_CTX *dctx;
57e71b7053SJung-uk Kim 
58e71b7053SJung-uk Kim     if ((dctx = OPENSSL_zalloc(sizeof(*dctx))) == NULL) {
59*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
601f13597dSJung-uk Kim         return 0;
61e71b7053SJung-uk Kim     }
62610a21fdSJung-uk Kim     dctx->prime_len = 2048;
637bded2dbSJung-uk Kim     dctx->subprime_len = -1;
641f13597dSJung-uk Kim     dctx->generator = 2;
657bded2dbSJung-uk Kim     dctx->kdf_type = EVP_PKEY_DH_KDF_NONE;
661f13597dSJung-uk Kim 
671f13597dSJung-uk Kim     ctx->data = dctx;
681f13597dSJung-uk Kim     ctx->keygen_info = dctx->gentmp;
691f13597dSJung-uk Kim     ctx->keygen_info_count = 2;
701f13597dSJung-uk Kim 
711f13597dSJung-uk Kim     return 1;
721f13597dSJung-uk Kim }
731f13597dSJung-uk Kim 
pkey_dh_cleanup(EVP_PKEY_CTX * ctx)74e71b7053SJung-uk Kim static void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
75e71b7053SJung-uk Kim {
76e71b7053SJung-uk Kim     DH_PKEY_CTX *dctx = ctx->data;
77*b077aed3SPierre Pronchery 
78e71b7053SJung-uk Kim     if (dctx != NULL) {
79e71b7053SJung-uk Kim         OPENSSL_free(dctx->kdf_ukm);
80e71b7053SJung-uk Kim         ASN1_OBJECT_free(dctx->kdf_oid);
81e71b7053SJung-uk Kim         OPENSSL_free(dctx);
82e71b7053SJung-uk Kim     }
83e71b7053SJung-uk Kim }
84e71b7053SJung-uk Kim 
85e71b7053SJung-uk Kim 
pkey_dh_copy(EVP_PKEY_CTX * dst,const EVP_PKEY_CTX * src)86*b077aed3SPierre Pronchery static int pkey_dh_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
871f13597dSJung-uk Kim {
881f13597dSJung-uk Kim     DH_PKEY_CTX *dctx, *sctx;
89*b077aed3SPierre Pronchery 
901f13597dSJung-uk Kim     if (!pkey_dh_init(dst))
911f13597dSJung-uk Kim         return 0;
921f13597dSJung-uk Kim     sctx = src->data;
931f13597dSJung-uk Kim     dctx = dst->data;
941f13597dSJung-uk Kim     dctx->prime_len = sctx->prime_len;
957bded2dbSJung-uk Kim     dctx->subprime_len = sctx->subprime_len;
961f13597dSJung-uk Kim     dctx->generator = sctx->generator;
97*b077aed3SPierre Pronchery     dctx->paramgen_type = sctx->paramgen_type;
98e71b7053SJung-uk Kim     dctx->pad = sctx->pad;
997bded2dbSJung-uk Kim     dctx->md = sctx->md;
100e71b7053SJung-uk Kim     dctx->param_nid = sctx->param_nid;
1017bded2dbSJung-uk Kim 
1027bded2dbSJung-uk Kim     dctx->kdf_type = sctx->kdf_type;
1037bded2dbSJung-uk Kim     dctx->kdf_oid = OBJ_dup(sctx->kdf_oid);
104e71b7053SJung-uk Kim     if (dctx->kdf_oid == NULL)
1057bded2dbSJung-uk Kim         return 0;
1067bded2dbSJung-uk Kim     dctx->kdf_md = sctx->kdf_md;
107e71b7053SJung-uk Kim     if (sctx->kdf_ukm != NULL) {
108e71b7053SJung-uk Kim         dctx->kdf_ukm = OPENSSL_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
109e71b7053SJung-uk Kim         if (dctx->kdf_ukm == NULL)
110e71b7053SJung-uk Kim           return 0;
1117bded2dbSJung-uk Kim         dctx->kdf_ukmlen = sctx->kdf_ukmlen;
1127bded2dbSJung-uk Kim     }
1137bded2dbSJung-uk Kim     dctx->kdf_outlen = sctx->kdf_outlen;
1141f13597dSJung-uk Kim     return 1;
1151f13597dSJung-uk Kim }
1161f13597dSJung-uk Kim 
pkey_dh_ctrl(EVP_PKEY_CTX * ctx,int type,int p1,void * p2)1171f13597dSJung-uk Kim static int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
1181f13597dSJung-uk Kim {
1191f13597dSJung-uk Kim     DH_PKEY_CTX *dctx = ctx->data;
1206f9291ceSJung-uk Kim     switch (type) {
1211f13597dSJung-uk Kim     case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
1221f13597dSJung-uk Kim         if (p1 < 256)
1231f13597dSJung-uk Kim             return -2;
1241f13597dSJung-uk Kim         dctx->prime_len = p1;
1251f13597dSJung-uk Kim         return 1;
1261f13597dSJung-uk Kim 
1277bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN:
128*b077aed3SPierre Pronchery         if (dctx->paramgen_type == DH_PARAMGEN_TYPE_GENERATOR)
1297bded2dbSJung-uk Kim             return -2;
1307bded2dbSJung-uk Kim         dctx->subprime_len = p1;
1317bded2dbSJung-uk Kim         return 1;
1327bded2dbSJung-uk Kim 
133e71b7053SJung-uk Kim     case EVP_PKEY_CTRL_DH_PAD:
134e71b7053SJung-uk Kim         dctx->pad = p1;
135e71b7053SJung-uk Kim         return 1;
136e71b7053SJung-uk Kim 
1371f13597dSJung-uk Kim     case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
138*b077aed3SPierre Pronchery         if (dctx->paramgen_type != DH_PARAMGEN_TYPE_GENERATOR)
1397bded2dbSJung-uk Kim             return -2;
1401f13597dSJung-uk Kim         dctx->generator = p1;
1411f13597dSJung-uk Kim         return 1;
1421f13597dSJung-uk Kim 
1437bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_PARAMGEN_TYPE:
1447bded2dbSJung-uk Kim #ifdef OPENSSL_NO_DSA
145*b077aed3SPierre Pronchery         if (p1 != DH_PARAMGEN_TYPE_GENERATOR)
1467bded2dbSJung-uk Kim             return -2;
1477bded2dbSJung-uk Kim #else
1487bded2dbSJung-uk Kim         if (p1 < 0 || p1 > 2)
1497bded2dbSJung-uk Kim             return -2;
1507bded2dbSJung-uk Kim #endif
151*b077aed3SPierre Pronchery         dctx->paramgen_type = p1;
1527bded2dbSJung-uk Kim         return 1;
1537bded2dbSJung-uk Kim 
1547bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_RFC5114:
155e71b7053SJung-uk Kim         if (p1 < 1 || p1 > 3 || dctx->param_nid != NID_undef)
1567bded2dbSJung-uk Kim             return -2;
157*b077aed3SPierre Pronchery         dctx->param_nid = p1;
1587bded2dbSJung-uk Kim         return 1;
1597bded2dbSJung-uk Kim 
160e71b7053SJung-uk Kim     case EVP_PKEY_CTRL_DH_NID:
161*b077aed3SPierre Pronchery         if (p1 <= 0 || dctx->param_nid != NID_undef)
162e71b7053SJung-uk Kim             return -2;
163e71b7053SJung-uk Kim         dctx->param_nid = p1;
164e71b7053SJung-uk Kim         return 1;
165e71b7053SJung-uk Kim 
1661f13597dSJung-uk Kim     case EVP_PKEY_CTRL_PEER_KEY:
1671f13597dSJung-uk Kim         /* Default behaviour is OK */
1681f13597dSJung-uk Kim         return 1;
1691f13597dSJung-uk Kim 
1707bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_KDF_TYPE:
1717bded2dbSJung-uk Kim         if (p1 == -2)
1727bded2dbSJung-uk Kim             return dctx->kdf_type;
1737bded2dbSJung-uk Kim         if (p1 != EVP_PKEY_DH_KDF_NONE && p1 != EVP_PKEY_DH_KDF_X9_42)
1747bded2dbSJung-uk Kim             return -2;
1757bded2dbSJung-uk Kim         dctx->kdf_type = p1;
1767bded2dbSJung-uk Kim         return 1;
1777bded2dbSJung-uk Kim 
1787bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_KDF_MD:
1797bded2dbSJung-uk Kim         dctx->kdf_md = p2;
1807bded2dbSJung-uk Kim         return 1;
1817bded2dbSJung-uk Kim 
1827bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_GET_DH_KDF_MD:
1837bded2dbSJung-uk Kim         *(const EVP_MD **)p2 = dctx->kdf_md;
1847bded2dbSJung-uk Kim         return 1;
1857bded2dbSJung-uk Kim 
1867bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_KDF_OUTLEN:
1877bded2dbSJung-uk Kim         if (p1 <= 0)
1887bded2dbSJung-uk Kim             return -2;
1897bded2dbSJung-uk Kim         dctx->kdf_outlen = (size_t)p1;
1907bded2dbSJung-uk Kim         return 1;
1917bded2dbSJung-uk Kim 
1927bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN:
1937bded2dbSJung-uk Kim         *(int *)p2 = dctx->kdf_outlen;
1947bded2dbSJung-uk Kim         return 1;
1957bded2dbSJung-uk Kim 
1967bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_KDF_UKM:
1977bded2dbSJung-uk Kim         OPENSSL_free(dctx->kdf_ukm);
1987bded2dbSJung-uk Kim         dctx->kdf_ukm = p2;
1997bded2dbSJung-uk Kim         if (p2)
2007bded2dbSJung-uk Kim             dctx->kdf_ukmlen = p1;
2017bded2dbSJung-uk Kim         else
2027bded2dbSJung-uk Kim             dctx->kdf_ukmlen = 0;
2037bded2dbSJung-uk Kim         return 1;
2047bded2dbSJung-uk Kim 
2057bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_GET_DH_KDF_UKM:
2067bded2dbSJung-uk Kim         *(unsigned char **)p2 = dctx->kdf_ukm;
2077bded2dbSJung-uk Kim         return dctx->kdf_ukmlen;
2087bded2dbSJung-uk Kim 
2097bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_DH_KDF_OID:
2107bded2dbSJung-uk Kim         ASN1_OBJECT_free(dctx->kdf_oid);
2117bded2dbSJung-uk Kim         dctx->kdf_oid = p2;
2127bded2dbSJung-uk Kim         return 1;
2137bded2dbSJung-uk Kim 
2147bded2dbSJung-uk Kim     case EVP_PKEY_CTRL_GET_DH_KDF_OID:
2157bded2dbSJung-uk Kim         *(ASN1_OBJECT **)p2 = dctx->kdf_oid;
2167bded2dbSJung-uk Kim         return 1;
2177bded2dbSJung-uk Kim 
2181f13597dSJung-uk Kim     default:
2191f13597dSJung-uk Kim         return -2;
2201f13597dSJung-uk Kim 
2211f13597dSJung-uk Kim     }
2221f13597dSJung-uk Kim }
2231f13597dSJung-uk Kim 
pkey_dh_ctrl_str(EVP_PKEY_CTX * ctx,const char * type,const char * value)2241f13597dSJung-uk Kim static int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
2251f13597dSJung-uk Kim                             const char *type, const char *value)
2261f13597dSJung-uk Kim {
227e71b7053SJung-uk Kim     if (strcmp(type, "dh_paramgen_prime_len") == 0) {
2281f13597dSJung-uk Kim         int len;
2291f13597dSJung-uk Kim         len = atoi(value);
2301f13597dSJung-uk Kim         return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
2311f13597dSJung-uk Kim     }
232e71b7053SJung-uk Kim     if (strcmp(type, "dh_rfc5114") == 0) {
2337bded2dbSJung-uk Kim         DH_PKEY_CTX *dctx = ctx->data;
234*b077aed3SPierre Pronchery         int id;
235*b077aed3SPierre Pronchery 
236*b077aed3SPierre Pronchery         id = atoi(value);
237*b077aed3SPierre Pronchery         if (id < 0 || id > 3)
2387bded2dbSJung-uk Kim             return -2;
239*b077aed3SPierre Pronchery         dctx->param_nid = id;
2407bded2dbSJung-uk Kim         return 1;
2417bded2dbSJung-uk Kim     }
242e71b7053SJung-uk Kim     if (strcmp(type, "dh_param") == 0) {
243e71b7053SJung-uk Kim         DH_PKEY_CTX *dctx = ctx->data;
244e71b7053SJung-uk Kim         int nid = OBJ_sn2nid(value);
245e71b7053SJung-uk Kim 
246e71b7053SJung-uk Kim         if (nid == NID_undef) {
247*b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME);
248e71b7053SJung-uk Kim             return -2;
249e71b7053SJung-uk Kim         }
250e71b7053SJung-uk Kim         dctx->param_nid = nid;
251e71b7053SJung-uk Kim         return 1;
252e71b7053SJung-uk Kim     }
253e71b7053SJung-uk Kim     if (strcmp(type, "dh_paramgen_generator") == 0) {
2541f13597dSJung-uk Kim         int len;
2551f13597dSJung-uk Kim         len = atoi(value);
2561f13597dSJung-uk Kim         return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
2571f13597dSJung-uk Kim     }
258e71b7053SJung-uk Kim     if (strcmp(type, "dh_paramgen_subprime_len") == 0) {
2597bded2dbSJung-uk Kim         int len;
2607bded2dbSJung-uk Kim         len = atoi(value);
2617bded2dbSJung-uk Kim         return EVP_PKEY_CTX_set_dh_paramgen_subprime_len(ctx, len);
2627bded2dbSJung-uk Kim     }
263e71b7053SJung-uk Kim     if (strcmp(type, "dh_paramgen_type") == 0) {
2647bded2dbSJung-uk Kim         int typ;
2657bded2dbSJung-uk Kim         typ = atoi(value);
2667bded2dbSJung-uk Kim         return EVP_PKEY_CTX_set_dh_paramgen_type(ctx, typ);
2677bded2dbSJung-uk Kim     }
268e71b7053SJung-uk Kim     if (strcmp(type, "dh_pad") == 0) {
269e71b7053SJung-uk Kim         int pad;
270e71b7053SJung-uk Kim         pad = atoi(value);
271e71b7053SJung-uk Kim         return EVP_PKEY_CTX_set_dh_pad(ctx, pad);
272e71b7053SJung-uk Kim     }
2731f13597dSJung-uk Kim     return -2;
2741f13597dSJung-uk Kim }
2751f13597dSJung-uk Kim 
ffc_params_generate(OSSL_LIB_CTX * libctx,DH_PKEY_CTX * dctx,BN_GENCB * pcb)276*b077aed3SPierre Pronchery static DH *ffc_params_generate(OSSL_LIB_CTX *libctx, DH_PKEY_CTX *dctx,
277*b077aed3SPierre Pronchery                                BN_GENCB *pcb)
2787bded2dbSJung-uk Kim {
279*b077aed3SPierre Pronchery     DH *ret;
2807bded2dbSJung-uk Kim     int rv = 0;
281*b077aed3SPierre Pronchery     int res;
2827bded2dbSJung-uk Kim     int prime_len = dctx->prime_len;
2837bded2dbSJung-uk Kim     int subprime_len = dctx->subprime_len;
284*b077aed3SPierre Pronchery 
285*b077aed3SPierre Pronchery     if (dctx->paramgen_type > DH_PARAMGEN_TYPE_FIPS_186_4)
2867bded2dbSJung-uk Kim         return NULL;
287*b077aed3SPierre Pronchery     ret = DH_new();
288e71b7053SJung-uk Kim     if (ret == NULL)
2897bded2dbSJung-uk Kim         return NULL;
290*b077aed3SPierre Pronchery 
2917bded2dbSJung-uk Kim     if (subprime_len == -1) {
2927bded2dbSJung-uk Kim         if (prime_len >= 2048)
2937bded2dbSJung-uk Kim             subprime_len = 256;
2947bded2dbSJung-uk Kim         else
2957bded2dbSJung-uk Kim             subprime_len = 160;
2967bded2dbSJung-uk Kim     }
297*b077aed3SPierre Pronchery 
298*b077aed3SPierre Pronchery     if (dctx->md != NULL)
299*b077aed3SPierre Pronchery         ossl_ffc_set_digest(&ret->params, EVP_MD_get0_name(dctx->md), NULL);
300*b077aed3SPierre Pronchery 
301*b077aed3SPierre Pronchery # ifndef FIPS_MODULE
302*b077aed3SPierre Pronchery     if (dctx->paramgen_type == DH_PARAMGEN_TYPE_FIPS_186_2)
303*b077aed3SPierre Pronchery         rv = ossl_ffc_params_FIPS186_2_generate(libctx, &ret->params,
304*b077aed3SPierre Pronchery                                                 FFC_PARAM_TYPE_DH,
305*b077aed3SPierre Pronchery                                                 prime_len, subprime_len, &res,
306*b077aed3SPierre Pronchery                                                 pcb);
3077bded2dbSJung-uk Kim     else
308*b077aed3SPierre Pronchery # endif
309*b077aed3SPierre Pronchery     /* For FIPS we always use the DH_PARAMGEN_TYPE_FIPS_186_4 generator */
310*b077aed3SPierre Pronchery     if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2)
311*b077aed3SPierre Pronchery         rv = ossl_ffc_params_FIPS186_4_generate(libctx, &ret->params,
312*b077aed3SPierre Pronchery                                                 FFC_PARAM_TYPE_DH,
313*b077aed3SPierre Pronchery                                                 prime_len, subprime_len, &res,
314*b077aed3SPierre Pronchery                                                 pcb);
3157bded2dbSJung-uk Kim     if (rv <= 0) {
316*b077aed3SPierre Pronchery         DH_free(ret);
3177bded2dbSJung-uk Kim         return NULL;
3187bded2dbSJung-uk Kim     }
3197bded2dbSJung-uk Kim     return ret;
3207bded2dbSJung-uk Kim }
3217bded2dbSJung-uk Kim 
pkey_dh_paramgen(EVP_PKEY_CTX * ctx,EVP_PKEY * pkey)322*b077aed3SPierre Pronchery static int pkey_dh_paramgen(EVP_PKEY_CTX *ctx,
323*b077aed3SPierre Pronchery                             EVP_PKEY *pkey)
3241f13597dSJung-uk Kim {
3251f13597dSJung-uk Kim     DH *dh = NULL;
3261f13597dSJung-uk Kim     DH_PKEY_CTX *dctx = ctx->data;
327*b077aed3SPierre Pronchery     BN_GENCB *pcb = NULL;
3281f13597dSJung-uk Kim     int ret;
3297bded2dbSJung-uk Kim 
330*b077aed3SPierre Pronchery     /*
331*b077aed3SPierre Pronchery      * Look for a safe prime group for key establishment. Which uses
332*b077aed3SPierre Pronchery      * either RFC_3526 (modp_XXXX) or RFC_7919 (ffdheXXXX).
333*b077aed3SPierre Pronchery      * RFC_5114 is also handled here for param_nid = (1..3)
334*b077aed3SPierre Pronchery      */
335*b077aed3SPierre Pronchery     if (dctx->param_nid != NID_undef) {
336*b077aed3SPierre Pronchery         int type = dctx->param_nid <= 3 ? EVP_PKEY_DHX : EVP_PKEY_DH;
3377bded2dbSJung-uk Kim 
338e71b7053SJung-uk Kim         if ((dh = DH_new_by_nid(dctx->param_nid)) == NULL)
339e71b7053SJung-uk Kim             return 0;
340*b077aed3SPierre Pronchery         EVP_PKEY_assign(pkey, type, dh);
341e71b7053SJung-uk Kim         return 1;
342e71b7053SJung-uk Kim     }
343e71b7053SJung-uk Kim 
344*b077aed3SPierre Pronchery     if (ctx->pkey_gencb != NULL) {
345e71b7053SJung-uk Kim         pcb = BN_GENCB_new();
346e71b7053SJung-uk Kim         if (pcb == NULL)
347e71b7053SJung-uk Kim             return 0;
3481f13597dSJung-uk Kim         evp_pkey_set_cb_translate(pcb, ctx);
349*b077aed3SPierre Pronchery     }
350*b077aed3SPierre Pronchery # ifdef FIPS_MODULE
351*b077aed3SPierre Pronchery     dctx->paramgen_type = DH_PARAMGEN_TYPE_FIPS_186_4;
352*b077aed3SPierre Pronchery # endif /* FIPS_MODULE */
353*b077aed3SPierre Pronchery     if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) {
354*b077aed3SPierre Pronchery         dh = ffc_params_generate(NULL, dctx, pcb);
355e71b7053SJung-uk Kim         BN_GENCB_free(pcb);
356*b077aed3SPierre Pronchery         if (dh == NULL)
3577bded2dbSJung-uk Kim             return 0;
3587bded2dbSJung-uk Kim         EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh);
3597bded2dbSJung-uk Kim         return 1;
3607bded2dbSJung-uk Kim     }
3611f13597dSJung-uk Kim     dh = DH_new();
362e71b7053SJung-uk Kim     if (dh == NULL) {
363e71b7053SJung-uk Kim         BN_GENCB_free(pcb);
3641f13597dSJung-uk Kim         return 0;
365e71b7053SJung-uk Kim     }
3661f13597dSJung-uk Kim     ret = DH_generate_parameters_ex(dh,
3671f13597dSJung-uk Kim                                     dctx->prime_len, dctx->generator, pcb);
368e71b7053SJung-uk Kim     BN_GENCB_free(pcb);
3691f13597dSJung-uk Kim     if (ret)
3701f13597dSJung-uk Kim         EVP_PKEY_assign_DH(pkey, dh);
3711f13597dSJung-uk Kim     else
3721f13597dSJung-uk Kim         DH_free(dh);
3731f13597dSJung-uk Kim     return ret;
3741f13597dSJung-uk Kim }
3751f13597dSJung-uk Kim 
pkey_dh_keygen(EVP_PKEY_CTX * ctx,EVP_PKEY * pkey)3761f13597dSJung-uk Kim static int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
3771f13597dSJung-uk Kim {
378e71b7053SJung-uk Kim     DH_PKEY_CTX *dctx = ctx->data;
3791f13597dSJung-uk Kim     DH *dh = NULL;
380e71b7053SJung-uk Kim 
381*b077aed3SPierre Pronchery     if (ctx->pkey == NULL && dctx->param_nid == NID_undef) {
382*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DH, DH_R_NO_PARAMETERS_SET);
3831f13597dSJung-uk Kim         return 0;
3841f13597dSJung-uk Kim     }
385*b077aed3SPierre Pronchery     if (dctx->param_nid != NID_undef)
386e71b7053SJung-uk Kim         dh = DH_new_by_nid(dctx->param_nid);
387e71b7053SJung-uk Kim     else
3881f13597dSJung-uk Kim         dh = DH_new();
389e71b7053SJung-uk Kim     if (dh == NULL)
3901f13597dSJung-uk Kim         return 0;
3917bded2dbSJung-uk Kim     EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, dh);
3921f13597dSJung-uk Kim     /* Note: if error return, pkey is freed by parent routine */
393e71b7053SJung-uk Kim     if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey))
3941f13597dSJung-uk Kim         return 0;
395*b077aed3SPierre Pronchery     return DH_generate_key((DH *)EVP_PKEY_get0_DH(pkey));
3961f13597dSJung-uk Kim }
3971f13597dSJung-uk Kim 
pkey_dh_derive(EVP_PKEY_CTX * ctx,unsigned char * key,size_t * keylen)3986f9291ceSJung-uk Kim static int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
3996f9291ceSJung-uk Kim                           size_t *keylen)
4001f13597dSJung-uk Kim {
4011f13597dSJung-uk Kim     int ret;
4027bded2dbSJung-uk Kim     DH *dh;
403*b077aed3SPierre Pronchery     const DH *dhpub;
4047bded2dbSJung-uk Kim     DH_PKEY_CTX *dctx = ctx->data;
405*b077aed3SPierre Pronchery     BIGNUM *dhpubbn;
406*b077aed3SPierre Pronchery 
407*b077aed3SPierre Pronchery     if (ctx->pkey == NULL || ctx->peerkey == NULL) {
408*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET);
4091f13597dSJung-uk Kim         return 0;
4101f13597dSJung-uk Kim     }
411*b077aed3SPierre Pronchery     dh = (DH *)EVP_PKEY_get0_DH(ctx->pkey);
412*b077aed3SPierre Pronchery     dhpub = EVP_PKEY_get0_DH(ctx->peerkey);
413*b077aed3SPierre Pronchery     if (dhpub == NULL) {
414*b077aed3SPierre Pronchery         ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET);
415*b077aed3SPierre Pronchery         return 0;
416*b077aed3SPierre Pronchery     }
417*b077aed3SPierre Pronchery     dhpubbn = dhpub->pub_key;
4187bded2dbSJung-uk Kim     if (dctx->kdf_type == EVP_PKEY_DH_KDF_NONE) {
4197bded2dbSJung-uk Kim         if (key == NULL) {
4207bded2dbSJung-uk Kim             *keylen = DH_size(dh);
4217bded2dbSJung-uk Kim             return 1;
4227bded2dbSJung-uk Kim         }
423e71b7053SJung-uk Kim         if (dctx->pad)
424*b077aed3SPierre Pronchery             ret = DH_compute_key_padded(key, dhpubbn, dh);
425e71b7053SJung-uk Kim         else
426*b077aed3SPierre Pronchery             ret = DH_compute_key(key, dhpubbn, dh);
4271f13597dSJung-uk Kim         if (ret < 0)
4281f13597dSJung-uk Kim             return ret;
4291f13597dSJung-uk Kim         *keylen = ret;
4301f13597dSJung-uk Kim         return 1;
43147902a71SJung-uk Kim     }
43247902a71SJung-uk Kim     else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) {
433e71b7053SJung-uk Kim 
4347bded2dbSJung-uk Kim         unsigned char *Z = NULL;
435*b077aed3SPierre Pronchery         int Zlen = 0;
436*b077aed3SPierre Pronchery 
4377bded2dbSJung-uk Kim         if (!dctx->kdf_outlen || !dctx->kdf_oid)
4387bded2dbSJung-uk Kim             return 0;
4397bded2dbSJung-uk Kim         if (key == NULL) {
4407bded2dbSJung-uk Kim             *keylen = dctx->kdf_outlen;
4417bded2dbSJung-uk Kim             return 1;
4427bded2dbSJung-uk Kim         }
4437bded2dbSJung-uk Kim         if (*keylen != dctx->kdf_outlen)
4447bded2dbSJung-uk Kim             return 0;
4457bded2dbSJung-uk Kim         ret = 0;
446*b077aed3SPierre Pronchery         if ((Zlen = DH_size(dh)) <= 0)
447*b077aed3SPierre Pronchery             return 0;
448*b077aed3SPierre Pronchery         if ((Z = OPENSSL_malloc(Zlen)) == NULL) {
449*b077aed3SPierre Pronchery             ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
450*b077aed3SPierre Pronchery             return 0;
4517bded2dbSJung-uk Kim         }
452*b077aed3SPierre Pronchery         if (DH_compute_key_padded(Z, dhpubbn, dh) <= 0)
4537bded2dbSJung-uk Kim             goto err;
4547bded2dbSJung-uk Kim         if (!DH_KDF_X9_42(key, *keylen, Z, Zlen, dctx->kdf_oid,
4557bded2dbSJung-uk Kim                           dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md))
4567bded2dbSJung-uk Kim             goto err;
4577bded2dbSJung-uk Kim         *keylen = dctx->kdf_outlen;
4587bded2dbSJung-uk Kim         ret = 1;
4597bded2dbSJung-uk Kim  err:
460e71b7053SJung-uk Kim         OPENSSL_clear_free(Z, Zlen);
4617bded2dbSJung-uk Kim         return ret;
4627bded2dbSJung-uk Kim     }
463dea77ea6SJung-uk Kim     return 0;
4641f13597dSJung-uk Kim }
4651f13597dSJung-uk Kim 
466*b077aed3SPierre Pronchery static const EVP_PKEY_METHOD dh_pkey_meth = {
4671f13597dSJung-uk Kim     EVP_PKEY_DH,
4687bded2dbSJung-uk Kim     0,
4697bded2dbSJung-uk Kim     pkey_dh_init,
4707bded2dbSJung-uk Kim     pkey_dh_copy,
4717bded2dbSJung-uk Kim     pkey_dh_cleanup,
4727bded2dbSJung-uk Kim 
4737bded2dbSJung-uk Kim     0,
4747bded2dbSJung-uk Kim     pkey_dh_paramgen,
4757bded2dbSJung-uk Kim 
4767bded2dbSJung-uk Kim     0,
4777bded2dbSJung-uk Kim     pkey_dh_keygen,
4787bded2dbSJung-uk Kim 
4797bded2dbSJung-uk Kim     0,
4807bded2dbSJung-uk Kim     0,
4817bded2dbSJung-uk Kim 
4827bded2dbSJung-uk Kim     0,
4837bded2dbSJung-uk Kim     0,
4847bded2dbSJung-uk Kim 
4857bded2dbSJung-uk Kim     0, 0,
4867bded2dbSJung-uk Kim 
4877bded2dbSJung-uk Kim     0, 0, 0, 0,
4887bded2dbSJung-uk Kim 
4897bded2dbSJung-uk Kim     0, 0,
4907bded2dbSJung-uk Kim 
4917bded2dbSJung-uk Kim     0, 0,
4927bded2dbSJung-uk Kim 
4937bded2dbSJung-uk Kim     0,
4947bded2dbSJung-uk Kim     pkey_dh_derive,
4957bded2dbSJung-uk Kim 
4967bded2dbSJung-uk Kim     pkey_dh_ctrl,
4977bded2dbSJung-uk Kim     pkey_dh_ctrl_str
4987bded2dbSJung-uk Kim };
4997bded2dbSJung-uk Kim 
ossl_dh_pkey_method(void)500*b077aed3SPierre Pronchery const EVP_PKEY_METHOD *ossl_dh_pkey_method(void)
501*b077aed3SPierre Pronchery {
502*b077aed3SPierre Pronchery     return &dh_pkey_meth;
503*b077aed3SPierre Pronchery }
504*b077aed3SPierre Pronchery 
505*b077aed3SPierre Pronchery static const EVP_PKEY_METHOD dhx_pkey_meth = {
5067bded2dbSJung-uk Kim     EVP_PKEY_DHX,
5077bded2dbSJung-uk Kim     0,
5081f13597dSJung-uk Kim     pkey_dh_init,
5091f13597dSJung-uk Kim     pkey_dh_copy,
5101f13597dSJung-uk Kim     pkey_dh_cleanup,
5111f13597dSJung-uk Kim 
5121f13597dSJung-uk Kim     0,
5131f13597dSJung-uk Kim     pkey_dh_paramgen,
5141f13597dSJung-uk Kim 
5151f13597dSJung-uk Kim     0,
5161f13597dSJung-uk Kim     pkey_dh_keygen,
5171f13597dSJung-uk Kim 
5181f13597dSJung-uk Kim     0,
5191f13597dSJung-uk Kim     0,
5201f13597dSJung-uk Kim 
5211f13597dSJung-uk Kim     0,
5221f13597dSJung-uk Kim     0,
5231f13597dSJung-uk Kim 
5241f13597dSJung-uk Kim     0, 0,
5251f13597dSJung-uk Kim 
5261f13597dSJung-uk Kim     0, 0, 0, 0,
5271f13597dSJung-uk Kim 
5281f13597dSJung-uk Kim     0, 0,
5291f13597dSJung-uk Kim 
5301f13597dSJung-uk Kim     0, 0,
5311f13597dSJung-uk Kim 
5321f13597dSJung-uk Kim     0,
5331f13597dSJung-uk Kim     pkey_dh_derive,
5341f13597dSJung-uk Kim 
5351f13597dSJung-uk Kim     pkey_dh_ctrl,
5361f13597dSJung-uk Kim     pkey_dh_ctrl_str
5371f13597dSJung-uk Kim };
538*b077aed3SPierre Pronchery 
ossl_dhx_pkey_method(void)539*b077aed3SPierre Pronchery const EVP_PKEY_METHOD *ossl_dhx_pkey_method(void)
540*b077aed3SPierre Pronchery {
541*b077aed3SPierre Pronchery     return &dhx_pkey_meth;
542*b077aed3SPierre Pronchery }
543