/src/openssl30/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 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 |  | /* | 
| 11 |  |  * DH low level APIs are deprecated for public use, but still ok for | 
| 12 |  |  * internal use. | 
| 13 |  |  */ | 
| 14 |  | #include "internal/deprecated.h" | 
| 15 |  |  | 
| 16 |  | #include <stdio.h> | 
| 17 |  | #include "internal/cryptlib.h" | 
| 18 |  | #include <openssl/bn.h> | 
| 19 |  | #include "dh_local.h" | 
| 20 |  | #include "crypto/dh.h" | 
| 21 |  |  | 
| 22 |  | /*- | 
| 23 |  |  * Check that p and g are suitable enough | 
| 24 |  |  * | 
| 25 |  |  * p is odd | 
| 26 |  |  * 1 < g < p - 1 | 
| 27 |  |  */ | 
| 28 |  | int DH_check_params_ex(const DH *dh) | 
| 29 | 0 | { | 
| 30 | 0 |     int errflags = 0; | 
| 31 |  | 
 | 
| 32 | 0 |     if (!DH_check_params(dh, &errflags)) | 
| 33 | 0 |         return 0; | 
| 34 |  |  | 
| 35 | 0 |     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) | 
| 36 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME); | 
| 37 | 0 |     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) | 
| 38 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR); | 
| 39 | 0 |     if ((errflags & DH_MODULUS_TOO_SMALL) != 0) | 
| 40 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); | 
| 41 | 0 |     if ((errflags & DH_MODULUS_TOO_LARGE) != 0) | 
| 42 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); | 
| 43 |  | 
 | 
| 44 | 0 |     return errflags == 0; | 
| 45 | 0 | } | 
| 46 |  |  | 
| 47 |  | #ifdef FIPS_MODULE | 
| 48 |  | int DH_check_params(const DH *dh, int *ret) | 
| 49 |  | { | 
| 50 |  |     int nid; | 
| 51 |  |  | 
| 52 |  |     *ret = 0; | 
| 53 |  |     /* | 
| 54 |  |      * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity | 
| 55 |  |      * (1a) The domain parameters correspond to any approved safe prime group. | 
| 56 |  |      */ | 
| 57 |  |     nid = DH_get_nid((DH *)dh); | 
| 58 |  |     if (nid != NID_undef) | 
| 59 |  |         return 1; | 
| 60 |  |     /* | 
| 61 |  |      * OR | 
| 62 |  |      * (2b) FFC domain params conform to FIPS-186-4 explicit domain param | 
| 63 |  |      * validity tests. | 
| 64 |  |      */ | 
| 65 |  |     return ossl_ffc_params_FIPS186_4_validate(dh->libctx, &dh->params, | 
| 66 |  |                                               FFC_PARAM_TYPE_DH, ret, NULL); | 
| 67 |  | } | 
| 68 |  | #else | 
| 69 |  | int DH_check_params(const DH *dh, int *ret) | 
| 70 | 0 | { | 
| 71 | 0 |     int ok = 0; | 
| 72 | 0 |     BIGNUM *tmp = NULL; | 
| 73 | 0 |     BN_CTX *ctx = NULL; | 
| 74 |  | 
 | 
| 75 | 0 |     *ret = 0; | 
| 76 | 0 |     ctx = BN_CTX_new_ex(dh->libctx); | 
| 77 | 0 |     if (ctx == NULL) | 
| 78 | 0 |         goto err; | 
| 79 | 0 |     BN_CTX_start(ctx); | 
| 80 | 0 |     tmp = BN_CTX_get(ctx); | 
| 81 | 0 |     if (tmp == NULL) | 
| 82 | 0 |         goto err; | 
| 83 |  |  | 
| 84 | 0 |     if (!BN_is_odd(dh->params.p)) | 
| 85 | 0 |         *ret |= DH_CHECK_P_NOT_PRIME; | 
| 86 | 0 |     if (BN_is_negative(dh->params.g) | 
| 87 | 0 |         || BN_is_zero(dh->params.g) | 
| 88 | 0 |         || BN_is_one(dh->params.g)) | 
| 89 | 0 |         *ret |= DH_NOT_SUITABLE_GENERATOR; | 
| 90 | 0 |     if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) | 
| 91 | 0 |         goto err; | 
| 92 | 0 |     if (BN_cmp(dh->params.g, tmp) >= 0) | 
| 93 | 0 |         *ret |= DH_NOT_SUITABLE_GENERATOR; | 
| 94 | 0 |     if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) | 
| 95 | 0 |         *ret |= DH_MODULUS_TOO_SMALL; | 
| 96 | 0 |     if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) | 
| 97 | 0 |         *ret |= DH_MODULUS_TOO_LARGE; | 
| 98 |  | 
 | 
