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