1/*
2 * Copyright 2020-2021 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#include "internal/deprecated.h"
11
12#include <openssl/core_names.h>
13#include <openssl/params.h>
14#include <openssl/err.h>
15#include <openssl/dh.h>
16#include "crypto/dh.h"
17#include "crypto/evp.h"
18
19static int dh_paramgen_check(EVP_PKEY_CTX *ctx)
20{
21    if (ctx == NULL || !EVP_PKEY_CTX_IS_GEN_OP(ctx)) {
22        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
23        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
24        return -2;
25    }
26    /* If key type not DH return error */
27    if (evp_pkey_ctx_is_legacy(ctx)
28        && ctx->pmeth->pkey_id != EVP_PKEY_DH
29        && ctx->pmeth->pkey_id != EVP_PKEY_DHX)
30        return -1;
31    return 1;
32}
33
34static int dh_param_derive_check(EVP_PKEY_CTX *ctx)
35{
36    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
37        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
38        /* Uses the same return values as EVP_PKEY_CTX_ctrl */
39        return -2;
40    }
41    /* If key type not DH return error */
42    if (evp_pkey_ctx_is_legacy(ctx)
43        && ctx->pmeth->pkey_id != EVP_PKEY_DH
44        && ctx->pmeth->pkey_id != EVP_PKEY_DHX)
45        return -1;
46    return 1;
47}
48
49int EVP_PKEY_CTX_set_dh_paramgen_gindex(EVP_PKEY_CTX *ctx, int gindex)
50{
51    int ret;
52    OSSL_PARAM params[2], *p = params;
53
54    if ((ret = dh_paramgen_check(ctx)) <= 0)
55        return ret;
56
57    *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_FFC_GINDEX, &gindex);
58    *p = OSSL_PARAM_construct_end();
59
60    return evp_pkey_ctx_set_params_strict(ctx, params);
61}
62
63int EVP_PKEY_CTX_set_dh_paramgen_seed(EVP_PKEY_CTX *ctx,
64                                      const unsigned char *seed,
65                                      size_t seedlen)
66{
67    int ret;
68    OSSL_PARAM params[2], *p = params;
69
70    if ((ret = dh_paramgen_check(ctx)) <= 0)
71        return ret;
72
73    *p++ = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_FFC_SEED,
74                                             (void *)seed, seedlen);
75    *p = OSSL_PARAM_construct_end();
76
77    return evp_pkey_ctx_set_params_strict(ctx, params);
78}
79
80/*
81 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
82 * simply because that's easier.
83 */
84int EVP_PKEY_CTX_set_dh_paramgen_type(EVP_PKEY_CTX *ctx, int typ)
85{
86    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH, EVP_PKEY_OP_PARAMGEN,
87                             EVP_PKEY_CTRL_DH_PARAMGEN_TYPE, typ, NULL);
88}
89
90int EVP_PKEY_CTX_set_dh_paramgen_prime_len(EVP_PKEY_CTX *ctx, int pbits)
91{
92    int ret;
93    OSSL_PARAM params[2], *p = params;
94    size_t bits = pbits;
95
96    if ((ret = dh_paramgen_check(ctx)) <= 0)
97        return ret;
98
99    *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_PBITS, &bits);
100    *p = OSSL_PARAM_construct_end();
101    return evp_pkey_ctx_set_params_strict(ctx, params);
102}
103
104int EVP_PKEY_CTX_set_dh_paramgen_subprime_len(EVP_PKEY_CTX *ctx, int qbits)
105{
106    int ret;
107    OSSL_PARAM params[2], *p = params;
108    size_t bits2 = qbits;
109
110    if ((ret = dh_paramgen_check(ctx)) <= 0)
111        return ret;
112
113    *p++ = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_FFC_QBITS, &bits2);
114    *p = OSSL_PARAM_construct_end();
115
116    return evp_pkey_ctx_set_params_strict(ctx, params);
117}
118
119int EVP_PKEY_CTX_set_dh_paramgen_generator(EVP_PKEY_CTX *ctx, int gen)
120{
121    int ret;
122    OSSL_PARAM params[2], *p = params;
123
124    if ((ret = dh_paramgen_check(ctx)) <= 0)
125        return ret;
126
127    *p++ = OSSL_PARAM_construct_int(OSSL_PKEY_PARAM_DH_GENERATOR, &gen);
128    *p = OSSL_PARAM_construct_end();
129
130    return evp_pkey_ctx_set_params_strict(ctx, params);
131}
132
133/*
134 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
135 * simply because that's easier.
136 */
137int EVP_PKEY_CTX_set_dh_rfc5114(EVP_PKEY_CTX *ctx, int gen)
138{
139    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_PARAMGEN,
140                             EVP_PKEY_CTRL_DH_RFC5114, gen, NULL);
141}
142
143int EVP_PKEY_CTX_set_dhx_rfc5114(EVP_PKEY_CTX *ctx, int gen)
144{
145    return EVP_PKEY_CTX_set_dh_rfc5114(ctx, gen);
146}
147
148/*
149 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
150 * simply because that's easier.
151 */
152int EVP_PKEY_CTX_set_dh_nid(EVP_PKEY_CTX *ctx, int nid)
153{
154    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DH,
155                             EVP_PKEY_OP_PARAMGEN | EVP_PKEY_OP_KEYGEN,
156                             EVP_PKEY_CTRL_DH_NID, nid, NULL);
157}
158
159int EVP_PKEY_CTX_set_dh_pad(EVP_PKEY_CTX *ctx, int pad)
160{
161    OSSL_PARAM dh_pad_params[2];
162    unsigned int upad = pad;
163
164    /* We use EVP_PKEY_CTX_ctrl return values */
165    if (ctx == NULL || !EVP_PKEY_CTX_IS_DERIVE_OP(ctx)) {
166        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
167        return -2;
168    }
169
170    dh_pad_params[0] = OSSL_PARAM_construct_uint(OSSL_EXCHANGE_PARAM_PAD, &upad);
171    dh_pad_params[1] = OSSL_PARAM_construct_end();
172
173    return evp_pkey_ctx_set_params_strict(ctx, dh_pad_params);
174}
175
176/*
177 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
178 * simply because that's easier.
179 */
180int EVP_PKEY_CTX_set_dh_kdf_type(EVP_PKEY_CTX *ctx, int kdf)
181{
182    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
183                             EVP_PKEY_CTRL_DH_KDF_TYPE, kdf, NULL);
184}
185
186/*
187 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
188 * simply because that's easier.
189 */
190int EVP_PKEY_CTX_get_dh_kdf_type(EVP_PKEY_CTX *ctx)
191{
192    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
193                             EVP_PKEY_CTRL_DH_KDF_TYPE, -2, NULL);
194}
195
196/*
197 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
198 * simply because that's easier.
199 */
200int EVP_PKEY_CTX_set0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT *oid)
201{
202    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
203                             EVP_PKEY_CTRL_DH_KDF_OID, 0, (void *)(oid));
204}
205
206/*
207 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
208 * simply because that's easier.
209 */
210int EVP_PKEY_CTX_get0_dh_kdf_oid(EVP_PKEY_CTX *ctx, ASN1_OBJECT **oid)
211{
212    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
213                             EVP_PKEY_CTRL_GET_DH_KDF_OID, 0, (void *)(oid));
214}
215
216/*
217 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
218 * simply because that's easier.
219 */
220int EVP_PKEY_CTX_set_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD *md)
221{
222    return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
223                             EVP_PKEY_CTRL_DH_KDF_MD, 0, (void *)(md));
224}
225
226/*
227 * This one is currently implemented as an EVP_PKEY_CTX_ctrl() wrapper,
228 * simply because that's easier.
229 */
230int EVP_PKEY_CTX_get_dh_kdf_md(EVP_PKEY_CTX *ctx, const EVP_MD **pmd)
231{
232        return EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_DHX, EVP_PKEY_OP_DERIVE,
233                                 EVP_PKEY_CTRL_GET_DH_KDF_MD, 0, (void *)(pmd));
234}
235
236int EVP_PKEY_CTX_set_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int outlen)
237{
238    int ret;
239    size_t len = outlen;
240    OSSL_PARAM params[2], *p = params;
241
242    ret = dh_param_derive_check(ctx);
243    if (ret != 1)
244        return ret;
245
246    if (outlen <= 0) {
247        /*
248         * This would ideally be -1 or 0, but we have to retain compatibility
249         * with legacy behaviour of EVP_PKEY_CTX_ctrl() which returned -2 if
250         * inlen <= 0
251         */
252        return -2;
253    }
254
255    *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
256                                       &len);
257    *p = OSSL_PARAM_construct_end();
258
259    ret = evp_pkey_ctx_set_params_strict(ctx, params);
260    if (ret == -2)
261        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
262    return ret;
263}
264
265int EVP_PKEY_CTX_get_dh_kdf_outlen(EVP_PKEY_CTX *ctx, int *plen)
266{
267    int ret;
268    size_t len = UINT_MAX;
269    OSSL_PARAM params[2], *p = params;
270
271    ret = dh_param_derive_check(ctx);
272    if (ret != 1)
273        return ret;
274
275    *p++ = OSSL_PARAM_construct_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN,
276                                       &len);
277    *p = OSSL_PARAM_construct_end();
278
279    ret = evp_pkey_ctx_get_params_strict(ctx, params);
280    if (ret == -2)
281        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
282    if (ret != 1 || len > INT_MAX)
283        return -1;
284
285    *plen = (int)len;
286
287    return 1;
288}
289
290int EVP_PKEY_CTX_set0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char *ukm, int len)
291{
292    int ret;
293    OSSL_PARAM params[2], *p = params;
294
295    if (len < 0)
296        return -1;
297
298    ret = dh_param_derive_check(ctx);
299    if (ret != 1)
300        return ret;
301
302    *p++ = OSSL_PARAM_construct_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM,
303                                            /*
304                                             * Cast away the const. This is read
305                                             * only so should be safe
306                                             */
307                                            (void *)ukm,
308                                            (size_t)len);
309    *p = OSSL_PARAM_construct_end();
310
311    ret = evp_pkey_ctx_set_params_strict(ctx, params);
312    if (ret == -2)
313        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
314    if (ret == 1)
315        OPENSSL_free(ukm);
316    return ret;
317}
318
319#ifndef OPENSSL_NO_DEPRECATED_3_0
320int EVP_PKEY_CTX_get0_dh_kdf_ukm(EVP_PKEY_CTX *ctx, unsigned char **pukm)
321{
322    int ret;
323    size_t ukmlen;
324    OSSL_PARAM params[2], *p = params;
325
326    ret = dh_param_derive_check(ctx);
327    if (ret != 1)
328        return ret;
329
330    *p++ = OSSL_PARAM_construct_octet_ptr(OSSL_EXCHANGE_PARAM_KDF_UKM,
331                                          (void **)pukm, 0);
332    *p = OSSL_PARAM_construct_end();
333
334    ret = evp_pkey_ctx_get_params_strict(ctx, params);
335    if (ret == -2)
336        ERR_raise(ERR_LIB_EVP, EVP_R_COMMAND_NOT_SUPPORTED);
337    if (ret != 1)
338        return -1;
339
340    ukmlen = params[0].return_size;
341    if (ukmlen > INT_MAX)
342        return -1;
343
344    return (int)ukmlen;
345}
346#endif
347