diff options
| author | tb <> | 2021-11-29 19:47:47 +0000 |
|---|---|---|
| committer | tb <> | 2021-11-29 19:47:47 +0000 |
| commit | 39831efe0c531b9f6d21f4f377dc9f07e7659f73 (patch) | |
| tree | 01be3c7134630f106551fee90012d481f8dff5d9 /src | |
| parent | 1bcf592f0a1b62a71dcfc1b44487050ade396863 (diff) | |
| download | openbsd-39831efe0c531b9f6d21f4f377dc9f07e7659f73.tar.gz openbsd-39831efe0c531b9f6d21f4f377dc9f07e7659f73.tar.bz2 openbsd-39831efe0c531b9f6d21f4f377dc9f07e7659f73.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
Diffstat (limited to 'src')
| -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 | ||
