[crypto/dh] side channel hardening for computing DH shared keys
[openssl.git] / crypto / dh / dh_backend.c
1 /*
2  * Copyright 2020 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 /*
11  * DH low level APIs are deprecated for public use, but still ok for
12  * internal use.
13  */
14 #include "internal/deprecated.h"
15
16 #include <openssl/core_names.h>
17 #include "internal/param_build_set.h"
18 #include "crypto/dh.h"
19
20 /*
21  * The intention with the "backend" source file is to offer backend functions
22  * for legacy backends (EVP_PKEY_ASN1_METHOD and EVP_PKEY_METHOD) and provider
23  * implementations alike.
24  */
25
26 static int dh_ffc_params_fromdata(DH *dh, const OSSL_PARAM params[])
27 {
28     int ret;
29     FFC_PARAMS *ffc;
30
31     if (dh == NULL)
32         return 0;
33     ffc = dh_get0_params(dh);
34     if (ffc == NULL)
35         return 0;
36
37     ret = ossl_ffc_params_fromdata(ffc, params);
38     if (ret)
39         dh_cache_named_group(dh); /* This increments dh->dirty_cnt */
40     return ret;
41 }
42
43 int dh_params_fromdata(DH *dh, const OSSL_PARAM params[])
44 {
45     const OSSL_PARAM *param_priv_len;
46     long priv_len;
47
48     if (!dh_ffc_params_fromdata(dh, params))
49         return 0;
50
51     param_priv_len =
52         OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_DH_PRIV_LEN);
53     if (param_priv_len != NULL
54         && (!OSSL_PARAM_get_long(param_priv_len, &priv_len)
55             || !DH_set_length(dh, priv_len)))
56         return 0;
57
58     return 1;
59 }
60
61 int dh_key_fromdata(DH *dh, const OSSL_PARAM params[])
62 {
63     const OSSL_PARAM *param_priv_key, *param_pub_key;
64     BIGNUM *priv_key = NULL, *pub_key = NULL;
65
66     if (dh == NULL)
67         return 0;
68
69     param_priv_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY);
70     param_pub_key = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY);
71
72     /*
73      * DH documentation says that a public key must be present if a
74      * private key is present.
75      * We want to have at least a public key either way, so we end up
76      * requiring it unconditionally.
77      */
78     if (param_priv_key != NULL && param_pub_key == NULL)
79         return 0;
80
81     if ((param_priv_key != NULL
82          && !OSSL_PARAM_get_BN(param_priv_key, &priv_key))
83         || (param_pub_key != NULL
84             && !OSSL_PARAM_get_BN(param_pub_key, &pub_key)))
85         goto err;
86
87     if (!DH_set0_key(dh, pub_key, priv_key))
88         goto err;
89
90     return 1;
91
92  err:
93     BN_clear_free(priv_key);
94     BN_free(pub_key);
95     return 0;
96 }
97
98 int dh_params_todata(DH *dh, OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
99 {
100     long l = DH_get_length(dh);
101
102     if (!ossl_ffc_params_todata(dh_get0_params(dh), bld, params))
103         return 0;
104     if (l > 0
105         && !ossl_param_build_set_long(bld, params, OSSL_PKEY_PARAM_DH_PRIV_LEN, l))
106         return 0;
107     return 1;
108 }
109
110 int dh_key_todata(DH *dh, OSSL_PARAM_BLD *bld, OSSL_PARAM params[])
111 {
112     const BIGNUM *priv = NULL, *pub = NULL;
113
114     if (dh == NULL)
115         return 0;
116
117     DH_get0_key(dh, &pub, &priv);
118     if (priv != NULL
119         && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PRIV_KEY, priv))
120         return 0;
121     if (pub != NULL
122         && !ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_PUB_KEY, pub))
123         return 0;
124
125     return 1;
126 }