| 99 | 0 |     ok = 1; | 
| 100 | 0 |  err: | 
| 101 | 0 |     BN_CTX_end(ctx); | 
| 102 | 0 |     BN_CTX_free(ctx); | 
| 103 | 0 |     return ok; | 
| 104 | 0 | } | 
| 105 |  | #endif /* FIPS_MODULE */ | 
| 106 |  |  | 
| 107 |  | /*- | 
| 108 |  |  * Check that p is a safe prime and | 
| 109 |  |  * g is a suitable generator. | 
| 110 |  |  */ | 
| 111 |  | int DH_check_ex(const DH *dh) | 
| 112 | 0 | { | 
| 113 | 0 |     int errflags = 0; | 
| 114 |  | 
 | 
| 115 | 0 |     if (!DH_check(dh, &errflags)) | 
| 116 | 0 |         return 0; | 
| 117 |  |  | 
| 118 | 0 |     if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) | 
| 119 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_NOT_SUITABLE_GENERATOR); | 
| 120 | 0 |     if ((errflags & DH_CHECK_Q_NOT_PRIME) != 0) | 
| 121 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_Q_NOT_PRIME); | 
| 122 | 0 |     if ((errflags & DH_CHECK_INVALID_Q_VALUE) != 0) | 
| 123 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_Q_VALUE); | 
| 124 | 0 |     if ((errflags & DH_CHECK_INVALID_J_VALUE) != 0) | 
| 125 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_INVALID_J_VALUE); | 
| 126 | 0 |     if ((errflags & DH_UNABLE_TO_CHECK_GENERATOR) != 0) | 
| 127 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_UNABLE_TO_CHECK_GENERATOR); | 
| 128 | 0 |     if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) | 
| 129 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_PRIME); | 
| 130 | 0 |     if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0) | 
| 131 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_P_NOT_SAFE_PRIME); | 
| 132 | 0 |     if ((errflags & DH_MODULUS_TOO_SMALL) != 0) | 
| 133 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_SMALL); | 
| 134 | 0 |     if ((errflags & DH_MODULUS_TOO_LARGE) != 0) | 
| 135 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); | 
| 136 |  | 
 | 
| 137 | 0 |     return errflags == 0; | 
| 138 | 0 | } | 
| 139 |  |  | 
| 140 |  | /* Note: according to documentation - this only checks the params */ | 
| 141 |  | int DH_check(const DH *dh, int *ret) | 
| 142 | 0 | { | 
| 143 |  | #ifdef FIPS_MODULE | 
| 144 |  |     return DH_check_params(dh, ret); | 
| 145 |  | #else | 
| 146 | 0 |     int ok = 0, r, q_good = 0; | 
| 147 | 0 |     BN_CTX *ctx = NULL; | 
| 148 | 0 |     BIGNUM *t1 = NULL, *t2 = NULL; | 
| 149 | 0 |     int nid = DH_get_nid((DH *)dh); | 
| 150 |  | 
 | 
| 151 | 0 |     *ret = 0; | 
| 152 | 0 |     if (nid != NID_undef) | 
| 153 | 0 |         return 1; | 
| 154 |  |  | 
| 155 |  |     /* Don't do any checks at all with an excessively large modulus */ | 
| 156 | 0 |     if (BN_num_bits(dh->params.p) > OPENSSL_DH_CHECK_MAX_MODULUS_BITS) { | 
| 157 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_MODULUS_TOO_LARGE); | 
| 158 | 0 |         *ret = DH_MODULUS_TOO_LARGE | DH_CHECK_P_NOT_PRIME; | 
| 159 | 0 |         return 0; | 
| 160 | 0 |     } | 
| 161 |  |  | 
| 162 | 0 |     if (!DH_check_params(dh, ret)) | 
| 163 | 0 |         return 0; | 
| 164 |  |  | 
| 165 | 0 |     ctx = BN_CTX_new_ex(dh->libctx); | 
| 166 | 0 |     if (ctx == NULL) | 
| 167 | 0 |         goto err; | 
| 168 | 0 |     BN_CTX_start(ctx); | 
| 169 | 0 |     t1 = BN_CTX_get(ctx); | 
| 170 | 0 |     t2 = BN_CTX_get(ctx); | 
| 171 | 0 |     if (t2 == NULL) | 
| 172 | 0 |         goto err; | 
| 173 |  |  | 
| 174 | 0 |     if (dh->params.q != NULL) { | 
| 175 | 0 |         if (BN_ucmp(dh->params.p, dh->params.q) > 0) | 
| 176 | 0 |             q_good = 1; | 
| 177 | 0 |         else | 
| 178 | 0 |             *ret |= DH_CHECK_INVALID_Q_VALUE; | 
| 179 | 0 |     } | 
| 180 |  | 
 | 
