11cb0ef41Sopenharmony_ci/*
21cb0ef41Sopenharmony_ci * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
31cb0ef41Sopenharmony_ci *
41cb0ef41Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
51cb0ef41Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
61cb0ef41Sopenharmony_ci * in the file LICENSE in the source distribution or at
71cb0ef41Sopenharmony_ci * https://www.openssl.org/source/license.html
81cb0ef41Sopenharmony_ci */
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci/*
111cb0ef41Sopenharmony_ci * DH & DSA low level APIs are deprecated for public use, but still ok for
121cb0ef41Sopenharmony_ci * internal use.
131cb0ef41Sopenharmony_ci */
141cb0ef41Sopenharmony_ci#include "internal/deprecated.h"
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci#include <stdio.h>
171cb0ef41Sopenharmony_ci#include "internal/cryptlib.h"
181cb0ef41Sopenharmony_ci#include <openssl/asn1t.h>
191cb0ef41Sopenharmony_ci#include <openssl/x509.h>
201cb0ef41Sopenharmony_ci#include <openssl/evp.h>
211cb0ef41Sopenharmony_ci#include "dh_local.h"
221cb0ef41Sopenharmony_ci#include <openssl/bn.h>
231cb0ef41Sopenharmony_ci#include <openssl/dsa.h>
241cb0ef41Sopenharmony_ci#include <openssl/objects.h>
251cb0ef41Sopenharmony_ci#include "crypto/evp.h"
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_ci/* DH pkey context structure */
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_citypedef struct {
301cb0ef41Sopenharmony_ci    /* Parameter gen parameters */
311cb0ef41Sopenharmony_ci    int prime_len;
321cb0ef41Sopenharmony_ci    int generator;
331cb0ef41Sopenharmony_ci    int paramgen_type;
341cb0ef41Sopenharmony_ci    int subprime_len;
351cb0ef41Sopenharmony_ci    int pad;
361cb0ef41Sopenharmony_ci    /* message digest used for parameter generation */
371cb0ef41Sopenharmony_ci    const EVP_MD *md;
381cb0ef41Sopenharmony_ci    int param_nid;
391cb0ef41Sopenharmony_ci    /* Keygen callback info */
401cb0ef41Sopenharmony_ci    int gentmp[2];
411cb0ef41Sopenharmony_ci    /* KDF (if any) to use for DH */
421cb0ef41Sopenharmony_ci    char kdf_type;
431cb0ef41Sopenharmony_ci    /* OID to use for KDF */
441cb0ef41Sopenharmony_ci    ASN1_OBJECT *kdf_oid;
451cb0ef41Sopenharmony_ci    /* Message digest to use for key derivation */
461cb0ef41Sopenharmony_ci    const EVP_MD *kdf_md;
471cb0ef41Sopenharmony_ci    /* User key material */
481cb0ef41Sopenharmony_ci    unsigned char *kdf_ukm;
491cb0ef41Sopenharmony_ci    size_t kdf_ukmlen;
501cb0ef41Sopenharmony_ci    /* KDF output length */
511cb0ef41Sopenharmony_ci    size_t kdf_outlen;
521cb0ef41Sopenharmony_ci} DH_PKEY_CTX;
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_cistatic int pkey_dh_init(EVP_PKEY_CTX *ctx)
551cb0ef41Sopenharmony_ci{
561cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx;
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci    if ((dctx = OPENSSL_zalloc(sizeof(*dctx))) == NULL) {
591cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
601cb0ef41Sopenharmony_ci        return 0;
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci    dctx->prime_len = 2048;
631cb0ef41Sopenharmony_ci    dctx->subprime_len = -1;
641cb0ef41Sopenharmony_ci    dctx->generator = 2;
651cb0ef41Sopenharmony_ci    dctx->kdf_type = EVP_PKEY_DH_KDF_NONE;
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_ci    ctx->data = dctx;
681cb0ef41Sopenharmony_ci    ctx->keygen_info = dctx->gentmp;
691cb0ef41Sopenharmony_ci    ctx->keygen_info_count = 2;
701cb0ef41Sopenharmony_ci
711cb0ef41Sopenharmony_ci    return 1;
721cb0ef41Sopenharmony_ci}
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_cistatic void pkey_dh_cleanup(EVP_PKEY_CTX *ctx)
751cb0ef41Sopenharmony_ci{
761cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx = ctx->data;
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci    if (dctx != NULL) {
791cb0ef41Sopenharmony_ci        OPENSSL_free(dctx->kdf_ukm);
801cb0ef41Sopenharmony_ci        ASN1_OBJECT_free(dctx->kdf_oid);
811cb0ef41Sopenharmony_ci        OPENSSL_free(dctx);
821cb0ef41Sopenharmony_ci    }
831cb0ef41Sopenharmony_ci}
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_cistatic int pkey_dh_copy(EVP_PKEY_CTX *dst, const EVP_PKEY_CTX *src)
871cb0ef41Sopenharmony_ci{
881cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx, *sctx;
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    if (!pkey_dh_init(dst))
911cb0ef41Sopenharmony_ci        return 0;
921cb0ef41Sopenharmony_ci    sctx = src->data;
931cb0ef41Sopenharmony_ci    dctx = dst->data;
941cb0ef41Sopenharmony_ci    dctx->prime_len = sctx->prime_len;
951cb0ef41Sopenharmony_ci    dctx->subprime_len = sctx->subprime_len;
961cb0ef41Sopenharmony_ci    dctx->generator = sctx->generator;
971cb0ef41Sopenharmony_ci    dctx->paramgen_type = sctx->paramgen_type;
981cb0ef41Sopenharmony_ci    dctx->pad = sctx->pad;
991cb0ef41Sopenharmony_ci    dctx->md = sctx->md;
1001cb0ef41Sopenharmony_ci    dctx->param_nid = sctx->param_nid;
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci    dctx->kdf_type = sctx->kdf_type;
1031cb0ef41Sopenharmony_ci    dctx->kdf_oid = OBJ_dup(sctx->kdf_oid);
1041cb0ef41Sopenharmony_ci    if (dctx->kdf_oid == NULL)
1051cb0ef41Sopenharmony_ci        return 0;
1061cb0ef41Sopenharmony_ci    dctx->kdf_md = sctx->kdf_md;
1071cb0ef41Sopenharmony_ci    if (sctx->kdf_ukm != NULL) {
1081cb0ef41Sopenharmony_ci        dctx->kdf_ukm = OPENSSL_memdup(sctx->kdf_ukm, sctx->kdf_ukmlen);
1091cb0ef41Sopenharmony_ci        if (dctx->kdf_ukm == NULL)
1101cb0ef41Sopenharmony_ci          return 0;
1111cb0ef41Sopenharmony_ci        dctx->kdf_ukmlen = sctx->kdf_ukmlen;
1121cb0ef41Sopenharmony_ci    }
1131cb0ef41Sopenharmony_ci    dctx->kdf_outlen = sctx->kdf_outlen;
1141cb0ef41Sopenharmony_ci    return 1;
1151cb0ef41Sopenharmony_ci}
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_cistatic int pkey_dh_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2)
1181cb0ef41Sopenharmony_ci{
1191cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx = ctx->data;
1201cb0ef41Sopenharmony_ci    switch (type) {
1211cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_PARAMGEN_PRIME_LEN:
1221cb0ef41Sopenharmony_ci        if (p1 < 256)
1231cb0ef41Sopenharmony_ci            return -2;
1241cb0ef41Sopenharmony_ci        dctx->prime_len = p1;
1251cb0ef41Sopenharmony_ci        return 1;
1261cb0ef41Sopenharmony_ci
1271cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_PARAMGEN_SUBPRIME_LEN:
1281cb0ef41Sopenharmony_ci        if (dctx->paramgen_type == DH_PARAMGEN_TYPE_GENERATOR)
1291cb0ef41Sopenharmony_ci            return -2;
1301cb0ef41Sopenharmony_ci        dctx->subprime_len = p1;
1311cb0ef41Sopenharmony_ci        return 1;
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_PAD:
1341cb0ef41Sopenharmony_ci        dctx->pad = p1;
1351cb0ef41Sopenharmony_ci        return 1;
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_PARAMGEN_GENERATOR:
1381cb0ef41Sopenharmony_ci        if (dctx->paramgen_type != DH_PARAMGEN_TYPE_GENERATOR)
1391cb0ef41Sopenharmony_ci            return -2;
1401cb0ef41Sopenharmony_ci        dctx->generator = p1;
1411cb0ef41Sopenharmony_ci        return 1;
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_PARAMGEN_TYPE:
1441cb0ef41Sopenharmony_ci#ifdef OPENSSL_NO_DSA
1451cb0ef41Sopenharmony_ci        if (p1 != DH_PARAMGEN_TYPE_GENERATOR)
1461cb0ef41Sopenharmony_ci            return -2;
1471cb0ef41Sopenharmony_ci#else
1481cb0ef41Sopenharmony_ci        if (p1 < 0 || p1 > 2)
1491cb0ef41Sopenharmony_ci            return -2;
1501cb0ef41Sopenharmony_ci#endif
1511cb0ef41Sopenharmony_ci        dctx->paramgen_type = p1;
1521cb0ef41Sopenharmony_ci        return 1;
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_RFC5114:
1551cb0ef41Sopenharmony_ci        if (p1 < 1 || p1 > 3 || dctx->param_nid != NID_undef)
1561cb0ef41Sopenharmony_ci            return -2;
1571cb0ef41Sopenharmony_ci        dctx->param_nid = p1;
1581cb0ef41Sopenharmony_ci        return 1;
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_NID:
1611cb0ef41Sopenharmony_ci        if (p1 <= 0 || dctx->param_nid != NID_undef)
1621cb0ef41Sopenharmony_ci            return -2;
1631cb0ef41Sopenharmony_ci        dctx->param_nid = p1;
1641cb0ef41Sopenharmony_ci        return 1;
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_PEER_KEY:
1671cb0ef41Sopenharmony_ci        /* Default behaviour is OK */
1681cb0ef41Sopenharmony_ci        return 1;
1691cb0ef41Sopenharmony_ci
1701cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_KDF_TYPE:
1711cb0ef41Sopenharmony_ci        if (p1 == -2)
1721cb0ef41Sopenharmony_ci            return dctx->kdf_type;
1731cb0ef41Sopenharmony_ci        if (p1 != EVP_PKEY_DH_KDF_NONE && p1 != EVP_PKEY_DH_KDF_X9_42)
1741cb0ef41Sopenharmony_ci            return -2;
1751cb0ef41Sopenharmony_ci        dctx->kdf_type = p1;
1761cb0ef41Sopenharmony_ci        return 1;
1771cb0ef41Sopenharmony_ci
1781cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_KDF_MD:
1791cb0ef41Sopenharmony_ci        dctx->kdf_md = p2;
1801cb0ef41Sopenharmony_ci        return 1;
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_GET_DH_KDF_MD:
1831cb0ef41Sopenharmony_ci        *(const EVP_MD **)p2 = dctx->kdf_md;
1841cb0ef41Sopenharmony_ci        return 1;
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_KDF_OUTLEN:
1871cb0ef41Sopenharmony_ci        if (p1 <= 0)
1881cb0ef41Sopenharmony_ci            return -2;
1891cb0ef41Sopenharmony_ci        dctx->kdf_outlen = (size_t)p1;
1901cb0ef41Sopenharmony_ci        return 1;
1911cb0ef41Sopenharmony_ci
1921cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_GET_DH_KDF_OUTLEN:
1931cb0ef41Sopenharmony_ci        *(int *)p2 = dctx->kdf_outlen;
1941cb0ef41Sopenharmony_ci        return 1;
1951cb0ef41Sopenharmony_ci
1961cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_KDF_UKM:
1971cb0ef41Sopenharmony_ci        OPENSSL_free(dctx->kdf_ukm);
1981cb0ef41Sopenharmony_ci        dctx->kdf_ukm = p2;
1991cb0ef41Sopenharmony_ci        if (p2)
2001cb0ef41Sopenharmony_ci            dctx->kdf_ukmlen = p1;
2011cb0ef41Sopenharmony_ci        else
2021cb0ef41Sopenharmony_ci            dctx->kdf_ukmlen = 0;
2031cb0ef41Sopenharmony_ci        return 1;
2041cb0ef41Sopenharmony_ci
2051cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_GET_DH_KDF_UKM:
2061cb0ef41Sopenharmony_ci        *(unsigned char **)p2 = dctx->kdf_ukm;
2071cb0ef41Sopenharmony_ci        return dctx->kdf_ukmlen;
2081cb0ef41Sopenharmony_ci
2091cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_DH_KDF_OID:
2101cb0ef41Sopenharmony_ci        ASN1_OBJECT_free(dctx->kdf_oid);
2111cb0ef41Sopenharmony_ci        dctx->kdf_oid = p2;
2121cb0ef41Sopenharmony_ci        return 1;
2131cb0ef41Sopenharmony_ci
2141cb0ef41Sopenharmony_ci    case EVP_PKEY_CTRL_GET_DH_KDF_OID:
2151cb0ef41Sopenharmony_ci        *(ASN1_OBJECT **)p2 = dctx->kdf_oid;
2161cb0ef41Sopenharmony_ci        return 1;
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    default:
2191cb0ef41Sopenharmony_ci        return -2;
2201cb0ef41Sopenharmony_ci
2211cb0ef41Sopenharmony_ci    }
2221cb0ef41Sopenharmony_ci}
2231cb0ef41Sopenharmony_ci
2241cb0ef41Sopenharmony_cistatic int pkey_dh_ctrl_str(EVP_PKEY_CTX *ctx,
2251cb0ef41Sopenharmony_ci                            const char *type, const char *value)
2261cb0ef41Sopenharmony_ci{
2271cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_paramgen_prime_len") == 0) {
2281cb0ef41Sopenharmony_ci        int len;
2291cb0ef41Sopenharmony_ci        len = atoi(value);
2301cb0ef41Sopenharmony_ci        return EVP_PKEY_CTX_set_dh_paramgen_prime_len(ctx, len);
2311cb0ef41Sopenharmony_ci    }
2321cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_rfc5114") == 0) {
2331cb0ef41Sopenharmony_ci        DH_PKEY_CTX *dctx = ctx->data;
2341cb0ef41Sopenharmony_ci        int id;
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci        id = atoi(value);
2371cb0ef41Sopenharmony_ci        if (id < 0 || id > 3)
2381cb0ef41Sopenharmony_ci            return -2;
2391cb0ef41Sopenharmony_ci        dctx->param_nid = id;
2401cb0ef41Sopenharmony_ci        return 1;
2411cb0ef41Sopenharmony_ci    }
2421cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_param") == 0) {
2431cb0ef41Sopenharmony_ci        DH_PKEY_CTX *dctx = ctx->data;
2441cb0ef41Sopenharmony_ci        int nid = OBJ_sn2nid(value);
2451cb0ef41Sopenharmony_ci
2461cb0ef41Sopenharmony_ci        if (nid == NID_undef) {
2471cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_DH, DH_R_INVALID_PARAMETER_NAME);
2481cb0ef41Sopenharmony_ci            return -2;
2491cb0ef41Sopenharmony_ci        }
2501cb0ef41Sopenharmony_ci        dctx->param_nid = nid;
2511cb0ef41Sopenharmony_ci        return 1;
2521cb0ef41Sopenharmony_ci    }
2531cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_paramgen_generator") == 0) {
2541cb0ef41Sopenharmony_ci        int len;
2551cb0ef41Sopenharmony_ci        len = atoi(value);
2561cb0ef41Sopenharmony_ci        return EVP_PKEY_CTX_set_dh_paramgen_generator(ctx, len);
2571cb0ef41Sopenharmony_ci    }
2581cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_paramgen_subprime_len") == 0) {
2591cb0ef41Sopenharmony_ci        int len;
2601cb0ef41Sopenharmony_ci        len = atoi(value);
2611cb0ef41Sopenharmony_ci        return EVP_PKEY_CTX_set_dh_paramgen_subprime_len(ctx, len);
2621cb0ef41Sopenharmony_ci    }
2631cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_paramgen_type") == 0) {
2641cb0ef41Sopenharmony_ci        int typ;
2651cb0ef41Sopenharmony_ci        typ = atoi(value);
2661cb0ef41Sopenharmony_ci        return EVP_PKEY_CTX_set_dh_paramgen_type(ctx, typ);
2671cb0ef41Sopenharmony_ci    }
2681cb0ef41Sopenharmony_ci    if (strcmp(type, "dh_pad") == 0) {
2691cb0ef41Sopenharmony_ci        int pad;
2701cb0ef41Sopenharmony_ci        pad = atoi(value);
2711cb0ef41Sopenharmony_ci        return EVP_PKEY_CTX_set_dh_pad(ctx, pad);
2721cb0ef41Sopenharmony_ci    }
2731cb0ef41Sopenharmony_ci    return -2;
2741cb0ef41Sopenharmony_ci}
2751cb0ef41Sopenharmony_ci
2761cb0ef41Sopenharmony_cistatic DH *ffc_params_generate(OSSL_LIB_CTX *libctx, DH_PKEY_CTX *dctx,
2771cb0ef41Sopenharmony_ci                               BN_GENCB *pcb)
2781cb0ef41Sopenharmony_ci{
2791cb0ef41Sopenharmony_ci    DH *ret;
2801cb0ef41Sopenharmony_ci    int rv = 0;
2811cb0ef41Sopenharmony_ci    int res;
2821cb0ef41Sopenharmony_ci    int prime_len = dctx->prime_len;
2831cb0ef41Sopenharmony_ci    int subprime_len = dctx->subprime_len;
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci    if (dctx->paramgen_type > DH_PARAMGEN_TYPE_FIPS_186_4)
2861cb0ef41Sopenharmony_ci        return NULL;
2871cb0ef41Sopenharmony_ci    ret = DH_new();
2881cb0ef41Sopenharmony_ci    if (ret == NULL)
2891cb0ef41Sopenharmony_ci        return NULL;
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci    if (subprime_len == -1) {
2921cb0ef41Sopenharmony_ci        if (prime_len >= 2048)
2931cb0ef41Sopenharmony_ci            subprime_len = 256;
2941cb0ef41Sopenharmony_ci        else
2951cb0ef41Sopenharmony_ci            subprime_len = 160;
2961cb0ef41Sopenharmony_ci    }
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci    if (dctx->md != NULL)
2991cb0ef41Sopenharmony_ci        ossl_ffc_set_digest(&ret->params, EVP_MD_get0_name(dctx->md), NULL);
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci# ifndef FIPS_MODULE
3021cb0ef41Sopenharmony_ci    if (dctx->paramgen_type == DH_PARAMGEN_TYPE_FIPS_186_2)
3031cb0ef41Sopenharmony_ci        rv = ossl_ffc_params_FIPS186_2_generate(libctx, &ret->params,
3041cb0ef41Sopenharmony_ci                                                FFC_PARAM_TYPE_DH,
3051cb0ef41Sopenharmony_ci                                                prime_len, subprime_len, &res,
3061cb0ef41Sopenharmony_ci                                                pcb);
3071cb0ef41Sopenharmony_ci    else
3081cb0ef41Sopenharmony_ci# endif
3091cb0ef41Sopenharmony_ci    /* For FIPS we always use the DH_PARAMGEN_TYPE_FIPS_186_4 generator */
3101cb0ef41Sopenharmony_ci    if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2)
3111cb0ef41Sopenharmony_ci        rv = ossl_ffc_params_FIPS186_4_generate(libctx, &ret->params,
3121cb0ef41Sopenharmony_ci                                                FFC_PARAM_TYPE_DH,
3131cb0ef41Sopenharmony_ci                                                prime_len, subprime_len, &res,
3141cb0ef41Sopenharmony_ci                                                pcb);
3151cb0ef41Sopenharmony_ci    if (rv <= 0) {
3161cb0ef41Sopenharmony_ci        DH_free(ret);
3171cb0ef41Sopenharmony_ci        return NULL;
3181cb0ef41Sopenharmony_ci    }
3191cb0ef41Sopenharmony_ci    return ret;
3201cb0ef41Sopenharmony_ci}
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_cistatic int pkey_dh_paramgen(EVP_PKEY_CTX *ctx,
3231cb0ef41Sopenharmony_ci                            EVP_PKEY *pkey)
3241cb0ef41Sopenharmony_ci{
3251cb0ef41Sopenharmony_ci    DH *dh = NULL;
3261cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx = ctx->data;
3271cb0ef41Sopenharmony_ci    BN_GENCB *pcb = NULL;
3281cb0ef41Sopenharmony_ci    int ret;
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci    /*
3311cb0ef41Sopenharmony_ci     * Look for a safe prime group for key establishment. Which uses
3321cb0ef41Sopenharmony_ci     * either RFC_3526 (modp_XXXX) or RFC_7919 (ffdheXXXX).
3331cb0ef41Sopenharmony_ci     * RFC_5114 is also handled here for param_nid = (1..3)
3341cb0ef41Sopenharmony_ci     */
3351cb0ef41Sopenharmony_ci    if (dctx->param_nid != NID_undef) {
3361cb0ef41Sopenharmony_ci        int type = dctx->param_nid <= 3 ? EVP_PKEY_DHX : EVP_PKEY_DH;
3371cb0ef41Sopenharmony_ci
3381cb0ef41Sopenharmony_ci        if ((dh = DH_new_by_nid(dctx->param_nid)) == NULL)
3391cb0ef41Sopenharmony_ci            return 0;
3401cb0ef41Sopenharmony_ci        EVP_PKEY_assign(pkey, type, dh);
3411cb0ef41Sopenharmony_ci        return 1;
3421cb0ef41Sopenharmony_ci    }
3431cb0ef41Sopenharmony_ci
3441cb0ef41Sopenharmony_ci    if (ctx->pkey_gencb != NULL) {
3451cb0ef41Sopenharmony_ci        pcb = BN_GENCB_new();
3461cb0ef41Sopenharmony_ci        if (pcb == NULL)
3471cb0ef41Sopenharmony_ci            return 0;
3481cb0ef41Sopenharmony_ci        evp_pkey_set_cb_translate(pcb, ctx);
3491cb0ef41Sopenharmony_ci    }
3501cb0ef41Sopenharmony_ci# ifdef FIPS_MODULE
3511cb0ef41Sopenharmony_ci    dctx->paramgen_type = DH_PARAMGEN_TYPE_FIPS_186_4;
3521cb0ef41Sopenharmony_ci# endif /* FIPS_MODULE */
3531cb0ef41Sopenharmony_ci    if (dctx->paramgen_type >= DH_PARAMGEN_TYPE_FIPS_186_2) {
3541cb0ef41Sopenharmony_ci        dh = ffc_params_generate(NULL, dctx, pcb);
3551cb0ef41Sopenharmony_ci        BN_GENCB_free(pcb);
3561cb0ef41Sopenharmony_ci        if (dh == NULL)
3571cb0ef41Sopenharmony_ci            return 0;
3581cb0ef41Sopenharmony_ci        EVP_PKEY_assign(pkey, EVP_PKEY_DHX, dh);
3591cb0ef41Sopenharmony_ci        return 1;
3601cb0ef41Sopenharmony_ci    }
3611cb0ef41Sopenharmony_ci    dh = DH_new();
3621cb0ef41Sopenharmony_ci    if (dh == NULL) {
3631cb0ef41Sopenharmony_ci        BN_GENCB_free(pcb);
3641cb0ef41Sopenharmony_ci        return 0;
3651cb0ef41Sopenharmony_ci    }
3661cb0ef41Sopenharmony_ci    ret = DH_generate_parameters_ex(dh,
3671cb0ef41Sopenharmony_ci                                    dctx->prime_len, dctx->generator, pcb);
3681cb0ef41Sopenharmony_ci    BN_GENCB_free(pcb);
3691cb0ef41Sopenharmony_ci    if (ret)
3701cb0ef41Sopenharmony_ci        EVP_PKEY_assign_DH(pkey, dh);
3711cb0ef41Sopenharmony_ci    else
3721cb0ef41Sopenharmony_ci        DH_free(dh);
3731cb0ef41Sopenharmony_ci    return ret;
3741cb0ef41Sopenharmony_ci}
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_cistatic int pkey_dh_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey)
3771cb0ef41Sopenharmony_ci{
3781cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx = ctx->data;
3791cb0ef41Sopenharmony_ci    DH *dh = NULL;
3801cb0ef41Sopenharmony_ci
3811cb0ef41Sopenharmony_ci    if (ctx->pkey == NULL && dctx->param_nid == NID_undef) {
3821cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_NO_PARAMETERS_SET);
3831cb0ef41Sopenharmony_ci        return 0;
3841cb0ef41Sopenharmony_ci    }
3851cb0ef41Sopenharmony_ci    if (dctx->param_nid != NID_undef)
3861cb0ef41Sopenharmony_ci        dh = DH_new_by_nid(dctx->param_nid);
3871cb0ef41Sopenharmony_ci    else
3881cb0ef41Sopenharmony_ci        dh = DH_new();
3891cb0ef41Sopenharmony_ci    if (dh == NULL)
3901cb0ef41Sopenharmony_ci        return 0;
3911cb0ef41Sopenharmony_ci    EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, dh);
3921cb0ef41Sopenharmony_ci    /* Note: if error return, pkey is freed by parent routine */
3931cb0ef41Sopenharmony_ci    if (ctx->pkey != NULL && !EVP_PKEY_copy_parameters(pkey, ctx->pkey))
3941cb0ef41Sopenharmony_ci        return 0;
3951cb0ef41Sopenharmony_ci    return DH_generate_key((DH *)EVP_PKEY_get0_DH(pkey));
3961cb0ef41Sopenharmony_ci}
3971cb0ef41Sopenharmony_ci
3981cb0ef41Sopenharmony_cistatic int pkey_dh_derive(EVP_PKEY_CTX *ctx, unsigned char *key,
3991cb0ef41Sopenharmony_ci                          size_t *keylen)
4001cb0ef41Sopenharmony_ci{
4011cb0ef41Sopenharmony_ci    int ret;
4021cb0ef41Sopenharmony_ci    DH *dh;
4031cb0ef41Sopenharmony_ci    const DH *dhpub;
4041cb0ef41Sopenharmony_ci    DH_PKEY_CTX *dctx = ctx->data;
4051cb0ef41Sopenharmony_ci    BIGNUM *dhpubbn;
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci    if (ctx->pkey == NULL || ctx->peerkey == NULL) {
4081cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET);
4091cb0ef41Sopenharmony_ci        return 0;
4101cb0ef41Sopenharmony_ci    }
4111cb0ef41Sopenharmony_ci    dh = (DH *)EVP_PKEY_get0_DH(ctx->pkey);
4121cb0ef41Sopenharmony_ci    dhpub = EVP_PKEY_get0_DH(ctx->peerkey);
4131cb0ef41Sopenharmony_ci    if (dhpub == NULL) {
4141cb0ef41Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_KEYS_NOT_SET);
4151cb0ef41Sopenharmony_ci        return 0;
4161cb0ef41Sopenharmony_ci    }
4171cb0ef41Sopenharmony_ci    dhpubbn = dhpub->pub_key;
4181cb0ef41Sopenharmony_ci    if (dctx->kdf_type == EVP_PKEY_DH_KDF_NONE) {
4191cb0ef41Sopenharmony_ci        if (key == NULL) {
4201cb0ef41Sopenharmony_ci            *keylen = DH_size(dh);
4211cb0ef41Sopenharmony_ci            return 1;
4221cb0ef41Sopenharmony_ci        }
4231cb0ef41Sopenharmony_ci        if (dctx->pad)
4241cb0ef41Sopenharmony_ci            ret = DH_compute_key_padded(key, dhpubbn, dh);
4251cb0ef41Sopenharmony_ci        else
4261cb0ef41Sopenharmony_ci            ret = DH_compute_key(key, dhpubbn, dh);
4271cb0ef41Sopenharmony_ci        if (ret < 0)
4281cb0ef41Sopenharmony_ci            return ret;
4291cb0ef41Sopenharmony_ci        *keylen = ret;
4301cb0ef41Sopenharmony_ci        return 1;
4311cb0ef41Sopenharmony_ci    }
4321cb0ef41Sopenharmony_ci    else if (dctx->kdf_type == EVP_PKEY_DH_KDF_X9_42) {
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci        unsigned char *Z = NULL;
4351cb0ef41Sopenharmony_ci        int Zlen = 0;
4361cb0ef41Sopenharmony_ci
4371cb0ef41Sopenharmony_ci        if (!dctx->kdf_outlen || !dctx->kdf_oid)
4381cb0ef41Sopenharmony_ci            return 0;
4391cb0ef41Sopenharmony_ci        if (key == NULL) {
4401cb0ef41Sopenharmony_ci            *keylen = dctx->kdf_outlen;
4411cb0ef41Sopenharmony_ci            return 1;
4421cb0ef41Sopenharmony_ci        }
4431cb0ef41Sopenharmony_ci        if (*keylen != dctx->kdf_outlen)
4441cb0ef41Sopenharmony_ci            return 0;
4451cb0ef41Sopenharmony_ci        ret = 0;
4461cb0ef41Sopenharmony_ci        if ((Zlen = DH_size(dh)) <= 0)
4471cb0ef41Sopenharmony_ci            return 0;
4481cb0ef41Sopenharmony_ci        if ((Z = OPENSSL_malloc(Zlen)) == NULL) {
4491cb0ef41Sopenharmony_ci            ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
4501cb0ef41Sopenharmony_ci            return 0;
4511cb0ef41Sopenharmony_ci        }
4521cb0ef41Sopenharmony_ci        if (DH_compute_key_padded(Z, dhpubbn, dh) <= 0)
4531cb0ef41Sopenharmony_ci            goto err;
4541cb0ef41Sopenharmony_ci        if (!DH_KDF_X9_42(key, *keylen, Z, Zlen, dctx->kdf_oid,
4551cb0ef41Sopenharmony_ci                          dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md))
4561cb0ef41Sopenharmony_ci            goto err;
4571cb0ef41Sopenharmony_ci        *keylen = dctx->kdf_outlen;
4581cb0ef41Sopenharmony_ci        ret = 1;
4591cb0ef41Sopenharmony_ci err:
4601cb0ef41Sopenharmony_ci        OPENSSL_clear_free(Z, Zlen);
4611cb0ef41Sopenharmony_ci        return ret;
4621cb0ef41Sopenharmony_ci    }
4631cb0ef41Sopenharmony_ci    return 0;
4641cb0ef41Sopenharmony_ci}
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_cistatic const EVP_PKEY_METHOD dh_pkey_meth = {
4671cb0ef41Sopenharmony_ci    EVP_PKEY_DH,
4681cb0ef41Sopenharmony_ci    0,
4691cb0ef41Sopenharmony_ci    pkey_dh_init,
4701cb0ef41Sopenharmony_ci    pkey_dh_copy,
4711cb0ef41Sopenharmony_ci    pkey_dh_cleanup,
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci    0,
4741cb0ef41Sopenharmony_ci    pkey_dh_paramgen,
4751cb0ef41Sopenharmony_ci
4761cb0ef41Sopenharmony_ci    0,
4771cb0ef41Sopenharmony_ci    pkey_dh_keygen,
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci    0,
4801cb0ef41Sopenharmony_ci    0,
4811cb0ef41Sopenharmony_ci
4821cb0ef41Sopenharmony_ci    0,
4831cb0ef41Sopenharmony_ci    0,
4841cb0ef41Sopenharmony_ci
4851cb0ef41Sopenharmony_ci    0, 0,
4861cb0ef41Sopenharmony_ci
4871cb0ef41Sopenharmony_ci    0, 0, 0, 0,
4881cb0ef41Sopenharmony_ci
4891cb0ef41Sopenharmony_ci    0, 0,
4901cb0ef41Sopenharmony_ci
4911cb0ef41Sopenharmony_ci    0, 0,
4921cb0ef41Sopenharmony_ci
4931cb0ef41Sopenharmony_ci    0,
4941cb0ef41Sopenharmony_ci    pkey_dh_derive,
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci    pkey_dh_ctrl,
4971cb0ef41Sopenharmony_ci    pkey_dh_ctrl_str
4981cb0ef41Sopenharmony_ci};
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ciconst EVP_PKEY_METHOD *ossl_dh_pkey_method(void)
5011cb0ef41Sopenharmony_ci{
5021cb0ef41Sopenharmony_ci    return &dh_pkey_meth;
5031cb0ef41Sopenharmony_ci}
5041cb0ef41Sopenharmony_ci
5051cb0ef41Sopenharmony_cistatic const EVP_PKEY_METHOD dhx_pkey_meth = {
5061cb0ef41Sopenharmony_ci    EVP_PKEY_DHX,
5071cb0ef41Sopenharmony_ci    0,
5081cb0ef41Sopenharmony_ci    pkey_dh_init,
5091cb0ef41Sopenharmony_ci    pkey_dh_copy,
5101cb0ef41Sopenharmony_ci    pkey_dh_cleanup,
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci    0,
5131cb0ef41Sopenharmony_ci    pkey_dh_paramgen,
5141cb0ef41Sopenharmony_ci
5151cb0ef41Sopenharmony_ci    0,
5161cb0ef41Sopenharmony_ci    pkey_dh_keygen,
5171cb0ef41Sopenharmony_ci
5181cb0ef41Sopenharmony_ci    0,
5191cb0ef41Sopenharmony_ci    0,
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci    0,
5221cb0ef41Sopenharmony_ci    0,
5231cb0ef41Sopenharmony_ci
5241cb0ef41Sopenharmony_ci    0, 0,
5251cb0ef41Sopenharmony_ci
5261cb0ef41Sopenharmony_ci    0, 0, 0, 0,
5271cb0ef41Sopenharmony_ci
5281cb0ef41Sopenharmony_ci    0, 0,
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci    0, 0,
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci    0,
5331cb0ef41Sopenharmony_ci    pkey_dh_derive,
5341cb0ef41Sopenharmony_ci
5351cb0ef41Sopenharmony_ci    pkey_dh_ctrl,
5361cb0ef41Sopenharmony_ci    pkey_dh_ctrl_str
5371cb0ef41Sopenharmony_ci};
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_ciconst EVP_PKEY_METHOD *ossl_dhx_pkey_method(void)
5401cb0ef41Sopenharmony_ci{
5411cb0ef41Sopenharmony_ci    return &dhx_pkey_meth;
5421cb0ef41Sopenharmony_ci}
543