c9679d7e52893a4cb1483cc31855509cc418cd31
[openssl.git] / crypto / dh / dh_lib.c
1 /*
2  * Copyright 1995-2018 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 <stdio.h>
11 #include "internal/cryptlib.h"
12 #include "internal/refcount.h"
13 #include <openssl/bn.h>
14 #include "dh_local.h"
15 #include "crypto/dh.h"
16 #include <openssl/engine.h>
17
18 #ifndef FIPS_MODE
19 int DH_set_method(DH *dh, const DH_METHOD *meth)
20 {
21     /*
22      * NB: The caller is specifically setting a method, so it's not up to us
23      * to deal with which ENGINE it comes from.
24      */
25     const DH_METHOD *mtmp;
26     mtmp = dh->meth;
27     if (mtmp->finish)
28         mtmp->finish(dh);
29 #ifndef OPENSSL_NO_ENGINE
30     ENGINE_finish(dh->engine);
31     dh->engine = NULL;
32 #endif
33     dh->meth = meth;
34     if (meth->init)
35         meth->init(dh);
36     return 1;
37 }
38 #endif /* !FIPS_MODE */
39
40 DH *DH_new(void)
41 {
42     return DH_new_method(NULL);
43 }
44
45 DH *DH_new_method(ENGINE *engine)
46 {
47     DH *ret = OPENSSL_zalloc(sizeof(*ret));
48
49     if (ret == NULL) {
50         DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
51         return NULL;
52     }
53
54     ret->references = 1;
55     ret->lock = CRYPTO_THREAD_lock_new();
56     if (ret->lock == NULL) {
57         DHerr(DH_F_DH_NEW_METHOD, ERR_R_MALLOC_FAILURE);
58         OPENSSL_free(ret);
59         return NULL;
60     }
61
62     ret->meth = DH_get_default_method();
63 #if !defined(FIPS_MODE) && !defined(OPENSSL_NO_ENGINE)
64     ret->flags = ret->meth->flags;  /* early default init */
65     if (engine) {
66         if (!ENGINE_init(engine)) {
67             DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
68             goto err;
69         }
70         ret->engine = engine;
71     } else
72         ret->engine = ENGINE_get_default_DH();
73     if (ret->engine) {
74         ret->meth = ENGINE_get_DH(ret->engine);
75         if (ret->meth == NULL) {
76             DHerr(DH_F_DH_NEW_METHOD, ERR_R_ENGINE_LIB);
77             goto err;
78         }
79     }
80 #endif
81
82     ret->flags = ret->meth->flags;
83
84 #ifndef FIPS_MODE
85     if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_DH, ret, &ret->ex_data))
86         goto err;
87 #endif /* FIPS_MODE */
88
89     if ((ret->meth->init != NULL) && !ret->meth->init(ret)) {
90         DHerr(DH_F_DH_NEW_METHOD, ERR_R_INIT_FAIL);
91         goto err;
92     }
93
94     return ret;
95
96  err:
97     DH_free(ret);
98     return NULL;
99 }
100
101 void DH_free(DH *r)
102 {
103     int i;
104
105     if (r == NULL)
106         return;
107
108     CRYPTO_DOWN_REF(&r->references, &i, r->lock);
109     REF_PRINT_COUNT("DH", r);
110     if (i > 0)
111         return;
112     REF_ASSERT_ISNT(i < 0);
113
114     if (r->meth != NULL && r->meth->finish != NULL)
115         r->meth->finish(r);
116 #if !defined(FIPS_MODE)
117 # if !defined(OPENSSL_NO_ENGINE)
118     ENGINE_finish(r->engine);
119 # endif
120     CRYPTO_free_ex_data(CRYPTO_EX_INDEX_DH, r, &r->ex_data);
121 #endif
122
123     CRYPTO_THREAD_lock_free(r->lock);
124
125     BN_clear_free(r->p);
126     BN_clear_free(r->g);
127     BN_clear_free(r->q);
128     BN_clear_free(r->j);
129     OPENSSL_free(r->seed);
130     BN_clear_free(r->counter);
131     BN_clear_free(r->pub_key);
132     BN_clear_free(r->priv_key);
133     OPENSSL_free(r);
134 }
135
136 int DH_up_ref(DH *r)
137 {
138     int i;
139
140     if (CRYPTO_UP_REF(&r->references, &i, r->lock) <= 0)
141         return 0;
142
143     REF_PRINT_COUNT("DH", r);
144     REF_ASSERT_ISNT(i < 2);
145     return ((i > 1) ? 1 : 0);
146 }
147
148 #ifndef FIPS_MODE
149 int DH_set_ex_data(DH *d, int idx, void *arg)
150 {
151     return CRYPTO_set_ex_data(&d->ex_data, idx, arg);
152 }
153
154 void *DH_get_ex_data(DH *d, int idx)
155 {
156     return CRYPTO_get_ex_data(&d->ex_data, idx);
157 }
158 #endif
159
160 int DH_bits(const DH *dh)
161 {
162     return BN_num_bits(dh->p);
163 }
164
165 int DH_size(const DH *dh)
166 {
167     return BN_num_bytes(dh->p);
168 }
169
170 int DH_security_bits(const DH *dh)
171 {
172     int N;
173     if (dh->q)
174         N = BN_num_bits(dh->q);
175     else if (dh->length)
176         N = dh->length;
177     else
178         N = -1;
179     return BN_security_bits(BN_num_bits(dh->p), N);
180 }
181
182 void DH_get0_pqg(const DH *dh,
183                  const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
184 {
185     if (p != NULL)
186         *p = dh->p;
187     if (q != NULL)
188         *q = dh->q;
189     if (g != NULL)
190         *g = dh->g;
191 }
192
193 int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g)
194 {
195     /* If the fields p and g in d are NULL, the corresponding input
196      * parameters MUST be non-NULL.  q may remain NULL.
197      */
198     if ((dh->p == NULL && p == NULL)
199         || (dh->g == NULL && g == NULL))
200         return 0;
201
202     if (p != NULL) {
203         BN_free(dh->p);
204         dh->p = p;
205     }
206     if (q != NULL) {
207         BN_free(dh->q);
208         dh->q = q;
209     }
210     if (g != NULL) {
211         BN_free(dh->g);
212         dh->g = g;
213     }
214
215     if (q != NULL) {
216         dh->length = BN_num_bits(q);
217     }
218
219     dh->dirty_cnt++;
220     return 1;
221 }
222
223 long DH_get_length(const DH *dh)
224 {
225     return dh->length;
226 }
227
228 int DH_set_length(DH *dh, long length)
229 {
230     dh->length = length;
231     return 1;
232 }
233
234 void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key)
235 {
236     if (pub_key != NULL)
237         *pub_key = dh->pub_key;
238     if (priv_key != NULL)
239         *priv_key = dh->priv_key;
240 }
241
242 int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key)
243 {
244     if (pub_key != NULL) {
245         BN_clear_free(dh->pub_key);
246         dh->pub_key = pub_key;
247     }
248     if (priv_key != NULL) {
249         BN_clear_free(dh->priv_key);
250         dh->priv_key = priv_key;
251     }
252
253     dh->dirty_cnt++;
254     return 1;
255 }
256
257 const BIGNUM *DH_get0_p(const DH *dh)
258 {
259     return dh->p;
260 }
261
262 const BIGNUM *DH_get0_q(const DH *dh)
263 {
264     return dh->q;
265 }
266
267 const BIGNUM *DH_get0_g(const DH *dh)
268 {
269     return dh->g;
270 }
271
272 const BIGNUM *DH_get0_priv_key(const DH *dh)
273 {
274     return dh->priv_key;
275 }
276
277 const BIGNUM *DH_get0_pub_key(const DH *dh)
278 {
279     return dh->pub_key;
280 }
281
282 void DH_clear_flags(DH *dh, int flags)
283 {
284     dh->flags &= ~flags;
285 }
286
287 int DH_test_flags(const DH *dh, int flags)
288 {
289     return dh->flags & flags;
290 }
291
292 void DH_set_flags(DH *dh, int flags)
293 {
294     dh->flags |= flags;
295 }
296
297 #ifndef FIPS_MODE
298 ENGINE *DH_get0_engine(DH *dh)
299 {
300     return dh->engine;
301 }
302 #endif /*FIPS_MODE */