| 181 | 0 |     if (q_good) { | 
| 182 | 0 |         if (BN_cmp(dh->params.g, BN_value_one()) <= 0) | 
| 183 | 0 |             *ret |= DH_NOT_SUITABLE_GENERATOR; | 
| 184 | 0 |         else if (BN_cmp(dh->params.g, dh->params.p) >= 0) | 
| 185 | 0 |             *ret |= DH_NOT_SUITABLE_GENERATOR; | 
| 186 | 0 |         else { | 
| 187 |  |             /* Check g^q == 1 mod p */ | 
| 188 | 0 |             if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) | 
| 189 | 0 |                 goto err; | 
| 190 | 0 |             if (!BN_is_one(t1)) | 
| 191 | 0 |                 *ret |= DH_NOT_SUITABLE_GENERATOR; | 
| 192 | 0 |         } | 
| 193 | 0 |         r = BN_check_prime(dh->params.q, ctx, NULL); | 
| 194 | 0 |         if (r < 0) | 
| 195 | 0 |             goto err; | 
| 196 | 0 |         if (!r) | 
| 197 | 0 |             *ret |= DH_CHECK_Q_NOT_PRIME; | 
| 198 |  |         /* Check p == 1 mod q  i.e. q divides p - 1 */ | 
| 199 | 0 |         if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) | 
| 200 | 0 |             goto err; | 
| 201 | 0 |         if (!BN_is_one(t2)) | 
| 202 | 0 |             *ret |= DH_CHECK_INVALID_Q_VALUE; | 
| 203 | 0 |         if (dh->params.j != NULL | 
| 204 | 0 |             && BN_cmp(dh->params.j, t1)) | 
| 205 | 0 |             *ret |= DH_CHECK_INVALID_J_VALUE; | 
| 206 | 0 |     } | 
| 207 |  |  | 
| 208 | 0 |     r = BN_check_prime(dh->params.p, ctx, NULL); | 
| 209 | 0 |     if (r < 0) | 
| 210 | 0 |         goto err; | 
| 211 | 0 |     if (!r) | 
| 212 | 0 |         *ret |= DH_CHECK_P_NOT_PRIME; | 
| 213 | 0 |     else if (dh->params.q == NULL) { | 
| 214 | 0 |         if (!BN_rshift1(t1, dh->params.p)) | 
| 215 | 0 |             goto err; | 
| 216 | 0 |         r = BN_check_prime(t1, ctx, NULL); | 
| 217 | 0 |         if (r < 0) | 
| 218 | 0 |             goto err; | 
| 219 | 0 |         if (!r) | 
| 220 | 0 |             *ret |= DH_CHECK_P_NOT_SAFE_PRIME; | 
| 221 | 0 |     } | 
| 222 | 0 |     ok = 1; | 
| 223 | 0 |  err: | 
| 224 | 0 |     BN_CTX_end(ctx); | 
| 225 | 0 |     BN_CTX_free(ctx); | 
| 226 | 0 |     return ok; | 
| 227 | 0 | #endif /* FIPS_MODULE */ | 
| 228 | 0 | } | 
| 229 |  |  | 
| 230 |  | int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) | 
| 231 | 0 | { | 
| 232 | 0 |     int errflags = 0; | 
| 233 |  | 
 | 
| 234 | 0 |     if (!DH_check_pub_key(dh, pub_key, &errflags)) | 
| 235 | 0 |         return 0; | 
| 236 |  |  | 
| 237 | 0 |     if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0) | 
| 238 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_SMALL); | 
| 239 | 0 |     if ((errflags & DH_CHECK_PUBKEY_TOO_LARGE) != 0) | 
| 240 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_TOO_LARGE); | 
| 241 | 0 |     if ((errflags & DH_CHECK_PUBKEY_INVALID) != 0) | 
| 242 | 0 |         ERR_raise(ERR_LIB_DH, DH_R_CHECK_PUBKEY_INVALID); | 
| 243 |  | 
 | 
