Author: Ross Kinsey <RossIKinsey@gmail.com>
[openssl.git] / crypto / dh / dh_check.c
1 /*
2  * Copyright 1995-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 <stdio.h>
11 #include "internal/cryptlib.h"
12 #include <openssl/bn.h>
13 #include "dh_local.h"
14
15 /*-
16  * Check that p and g are suitable enough
17  *
18  * p is odd
19  * 1 < g < p - 1
20  */
21 int DH_check_params_ex(const DH *dh)
22 {
23     int errflags = 0;
24
25     if (!DH_check_params(dh, &errflags))
26         return 0;
27
28     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
29         DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_CHECK_P_NOT_PRIME);
30     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
31         DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_NOT_SUITABLE_GENERATOR);
32     if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
33         DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_MODULUS_TOO_SMALL);
34     if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
35         DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_MODULUS_TOO_LARGE);
36
37     return errflags == 0;
38 }
39
40 int DH_check_params(const DH *dh, int *ret)
41 {
42     int ok = 0;
43     BIGNUM *tmp = NULL;
44     BN_CTX *ctx = NULL;
45
46     *ret = 0;
47     ctx = BN_CTX_new();
48     if (ctx == NULL)
49         goto err;
50     BN_CTX_start(ctx);
51     tmp = BN_CTX_get(ctx);
52     if (tmp == NULL)
53         goto err;
54
55     if (!BN_is_odd(dh->params.p))
56         *ret |= DH_CHECK_P_NOT_PRIME;
57     if (BN_is_negative(dh->params.g)
58         || BN_is_zero(dh->params.g)
59         || BN_is_one(dh->params.g))
60         *ret |= DH_NOT_SUITABLE_GENERATOR;
61     if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
62         goto err;
63     if (BN_cmp(dh->params.g, tmp) >= 0)
64         *ret |= DH_NOT_SUITABLE_GENERATOR;
65     if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS)
66         *ret |= DH_MODULUS_TOO_SMALL;
67     if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS)
68         *ret |= DH_MODULUS_TOO_LARGE;
69
70     ok = 1;
71  err:
72     BN_CTX_end(ctx);
73     BN_CTX_free(ctx);
74     return ok;
75 }
76
77 /*-
78  * Check that p is a safe prime and
79  * g is a suitable generator.
80  */
81 int DH_check_ex(const DH *dh)
82 {
83     int errflags = 0;
84
85     if (!DH_check(dh, &errflags))
86         return 0;
87
88     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0)
89         DHerr(DH_F_DH_CHECK_EX, DH_R_NOT_SUITABLE_GENERATOR);
90     if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0)
91         DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_Q_NOT_PRIME);
92     if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0)
93         DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_Q_VALUE);
94     if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0)
95         DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_INVALID_J_VALUE);
96     if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0)
97         DHerr(DH_F_DH_CHECK_EX, DH_R_UNABLE_TO_CHECK_GENERATOR);
98     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0)
99         DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_PRIME);
100     if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0)
101         DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_SAFE_PRIME);
102     if ((errflags & DH_MODULUS_TOO_SMALL) != 0)
103         DHerr(DH_F_DH_CHECK_EX, DH_R_MODULUS_TOO_SMALL);
104     if ((errflags & DH_MODULUS_TOO_LARGE) != 0)
105         DHerr(DH_F_DH_CHECK_EX, DH_R_MODULUS_TOO_LARGE);
106
107     return errflags == 0;
108 }
109
110 int DH_check(const DH *dh, int *ret)
111 {
112     int ok = 0, r;
113     BN_CTX *ctx = NULL;
114     BIGNUM *t1 = NULL, *t2 = NULL;
115
116     if (!DH_check_params(dh, ret))
117         return 0;
118
119     ctx = BN_CTX_new();
120     if (ctx == NULL)
121         goto err;
122     BN_CTX_start(ctx);
123     t1 = BN_CTX_get(ctx);
124     t2 = BN_CTX_get(ctx);
125     if (t2 == NULL)
126         goto err;
127
128     if (dh->params.q != NULL) {
129         if (BN_cmp(dh->params.g, BN_value_one()) <= 0)
130             *ret |= DH_NOT_SUITABLE_GENERATOR;
131         else if (BN_cmp(dh->params.g, dh->params.p) >= 0)
132             *ret |= DH_NOT_SUITABLE_GENERATOR;
133         else {
134             /* Check g^q == 1 mod p */
135             if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx))
136                 goto err;
137             if (!BN_is_one(t1))
138                 *ret |= DH_NOT_SUITABLE_GENERATOR;
139         }
140         r = BN_check_prime(dh->params.q, ctx, NULL);
141         if (r < 0)
142             goto err;
143         if (!r)
144             *ret |= DH_CHECK_Q_NOT_PRIME;
145         /* Check p == 1 mod q  i.e. q divides p - 1 */
146         if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx))
147             goto err;
148         if (!BN_is_one(t2))
149             *ret |= DH_CHECK_INVALID_Q_VALUE;
150         if (dh->params.j != NULL
151             && BN_cmp(dh->params.j, t1))
152             *ret |= DH_CHECK_INVALID_J_VALUE;
153     }
154
155     r = BN_check_prime(dh->params.p, ctx, NULL);
156     if (r < 0)
157         goto err;
158     if (!r)
159         *ret |= DH_CHECK_P_NOT_PRIME;
160     else if (dh->params.q == NULL) {
161         if (!BN_rshift1(t1, dh->params.p))
162             goto err;
163         r = BN_check_prime(t1, ctx, NULL);
164         if (r < 0)
165             goto err;
166         if (!r)
167             *ret |= DH_CHECK_P_NOT_SAFE_PRIME;
168     }
169     ok = 1;
170  err:
171     BN_CTX_end(ctx);
172     BN_CTX_free(ctx);
173     return ok;
174 }
175
176 int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key)
177 {
178     int errflags = 0;
179
180     if (!DH_check_pub_key(dh, pub_key, &errflags))
181         return 0;
182
183     if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0)
184         DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_SMALL);
185     if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0)
186         DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_LARGE);
187     if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0)
188         DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_INVALID);
189
190     return errflags == 0;
191 }
192
193 int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret)
194 {
195     int ok = 0;
196     BIGNUM *tmp = NULL;
197     BN_CTX *ctx = NULL;
198
199     *ret = 0;
200     ctx = BN_CTX_new();
201     if (ctx == NULL)
202         goto err;
203     BN_CTX_start(ctx);
204     tmp = BN_CTX_get(ctx);
205     if (tmp == NULL || !BN_set_word(tmp, 1))
206         goto err;
207     if (BN_cmp(pub_key, tmp) <= 0)
208         *ret |= DH_CHECK_PUBKEY_TOO_SMALL;
209     if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1))
210         goto err;
211     if (BN_cmp(pub_key, tmp) >= 0)
212         *ret |= DH_CHECK_PUBKEY_TOO_LARGE;
213
214     if (dh->params.q != NULL) {
215         /* Check pub_key^q == 1 mod p */
216         if (!BN_mod_exp(tmp, pub_key, dh->params.q, dh->params.p, ctx))
217             goto err;
218         if (!BN_is_one(tmp))
219             *ret |= DH_CHECK_PUBKEY_INVALID;
220     }
221
222     ok = 1;
223  err:
224     BN_CTX_end(ctx);
225     BN_CTX_free(ctx);
226     return ok;
227 }