xref: /third_party/openssl/crypto/dh/dh_ameth.c (revision e1051a39)
1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2006-2022 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * DH low level APIs are deprecated for public use, but still ok for
12e1051a39Sopenharmony_ci * internal use.
13e1051a39Sopenharmony_ci */
14e1051a39Sopenharmony_ci#include "internal/deprecated.h"
15e1051a39Sopenharmony_ci
16e1051a39Sopenharmony_ci#include <stdio.h>
17e1051a39Sopenharmony_ci#include <openssl/x509.h>
18e1051a39Sopenharmony_ci#include <openssl/asn1.h>
19e1051a39Sopenharmony_ci#include <openssl/bn.h>
20e1051a39Sopenharmony_ci#include <openssl/core_names.h>
21e1051a39Sopenharmony_ci#include <openssl/param_build.h>
22e1051a39Sopenharmony_ci#include "internal/ffc.h"
23e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
24e1051a39Sopenharmony_ci#include "crypto/asn1.h"
25e1051a39Sopenharmony_ci#include "crypto/dh.h"
26e1051a39Sopenharmony_ci#include "crypto/evp.h"
27e1051a39Sopenharmony_ci#include "dh_local.h"
28e1051a39Sopenharmony_ci
29e1051a39Sopenharmony_ci/*
30e1051a39Sopenharmony_ci * i2d/d2i like DH parameter functions which use the appropriate routine for
31e1051a39Sopenharmony_ci * PKCS#3 DH or X9.42 DH.
32e1051a39Sopenharmony_ci */
33e1051a39Sopenharmony_ci
34e1051a39Sopenharmony_cistatic DH *d2i_dhp(const EVP_PKEY *pkey, const unsigned char **pp,
35e1051a39Sopenharmony_ci                   long length)
36e1051a39Sopenharmony_ci{
37e1051a39Sopenharmony_ci    DH *dh = NULL;
38e1051a39Sopenharmony_ci    int is_dhx = (pkey->ameth == &ossl_dhx_asn1_meth);
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci    if (is_dhx)
41e1051a39Sopenharmony_ci        dh = d2i_DHxparams(NULL, pp, length);
42e1051a39Sopenharmony_ci    else
43e1051a39Sopenharmony_ci        dh = d2i_DHparams(NULL, pp, length);
44e1051a39Sopenharmony_ci
45e1051a39Sopenharmony_ci    return dh;
46e1051a39Sopenharmony_ci}
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_cistatic int i2d_dhp(const EVP_PKEY *pkey, const DH *a, unsigned char **pp)
49e1051a39Sopenharmony_ci{
50e1051a39Sopenharmony_ci    if (pkey->ameth == &ossl_dhx_asn1_meth)
51e1051a39Sopenharmony_ci        return i2d_DHxparams(a, pp);
52e1051a39Sopenharmony_ci    return i2d_DHparams(a, pp);
53e1051a39Sopenharmony_ci}
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_cistatic void int_dh_free(EVP_PKEY *pkey)
56e1051a39Sopenharmony_ci{
57e1051a39Sopenharmony_ci    DH_free(pkey->pkey.dh);
58e1051a39Sopenharmony_ci}
59e1051a39Sopenharmony_ci
60e1051a39Sopenharmony_cistatic int dh_pub_decode(EVP_PKEY *pkey, const X509_PUBKEY *pubkey)
61e1051a39Sopenharmony_ci{
62e1051a39Sopenharmony_ci    const unsigned char *p, *pm;
63e1051a39Sopenharmony_ci    int pklen, pmlen;
64e1051a39Sopenharmony_ci    int ptype;
65e1051a39Sopenharmony_ci    const void *pval;
66e1051a39Sopenharmony_ci    const ASN1_STRING *pstr;
67e1051a39Sopenharmony_ci    X509_ALGOR *palg;
68e1051a39Sopenharmony_ci    ASN1_INTEGER *public_key = NULL;
69e1051a39Sopenharmony_ci
70e1051a39Sopenharmony_ci    DH *dh = NULL;
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_ci    if (!X509_PUBKEY_get0_param(NULL, &p, &pklen, &palg, pubkey))
73e1051a39Sopenharmony_ci        return 0;
74e1051a39Sopenharmony_ci    X509_ALGOR_get0(NULL, &ptype, &pval, palg);
75e1051a39Sopenharmony_ci
76e1051a39Sopenharmony_ci    if (ptype != V_ASN1_SEQUENCE) {
77e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_PARAMETER_ENCODING_ERROR);
78e1051a39Sopenharmony_ci        goto err;
79e1051a39Sopenharmony_ci    }
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_ci    pstr = pval;
82e1051a39Sopenharmony_ci    pm = pstr->data;
83e1051a39Sopenharmony_ci    pmlen = pstr->length;
84e1051a39Sopenharmony_ci
85e1051a39Sopenharmony_ci    if ((dh = d2i_dhp(pkey, &pm, pmlen)) == NULL) {
86e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR);
87e1051a39Sopenharmony_ci        goto err;
88e1051a39Sopenharmony_ci    }
89e1051a39Sopenharmony_ci
90e1051a39Sopenharmony_ci    if ((public_key = d2i_ASN1_INTEGER(NULL, &p, pklen)) == NULL) {
91e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_DECODE_ERROR);
92e1051a39Sopenharmony_ci        goto err;
93e1051a39Sopenharmony_ci    }
94e1051a39Sopenharmony_ci
95e1051a39Sopenharmony_ci    /* We have parameters now set public key */
96e1051a39Sopenharmony_ci    if ((dh->pub_key = ASN1_INTEGER_to_BN(public_key, NULL)) == NULL) {
97e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_BN_DECODE_ERROR);
98e1051a39Sopenharmony_ci        goto err;
99e1051a39Sopenharmony_ci    }
100e1051a39Sopenharmony_ci
101e1051a39Sopenharmony_ci    ASN1_INTEGER_free(public_key);
102e1051a39Sopenharmony_ci    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
103e1051a39Sopenharmony_ci    return 1;
104e1051a39Sopenharmony_ci
105e1051a39Sopenharmony_ci err:
106e1051a39Sopenharmony_ci    ASN1_INTEGER_free(public_key);
107e1051a39Sopenharmony_ci    DH_free(dh);
108e1051a39Sopenharmony_ci    return 0;
109e1051a39Sopenharmony_ci}
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_cistatic int dh_pub_encode(X509_PUBKEY *pk, const EVP_PKEY *pkey)
112e1051a39Sopenharmony_ci{
113e1051a39Sopenharmony_ci    DH *dh;
114e1051a39Sopenharmony_ci    int ptype;
115e1051a39Sopenharmony_ci    unsigned char *penc = NULL;
116e1051a39Sopenharmony_ci    int penclen;
117e1051a39Sopenharmony_ci    ASN1_STRING *str;
118e1051a39Sopenharmony_ci    ASN1_INTEGER *pub_key = NULL;
119e1051a39Sopenharmony_ci
120e1051a39Sopenharmony_ci    dh = pkey->pkey.dh;
121e1051a39Sopenharmony_ci
122e1051a39Sopenharmony_ci    str = ASN1_STRING_new();
123e1051a39Sopenharmony_ci    if (str == NULL) {
124e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
125e1051a39Sopenharmony_ci        goto err;
126e1051a39Sopenharmony_ci    }
127e1051a39Sopenharmony_ci    str->length = i2d_dhp(pkey, dh, &str->data);
128e1051a39Sopenharmony_ci    if (str->length <= 0) {
129e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
130e1051a39Sopenharmony_ci        goto err;
131e1051a39Sopenharmony_ci    }
132e1051a39Sopenharmony_ci    ptype = V_ASN1_SEQUENCE;
133e1051a39Sopenharmony_ci
134e1051a39Sopenharmony_ci    pub_key = BN_to_ASN1_INTEGER(dh->pub_key, NULL);
135e1051a39Sopenharmony_ci    if (pub_key == NULL)
136e1051a39Sopenharmony_ci        goto err;
137e1051a39Sopenharmony_ci
138e1051a39Sopenharmony_ci    penclen = i2d_ASN1_INTEGER(pub_key, &penc);
139e1051a39Sopenharmony_ci
140e1051a39Sopenharmony_ci    ASN1_INTEGER_free(pub_key);
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_ci    if (penclen <= 0) {
143e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
144e1051a39Sopenharmony_ci        goto err;
145e1051a39Sopenharmony_ci    }
146e1051a39Sopenharmony_ci
147e1051a39Sopenharmony_ci    if (X509_PUBKEY_set0_param(pk, OBJ_nid2obj(pkey->ameth->pkey_id),
148e1051a39Sopenharmony_ci                               ptype, str, penc, penclen))
149e1051a39Sopenharmony_ci        return 1;
150e1051a39Sopenharmony_ci
151e1051a39Sopenharmony_ci err:
152e1051a39Sopenharmony_ci    OPENSSL_free(penc);
153e1051a39Sopenharmony_ci    ASN1_STRING_free(str);
154e1051a39Sopenharmony_ci
155e1051a39Sopenharmony_ci    return 0;
156e1051a39Sopenharmony_ci}
157e1051a39Sopenharmony_ci
158e1051a39Sopenharmony_ci/*
159e1051a39Sopenharmony_ci * PKCS#8 DH is defined in PKCS#11 of all places. It is similar to DH in that
160e1051a39Sopenharmony_ci * the AlgorithmIdentifier contains the parameters, the private key is
161e1051a39Sopenharmony_ci * explicitly included and the pubkey must be recalculated.
162e1051a39Sopenharmony_ci */
163e1051a39Sopenharmony_ci
164e1051a39Sopenharmony_cistatic int dh_priv_decode(EVP_PKEY *pkey, const PKCS8_PRIV_KEY_INFO *p8)
165e1051a39Sopenharmony_ci{
166e1051a39Sopenharmony_ci    int ret = 0;
167e1051a39Sopenharmony_ci    DH *dh = ossl_dh_key_from_pkcs8(p8, NULL, NULL);
168e1051a39Sopenharmony_ci
169e1051a39Sopenharmony_ci    if (dh != NULL) {
170e1051a39Sopenharmony_ci        ret = 1;
171e1051a39Sopenharmony_ci        EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
172e1051a39Sopenharmony_ci    }
173e1051a39Sopenharmony_ci
174e1051a39Sopenharmony_ci    return ret;
175e1051a39Sopenharmony_ci}
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_cistatic int dh_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey)
178e1051a39Sopenharmony_ci{
179e1051a39Sopenharmony_ci    ASN1_STRING *params = NULL;
180e1051a39Sopenharmony_ci    ASN1_INTEGER *prkey = NULL;
181e1051a39Sopenharmony_ci    unsigned char *dp = NULL;
182e1051a39Sopenharmony_ci    int dplen;
183e1051a39Sopenharmony_ci
184e1051a39Sopenharmony_ci    params = ASN1_STRING_new();
185e1051a39Sopenharmony_ci
186e1051a39Sopenharmony_ci    if (params == NULL) {
187e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
188e1051a39Sopenharmony_ci        goto err;
189e1051a39Sopenharmony_ci    }
190e1051a39Sopenharmony_ci
191e1051a39Sopenharmony_ci    params->length = i2d_dhp(pkey, pkey->pkey.dh, &params->data);
192e1051a39Sopenharmony_ci    if (params->length <= 0) {
193e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
194e1051a39Sopenharmony_ci        goto err;
195e1051a39Sopenharmony_ci    }
196e1051a39Sopenharmony_ci    params->type = V_ASN1_SEQUENCE;
197e1051a39Sopenharmony_ci
198e1051a39Sopenharmony_ci    /* Get private key into integer */
199e1051a39Sopenharmony_ci    prkey = BN_to_ASN1_INTEGER(pkey->pkey.dh->priv_key, NULL);
200e1051a39Sopenharmony_ci
201e1051a39Sopenharmony_ci    if (prkey == NULL) {
202e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR);
203e1051a39Sopenharmony_ci        goto err;
204e1051a39Sopenharmony_ci    }
205e1051a39Sopenharmony_ci
206e1051a39Sopenharmony_ci    dplen = i2d_ASN1_INTEGER(prkey, &dp);
207e1051a39Sopenharmony_ci
208e1051a39Sopenharmony_ci    ASN1_STRING_clear_free(prkey);
209e1051a39Sopenharmony_ci
210e1051a39Sopenharmony_ci    if (dplen <= 0) {
211e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_BN_ERROR);
212e1051a39Sopenharmony_ci        goto err;
213e1051a39Sopenharmony_ci    }
214e1051a39Sopenharmony_ci
215e1051a39Sopenharmony_ci    if (!PKCS8_pkey_set0(p8, OBJ_nid2obj(pkey->ameth->pkey_id), 0,
216e1051a39Sopenharmony_ci                         V_ASN1_SEQUENCE, params, dp, dplen)) {
217e1051a39Sopenharmony_ci        OPENSSL_clear_free(dp, dplen);
218e1051a39Sopenharmony_ci        goto err;
219e1051a39Sopenharmony_ci    }
220e1051a39Sopenharmony_ci    return 1;
221e1051a39Sopenharmony_ci
222e1051a39Sopenharmony_ci err:
223e1051a39Sopenharmony_ci    ASN1_STRING_free(params);
224e1051a39Sopenharmony_ci    return 0;
225e1051a39Sopenharmony_ci}
226e1051a39Sopenharmony_ci
227e1051a39Sopenharmony_cistatic int dh_param_decode(EVP_PKEY *pkey,
228e1051a39Sopenharmony_ci                           const unsigned char **pder, int derlen)
229e1051a39Sopenharmony_ci{
230e1051a39Sopenharmony_ci    DH *dh;
231e1051a39Sopenharmony_ci
232e1051a39Sopenharmony_ci    if ((dh = d2i_dhp(pkey, pder, derlen)) == NULL)
233e1051a39Sopenharmony_ci        return 0;
234e1051a39Sopenharmony_ci    dh->dirty_cnt++;
235e1051a39Sopenharmony_ci    EVP_PKEY_assign(pkey, pkey->ameth->pkey_id, dh);
236e1051a39Sopenharmony_ci    return 1;
237e1051a39Sopenharmony_ci}
238e1051a39Sopenharmony_ci
239e1051a39Sopenharmony_cistatic int dh_param_encode(const EVP_PKEY *pkey, unsigned char **pder)
240e1051a39Sopenharmony_ci{
241e1051a39Sopenharmony_ci    return i2d_dhp(pkey, pkey->pkey.dh, pder);
242e1051a39Sopenharmony_ci}
243e1051a39Sopenharmony_ci
244e1051a39Sopenharmony_cistatic int do_dh_print(BIO *bp, const DH *x, int indent, int ptype)
245e1051a39Sopenharmony_ci{
246e1051a39Sopenharmony_ci    int reason = ERR_R_BUF_LIB;
247e1051a39Sopenharmony_ci    const char *ktype = NULL;
248e1051a39Sopenharmony_ci    BIGNUM *priv_key, *pub_key;
249e1051a39Sopenharmony_ci
250e1051a39Sopenharmony_ci    if (ptype == 2)
251e1051a39Sopenharmony_ci        priv_key = x->priv_key;
252e1051a39Sopenharmony_ci    else
253e1051a39Sopenharmony_ci        priv_key = NULL;
254e1051a39Sopenharmony_ci
255e1051a39Sopenharmony_ci    if (ptype > 0)
256e1051a39Sopenharmony_ci        pub_key = x->pub_key;
257e1051a39Sopenharmony_ci    else
258e1051a39Sopenharmony_ci        pub_key = NULL;
259e1051a39Sopenharmony_ci
260e1051a39Sopenharmony_ci    if (x->params.p == NULL || (ptype == 2 && priv_key == NULL)
261e1051a39Sopenharmony_ci            || (ptype > 0 && pub_key == NULL)) {
262e1051a39Sopenharmony_ci        reason = ERR_R_PASSED_NULL_PARAMETER;
263e1051a39Sopenharmony_ci        goto err;
264e1051a39Sopenharmony_ci    }
265e1051a39Sopenharmony_ci
266e1051a39Sopenharmony_ci    if (ptype == 2)
267e1051a39Sopenharmony_ci        ktype = "DH Private-Key";
268e1051a39Sopenharmony_ci    else if (ptype == 1)
269e1051a39Sopenharmony_ci        ktype = "DH Public-Key";
270e1051a39Sopenharmony_ci    else
271e1051a39Sopenharmony_ci        ktype = "DH Parameters";
272e1051a39Sopenharmony_ci
273e1051a39Sopenharmony_ci    if (!BIO_indent(bp, indent, 128)
274e1051a39Sopenharmony_ci            || BIO_printf(bp, "%s: (%d bit)\n", ktype, DH_bits(x)) <= 0)
275e1051a39Sopenharmony_ci        goto err;
276e1051a39Sopenharmony_ci    indent += 4;
277e1051a39Sopenharmony_ci
278e1051a39Sopenharmony_ci    if (!ASN1_bn_print(bp, "private-key:", priv_key, NULL, indent))
279e1051a39Sopenharmony_ci        goto err;
280e1051a39Sopenharmony_ci    if (!ASN1_bn_print(bp, "public-key:", pub_key, NULL, indent))
281e1051a39Sopenharmony_ci        goto err;
282e1051a39Sopenharmony_ci
283e1051a39Sopenharmony_ci    if (!ossl_ffc_params_print(bp, &x->params, indent))
284e1051a39Sopenharmony_ci        goto err;
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_ci    if (x->length != 0) {
287e1051a39Sopenharmony_ci        if (!BIO_indent(bp, indent, 128)
288e1051a39Sopenharmony_ci                || BIO_printf(bp, "recommended-private-length: %d bits\n",
289e1051a39Sopenharmony_ci                              (int)x->length) <= 0)
290e1051a39Sopenharmony_ci            goto err;
291e1051a39Sopenharmony_ci    }
292e1051a39Sopenharmony_ci
293e1051a39Sopenharmony_ci    return 1;
294e1051a39Sopenharmony_ci
295e1051a39Sopenharmony_ci err:
296e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_DH, reason);
297e1051a39Sopenharmony_ci    return 0;
298e1051a39Sopenharmony_ci}
299e1051a39Sopenharmony_ci
300e1051a39Sopenharmony_cistatic int int_dh_size(const EVP_PKEY *pkey)
301e1051a39Sopenharmony_ci{
302e1051a39Sopenharmony_ci    return DH_size(pkey->pkey.dh);
303e1051a39Sopenharmony_ci}
304e1051a39Sopenharmony_ci
305e1051a39Sopenharmony_cistatic int dh_bits(const EVP_PKEY *pkey)
306e1051a39Sopenharmony_ci{
307e1051a39Sopenharmony_ci    return DH_bits(pkey->pkey.dh);
308e1051a39Sopenharmony_ci}
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_cistatic int dh_security_bits(const EVP_PKEY *pkey)
311e1051a39Sopenharmony_ci{
312e1051a39Sopenharmony_ci    return DH_security_bits(pkey->pkey.dh);
313e1051a39Sopenharmony_ci}
314e1051a39Sopenharmony_ci
315e1051a39Sopenharmony_cistatic int dh_cmp_parameters(const EVP_PKEY *a, const EVP_PKEY *b)
316e1051a39Sopenharmony_ci{
317e1051a39Sopenharmony_ci    return ossl_ffc_params_cmp(&a->pkey.dh->params, &b->pkey.dh->params,
318e1051a39Sopenharmony_ci                               a->ameth != &ossl_dhx_asn1_meth);
319e1051a39Sopenharmony_ci}
320e1051a39Sopenharmony_ci
321e1051a39Sopenharmony_cistatic int int_dh_param_copy(DH *to, const DH *from, int is_x942)
322e1051a39Sopenharmony_ci{
323e1051a39Sopenharmony_ci    if (is_x942 == -1)
324e1051a39Sopenharmony_ci        is_x942 = (from->params.q != NULL);
325e1051a39Sopenharmony_ci    if (!ossl_ffc_params_copy(&to->params, &from->params))
326e1051a39Sopenharmony_ci        return 0;
327e1051a39Sopenharmony_ci    if (!is_x942)
328e1051a39Sopenharmony_ci        to->length = from->length;
329e1051a39Sopenharmony_ci    to->dirty_cnt++;
330e1051a39Sopenharmony_ci    return 1;
331e1051a39Sopenharmony_ci}
332e1051a39Sopenharmony_ci
333e1051a39Sopenharmony_ciDH *DHparams_dup(const DH *dh)
334e1051a39Sopenharmony_ci{
335e1051a39Sopenharmony_ci    DH *ret;
336e1051a39Sopenharmony_ci    ret = DH_new();
337e1051a39Sopenharmony_ci    if (ret == NULL)
338e1051a39Sopenharmony_ci        return NULL;
339e1051a39Sopenharmony_ci    if (!int_dh_param_copy(ret, dh, -1)) {
340e1051a39Sopenharmony_ci        DH_free(ret);
341e1051a39Sopenharmony_ci        return NULL;
342e1051a39Sopenharmony_ci    }
343e1051a39Sopenharmony_ci    return ret;
344e1051a39Sopenharmony_ci}
345e1051a39Sopenharmony_ci
346e1051a39Sopenharmony_cistatic int dh_copy_parameters(EVP_PKEY *to, const EVP_PKEY *from)
347e1051a39Sopenharmony_ci{
348e1051a39Sopenharmony_ci    if (to->pkey.dh == NULL) {
349e1051a39Sopenharmony_ci        to->pkey.dh = DH_new();
350e1051a39Sopenharmony_ci        if (to->pkey.dh == NULL)
351e1051a39Sopenharmony_ci            return 0;
352e1051a39Sopenharmony_ci    }
353e1051a39Sopenharmony_ci    return int_dh_param_copy(to->pkey.dh, from->pkey.dh,
354e1051a39Sopenharmony_ci                             from->ameth == &ossl_dhx_asn1_meth);
355e1051a39Sopenharmony_ci}
356e1051a39Sopenharmony_ci
357e1051a39Sopenharmony_cistatic int dh_missing_parameters(const EVP_PKEY *a)
358e1051a39Sopenharmony_ci{
359e1051a39Sopenharmony_ci    return a->pkey.dh == NULL
360e1051a39Sopenharmony_ci        || a->pkey.dh->params.p == NULL
361e1051a39Sopenharmony_ci        || a->pkey.dh->params.g == NULL;
362e1051a39Sopenharmony_ci}
363e1051a39Sopenharmony_ci
364e1051a39Sopenharmony_cistatic int dh_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b)
365e1051a39Sopenharmony_ci{
366e1051a39Sopenharmony_ci    if (dh_cmp_parameters(a, b) == 0)
367e1051a39Sopenharmony_ci        return 0;
368e1051a39Sopenharmony_ci    if (BN_cmp(b->pkey.dh->pub_key, a->pkey.dh->pub_key) != 0)
369e1051a39Sopenharmony_ci        return 0;
370e1051a39Sopenharmony_ci    else
371e1051a39Sopenharmony_ci        return 1;
372e1051a39Sopenharmony_ci}
373e1051a39Sopenharmony_ci
374e1051a39Sopenharmony_cistatic int dh_param_print(BIO *bp, const EVP_PKEY *pkey, int indent,
375e1051a39Sopenharmony_ci                          ASN1_PCTX *ctx)
376e1051a39Sopenharmony_ci{
377e1051a39Sopenharmony_ci    return do_dh_print(bp, pkey->pkey.dh, indent, 0);
378e1051a39Sopenharmony_ci}
379e1051a39Sopenharmony_ci
380e1051a39Sopenharmony_cistatic int dh_public_print(BIO *bp, const EVP_PKEY *pkey, int indent,
381e1051a39Sopenharmony_ci                           ASN1_PCTX *ctx)
382e1051a39Sopenharmony_ci{
383e1051a39Sopenharmony_ci    return do_dh_print(bp, pkey->pkey.dh, indent, 1);
384e1051a39Sopenharmony_ci}
385e1051a39Sopenharmony_ci
386e1051a39Sopenharmony_cistatic int dh_private_print(BIO *bp, const EVP_PKEY *pkey, int indent,
387e1051a39Sopenharmony_ci                            ASN1_PCTX *ctx)
388e1051a39Sopenharmony_ci{
389e1051a39Sopenharmony_ci    return do_dh_print(bp, pkey->pkey.dh, indent, 2);
390e1051a39Sopenharmony_ci}
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ciint DHparams_print(BIO *bp, const DH *x)
393e1051a39Sopenharmony_ci{
394e1051a39Sopenharmony_ci    return do_dh_print(bp, x, 4, 0);
395e1051a39Sopenharmony_ci}
396e1051a39Sopenharmony_ci
397e1051a39Sopenharmony_cistatic int dh_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
398e1051a39Sopenharmony_ci{
399e1051a39Sopenharmony_ci    DH *dh;
400e1051a39Sopenharmony_ci    switch (op) {
401e1051a39Sopenharmony_ci    case ASN1_PKEY_CTRL_SET1_TLS_ENCPT:
402e1051a39Sopenharmony_ci        /* We should only be here if we have a legacy key */
403e1051a39Sopenharmony_ci        if (!ossl_assert(evp_pkey_is_legacy(pkey)))
404e1051a39Sopenharmony_ci            return 0;
405e1051a39Sopenharmony_ci        dh = (DH *) evp_pkey_get0_DH_int(pkey);
406e1051a39Sopenharmony_ci        if (dh == NULL)
407e1051a39Sopenharmony_ci            return 0;
408e1051a39Sopenharmony_ci        return ossl_dh_buf2key(dh, arg2, arg1);
409e1051a39Sopenharmony_ci    case ASN1_PKEY_CTRL_GET1_TLS_ENCPT:
410e1051a39Sopenharmony_ci        dh = (DH *) EVP_PKEY_get0_DH(pkey);
411e1051a39Sopenharmony_ci        if (dh == NULL)
412e1051a39Sopenharmony_ci            return 0;
413e1051a39Sopenharmony_ci        return ossl_dh_key2buf(dh, arg2, 0, 1);
414e1051a39Sopenharmony_ci    default:
415e1051a39Sopenharmony_ci        return -2;
416e1051a39Sopenharmony_ci    }
417e1051a39Sopenharmony_ci}
418e1051a39Sopenharmony_ci
419e1051a39Sopenharmony_cistatic int dhx_pkey_ctrl(EVP_PKEY *pkey, int op, long arg1, void *arg2)
420e1051a39Sopenharmony_ci{
421e1051a39Sopenharmony_ci    switch (op) {
422e1051a39Sopenharmony_ci    default:
423e1051a39Sopenharmony_ci        return -2;
424e1051a39Sopenharmony_ci    }
425e1051a39Sopenharmony_ci
426e1051a39Sopenharmony_ci}
427e1051a39Sopenharmony_ci
428e1051a39Sopenharmony_cistatic int dh_pkey_public_check(const EVP_PKEY *pkey)
429e1051a39Sopenharmony_ci{
430e1051a39Sopenharmony_ci    DH *dh = pkey->pkey.dh;
431e1051a39Sopenharmony_ci
432e1051a39Sopenharmony_ci    if (dh->pub_key == NULL) {
433e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, DH_R_MISSING_PUBKEY);
434e1051a39Sopenharmony_ci        return 0;
435e1051a39Sopenharmony_ci    }
436e1051a39Sopenharmony_ci
437e1051a39Sopenharmony_ci    return DH_check_pub_key_ex(dh, dh->pub_key);
438e1051a39Sopenharmony_ci}
439e1051a39Sopenharmony_ci
440e1051a39Sopenharmony_cistatic int dh_pkey_param_check(const EVP_PKEY *pkey)
441e1051a39Sopenharmony_ci{
442e1051a39Sopenharmony_ci    DH *dh = pkey->pkey.dh;
443e1051a39Sopenharmony_ci
444e1051a39Sopenharmony_ci    return DH_check_ex(dh);
445e1051a39Sopenharmony_ci}
446e1051a39Sopenharmony_ci
447e1051a39Sopenharmony_cistatic size_t dh_pkey_dirty_cnt(const EVP_PKEY *pkey)
448e1051a39Sopenharmony_ci{
449e1051a39Sopenharmony_ci    return pkey->pkey.dh->dirty_cnt;
450e1051a39Sopenharmony_ci}
451e1051a39Sopenharmony_ci
452e1051a39Sopenharmony_cistatic int dh_pkey_export_to(const EVP_PKEY *from, void *to_keydata,
453e1051a39Sopenharmony_ci                             OSSL_FUNC_keymgmt_import_fn *importer,
454e1051a39Sopenharmony_ci                             OSSL_LIB_CTX *libctx, const char *propq)
455e1051a39Sopenharmony_ci{
456e1051a39Sopenharmony_ci    DH *dh = from->pkey.dh;
457e1051a39Sopenharmony_ci    OSSL_PARAM_BLD *tmpl;
458e1051a39Sopenharmony_ci    const BIGNUM *p = DH_get0_p(dh), *g = DH_get0_g(dh), *q = DH_get0_q(dh);
459e1051a39Sopenharmony_ci    long l = DH_get_length(dh);
460e1051a39Sopenharmony_ci    const BIGNUM *pub_key = DH_get0_pub_key(dh);
461e1051a39Sopenharmony_ci    const BIGNUM *priv_key = DH_get0_priv_key(dh);
462e1051a39Sopenharmony_ci    OSSL_PARAM *params = NULL;
463e1051a39Sopenharmony_ci    int selection = 0;
464e1051a39Sopenharmony_ci    int rv = 0;
465e1051a39Sopenharmony_ci
466e1051a39Sopenharmony_ci    if (p == NULL || g == NULL)
467e1051a39Sopenharmony_ci        return 0;
468e1051a39Sopenharmony_ci
469e1051a39Sopenharmony_ci    tmpl = OSSL_PARAM_BLD_new();
470e1051a39Sopenharmony_ci    if (tmpl == NULL)
471e1051a39Sopenharmony_ci        return 0;
472e1051a39Sopenharmony_ci    if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, p)
473e1051a39Sopenharmony_ci        || !OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, g))
474e1051a39Sopenharmony_ci        goto err;
475e1051a39Sopenharmony_ci    if (q != NULL) {
476e1051a39Sopenharmony_ci        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_Q, q))
477e1051a39Sopenharmony_ci            goto err;
478e1051a39Sopenharmony_ci    }
479e1051a39Sopenharmony_ci    selection |= OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS;
480e1051a39Sopenharmony_ci    if (l > 0) {
481e1051a39Sopenharmony_ci        if (!OSSL_PARAM_BLD_push_long(tmpl, OSSL_PKEY_PARAM_DH_PRIV_LEN, l))
482e1051a39Sopenharmony_ci            goto err;
483e1051a39Sopenharmony_ci        selection |= OSSL_KEYMGMT_SELECT_OTHER_PARAMETERS;
484e1051a39Sopenharmony_ci    }
485e1051a39Sopenharmony_ci    if (pub_key != NULL) {
486e1051a39Sopenharmony_ci        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PUB_KEY, pub_key))
487e1051a39Sopenharmony_ci            goto err;
488e1051a39Sopenharmony_ci        selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
489e1051a39Sopenharmony_ci    }
490e1051a39Sopenharmony_ci    if (priv_key != NULL) {
491e1051a39Sopenharmony_ci        if (!OSSL_PARAM_BLD_push_BN(tmpl, OSSL_PKEY_PARAM_PRIV_KEY,
492e1051a39Sopenharmony_ci                                    priv_key))
493e1051a39Sopenharmony_ci            goto err;
494e1051a39Sopenharmony_ci        selection |= OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
495e1051a39Sopenharmony_ci    }
496e1051a39Sopenharmony_ci
497e1051a39Sopenharmony_ci    if ((params = OSSL_PARAM_BLD_to_param(tmpl)) == NULL)
498e1051a39Sopenharmony_ci        goto err;
499e1051a39Sopenharmony_ci
500e1051a39Sopenharmony_ci    /* We export, the provider imports */
501e1051a39Sopenharmony_ci    rv = importer(to_keydata, selection, params);
502e1051a39Sopenharmony_ci
503e1051a39Sopenharmony_ci    OSSL_PARAM_free(params);
504e1051a39Sopenharmony_cierr:
505e1051a39Sopenharmony_ci    OSSL_PARAM_BLD_free(tmpl);
506e1051a39Sopenharmony_ci    return rv;
507e1051a39Sopenharmony_ci}
508e1051a39Sopenharmony_ci
509e1051a39Sopenharmony_cistatic int dh_pkey_import_from_type(const OSSL_PARAM params[], void *vpctx,
510e1051a39Sopenharmony_ci                                    int type)
511e1051a39Sopenharmony_ci{
512e1051a39Sopenharmony_ci    EVP_PKEY_CTX *pctx = vpctx;
513e1051a39Sopenharmony_ci    EVP_PKEY *pkey = EVP_PKEY_CTX_get0_pkey(pctx);
514e1051a39Sopenharmony_ci    DH *dh = ossl_dh_new_ex(pctx->libctx);
515e1051a39Sopenharmony_ci
516e1051a39Sopenharmony_ci    if (dh == NULL) {
517e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DH, ERR_R_MALLOC_FAILURE);
518e1051a39Sopenharmony_ci        return 0;
519e1051a39Sopenharmony_ci    }
520e1051a39Sopenharmony_ci    DH_clear_flags(dh, DH_FLAG_TYPE_MASK);
521e1051a39Sopenharmony_ci    DH_set_flags(dh, type == EVP_PKEY_DH ? DH_FLAG_TYPE_DH : DH_FLAG_TYPE_DHX);
522e1051a39Sopenharmony_ci
523e1051a39Sopenharmony_ci    if (!ossl_dh_params_fromdata(dh, params)
524e1051a39Sopenharmony_ci        || !ossl_dh_key_fromdata(dh, params, 1)
525e1051a39Sopenharmony_ci        || !EVP_PKEY_assign(pkey, type, dh)) {
526e1051a39Sopenharmony_ci        DH_free(dh);
527e1051a39Sopenharmony_ci        return 0;
528e1051a39Sopenharmony_ci    }
529e1051a39Sopenharmony_ci    return 1;
530e1051a39Sopenharmony_ci}
531e1051a39Sopenharmony_ci
532e1051a39Sopenharmony_cistatic int dh_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
533e1051a39Sopenharmony_ci{
534e1051a39Sopenharmony_ci    return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DH);
535e1051a39Sopenharmony_ci}
536e1051a39Sopenharmony_ci
537e1051a39Sopenharmony_cistatic int dhx_pkey_import_from(const OSSL_PARAM params[], void *vpctx)
538e1051a39Sopenharmony_ci{
539e1051a39Sopenharmony_ci    return dh_pkey_import_from_type(params, vpctx, EVP_PKEY_DHX);
540e1051a39Sopenharmony_ci}
541e1051a39Sopenharmony_ci
542e1051a39Sopenharmony_cistatic int dh_pkey_copy(EVP_PKEY *to, EVP_PKEY *from)
543e1051a39Sopenharmony_ci{
544e1051a39Sopenharmony_ci    DH *dh = from->pkey.dh;
545e1051a39Sopenharmony_ci    DH *dupkey = NULL;
546e1051a39Sopenharmony_ci    int ret;
547e1051a39Sopenharmony_ci
548e1051a39Sopenharmony_ci    if (dh != NULL) {
549e1051a39Sopenharmony_ci        dupkey = ossl_dh_dup(dh, OSSL_KEYMGMT_SELECT_ALL);
550e1051a39Sopenharmony_ci        if (dupkey == NULL)
551e1051a39Sopenharmony_ci            return 0;
552e1051a39Sopenharmony_ci    }
553e1051a39Sopenharmony_ci
554e1051a39Sopenharmony_ci    ret = EVP_PKEY_assign(to, from->type, dupkey);
555e1051a39Sopenharmony_ci    if (!ret)
556e1051a39Sopenharmony_ci        DH_free(dupkey);
557e1051a39Sopenharmony_ci    return ret;
558e1051a39Sopenharmony_ci}
559e1051a39Sopenharmony_ci
560e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD ossl_dh_asn1_meth = {
561e1051a39Sopenharmony_ci    EVP_PKEY_DH,
562e1051a39Sopenharmony_ci    EVP_PKEY_DH,
563e1051a39Sopenharmony_ci    0,
564e1051a39Sopenharmony_ci
565e1051a39Sopenharmony_ci    "DH",
566e1051a39Sopenharmony_ci    "OpenSSL PKCS#3 DH method",
567e1051a39Sopenharmony_ci
568e1051a39Sopenharmony_ci    dh_pub_decode,
569e1051a39Sopenharmony_ci    dh_pub_encode,
570e1051a39Sopenharmony_ci    dh_pub_cmp,
571e1051a39Sopenharmony_ci    dh_public_print,
572e1051a39Sopenharmony_ci
573e1051a39Sopenharmony_ci    dh_priv_decode,
574e1051a39Sopenharmony_ci    dh_priv_encode,
575e1051a39Sopenharmony_ci    dh_private_print,
576e1051a39Sopenharmony_ci
577e1051a39Sopenharmony_ci    int_dh_size,
578e1051a39Sopenharmony_ci    dh_bits,
579e1051a39Sopenharmony_ci    dh_security_bits,
580e1051a39Sopenharmony_ci
581e1051a39Sopenharmony_ci    dh_param_decode,
582e1051a39Sopenharmony_ci    dh_param_encode,
583e1051a39Sopenharmony_ci    dh_missing_parameters,
584e1051a39Sopenharmony_ci    dh_copy_parameters,
585e1051a39Sopenharmony_ci    dh_cmp_parameters,
586e1051a39Sopenharmony_ci    dh_param_print,
587e1051a39Sopenharmony_ci    0,
588e1051a39Sopenharmony_ci
589e1051a39Sopenharmony_ci    int_dh_free,
590e1051a39Sopenharmony_ci    dh_pkey_ctrl,
591e1051a39Sopenharmony_ci
592e1051a39Sopenharmony_ci    0, 0, 0, 0, 0,
593e1051a39Sopenharmony_ci
594e1051a39Sopenharmony_ci    0,
595e1051a39Sopenharmony_ci    dh_pkey_public_check,
596e1051a39Sopenharmony_ci    dh_pkey_param_check,
597e1051a39Sopenharmony_ci
598e1051a39Sopenharmony_ci    0, 0, 0, 0,
599e1051a39Sopenharmony_ci
600e1051a39Sopenharmony_ci    dh_pkey_dirty_cnt,
601e1051a39Sopenharmony_ci    dh_pkey_export_to,
602e1051a39Sopenharmony_ci    dh_pkey_import_from,
603e1051a39Sopenharmony_ci    dh_pkey_copy
604e1051a39Sopenharmony_ci};
605e1051a39Sopenharmony_ci
606e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD ossl_dhx_asn1_meth = {
607e1051a39Sopenharmony_ci    EVP_PKEY_DHX,
608e1051a39Sopenharmony_ci    EVP_PKEY_DHX,
609e1051a39Sopenharmony_ci    0,
610e1051a39Sopenharmony_ci
611e1051a39Sopenharmony_ci    "X9.42 DH",
612e1051a39Sopenharmony_ci    "OpenSSL X9.42 DH method",
613e1051a39Sopenharmony_ci
614e1051a39Sopenharmony_ci    dh_pub_decode,
615e1051a39Sopenharmony_ci    dh_pub_encode,
616e1051a39Sopenharmony_ci    dh_pub_cmp,
617e1051a39Sopenharmony_ci    dh_public_print,
618e1051a39Sopenharmony_ci
619e1051a39Sopenharmony_ci    dh_priv_decode,
620e1051a39Sopenharmony_ci    dh_priv_encode,
621e1051a39Sopenharmony_ci    dh_private_print,
622e1051a39Sopenharmony_ci
623e1051a39Sopenharmony_ci    int_dh_size,
624e1051a39Sopenharmony_ci    dh_bits,
625e1051a39Sopenharmony_ci    dh_security_bits,
626e1051a39Sopenharmony_ci
627e1051a39Sopenharmony_ci    dh_param_decode,
628e1051a39Sopenharmony_ci    dh_param_encode,
629e1051a39Sopenharmony_ci    dh_missing_parameters,
630e1051a39Sopenharmony_ci    dh_copy_parameters,
631e1051a39Sopenharmony_ci    dh_cmp_parameters,
632e1051a39Sopenharmony_ci    dh_param_print,
633e1051a39Sopenharmony_ci    0,
634e1051a39Sopenharmony_ci
635e1051a39Sopenharmony_ci    int_dh_free,
636e1051a39Sopenharmony_ci    dhx_pkey_ctrl,
637e1051a39Sopenharmony_ci
638e1051a39Sopenharmony_ci    0, 0, 0, 0, 0,
639e1051a39Sopenharmony_ci
640e1051a39Sopenharmony_ci    0,
641e1051a39Sopenharmony_ci    dh_pkey_public_check,
642e1051a39Sopenharmony_ci    dh_pkey_param_check,
643e1051a39Sopenharmony_ci    0, 0, 0, 0,
644e1051a39Sopenharmony_ci    dh_pkey_dirty_cnt,
645e1051a39Sopenharmony_ci    dh_pkey_export_to,
646e1051a39Sopenharmony_ci    dhx_pkey_import_from,
647e1051a39Sopenharmony_ci    dh_pkey_copy
648e1051a39Sopenharmony_ci};
649