1 | /* |
2 | * Copyright 2019 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 <openssl/core_numbers.h> |
11 | #include <openssl/core_names.h> |
12 | #include <openssl/bn.h> |
13 | #include <openssl/dh.h> |
14 | #include <openssl/params.h> |
15 | #include "internal/param_build.h" |
16 | #include "prov/implementations.h" |
17 | #include "prov/providercommon.h" |
18 | |
19 | static OSSL_OP_keymgmt_importdomparams_fn dh_importdomparams; |
20 | static OSSL_OP_keymgmt_exportdomparams_fn dh_exportdomparams; |
21 | static OSSL_OP_keymgmt_importkey_fn dh_importkey; |
22 | static OSSL_OP_keymgmt_exportkey_fn dh_exportkey; |
23 | |
24 | static int params_to_domparams(DH *dh, const OSSL_PARAM params[]) |
25 | { |
26 | const OSSL_PARAM *param_p, *param_g; |
27 | BIGNUM *p = NULL, *g = NULL; |
28 | |
29 | if (dh == NULL) |
30 | return 0; |
31 | |
32 | param_p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_P); |
33 | param_g = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_FFC_G); |
34 | |
35 | if ((param_p != NULL && !OSSL_PARAM_get_BN(param_p, &p)) |
36 | || (param_g != NULL && !OSSL_PARAM_get_BN(param_g, &g))) |
37 | goto err; |
38 | |
39 | if (!DH_set0_pqg(dh, p, NULL, g)) |
40 | goto err; |
41 | |
42 | return 1; |
43 | |
44 | err: |
45 | BN_free(p); |
46 | BN_free(g); |
47 | return 0; |
48 | } |
49 | |
50 | static int domparams_to_params(DH *dh, OSSL_PARAM_BLD *tmpl) |
51 | { |
52 | const BIGNUM *dh_p = NULL, *dh_g = NULL; |
53 | |
54 | if (dh == NULL) |
55 | return 0; |
56 | |
57 | DH_get0_pqg(dh, &dh_p, NULL, &dh_g); |
58 | if (dh_p != NULL |
59 | && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_P, dh_p)) |
60 | return 0; |
61 | if (dh_g != NULL |
62 | && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_FFC_G, dh_g)) |
63 | return 0; |
64 | |
65 | return 1; |
66 | } |
67 | |
68 | static int params_to_key(DH *dh, const OSSL_PARAM params[]) |
69 | { |
70 | const OSSL_PARAM *param_priv_key, *param_pub_key; |
71 | BIGNUM *priv_key = NULL, *pub_key = NULL; |
72 | |
73 | if (dh == NULL) |
74 | return 0; |
75 | |
76 | if (!params_to_domparams(dh, params)) |
77 | return 0; |
78 | |
79 | param_priv_key = |
80 | OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_KEY); |
81 | param_pub_key = |
82 | OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PUB_KEY); |
83 | |
84 | /* |
85 | * DH documentation says that a public key must be present if a |
86 | * private key is present. |
87 | * We want to have at least a public key either way, so we end up |
88 | * requiring it unconditionally. |
89 | */ |
90 | if (param_pub_key == NULL) |
91 | return 0; |
92 | |
93 | if ((param_priv_key != NULL |
94 | && !OSSL_PARAM_get_BN(param_priv_key, &priv_key)) |
95 | || !OSSL_PARAM_get_BN(param_pub_key, &pub_key)) |
96 | goto err; |
97 | |
98 | if (!DH_set0_key(dh, pub_key, priv_key)) |
99 | goto err; |
100 | |
101 | return 1; |
102 | |
103 | err: |
104 | BN_free(priv_key); |
105 | BN_free(pub_key); |
106 | return 0; |
107 | } |
108 | |
109 | static int key_to_params(DH *dh, OSSL_PARAM_BLD *tmpl) |
110 | { |
111 | const BIGNUM *priv_key = NULL, *pub_key = NULL; |
112 | |
113 | if (dh == NULL) |
114 | return 0; |
115 | if (!domparams_to_params(dh, tmpl)) |
116 | return 0; |
117 | |
118 | DH_get0_key(dh, &pub_key, &priv_key); |
119 | if (priv_key != NULL |
120 | && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DH_PRIV_KEY, priv_key)) |
121 | return 0; |
122 | if (pub_key != NULL |
123 | && !ossl_param_bld_push_BN(tmpl, OSSL_PKEY_PARAM_DH_PUB_KEY, pub_key)) |
124 | return 0; |
125 | |
126 | return 1; |
127 | } |
128 | |
129 | static void *dh_importdomparams(void *provctx, const OSSL_PARAM params[]) |
130 | { |
131 | DH *dh; |
132 | |
133 | if ((dh = DH_new()) == NULL |
134 | || !params_to_domparams(dh, params)) { |
135 | DH_free(dh); |
136 | dh = NULL; |
137 | } |
138 | return dh; |
139 | } |
140 | |
141 | static int dh_exportdomparams(void *domparams, OSSL_CALLBACK *param_cb, |
142 | void *cbarg) |
143 | { |
144 | DH *dh = domparams; |
145 | OSSL_PARAM_BLD tmpl; |
146 | OSSL_PARAM *params = NULL; |
147 | int ret; |
148 | |
149 | ossl_param_bld_init(&tmpl); |
150 | if (dh == NULL |
151 | || !domparams_to_params(dh, &tmpl) |
152 | || (params = ossl_param_bld_to_param(&tmpl)) == NULL) |
153 | return 0; |
154 | ret = param_cb(params, cbarg); |
155 | ossl_param_bld_free(params); |
156 | return ret; |
157 | } |
158 | |
159 | static void *dh_importkey(void *provctx, const OSSL_PARAM params[]) |
160 | { |
161 | DH *dh; |
162 | |
163 | if ((dh = DH_new()) == NULL |
164 | || !params_to_key(dh, params)) { |
165 | DH_free(dh); |
166 | dh = NULL; |
167 | } |
168 | return dh; |
169 | } |
170 | |
171 | static int dh_exportkey(void *key, OSSL_CALLBACK *param_cb, void *cbarg) |
172 | { |
173 | DH *dh = key; |
174 | OSSL_PARAM_BLD tmpl; |
175 | OSSL_PARAM *params = NULL; |
176 | int ret; |
177 | |
178 | ossl_param_bld_init(&tmpl); |
179 | if (dh == NULL |
180 | || !key_to_params(dh, &tmpl) |
181 | || (params = ossl_param_bld_to_param(&tmpl)) == NULL) |
182 | return 0; |
183 | ret = param_cb(params, cbarg); |
184 | ossl_param_bld_free(params); |
185 | return ret; |
186 | } |
187 | |
188 | const OSSL_DISPATCH dh_keymgmt_functions[] = { |
189 | /* |
190 | * TODO(3.0) When implementing OSSL_FUNC_KEYMGMT_GENKEY, remember to also |
191 | * implement OSSL_FUNC_KEYMGMT_EXPORTKEY. |
192 | */ |
193 | { OSSL_FUNC_KEYMGMT_IMPORTDOMPARAMS, (void (*)(void))dh_importdomparams }, |
194 | { OSSL_FUNC_KEYMGMT_EXPORTDOMPARAMS, (void (*)(void))dh_exportdomparams }, |
195 | { OSSL_FUNC_KEYMGMT_FREEDOMPARAMS, (void (*)(void))DH_free }, |
196 | { OSSL_FUNC_KEYMGMT_IMPORTKEY, (void (*)(void))dh_importkey }, |
197 | { OSSL_FUNC_KEYMGMT_EXPORTKEY, (void (*)(void))dh_exportkey }, |
198 | { OSSL_FUNC_KEYMGMT_FREEKEY, (void (*)(void))DH_free }, |
199 | { 0, NULL } |
200 | }; |
201 | |