diff options
author | Shane Lontis <shane.lontis@oracle.com> | 2020-03-03 05:02:36 +0100 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2020-03-03 05:02:36 +0100 |
commit | 47c239c6b8d6e5d66a6ceef3a2c543b6ea338759 (patch) | |
tree | 67d58074df00d4d53d4e4a6ab50882bc9be56d44 /crypto | |
parent | .travis.yml: Remove NOUPDATE support (diff) | |
download | openssl-47c239c6b8d6e5d66a6ceef3a2c543b6ea338759.tar.xz openssl-47c239c6b8d6e5d66a6ceef3a2c543b6ea338759.zip |
Add pairwise consistency self tests to asym keygenerators
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10952)
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/build.info | 4 | ||||
-rw-r--r-- | crypto/dh/dh_gen.c | 7 | ||||
-rw-r--r-- | crypto/dsa/dsa_key.c | 67 | ||||
-rw-r--r-- | crypto/ec/ec_key.c | 68 | ||||
-rw-r--r-- | crypto/ec/ecp_s390x_nistp.c | 5 | ||||
-rw-r--r-- | crypto/rsa/rsa_gen.c | 98 | ||||
-rw-r--r-- | crypto/self_test_core.c | 108 |
7 files changed, 333 insertions, 24 deletions
diff --git a/crypto/build.info b/crypto/build.info index b21cf3f45a..a688248acf 100644 --- a/crypto/build.info +++ b/crypto/build.info @@ -61,9 +61,9 @@ ENDIF # The Core $CORE_COMMON=provider_core.c provider_predefined.c \ - core_fetch.c core_algorithm.c core_namemap.c + core_fetch.c core_algorithm.c core_namemap.c self_test_core.c -SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c self_test_core.c +SOURCE[../libcrypto]=$CORE_COMMON provider_conf.c SOURCE[../providers/libfips.a]=$CORE_COMMON # Central utilities diff --git a/crypto/dh/dh_gen.c b/crypto/dh/dh_gen.c index 8e2b773703..f8cda1b7e9 100644 --- a/crypto/dh/dh_gen.c +++ b/crypto/dh/dh_gen.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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 @@ -15,6 +15,11 @@ /* * DH low level APIs are deprecated for public use, but still ok for * internal use. + * + * NOTE: When generating keys for key-agreement schemes - FIPS 140-2 IG 9.9 + * states that no additional pairwise tests are required (apart from the tests + * specified in SP800-56A) when generating keys. Hence DH pairwise tests are + * omitted here. */ #include "internal/deprecated.h" diff --git a/crypto/dsa/dsa_key.c b/crypto/dsa/dsa_key.c index c93ea15b76..2dec35f28f 100644 --- a/crypto/dsa/dsa_key.c +++ b/crypto/dsa/dsa_key.c @@ -1,5 +1,5 @@ /* - * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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 @@ -17,10 +17,12 @@ #include <time.h> #include "internal/cryptlib.h" #include <openssl/bn.h> +#include <openssl/self_test.h> #include "crypto/dsa.h" #include "dsa_local.h" -static int dsa_builtin_keygen(DSA *dsa); +static int dsa_keygen(DSA *dsa, int pairwise_test); +static int dsa_keygen_pairwise_test(DSA *dsa, OSSL_CALLBACK *cb, void *cbarg); int DSA_generate_key(DSA *dsa) { @@ -28,7 +30,7 @@ int DSA_generate_key(DSA *dsa) if (dsa->meth->dsa_keygen != NULL) return dsa->meth->dsa_keygen(dsa); #endif - return dsa_builtin_keygen(dsa); + return dsa_keygen(dsa, 0); } int dsa_generate_public_key(BN_CTX *ctx, const DSA *dsa, const BIGNUM *priv_key, @@ -50,7 +52,7 @@ err: return ret; } -static int dsa_builtin_keygen(DSA *dsa) +static int dsa_keygen(DSA *dsa, int pairwise_test) { int ok = 0; BN_CTX *ctx = NULL; @@ -82,8 +84,26 @@ static int dsa_builtin_keygen(DSA *dsa) dsa->priv_key = priv_key; dsa->pub_key = pub_key; - dsa->dirty_cnt++; + +#ifdef FIPS_MODE + pairwise_test = 1; +#endif /* FIPS_MODE */ + ok = 1; + if (pairwise_test) { + OSSL_CALLBACK *cb = NULL; + void *cbarg = NULL; + + OSSL_SELF_TEST_get_callback(dsa->libctx, &cb, &cbarg); + ok = dsa_keygen_pairwise_test(dsa, cb, cbarg); + if (!ok) { + BN_free(dsa->pub_key); + BN_clear_free(dsa->priv_key); + BN_CTX_free(ctx); + return ok; + } + } + dsa->dirty_cnt++; err: if (pub_key != dsa->pub_key) @@ -91,5 +111,42 @@ static int dsa_builtin_keygen(DSA *dsa) if (priv_key != dsa->priv_key) BN_free(priv_key); BN_CTX_free(ctx); + return ok; } + +/* + * FIPS 140-2 IG 9.9 AS09.33 + * Perform a sign/verify operation. + */ +static int dsa_keygen_pairwise_test(DSA *dsa, OSSL_CALLBACK *cb, void *cbarg) +{ + int ret = 0; + unsigned char dgst[16] = {0}; + unsigned int dgst_len = (unsigned int)sizeof(dgst); + DSA_SIG *sig = NULL; + OSSL_SELF_TEST *st = NULL; + + st = OSSL_SELF_TEST_new(cb, cbarg); + if (st == NULL) + goto err; + + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT, + OSSL_SELF_TEST_DESC_PCT_DSA); + + sig = DSA_do_sign(dgst, (int)dgst_len, dsa); + if (sig == NULL) + goto err; + + OSSL_SELF_TEST_oncorrupt_byte(st, dgst); + + if (DSA_do_verify(dgst, dgst_len, sig, dsa) != 1) + goto err; + + ret = 1; +err: + OSSL_SELF_TEST_onend(st, ret); + OSSL_SELF_TEST_free(st); + DSA_SIG_free(sig); + return ret; +} diff --git a/crypto/ec/ec_key.c b/crypto/ec/ec_key.c index 4c56777dfe..18b544b9d3 100644 --- a/crypto/ec/ec_key.c +++ b/crypto/ec/ec_key.c @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2002-2020 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * * Licensed under the Apache License 2.0 (the "License"). You may not use @@ -20,8 +20,12 @@ #include "internal/refcount.h" #include <openssl/err.h> #include <openssl/engine.h> +#include <openssl/self_test.h> #include "crypto/bn.h" +static int ecdsa_keygen_pairwise_test(EC_KEY *eckey, OSSL_CALLBACK *cb, + void *cbarg); + #ifndef FIPS_MODE EC_KEY *EC_KEY_new(void) { @@ -241,11 +245,14 @@ int ossl_ec_key_gen(EC_KEY *eckey) * See SP800-56AR3 5.6.1.2.2 "Key Pair Generation by Testing Candidates" * * Params: + * libctx A context containing an optional self test callback. * eckey An EC key object that contains domain params. The generated keypair * is stored in this object. + * pairwise_test Set to non zero to perform a pairwise test. If the test + * fails then the keypair is not generated, * Returns 1 if the keypair was generated or 0 otherwise. */ -int ec_key_simple_generate_key(EC_KEY *eckey) +int ec_generate_key(OPENSSL_CTX *libctx, EC_KEY *eckey, int pairwise_test) { int ok = 0; BIGNUM *priv_key = NULL; @@ -305,8 +312,18 @@ int ec_key_simple_generate_key(EC_KEY *eckey) eckey->dirty_cnt++; +#ifdef FIPS_MODE + pairwise_test = 1; +#endif /* FIPS_MODE */ + ok = 1; + if (pairwise_test) { + OSSL_CALLBACK *cb = NULL; + void *cbarg = NULL; + OSSL_SELF_TEST_get_callback(libctx, &cb, &cbarg); + ok = ecdsa_keygen_pairwise_test(eckey, cb, cbarg); + } err: /* Step (9): If there is an error return an invalid keypair. */ if (!ok) { @@ -321,6 +338,11 @@ err: return ok; } +int ec_key_simple_generate_key(EC_KEY *eckey) +{ + return ec_generate_key(NULL, eckey, 0); +} + int ec_key_simple_generate_public_key(EC_KEY *eckey) { int ret; @@ -849,3 +871,45 @@ int EC_KEY_can_sign(const EC_KEY *eckey) return 0; return 1; } + +/* + * FIPS 140-2 IG 9.9 AS09.33 + * Perform a sign/verify operation. + * + * NOTE: When generating keys for key-agreement schemes - FIPS 140-2 IG 9.9 + * states that no additional pairwise tests are required (apart from the tests + * specified in SP800-56A) when generating keys. Hence pairwise ECDH tests are + * omitted here. + */ +static int ecdsa_keygen_pairwise_test(EC_KEY *eckey, OSSL_CALLBACK *cb, + void *cbarg) +{ + int ret = 0; + unsigned char dgst[16] = {0}; + int dgst_len = (int)sizeof(dgst); + ECDSA_SIG *sig = NULL; + OSSL_SELF_TEST *st = NULL; + + st = OSSL_SELF_TEST_new(cb, cbarg); + if (st == NULL) + return 0; + + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT, + OSSL_SELF_TEST_DESC_PCT_ECDSA); + + sig = ECDSA_do_sign(dgst, dgst_len, eckey); + if (sig == NULL) + goto err; + + OSSL_SELF_TEST_oncorrupt_byte(st, dgst); + + if (ECDSA_do_verify(dgst, dgst_len, sig, eckey) != 1) + goto err; + + ret = 1; +err: + OSSL_SELF_TEST_onend(st, ret); + OSSL_SELF_TEST_free(st); + ECDSA_SIG_free(sig); + return ret; +} diff --git a/crypto/ec/ecp_s390x_nistp.c b/crypto/ec/ecp_s390x_nistp.c index a7cb5d3186..92b199d96a 100644 --- a/crypto/ec/ecp_s390x_nistp.c +++ b/crypto/ec/ecp_s390x_nistp.c @@ -169,12 +169,13 @@ static ECDSA_SIG *ecdsa_s390x_nistp_sign_sig(const unsigned char *dgst, if (r == NULL || kinv == NULL) { /* - * Generate random k and copy to param param block. RAND_priv_bytes + * Generate random k and copy to param param block. RAND_priv_bytes_ex * is used instead of BN_priv_rand_range or BN_generate_dsa_nonce * because kdsa instruction constructs an in-range, invertible nonce * internally implementing counter-measures for RNG weakness. */ - if (RAND_priv_bytes(param + S390X_OFF_RN(len), len) != 1) { + if (RAND_priv_bytes_ex(eckey->libctx, param + S390X_OFF_RN(len), + len) != 1) { ECerr(EC_F_ECDSA_S390X_NISTP_SIGN_SIG, EC_R_RANDOM_NUMBER_GENERATION_FAILED); goto ret; diff --git a/crypto/rsa/rsa_gen.c b/crypto/rsa/rsa_gen.c index 5778bdada5..5d82ae6f34 100644 --- a/crypto/rsa/rsa_gen.c +++ b/crypto/rsa/rsa_gen.c @@ -23,10 +23,12 @@ #include <time.h> #include "internal/cryptlib.h" #include <openssl/bn.h> +#include <openssl/self_test.h> #include "rsa_local.h" -static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value, - BN_GENCB *cb); +static int rsa_keygen_pairwise_test(RSA *rsa, OSSL_CALLBACK *cb, void *cbarg); +static int rsa_keygen(OPENSSL_CTX *libctx, RSA *rsa, int bits, int primes, + BIGNUM *e_value, BN_GENCB *cb, int pairwise_test); /* * NB: this wrapper would normally be placed in rsa_lib.c and the static @@ -65,19 +67,21 @@ int RSA_generate_multi_prime_key(RSA *rsa, int bits, int primes, return 0; } #endif /* FIPS_MODE */ - return rsa_builtin_keygen(rsa, bits, primes, e_value, cb); + return rsa_keygen(NULL, rsa, bits, primes, e_value, cb, 0); } -static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value, - BN_GENCB *cb) +static int rsa_keygen(OPENSSL_CTX *libctx, RSA *rsa, int bits, int primes, + BIGNUM *e_value, BN_GENCB *cb, int pairwise_test) { + int ok = -1; #ifdef FIPS_MODE if (primes != 2) return 0; - return rsa_sp800_56b_generate_key(rsa, bits, e_value, cb); + ok = rsa_sp800_56b_generate_key(rsa, bits, e_value, cb); + pairwise_test = 1; /* FIPS MODE needs to always run the pairwise test */ #else BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *tmp, *prime; - int ok = -1, n = 0, bitsr[RSA_MAX_PRIME_NUM], bitse = 0; + int n = 0, bitsr[RSA_MAX_PRIME_NUM], bitse = 0; int i = 0, quo = 0, rmd = 0, adj = 0, retries = 0; RSA_PRIME_INFO *pinfo = NULL; STACK_OF(RSA_PRIME_INFO) *prime_infos = NULL; @@ -87,13 +91,13 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value, if (bits < RSA_MIN_MODULUS_BITS) { ok = 0; /* we set our own err */ - RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_SIZE_TOO_SMALL); + RSAerr(0, RSA_R_KEY_SIZE_TOO_SMALL); goto err; } if (primes < RSA_DEFAULT_PRIME_NUM || primes > rsa_multip_cap(bits)) { ok = 0; /* we set our own err */ - RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, RSA_R_KEY_PRIME_NUM_INVALID); + RSAerr(0, RSA_R_KEY_PRIME_NUM_INVALID); goto err; } @@ -398,11 +402,83 @@ static int rsa_builtin_keygen(RSA *rsa, int bits, int primes, BIGNUM *e_value, ok = 1; err: if (ok == -1) { - RSAerr(RSA_F_RSA_BUILTIN_KEYGEN, ERR_LIB_BN); + RSAerr(0, ERR_LIB_BN); ok = 0; } BN_CTX_end(ctx); BN_CTX_free(ctx); - return ok; #endif /* FIPS_MODE */ + + if (pairwise_test && ok > 0) { + OSSL_CALLBACK *stcb = NULL; + void *stcbarg = NULL; + + OSSL_SELF_TEST_get_callback(libctx, &stcb, &stcbarg); + ok = rsa_keygen_pairwise_test(rsa, stcb, stcbarg); + if (!ok) { + /* Clear intermediate results */ + BN_clear_free(rsa->d); + BN_clear_free(rsa->p); + BN_clear_free(rsa->q); + BN_clear_free(rsa->dmp1); + BN_clear_free(rsa->dmq1); + BN_clear_free(rsa->iqmp); + } + } + return ok; +} + +/* + * For RSA key generation it is not known whether the key pair will be used + * for key transport or signatures. FIPS 140-2 IG 9.9 states that in this case + * either a signature verification OR an encryption operation may be used to + * perform the pairwise consistency check. The simpler encrypt/decrypt operation + * has been chosen for this case. + */ +static int rsa_keygen_pairwise_test(RSA *rsa, OSSL_CALLBACK *cb, void *cbarg) +{ + int ret = 0; + unsigned int ciphertxt_len; + unsigned char *ciphertxt = NULL; + const unsigned char plaintxt[16] = {0}; + unsigned char decoded[256]; + unsigned int decoded_len; + unsigned int plaintxt_len = (unsigned int)sizeof(plaintxt_len); + int padding = RSA_PKCS1_PADDING; + OSSL_SELF_TEST *st = NULL; + + st = OSSL_SELF_TEST_new(cb, cbarg); + if (st == NULL) + goto err; + OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_PCT, + OSSL_SELF_TEST_DESC_PCT_RSA_PKCS1); + + ciphertxt_len = RSA_size(rsa); + ciphertxt = OPENSSL_zalloc(ciphertxt_len); + if (ciphertxt == NULL) + goto err; + + ciphertxt_len = RSA_public_encrypt(plaintxt_len, plaintxt, ciphertxt, rsa, + padding); + if (ciphertxt_len <= 0) + goto err; + if (ciphertxt_len == plaintxt_len + && memcmp(decoded, plaintxt, plaintxt_len) == 0) + goto err; + + OSSL_SELF_TEST_oncorrupt_byte(st, ciphertxt); + + decoded_len = RSA_private_decrypt(ciphertxt_len, ciphertxt, decoded, rsa, + padding); + if (decoded_len != plaintxt_len + || memcmp(decoded, plaintxt, decoded_len) != 0) + goto err; + + ret = 1; +err: + OSSL_SELF_TEST_onend(st, ret); + OSSL_SELF_TEST_free(st); + OPENSSL_free(ciphertxt); + + return ret; } diff --git a/crypto/self_test_core.c b/crypto/self_test_core.c index 77864a230b..bee3161ed5 100644 --- a/crypto/self_test_core.c +++ b/crypto/self_test_core.c @@ -1,5 +1,5 @@ /* - * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2019-2020 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 @@ -8,6 +8,8 @@ */ #include <openssl/self_test.h> +#include <openssl/core_names.h> +#include <openssl/params.h> #include "internal/cryptlib.h" typedef struct self_test_cb_st @@ -16,6 +18,19 @@ typedef struct self_test_cb_st void *cbarg; } SELF_TEST_CB; +struct ossl_self_test_st +{ + /* local state variables */ + const char *phase; + const char *type; + const char *desc; + OSSL_CALLBACK *cb; + + /* callback related variables used to pass the state back to the user */ + OSSL_PARAM params[4]; + void *cb_arg; +}; + static void *self_test_set_callback_new(OPENSSL_CTX *ctx) { SELF_TEST_CB *stcb; @@ -40,6 +55,7 @@ static SELF_TEST_CB *get_self_test_callback(OPENSSL_CTX *libctx) &self_test_set_callback_method); } +#ifndef FIPS_MODE void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb, void *cbarg) { @@ -50,6 +66,8 @@ void OSSL_SELF_TEST_set_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK *cb, stcb->cbarg = cbarg; } } +#endif /* FIPS_MODE */ + void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb, void **cbarg) { @@ -60,3 +78,91 @@ void OSSL_SELF_TEST_get_callback(OPENSSL_CTX *libctx, OSSL_CALLBACK **cb, if (cbarg != NULL) *cbarg = (stcb != NULL ? stcb->cbarg : NULL); } + +static void self_test_setparams(OSSL_SELF_TEST *st) +{ + size_t n = 0; + + if (st->cb != NULL) { + st->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_PHASE, + (char *)st->phase, 0); + st->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_TYPE, + (char *)st->type, 0); + st->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_DESC, + (char *)st->desc, 0); + } + st->params[n++] = OSSL_PARAM_construct_end(); +} + +OSSL_SELF_TEST *OSSL_SELF_TEST_new(OSSL_CALLBACK *cb, void *cbarg) +{ + OSSL_SELF_TEST *ret = OPENSSL_zalloc(sizeof(*ret)); + + if (ret == NULL) + return NULL; + + ret->cb = cb; + ret->cb_arg = cbarg; + ret->phase = ""; + ret->type = ""; + ret->desc = ""; + self_test_setparams(ret); + return ret; +} + +void OSSL_SELF_TEST_free(OSSL_SELF_TEST *st) +{ + OPENSSL_free(st); +} + +/* Can be used during application testing to log that a test has started. */ +void OSSL_SELF_TEST_onbegin(OSSL_SELF_TEST *st, const char *type, + const char *desc) +{ + if (st != NULL && st->cb != NULL) { + st->phase = OSSL_SELF_TEST_PHASE_START; + st->type = type; + st->desc = desc; + self_test_setparams(st); + (void)st->cb(st->params, st->cb_arg); + } +} + +/* + * Can be used during application testing to log that a test has either + * passed or failed. + */ +void OSSL_SELF_TEST_onend(OSSL_SELF_TEST *st, int ret) +{ + if (st != NULL && st->cb != NULL) { + st->phase = + (ret == 1 ? OSSL_SELF_TEST_PHASE_PASS : OSSL_SELF_TEST_PHASE_FAIL); + self_test_setparams(st); + (void)st->cb(st->params, st->cb_arg); + + st->phase = OSSL_SELF_TEST_PHASE_NONE; + st->type = OSSL_SELF_TEST_TYPE_NONE; + st->desc = OSSL_SELF_TEST_DESC_NONE; + } +} + +/* + * Used for failure testing. + * + * Call the applications SELF_TEST_cb() if it exists. + * If the application callback decides to return 0 then the first byte of 'bytes' + * is modified (corrupted). This is used to modify output signatures or + * ciphertext before they are verified or decrypted. + */ +void OSSL_SELF_TEST_oncorrupt_byte(OSSL_SELF_TEST *st, unsigned char *bytes) +{ + if (st != NULL && st->cb != NULL) { + st->phase = OSSL_SELF_TEST_PHASE_CORRUPT; + self_test_setparams(st); + if (!st->cb(st->params, st->cb_arg)) + bytes[0] ^= 1; + } +} |