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