diff options
author | tb <> | 2021-11-29 19:47:47 +0000 |
---|---|---|
committer | tb <> | 2021-11-29 19:47:47 +0000 |
commit | b753fe631ca17cfd52a93a2e4d1cd2b5bccebcc9 (patch) | |
tree | 01be3c7134630f106551fee90012d481f8dff5d9 | |
parent | 4603a555cb11f07168441cba6bf88feeae093985 (diff) | |
download | openbsd-b753fe631ca17cfd52a93a2e4d1cd2b5bccebcc9.tar.gz openbsd-b753fe631ca17cfd52a93a2e4d1cd2b5bccebcc9.tar.bz2 openbsd-b753fe631ca17cfd52a93a2e4d1cd2b5bccebcc9.zip |
Synchronize DH_check() mostly with OpenSSL 1.1.1 with some
simplifications and readability tweaks. This ensures in
particular that dh->q is suitable if present.
Based on work by Stephen Henson and Bernd Edlinger in OpenSSL.
Issues with the current implementation found via regression
tests in py-cryptography.
ok inoguchi jsing
-rw-r--r-- | src/lib/libcrypto/dh/dh_check.c | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/src/lib/libcrypto/dh/dh_check.c b/src/lib/libcrypto/dh/dh_check.c index d0524fd631..258cc8d916 100644 --- a/src/lib/libcrypto/dh/dh_check.c +++ b/src/lib/libcrypto/dh/dh_check.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dh_check.c,v 1.18 2021/11/29 19:41:02 tb Exp $ */ | 1 | /* $OpenBSD: dh_check.c,v 1.19 2021/11/29 19:47:47 tb Exp $ */ |
2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) | 2 | /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) |
3 | * All rights reserved. | 3 | * All rights reserved. |
4 | * | 4 | * |
@@ -61,6 +61,8 @@ | |||
61 | #include <openssl/bn.h> | 61 | #include <openssl/bn.h> |
62 | #include <openssl/dh.h> | 62 | #include <openssl/dh.h> |
63 | 63 | ||
64 | #include "bn_lcl.h" | ||
65 | |||
64 | int | 66 | int |
65 | DH_check_params(const DH *dh, int *flags) | 67 | DH_check_params(const DH *dh, int *flags) |
66 | { | 68 | { |
@@ -104,65 +106,78 @@ DH_check_params(const DH *dh, int *flags) | |||
104 | } | 106 | } |
105 | 107 | ||
106 | /* | 108 | /* |
107 | * Check that p is a safe prime and | 109 | * Check that p is a safe prime and that g is a suitable generator. |
108 | * if g is 2, 3 or 5, check that it is a suitable generator | ||
109 | * where | ||
110 | * for 2, p mod 24 == 11 | ||
111 | * for 3, p mod 12 == 5 | ||
112 | * for 5, p mod 10 == 3 or 7 | ||
113 | * should hold. | ||
114 | */ | 110 | */ |
115 | 111 | ||
116 | int | 112 | int |
117 | DH_check(const DH *dh, int *ret) | 113 | DH_check(const DH *dh, int *flags) |
118 | { | 114 | { |
119 | int is_prime, ok = 0; | ||
120 | BN_CTX *ctx = NULL; | 115 | BN_CTX *ctx = NULL; |
121 | BN_ULONG l; | 116 | int is_prime; |
122 | BIGNUM *q = NULL; | 117 | int ok = 0; |
118 | |||
119 | *flags = 0; | ||
120 | |||
121 | if (!DH_check_params(dh, flags)) | ||
122 | goto err; | ||
123 | 123 | ||
124 | *ret = 0; | ||
125 | ctx = BN_CTX_new(); | 124 | ctx = BN_CTX_new(); |
126 | if (ctx == NULL) | 125 | if (ctx == NULL) |
127 | goto err; | 126 | goto err; |
128 | q = BN_new(); | 127 | BN_CTX_start(ctx); |
129 | if (q == NULL) | ||
130 | goto err; | ||
131 | 128 | ||
132 | if (BN_is_word(dh->g, DH_GENERATOR_2)) { | 129 | if (dh->q != NULL) { |
133 | l = BN_mod_word(dh->p, 24); | 130 | BIGNUM *quotient, *residue; |
134 | if (l == (BN_ULONG)-1) | 131 | |
132 | if ((quotient = BN_CTX_get(ctx)) == NULL) | ||
133 | goto err; | ||
134 | if ((residue = BN_CTX_get(ctx)) == NULL) | ||
135 | goto err; | ||
136 | if ((*flags & DH_NOT_SUITABLE_GENERATOR) == 0) { | ||
137 | /* Check g^q == 1 mod p */ | ||
138 | if (!BN_mod_exp_ct(residue, dh->g, dh->q, dh->p, ctx)) | ||
139 | goto err; | ||
140 | if (!BN_is_one(residue)) | ||
141 | *flags |= DH_NOT_SUITABLE_GENERATOR; | ||
142 | } | ||
143 | is_prime = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL); | ||
144 | if (is_prime < 0) | ||
135 | goto err; | 145 | goto err; |
136 | if (l != 11) | 146 | if (is_prime == 0) |
137 | *ret |= DH_NOT_SUITABLE_GENERATOR; | 147 | *flags |= DH_CHECK_Q_NOT_PRIME; |
138 | } else if (BN_is_word(dh->g, DH_GENERATOR_5)) { | 148 | /* Check p == 1 mod q, i.e., q divides p - 1 */ |
139 | l = BN_mod_word(dh->p, 10); | 149 | if (!BN_div_ct(quotient, residue, dh->p, dh->q, ctx)) |
140 | if (l == (BN_ULONG)-1) | ||
141 | goto err; | 150 | goto err; |
142 | if (l != 3 && l != 7) | 151 | if (!BN_is_one(residue)) |
143 | *ret |= DH_NOT_SUITABLE_GENERATOR; | 152 | *flags |= DH_CHECK_INVALID_Q_VALUE; |
144 | } else | 153 | if (dh->j != NULL && BN_cmp(dh->j, quotient) != 0) |
145 | *ret |= DH_UNABLE_TO_CHECK_GENERATOR; | 154 | *flags |= DH_CHECK_INVALID_J_VALUE; |
155 | } | ||
146 | 156 | ||
147 | is_prime = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL); | 157 | is_prime = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL); |
148 | if (is_prime < 0) | 158 | if (is_prime < 0) |
149 | goto err; | 159 | goto err; |
150 | if (is_prime == 0) | 160 | if (is_prime == 0) |
151 | *ret |= DH_CHECK_P_NOT_PRIME; | 161 | *flags |= DH_CHECK_P_NOT_PRIME; |
152 | else { | 162 | else if (dh->q == NULL) { |
163 | BIGNUM *q; | ||
164 | |||
165 | if ((q = BN_CTX_get(ctx)) == NULL) | ||
166 | goto err; | ||
153 | if (!BN_rshift1(q, dh->p)) | 167 | if (!BN_rshift1(q, dh->p)) |
154 | goto err; | 168 | goto err; |
155 | is_prime = BN_is_prime_ex(q, BN_prime_checks, ctx, NULL); | 169 | is_prime = BN_is_prime_ex(q, BN_prime_checks, ctx, NULL); |
156 | if (is_prime < 0) | 170 | if (is_prime < 0) |
157 | goto err; | 171 | goto err; |
158 | if (is_prime == 0) | 172 | if (is_prime == 0) |
159 | *ret |= DH_CHECK_P_NOT_SAFE_PRIME; | 173 | *flags |= DH_CHECK_P_NOT_SAFE_PRIME; |
160 | } | 174 | } |
175 | |||
161 | ok = 1; | 176 | ok = 1; |
162 | 177 | ||
163 | err: | 178 | err: |
179 | BN_CTX_end(ctx); | ||
164 | BN_CTX_free(ctx); | 180 | BN_CTX_free(ctx); |
165 | BN_free(q); | ||
166 | return ok; | 181 | return ok; |
167 | } | 182 | } |
168 | 183 | ||