]>
Commit | Line | Data |
---|---|---|
aa6bb135 | 1 | /* |
a38c878c | 2 | * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. |
d02b48c6 | 3 | * |
e38873f5 | 4 | * Licensed under the Apache License 2.0 (the "License"). You may not use |
aa6bb135 RS |
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 | |
d02b48c6 RE |
8 | */ |
9 | ||
10 | #include <stdio.h> | |
b39fc560 | 11 | #include "internal/cryptlib.h" |
ec577822 | 12 | #include <openssl/bn.h> |
706457b7 | 13 | #include "dh_local.h" |
d02b48c6 | 14 | |
26505153 RL |
15 | /*- |
16 | * Check that p and g are suitable enough | |
17 | * | |
18 | * p is odd | |
19 | * 1 < g < p - 1 | |
20 | */ | |
b0004708 PY |
21 | int DH_check_params_ex(const DH *dh) |
22 | { | |
23 | int errflags = 0; | |
24 | ||
a38c878c BE |
25 | if (!DH_check_params(dh, &errflags)) |
26 | return 0; | |
b0004708 PY |
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); | |
feeb7ecd BE |
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); | |
b0004708 PY |
36 | |
37 | return errflags == 0; | |
38 | } | |
26505153 RL |
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 | ||
dc8de3e6 | 55 | if (!BN_is_odd(dh->params.p)) |
26505153 | 56 | *ret |= DH_CHECK_P_NOT_PRIME; |
dc8de3e6 SL |
57 | if (BN_is_negative(dh->params.g) |
58 | || BN_is_zero(dh->params.g) | |
59 | || BN_is_one(dh->params.g)) | |
26505153 | 60 | *ret |= DH_NOT_SUITABLE_GENERATOR; |
dc8de3e6 | 61 | if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) |
26505153 | 62 | goto err; |
dc8de3e6 | 63 | if (BN_cmp(dh->params.g, tmp) >= 0) |
26505153 | 64 | *ret |= DH_NOT_SUITABLE_GENERATOR; |
dc8de3e6 | 65 | if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) |
feeb7ecd | 66 | *ret |= DH_MODULUS_TOO_SMALL; |
dc8de3e6 | 67 | if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) |
feeb7ecd | 68 | *ret |= DH_MODULUS_TOO_LARGE; |
26505153 RL |
69 | |
70 | ok = 1; | |
71 | err: | |
ce1415ed SL |
72 | BN_CTX_end(ctx); |
73 | BN_CTX_free(ctx); | |
26a7d938 | 74 | return ok; |
26505153 RL |
75 | } |
76 | ||
1d97c843 TH |
77 | /*- |
78 | * Check that p is a safe prime and | |
a38c878c | 79 | * g is a suitable generator. |
d02b48c6 | 80 | */ |
b0004708 PY |
81 | int DH_check_ex(const DH *dh) |
82 | { | |
83 | int errflags = 0; | |
84 | ||
a38c878c BE |
85 | if (!DH_check(dh, &errflags)) |
86 | return 0; | |
b0004708 PY |
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); | |
feeb7ecd BE |
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); | |
b0004708 PY |
106 | |
107 | return errflags == 0; | |
108 | } | |
d02b48c6 | 109 | |
f971ccb2 | 110 | int DH_check(const DH *dh, int *ret) |
0f113f3e | 111 | { |
748e8530 | 112 | int ok = 0, r; |
0f113f3e | 113 | BN_CTX *ctx = NULL; |
0f113f3e MC |
114 | BIGNUM *t1 = NULL, *t2 = NULL; |
115 | ||
a38c878c BE |
116 | if (!DH_check_params(dh, ret)) |
117 | return 0; | |
118 | ||
0f113f3e MC |
119 | ctx = BN_CTX_new(); |
120 | if (ctx == NULL) | |
121 | goto err; | |
122 | BN_CTX_start(ctx); | |
123 | t1 = BN_CTX_get(ctx); | |
0f113f3e MC |
124 | t2 = BN_CTX_get(ctx); |
125 | if (t2 == NULL) | |
126 | goto err; | |
d02b48c6 | 127 | |
dc8de3e6 SL |
128 | if (dh->params.q != NULL) { |
129 | if (BN_cmp(dh->params.g, BN_value_one()) <= 0) | |
0f113f3e | 130 | *ret |= DH_NOT_SUITABLE_GENERATOR; |
dc8de3e6 | 131 | else if (BN_cmp(dh->params.g, dh->params.p) >= 0) |
0f113f3e MC |
132 | *ret |= DH_NOT_SUITABLE_GENERATOR; |
133 | else { | |
134 | /* Check g^q == 1 mod p */ | |
dc8de3e6 | 135 | if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) |
0f113f3e MC |
136 | goto err; |
137 | if (!BN_is_one(t1)) | |
138 | *ret |= DH_NOT_SUITABLE_GENERATOR; | |
139 | } | |
dc8de3e6 | 140 | r = BN_check_prime(dh->params.q, ctx, NULL); |
748e8530 DB |
141 | if (r < 0) |
142 | goto err; | |
143 | if (!r) | |
0f113f3e MC |
144 | *ret |= DH_CHECK_Q_NOT_PRIME; |
145 | /* Check p == 1 mod q i.e. q divides p - 1 */ | |
dc8de3e6 | 146 | if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) |
0f113f3e MC |
147 | goto err; |
148 | if (!BN_is_one(t2)) | |
149 | *ret |= DH_CHECK_INVALID_Q_VALUE; | |
dc8de3e6 SL |
150 | if (dh->params.j != NULL |
151 | && BN_cmp(dh->params.j, t1)) | |
0f113f3e | 152 | *ret |= DH_CHECK_INVALID_J_VALUE; |
a38c878c | 153 | } |
d02b48c6 | 154 | |
dc8de3e6 | 155 | r = BN_check_prime(dh->params.p, ctx, NULL); |
748e8530 DB |
156 | if (r < 0) |
157 | goto err; | |
158 | if (!r) | |
0f113f3e | 159 | *ret |= DH_CHECK_P_NOT_PRIME; |
dc8de3e6 SL |
160 | else if (dh->params.q == NULL) { |
161 | if (!BN_rshift1(t1, dh->params.p)) | |
0f113f3e | 162 | goto err; |
42619397 | 163 | r = BN_check_prime(t1, ctx, NULL); |
748e8530 DB |
164 | if (r < 0) |
165 | goto err; | |
e705fcf1 | 166 | if (!r) |
0f113f3e MC |
167 | *ret |= DH_CHECK_P_NOT_SAFE_PRIME; |
168 | } | |
169 | ok = 1; | |
170 | err: | |
ce1415ed SL |
171 | BN_CTX_end(ctx); |
172 | BN_CTX_free(ctx); | |
26a7d938 | 173 | return ok; |
0f113f3e | 174 | } |
bf3d6c0c | 175 | |
b0004708 PY |
176 | int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) |
177 | { | |
178 | int errflags = 0; | |
179 | ||
2b95e8ef BE |
180 | if (!DH_check_pub_key(dh, pub_key, &errflags)) |
181 | return 0; | |
b0004708 PY |
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 | ||
bf3d6c0c | 193 | int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) |
0f113f3e MC |
194 | { |
195 | int ok = 0; | |
b128abc3 MC |
196 | BIGNUM *tmp = NULL; |
197 | BN_CTX *ctx = NULL; | |
bf3d6c0c | 198 | |
0f113f3e | 199 | *ret = 0; |
b128abc3 MC |
200 | ctx = BN_CTX_new(); |
201 | if (ctx == NULL) | |
0f113f3e | 202 | goto err; |
b128abc3 MC |
203 | BN_CTX_start(ctx); |
204 | tmp = BN_CTX_get(ctx); | |
f5a12207 | 205 | if (tmp == NULL || !BN_set_word(tmp, 1)) |
b128abc3 | 206 | goto err; |
b128abc3 | 207 | if (BN_cmp(pub_key, tmp) <= 0) |
0f113f3e | 208 | *ret |= DH_CHECK_PUBKEY_TOO_SMALL; |
dc8de3e6 | 209 | if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) |
f5a12207 | 210 | goto err; |
b128abc3 | 211 | if (BN_cmp(pub_key, tmp) >= 0) |
0f113f3e | 212 | *ret |= DH_CHECK_PUBKEY_TOO_LARGE; |
bf3d6c0c | 213 | |
dc8de3e6 | 214 | if (dh->params.q != NULL) { |
b128abc3 | 215 | /* Check pub_key^q == 1 mod p */ |
dc8de3e6 | 216 | if (!BN_mod_exp(tmp, pub_key, dh->params.q, dh->params.p, ctx)) |
b128abc3 MC |
217 | goto err; |
218 | if (!BN_is_one(tmp)) | |
219 | *ret |= DH_CHECK_PUBKEY_INVALID; | |
220 | } | |
221 | ||
0f113f3e MC |
222 | ok = 1; |
223 | err: | |
ce1415ed SL |
224 | BN_CTX_end(ctx); |
225 | BN_CTX_free(ctx); | |
26a7d938 | 226 | return ok; |
0f113f3e | 227 | } |