X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=crypto%2Fdh%2Fdh_check.c;h=85ef17b36fa4531417df1c8960603fe4e3e712c1;hb=ada66e78ef535fe80e422bbbadffe8e7863d457c;hp=cd7f70b67278aae413cbce44d31915f3a70be1ec;hpb=ce1415ed2ce15305356cd028bcf7b9bc688d6d5c;p=thirdparty%2Fopenssl.git diff --git a/crypto/dh/dh_check.c b/crypto/dh/dh_check.c index cd7f70b672..85ef17b36f 100644 --- a/crypto/dh/dh_check.c +++ b/crypto/dh/dh_check.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2017 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,10 +7,17 @@ * https://www.openssl.org/source/license.html */ +/* + * DH low level APIs are deprecated for public use, but still ok for + * internal use. + */ +#include "internal/deprecated.h" + #include #include "internal/cryptlib.h" #include -#include "dh_locl.h" +#include "dh_local.h" +#include "crypto/dh.h" /*- * Check that p and g are suitable enough @@ -22,16 +29,43 @@ int DH_check_params_ex(const DH *dh) { int errflags = 0; - (void)DH_check_params(dh, &errflags); + if (!DH_check_params(dh, &errflags)) + return 0; if ((errflags & DH_CHECK_P_NOT_PRIME) != 0) DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_CHECK_P_NOT_PRIME); if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_NOT_SUITABLE_GENERATOR); + if ((errflags & DH_MODULUS_TOO_SMALL) != 0) + DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_MODULUS_TOO_SMALL); + if ((errflags & DH_MODULUS_TOO_LARGE) != 0) + DHerr(DH_F_DH_CHECK_PARAMS_EX, DH_R_MODULUS_TOO_LARGE); return errflags == 0; } +#ifdef FIPS_MODE +int DH_check_params(const DH *dh, int *ret) +{ + int nid; + + *ret = 0; + /* + * SP800-56A R3 Section 5.5.2 Assurances of Domain Parameter Validity + * (1a) The domain parameters correspond to any approved safe prime group. + */ + nid = DH_get_nid((DH *)dh); + if (nid != NID_undef) + return 1; + /* + * OR + * (2b) FFC domain params conform to FIPS-186-4 explicit domain param + * validity tests. + */ + return ffc_params_FIPS186_4_validate(&dh->params, FFC_PARAM_TYPE_DH, NULL, + FFC_PARAMS_VALIDATE_ALL, ret, NULL); +} +#else int DH_check_params(const DH *dh, int *ret) { int ok = 0; @@ -47,14 +81,20 @@ int DH_check_params(const DH *dh, int *ret) if (tmp == NULL) goto err; - if (!BN_is_odd(dh->p)) + if (!BN_is_odd(dh->params.p)) *ret |= DH_CHECK_P_NOT_PRIME; - if (BN_is_negative(dh->g) || BN_is_zero(dh->g) || BN_is_one(dh->g)) + if (BN_is_negative(dh->params.g) + || BN_is_zero(dh->params.g) + || BN_is_one(dh->params.g)) *ret |= DH_NOT_SUITABLE_GENERATOR; - if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1)) + if (BN_copy(tmp, dh->params.p) == NULL || !BN_sub_word(tmp, 1)) goto err; - if (BN_cmp(dh->g, tmp) >= 0) + if (BN_cmp(dh->params.g, tmp) >= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; + if (BN_num_bits(dh->params.p) < DH_MIN_MODULUS_BITS) + *ret |= DH_MODULUS_TOO_SMALL; + if (BN_num_bits(dh->params.p) > OPENSSL_DH_MAX_MODULUS_BITS) + *ret |= DH_MODULUS_TOO_LARGE; ok = 1; err: @@ -62,21 +102,18 @@ int DH_check_params(const DH *dh, int *ret) BN_CTX_free(ctx); return ok; } +#endif /* FIPS_MODE */ /*- * Check that p is a safe prime and - * if g is 2, 3 or 5, check that it is a suitable generator - * where - * for 2, p mod 24 == 11 - * for 3, p mod 12 == 5 - * for 5, p mod 10 == 3 or 7 - * should hold. + * g is a suitable generator. */ int DH_check_ex(const DH *dh) { int errflags = 0; - (void)DH_check(dh, &errflags); + if (!DH_check(dh, &errflags)) + return 0; if ((errflags & DH_NOT_SUITABLE_GENERATOR) != 0) DHerr(DH_F_DH_CHECK_EX, DH_R_NOT_SUITABLE_GENERATOR); @@ -92,18 +129,32 @@ int DH_check_ex(const DH *dh) DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_PRIME); if ((errflags & DH_CHECK_P_NOT_SAFE_PRIME) != 0) DHerr(DH_F_DH_CHECK_EX, DH_R_CHECK_P_NOT_SAFE_PRIME); + if ((errflags & DH_MODULUS_TOO_SMALL) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_MODULUS_TOO_SMALL); + if ((errflags & DH_MODULUS_TOO_LARGE) != 0) + DHerr(DH_F_DH_CHECK_EX, DH_R_MODULUS_TOO_LARGE); return errflags == 0; } +/* Note: according to documentation - this only checks the params */ int DH_check(const DH *dh, int *ret) { +#ifdef FIPS_MODE + return DH_check_params(dh, ret); +#else int ok = 0, r; BN_CTX *ctx = NULL; - BN_ULONG l; BIGNUM *t1 = NULL, *t2 = NULL; + int nid = DH_get_nid((DH *)dh); *ret = 0; + if (nid != NID_undef) + return 1; + + if (!DH_check_params(dh, ret)) + return 0; + ctx = BN_CTX_new(); if (ctx == NULL) goto err; @@ -113,55 +164,42 @@ int DH_check(const DH *dh, int *ret) if (t2 == NULL) goto err; - if (dh->q) { - if (BN_cmp(dh->g, BN_value_one()) <= 0) + if (dh->params.q != NULL) { + if (BN_cmp(dh->params.g, BN_value_one()) <= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; - else if (BN_cmp(dh->g, dh->p) >= 0) + else if (BN_cmp(dh->params.g, dh->params.p) >= 0) *ret |= DH_NOT_SUITABLE_GENERATOR; else { /* Check g^q == 1 mod p */ - if (!BN_mod_exp(t1, dh->g, dh->q, dh->p, ctx)) + if (!BN_mod_exp(t1, dh->params.g, dh->params.q, dh->params.p, ctx)) goto err; if (!BN_is_one(t1)) *ret |= DH_NOT_SUITABLE_GENERATOR; } - r = BN_is_prime_ex(dh->q, BN_prime_checks, ctx, NULL); + r = BN_check_prime(dh->params.q, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_Q_NOT_PRIME; /* Check p == 1 mod q i.e. q divides p - 1 */ - if (!BN_div(t1, t2, dh->p, dh->q, ctx)) + if (!BN_div(t1, t2, dh->params.p, dh->params.q, ctx)) goto err; if (!BN_is_one(t2)) *ret |= DH_CHECK_INVALID_Q_VALUE; - if (dh->j && BN_cmp(dh->j, t1)) + if (dh->params.j != NULL + && BN_cmp(dh->params.j, t1)) *ret |= DH_CHECK_INVALID_J_VALUE; + } - } else if (BN_is_word(dh->g, DH_GENERATOR_2)) { - l = BN_mod_word(dh->p, 24); - if (l == (BN_ULONG)-1) - goto err; - if (l != 11) - *ret |= DH_NOT_SUITABLE_GENERATOR; - } else if (BN_is_word(dh->g, DH_GENERATOR_5)) { - l = BN_mod_word(dh->p, 10); - if (l == (BN_ULONG)-1) - goto err; - if ((l != 3) && (l != 7)) - *ret |= DH_NOT_SUITABLE_GENERATOR; - } else - *ret |= DH_UNABLE_TO_CHECK_GENERATOR; - - r = BN_is_prime_ex(dh->p, BN_prime_checks, ctx, NULL); + r = BN_check_prime(dh->params.p, ctx, NULL); if (r < 0) goto err; if (!r) *ret |= DH_CHECK_P_NOT_PRIME; - else if (!dh->q) { - if (!BN_rshift1(t1, dh->p)) + else if (dh->params.q == NULL) { + if (!BN_rshift1(t1, dh->params.p)) goto err; - r = BN_is_prime_ex(t1, BN_prime_checks, ctx, NULL); + r = BN_check_prime(t1, ctx, NULL); if (r < 0) goto err; if (!r) @@ -172,13 +210,15 @@ int DH_check(const DH *dh, int *ret) BN_CTX_end(ctx); BN_CTX_free(ctx); return ok; +#endif /* FIPS_MODE */ } int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) { int errflags = 0; - (void)DH_check(dh, &errflags); + if (!DH_check_pub_key(dh, pub_key, &errflags)) + return 0; if ((errflags & DH_CHECK_PUBKEY_TOO_SMALL) != 0) DHerr(DH_F_DH_CHECK_PUB_KEY_EX, DH_R_CHECK_PUBKEY_TOO_SMALL); @@ -190,38 +230,83 @@ int DH_check_pub_key_ex(const DH *dh, const BIGNUM *pub_key) return errflags == 0; } +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Full public key validation. + */ int DH_check_pub_key(const DH *dh, const BIGNUM *pub_key, int *ret) +{ + return ffc_validate_public_key(&dh->params, pub_key, ret); +} + +/* + * See SP800-56Ar3 Section 5.6.2.3.1 : FFC Partial public key validation. + * To only be used with ephemeral FFC public keys generated using the approved + * safe-prime groups. + */ +int dh_check_pub_key_partial(const DH *dh, const BIGNUM *pub_key, int *ret) +{ + return ffc_validate_public_key_partial(&dh->params, pub_key, ret); +} + +int dh_check_priv_key(const DH *dh, const BIGNUM *priv_key, int *ret) { int ok = 0; - BIGNUM *tmp = NULL; - BN_CTX *ctx = NULL; + BIGNUM *two_powN = NULL, *upper; *ret = 0; - ctx = BN_CTX_new(); - if (ctx == NULL) - goto err; - BN_CTX_start(ctx); - tmp = BN_CTX_get(ctx); - if (tmp == NULL || !BN_set_word(tmp, 1)) + two_powN = BN_new(); + if (two_powN == NULL) + return 0; + if (dh->params.q == NULL) goto err; - if (BN_cmp(pub_key, tmp) <= 0) - *ret |= DH_CHECK_PUBKEY_TOO_SMALL; - if (BN_copy(tmp, dh->p) == NULL || !BN_sub_word(tmp, 1)) - goto err; - if (BN_cmp(pub_key, tmp) >= 0) - *ret |= DH_CHECK_PUBKEY_TOO_LARGE; + upper = dh->params.q; - if (dh->q != NULL) { - /* Check pub_key^q == 1 mod p */ - if (!BN_mod_exp(tmp, pub_key, dh->q, dh->p, ctx)) + /* Is it from an approved Safe prime group ?*/ + if (DH_get_nid((DH *)dh) != NID_undef) { + if (!BN_lshift(two_powN, BN_value_one(), dh->length)) goto err; - if (!BN_is_one(tmp)) - *ret |= DH_CHECK_PUBKEY_INVALID; + if (BN_cmp(two_powN, dh->params.q) < 0) + upper = two_powN; } + if (!ffc_validate_private_key(upper, priv_key, ret)) + goto err; ok = 1; - err: - BN_CTX_end(ctx); - BN_CTX_free(ctx); +err: + BN_free(two_powN); return ok; } + +/* + * FFC pairwise check from SP800-56A R3. + * Section 5.6.2.1.4 Owner Assurance of Pair-wise Consistency + */ +int dh_check_pairwise(DH *dh) +{ + int ret = 0; + BN_CTX *ctx = NULL; + BIGNUM *pub_key = NULL; + + if (dh->params.p == NULL + || dh->params.g == NULL + || dh->priv_key == NULL + || dh->pub_key == NULL) + return 0; + + ctx = BN_CTX_new_ex(dh->libctx); + if (ctx == NULL) + goto err; + pub_key = BN_new(); + if (pub_key == NULL) + goto err; + + /* recalculate the public key = (g ^ priv) mod p */ + if (!dh_generate_public_key(ctx, dh, dh->priv_key, pub_key)) + goto err; + /* check it matches the existing pubic_key */ + ret = BN_cmp(pub_key, dh->pub_key) == 0; +err: + BN_free(pub_key); + BN_CTX_free(ctx); + return ret; +}