xref: /freebsd/crypto/openssl/crypto/dh/dh_check.c (revision 88b8b7f0c4e9948667a2279e78e975a784049cba)
1 /*
2  * Copyright 1995-2025 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 <stdio.h>
17 #include "internal/cryptlib.h"
18 #include <openssl/bn.h>
19 #include <openssl/self_test.h>
20 #include "dh_local.h"
21 #include "crypto/dh.h"
22 
23 /*-
24  * Check that p and g are suitable enough
25  *
26  * p is odd
27  * 1 < g < p - 1
28  */
DH_check_params_ex(const DH * dh)29 int DH_check_params_ex(const DH *dh)
30 {
31     int errflags = 0;
32 
33     if (!DH_check_params(dh, &errflags))
34         return 0;
35 
36     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
37         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME);
38     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
39         ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR);
40     if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
41         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
42     if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
43         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
44 
45     return errflags == 0;
46 }
47 
48 #ifdef FIPS_MODULE
DH_check_params(const DH * dh,int * ret)49 int DH_check_params(const DH *dh, int *ret)
50 {
51     int nid;
52 
53     *ret = 0;
54     /*
55      * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity
56      * (1a) The domain parameters correspond to any approved safe prime group.
57      */
58     nid = DH_get_nid((DH *)dh);
59     if (nid != NID_undef)
60         return 1;
61     /*
62      * OR
63      * (2b) FFC domain params conform to FIPS-186-4 explicit domain param
64      * validity tests.
65      */
66     return ossl_ffc_params_FIPS186_4_validate(dh->libctx, &dh->params,
67                                               FFC_PARAM_TYPE_DH, ret, NULL);
68 }
69 #else
DH_check_params(const DH * dh,int * ret)70 int DH_check_params(const DH *dh, int *ret)
71 {
72     int ok = 0;
73     BIGNUM *tmp = NULL;
74     BN_CTX *ctx = NULL;
75 
76     *ret = 0;
77     ctx = BN_CTX_new_ex(dh->libctx);
78     if (ctx == NULL)
79         goto err;
80     BN_CTX_start(ctx);
81     tmp = BN_CTX_get(ctx);
82     if (tmp == NULL)
83         goto err;
84 
85     if (!BN_is_odd(dh->params.p))
86         *ret |= DH_CHECK_P_NOT_PRIME;
87     if (BN_is_negative(dh->params.g)
88         || BN_is_zero(dh->params.g)
89         || BN_is_one(dh->params.g))
90         *ret |= DH_NOT_SUITABLE_GENERATOR;
91     if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
92         goto err;
93     if (BN_cmp(dh->params.g, tmp) >= 0)
94         *ret |= DH_NOT_SUITABLE_GENERATOR;
95     if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS)
96         *ret |= DH_MODULUS_TOO_SMALL;
97     if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS)
98         *ret |= DH_MODULUS_TOO_LARGE;
99 
100     ok = 1;
101  err:
102     BN_CTX_end(ctx);
103     BN_CTX_free(ctx);
104     return ok;
105 }
106 #endif /* FIPS_MODULE */
107 
108 /*-
109  * Check that p is a safe prime and
110  * g is a suitable generator.
111  */
DH_check_ex(const DH * dh)112 int DH_check_ex(const DH *dh)
113 {
114     int errflags = 0;
115 
116     if (!DH_check(dh, &errflags))
117         return 0;
118 
119     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
120         ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR);
121     if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0)
122         ERR_raise(ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME);
123     if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0)
124         ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE);
125     if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0)
126         ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE);
127     if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0)
128         ERR_raise(ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR);
129     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
130         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME);
131     if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0)
132         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME);
133     if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
134         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL);
135     if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
136         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
137 
138     return errflags == 0;
139 }
140 
141 /* Note: according to documentation - this only checks the params */
DH_check(const DH * dh,int * ret)142 int DH_check(const DH *dh, int *ret)
143 {
144 #ifdef FIPS_MODULE
145     return DH_check_params(dh, ret);
146 #else
147     int ok = 0, r, q_good = 0;
148     BN_CTX *ctx = NULL;
149     BIGNUM *t1 = NULL, *t2 = NULL;
150     int nid = DH_get_nid((DH *)dh);
151 
152     *ret = 0;
153     if (nid != NID_undef)
154         return 1;
155 
156     /* Don't do any checks at all with an excessively large modulus */
157     if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) {
158         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
159         *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME;
160         return 0;
161     }
162 
163     if (!DH_check_params(dh, ret))
164         return 0;
165 
166     ctx = BN_CTX_new_ex(dh->libctx);
167     if (ctx == NULL)
168         goto err;
169     BN_CTX_start(ctx);
170     t1 = BN_CTX_get(ctx);
171     t2 = BN_CTX_get(ctx);
172     if (t2 == NULL)
173         goto err;
174 
175     if (dh->params.q != NULL) {
176         if (BN_ucmp(dh->params.p, dh->params.q) > 0)
177             q_good = 1;
178         else
179             *ret |= DH_CHECK_INVALID_Q_VALUE;
180     }
181 
182     if (q_good) {
183         if (BN_cmp(dh->params.g, BN_value_one()) <= 0)
184             *ret |= DH_NOT_SUITABLE_GENERATOR;
185         else if (BN_cmp(dh->params.g, dh->params.p) >= 0)
186             *ret |= DH_NOT_SUITABLE_GENERATOR;
187         else {
188             /* Check g^q == 1 mod p */
189             if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx))
190                 goto err;
191             if (!BN_is_one(t1))
192                 *ret |= DH_NOT_SUITABLE_GENERATOR;
193         }
194         r = BN_check_prime(dh->params.q, ctx, NULL);
195         if (r < 0)
196             goto err;
197         if (!r)
198             *ret |= DH_CHECK_Q_NOT_PRIME;
199         /* Check p == 1 mod q  i.e. q divides p - 1 */
200         if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx))
201             goto err;
202         if (!BN_is_one(t2))
203             *ret |= DH_CHECK_INVALID_Q_VALUE;
204         if (dh->params.j != NULL
205             && BN_cmp(dh->params.j, t1))
206             *ret |= DH_CHECK_INVALID_J_VALUE;
207     }
208 
209     r = BN_check_prime(dh->params.p, ctx, NULL);
210     if (r < 0)
211         goto err;
212     if (!r)
213         *ret |= DH_CHECK_P_NOT_PRIME;
214     else if (dh->params.q == NULL) {
215         if (!BN_rshift1(t1, dh->params.p))
216             goto err;
217         r = BN_check_prime(t1, ctx, NULL);
218         if (r < 0)
219             goto err;
220         if (!r)
221             *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
222     }
223     ok = 1;
224  err:
225     BN_CTX_end(ctx);
226     BN_CTX_free(ctx);
227     return ok;
228 #endif /* FIPS_MODULE */
229 }
230 
DH_check_pub_key_ex(const DH * dh,const BIGNUM * pub_key)231 int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key)
232 {
233     int errflags = 0;
234 
235     if (!DH_check_pub_key(dh, pub_key, &errflags))
236         return 0;
237 
238     if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0)
239         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL);
240     if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0)
241         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE);
242     if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0)
243         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID);
244 
245     return errflags == 0;
246 }
247 
248 /*
249  * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation.
250  */
DH_check_pub_key(const DH * dh,const BIGNUM * pub_key,int * ret)251 int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret)
252 {
253     /* Don't do any checks at all with an excessively large modulus */
254     if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) {
255         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE);
256         *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_PUBKEY_INVALID;
257         return 0;
258     }
259 
260     if (dh->params.q != NULL && BN_ucmp(dh->params.p, dh->params.q) < 0) {
261         *ret |= DH_CHECK_INVALID_Q_VALUE | DH_CHECK_PUBKEY_INVALID;
262         return 1;
263     }
264 
265     return ossl_ffc_validate_public_key(&dh->params, pub_key, ret);
266 }
267 
268 /*
269  * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation.
270  * To only be used with ephemeral FFC public keys generated using the approved
271  * safe-prime groups.
272  */
ossl_dh_check_pub_key_partial(const DH * dh,const BIGNUM * pub_key,int * ret)273 int ossl_dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret)
274 {
275     return ossl_ffc_validate_public_key_partial(&dh->params, pub_key, ret)
276            && *ret == 0;
277 }
278 
ossl_dh_check_priv_key(const DH * dh,const BIGNUM * priv_key,int * ret)279 int ossl_dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret)
280 {
281     int ok = 0;
282     BIGNUM *two_powN = NULL, *upper;
283 
284     *ret = 0;
285     two_powN = BN_new();
286     if (two_powN == NULL)
287         return 0;
288 
289     if (dh->params.q != NULL) {
290         upper = dh->params.q;
291 #ifndef FIPS_MODULE
292     } else if (dh->params.p != NULL) {
293         /*
294          * We do not have q so we just check the key is within some
295          * reasonable range, or the number of bits is equal to dh->length.
296          */
297         int length = dh->length;
298 
299         if (length == 0) {
300             length = BN_num_bits(dh->params.p) - 1;
301             if (BN_num_bits(priv_key) <= length
302                 && BN_num_bits(priv_key) > 1)
303                 ok = 1;
304         } else if (BN_num_bits(priv_key) == length) {
305             ok = 1;
306         }
307         goto end;
308 #endif
309     } else {
310         goto end;
311     }
312 
313     /* Is it from an approved Safe prime group ?*/
314     if (DH_get_nid((DH *)dh) != NID_undef && dh->length != 0) {
315         if (!BN_lshift(two_powN, BN_value_one(), dh->length))
316             goto end;
317         if (BN_cmp(two_powN, dh->params.q) < 0)
318             upper = two_powN;
319     }
320     if (!ossl_ffc_validate_private_key(upper, priv_key, ret))
321         goto end;
322 
323     ok = 1;
324 end:
325     BN_free(two_powN);
326     return ok;
327 }
328 
329 /*
330  * FFC pairwise check from SP800-56A R3.
331  *    Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency
332  */
ossl_dh_check_pairwise(const DH * dh,int return_on_null_numbers)333 int ossl_dh_check_pairwise(const DH *dh, int return_on_null_numbers)
334 {
335     int ret = 0;
336     BN_CTX *ctx = NULL;
337     BIGNUM *pub_key = NULL;
338     OSSL_SELF_TEST *st = NULL;
339     OSSL_CALLBACK *stcb = NULL;
340     void *stcbarg = NULL;
341 
342     if (dh->params.p == NULL
343         || dh->params.g == NULL
344         || dh->priv_key == NULL
345         || dh->pub_key == NULL)
346         return return_on_null_numbers;
347 
348     OSSL_SELF_TEST_get_callback(dh->libctx, &stcb, &stcbarg);
349     st = OSSL_SELF_TEST_new(stcb, stcbarg);
350     if (st == NULL)
351         goto err;
352     OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT,
353                            OSSL_SELF_TEST_DESC_PCT_DH);
354 
355     ctx = BN_CTX_new_ex(dh->libctx);
356     if (ctx == NULL)
357         goto err;
358     pub_key = BN_new();
359     if (pub_key == NULL)
360         goto err;
361 
362     /* recalculate the public key = (g ^ priv) mod p */
363     if (!ossl_dh_generate_public_key(ctx, dh, dh->priv_key, pub_key))
364         goto err;
365 
366 #ifdef FIPS_MODULE
367     {
368         int len;
369         unsigned char bytes[1024] = {0};    /* Max key size of 8192 bits */
370 
371         if (BN_num_bytes(pub_key) > (int)sizeof(bytes))
372             goto err;
373         len = BN_bn2bin(pub_key, bytes);
374         OSSL_SELF_TEST_oncorrupt_byte(st, bytes);
375         if (BN_bin2bn(bytes, len, pub_key) == NULL)
376             goto err;
377     }
378 #endif
379     /* check it matches the existing public_key */
380     ret = BN_cmp(pub_key, dh->pub_key) == 0;
381  err:
382     BN_free(pub_key);
383     BN_CTX_free(ctx);
384 
385     OSSL_SELF_TEST_onend(st, ret);
386     OSSL_SELF_TEST_free(st);
387     return ret;
388 }
389