| 244 | 0 |     return errflags == 0; | 
| 245 | 0 | } | 
| 246 |  |  | 
| 247 |  | /* | 
| 248 |  |  * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. | 
| 249 |  |  */ | 
| 250 |  | int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) | 
| 251 | 0 | { | 
| 252 | 0 |     return ossl_ffc_validate_public_key(&dh->params, pub_key, ret); | 
| 253 | 0 | } | 
| 254 |  |  | 
| 255 |  | /* | 
| 256 |  |  * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. | 
| 257 |  |  * To only be used with ephemeral FFC public keys generated using the approved | 
| 258 |  |  * safe-prime groups. | 
| 259 |  |  */ | 
| 260 |  | int ossl_dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret) | 
| 261 | 0 | { | 
| 262 | 0 |     return ossl_ffc_validate_public_key_partial(&dh->params, pub_key, ret); | 
| 263 | 0 | } | 
| 264 |  |  | 
| 265 |  | int ossl_dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret) | 
| 266 | 0 | { | 
| 267 | 0 |     int ok = 0; | 
| 268 | 0 |     BIGNUM *two_powN = NULL, *upper; | 
| 269 |  | 
 | 
| 270 | 0 |     *ret = 0; | 
| 271 | 0 |     two_powN = BN_new(); | 
| 272 | 0 |     if (two_powN == NULL) | 
| 273 | 0 |         return 0; | 
| 274 |  |  | 
| 275 | 0 |     if (dh->params.q != NULL) { | 
| 276 | 0 |         upper = dh->params.q; | 
| 277 | 0 | #ifndef FIPS_MODULE | 
| 278 | 0 |     } else if (dh->params.p != NULL) { | 
| 279 |  |         /* | 
| 280 |  |          * We do not have q so we just check the key is within some | 
| 281 |  |          * reasonable range, or the number of bits is equal to dh->length. | 
| 282 |  |          */ | 
| 283 | 0 |         int length = dh->length; | 
| 284 |  | 
 | 
| 285 | 0 |         if (length == 0) { | 
| 286 | 0 |             length = BN_num_bits(dh->params.p) - 1; | 
| 287 | 0 |             if (BN_num_bits(priv_key) <= length | 
| 288 | 0 |                 && BN_num_bits(priv_key) > 1) | 
| 289 | 0 |                 ok = 1; | 
| 290 | 0 |         } else if (BN_num_bits(priv_key) == length) { | 
| 291 | 0 |             ok = 1; | 
| 292 | 0 |         } | 
| 293 | 0 |         goto end; | 
| 294 | 0 | #endif | 
| 295 | 0 |     } else { | 
| 296 | 0 |         goto end; | 
| 297 | 0 |     } | 
| 298 |  |  | 
| 299 |  |     /* Is it from an approved Safe prime group ?*/ | 
| 300 | 0 |     if (DH_get_nid((DH *)dh) != NID_undef && dh->length != 0) { | 
| 301 | 0 |         if (!BN_lshift(two_powN, BN_value_one(), dh->length)) | 
| 302 | 0 |             goto end; | 
| 303 | 0 |         if (BN_cmp(two_powN, dh->params.q) < 0) | 
| 304 | 0 |             upper = two_powN; | 
| 305 | 0 |     } | 
| 306 | 0 |     if (!ossl_ffc_validate_private_key(upper, priv_key, ret)) | 
| 307 | 0 |         goto end; | 
| 308 |  |  | 
| 309 | 0 |     ok = 1; | 
| 310 | 0 | end: | 
| 311 | 0 |     BN_free(two_powN); | 
| 312 | 0 |     return ok; | 
| 313 | 0 | } | 
| 314 |  |  | 
| 315 |  | /* | 
| 316 |  |  * FFC pairwise check from SP800-56A R3. | 
| 317 |  |  *    Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency | 
| 318 |  |  */ | 
| 319 |  | int ossl_dh_check_pairwise(const DH *dh) | 
| 320 | 0 | { | 
| 321 | 0 |     int ret = 0; | 
| 322 | 0 |     BN_CTX *ctx = NULL; | 
| 323 | 0 |     BIGNUM *pub_key = NULL; | 
| 324 |  | 
 | 
| 325 | 0 |     if (dh->params.p == NULL | 
| 326 | 0 |         || dh->params.g == NULL | 
| 327 | 0 |         || dh->priv_key == NULL | 
| 328 | 0 |         || dh->pub_key == NULL) | 
| 329 | 0 |         return 0; | 
| 330 |  |  | 
| 331 | 0 |     ctx = BN_CTX_new_ex(dh->libctx); | 
| 332 | 0 |     if (ctx == NULL) | 
| 333 | 0 |         goto err; | 
| 334 | 0 |     pub_key = BN_new(); | 
| 335 | 0 |     if (pub_key == NULL) | 
| 336 | 0 |         goto err; | 
| 337 |  |  | 
| 338 |  |     /* recalculate the public key = (g ^ priv) mod p */ | 
| 339 | 0 |     if (!ossl_dh_generate_public_key(ctx, dh, dh->priv_key, pub_key)) | 
| 340 | 0 |         goto err; | 
| 341 |  |     /* check it matches the existing pubic_key */ | 
| 342 | 0 |     ret = BN_cmp(pub_key, dh->pub_key) == 0; | 
| 343 | 0 | err: | 
| 344 | 0 |     BN_free(pub_key); | 
| 345 | 0 |     BN_CTX_free(ctx); | 
| 346 | 0 |     return ret; | 
| 347 | 0 | } |