diff options
author | Shane Lontis <shane.lontis@oracle.com> | 2020-01-15 10:48:01 +1000 |
---|---|---|
committer | Shane Lontis <shane.lontis@oracle.com> | 2020-01-15 10:48:01 +1000 |
commit | 36fc5fc6bd5ca53fb30aabc38e3fefbab0005b2c (patch) | |
tree | 16e416a148ab7e40d416977ab971e315f7b034f1 /providers/fips | |
parent | 76123661a1db136b9ef368dc296a628818e7a4cc (diff) |
Add FIPS Self test kats for digests
Added an API to optionally set a self test callback.
The callback has the following 2 purposes
(1) Output information about the KAT tests.
(2) Allow the ability to corrupt one of the KAT's
The fipsinstall program uses the API.
Some KATS are not included in this PR since the required functionality did not yet exist in the provider.
Reviewed-by: Matt Caswell <matt@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/10374)
Diffstat (limited to 'providers/fips')
-rw-r--r-- | providers/fips/build.info | 3 | ||||
-rw-r--r-- | providers/fips/fipsprov.c | 20 | ||||
-rw-r--r-- | providers/fips/self_test.c (renamed from providers/fips/selftest.c) | 21 | ||||
-rw-r--r-- | providers/fips/self_test.h (renamed from providers/fips/selftest.h) | 24 | ||||
-rw-r--r-- | providers/fips/self_test_data.inc | 191 | ||||
-rw-r--r-- | providers/fips/self_test_event.c | 93 | ||||
-rw-r--r-- | providers/fips/self_test_kats.c | 246 |
7 files changed, 590 insertions, 8 deletions
diff --git a/providers/fips/build.info b/providers/fips/build.info index 12ca452073..d12849ebb0 100644 --- a/providers/fips/build.info +++ b/providers/fips/build.info @@ -1,3 +1,2 @@ - -SOURCE[../fips]=fipsprov.c selftest.c +SOURCE[../fips]=fipsprov.c self_test.c self_test_kats.c self_test_event.c INCLUDE[../fips]=../implementations/include ../common/include ../.. diff --git a/providers/fips/fipsprov.c b/providers/fips/fipsprov.c index 788963911b..cf4181dd2a 100644 --- a/providers/fips/fipsprov.c +++ b/providers/fips/fipsprov.c @@ -31,7 +31,7 @@ #include "prov/provider_ctx.h" #include "prov/providercommon.h" #include "prov/provider_util.h" -#include "selftest.h" +#include "self_test.h" #define ALGC(NAMES, FUNC, CHECK) { { NAMES, "fips=yes", FUNC }, CHECK } #define ALG(NAMES, FUNC) ALGC(NAMES, FUNC, NULL) @@ -649,9 +649,14 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider, { FIPS_GLOBAL *fgbl; OPENSSL_CTX *ctx; + OSSL_self_test_cb_fn *stcbfn = NULL; + OSSL_core_get_library_context_fn *c_get_libctx = NULL; for (; in->function_id != 0; in++) { switch (in->function_id) { + case OSSL_FUNC_CORE_GET_LIBRARY_CONTEXT: + c_get_libctx = OSSL_get_core_get_library_context(in); + break; case OSSL_FUNC_CORE_GETTABLE_PARAMS: c_gettable_params = OSSL_get_core_gettable_params(in); break; @@ -715,12 +720,25 @@ int OSSL_provider_init(const OSSL_PROVIDER *provider, case OSSL_FUNC_BIO_FREE: selftest_params.bio_free_cb = OSSL_get_BIO_free(in); break; + case OSSL_FUNC_SELF_TEST_CB: { + stcbfn = OSSL_get_self_test_cb(in); + break; + } default: /* Just ignore anything we don't understand */ break; } } + if (stcbfn != NULL && c_get_libctx != NULL) { + stcbfn(c_get_libctx(provider), &selftest_params.event_cb, + &selftest_params.event_cb_arg); + } + else { + selftest_params.event_cb = NULL; + selftest_params.event_cb_arg = NULL; + } + if (!c_get_params(provider, core_params)) return 0; diff --git a/providers/fips/selftest.c b/providers/fips/self_test.c index 91e4bb07f5..e486dd0db0 100644 --- a/providers/fips/selftest.c +++ b/providers/fips/self_test.c @@ -20,7 +20,7 @@ */ #define ALLOW_RUN_ONCE_IN_FIPS #include <internal/thread_once.h> -#include "selftest.h" +#include "self_test.h" #define FIPS_STATE_INIT 0 #define FIPS_STATE_SELFTEST 1 @@ -132,7 +132,8 @@ DEP_FINI_ATTRIBUTE void cleanup(void) */ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, unsigned char *expected, size_t expected_len, - OPENSSL_CTX *libctx) + OPENSSL_CTX *libctx, OSSL_ST_EVENT *ev, + const char *event_type) { int ret = 0, status; unsigned char out[MAX_MD_SIZE]; @@ -142,6 +143,8 @@ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, EVP_MAC_CTX *ctx = NULL; OSSL_PARAM params[3], *p = params; + SELF_TEST_EVENT_onbegin(ev, event_type, OSSL_SELF_TEST_DESC_INTEGRITY_HMAC); + mac = EVP_MAC_fetch(libctx, MAC_NAME, NULL); ctx = EVP_MAC_CTX_new(mac); if (mac == NULL || ctx == NULL) @@ -167,11 +170,13 @@ static int verify_integrity(BIO *bio, OSSL_BIO_read_ex_fn read_ex_cb, if (!EVP_MAC_final(ctx, out, &out_len, sizeof(out))) goto err; + SELF_TEST_EVENT_oncorrupt_byte(ev, out); if (expected_len != out_len || memcmp(expected, out, out_len) != 0) goto err; ret = 1; err: + SELF_TEST_EVENT_onend(ev, ret); EVP_MAC_CTX_free(ctx); EVP_MAC_free(mac); return ret; @@ -187,6 +192,7 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) unsigned char *module_checksum = NULL; unsigned char *indicator_checksum = NULL; int loclstate; + OSSL_ST_EVENT ev; if (!RUN_ONCE(&fips_self_test_init, do_fips_self_test_init)) return 0; @@ -217,6 +223,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) || st->module_checksum_data == NULL) goto end; + SELF_TEST_EVENT_init(&ev, st->event_cb, st->event_cb_arg); + module_checksum = OPENSSL_hexstr2buf(st->module_checksum_data, &checksum_len); if (module_checksum == NULL) @@ -226,7 +234,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) /* Always check the integrity of the fips module */ if (bio_module == NULL || !verify_integrity(bio_module, st->bio_read_ex_cb, - module_checksum, checksum_len, st->libctx)) + module_checksum, checksum_len, st->libctx, + &ev, OSSL_SELF_TEST_TYPE_MODULE_INTEGRITY)) goto end; /* This will be NULL during installation - so the self test KATS will run */ @@ -248,7 +257,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) if (bio_indicator == NULL || !verify_integrity(bio_indicator, st->bio_read_ex_cb, indicator_checksum, checksum_len, - st->libctx)) + st->libctx, &ev, + OSSL_SELF_TEST_TYPE_INSTALL_INTEGRITY)) goto end; else kats_already_passed = 1; @@ -256,7 +266,8 @@ int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test) /* Only runs the KAT's during installation OR on_demand() */ if (on_demand_test || kats_already_passed == 0) { - /*TODO (3.0) Add self test KATS */ + if (!SELF_TEST_kats(&ev, st->libctx)) + goto end; } ok = 1; end: diff --git a/providers/fips/selftest.h b/providers/fips/self_test.h index a56e42c7ab..5d995adac3 100644 --- a/providers/fips/selftest.h +++ b/providers/fips/self_test.h @@ -9,6 +9,7 @@ #include <openssl/core_numbers.h> #include <openssl/types.h> +#include <openssl/self_test.h> typedef struct self_test_post_params_st { /* FIPS module integrity check parameters */ @@ -25,8 +26,31 @@ typedef struct self_test_post_params_st { OSSL_BIO_new_membuf_fn *bio_new_buffer_cb; OSSL_BIO_read_ex_fn *bio_read_ex_cb; OSSL_BIO_free_fn *bio_free_cb; + OSSL_CALLBACK *event_cb; + void *event_cb_arg; OPENSSL_CTX *libctx; } SELF_TEST_POST_PARAMS; +typedef struct st_event_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; + +} OSSL_ST_EVENT; + int SELF_TEST_post(SELF_TEST_POST_PARAMS *st, int on_demand_test); +int SELF_TEST_kats(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx); + +void SELF_TEST_EVENT_init(OSSL_ST_EVENT *ev, OSSL_CALLBACK *cb, void *cbarg); +void SELF_TEST_EVENT_onbegin(OSSL_ST_EVENT *ev, const char *type, + const char *desc); +void SELF_TEST_EVENT_onend(OSSL_ST_EVENT *ev, int ret); +void SELF_TEST_EVENT_oncorrupt_byte(OSSL_ST_EVENT *ev, unsigned char *bytes); diff --git a/providers/fips/self_test_data.inc b/providers/fips/self_test_data.inc new file mode 100644 index 0000000000..28616a0079 --- /dev/null +++ b/providers/fips/self_test_data.inc @@ -0,0 +1,191 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +typedef struct st_kat_st { + const char *desc; + const char *algorithm; + const unsigned char *pt; + size_t pt_len; + const unsigned char *expected; + size_t expected_len; +} ST_KAT; + +typedef ST_KAT ST_KAT_DIGEST; +typedef struct st_kat_cipher_st { + ST_KAT base; + const unsigned char *key; + size_t key_len; + const unsigned char *iv; + size_t iv_len; + const unsigned char *aad; + size_t aad_len; + const unsigned char *tag; + size_t tag_len; +} ST_KAT_CIPHER; + +typedef struct st_kat_nvp_st { + const char *name; + const char *value; +} ST_KAT_NVP; + +typedef struct st_kat_kdf_st { + const char *desc; + const char *algorithm; + const ST_KAT_NVP *ctrls; + const unsigned char *expected; + size_t expected_len; +} ST_KAT_KDF; + +/* Macros to build Self test data */ +#define ITM(x) x, sizeof(x) +#define ITM_STR(x) x, sizeof(x) - 1 + +/*- DIGEST TEST DATA */ +static const unsigned char sha1_pt[] = "abc"; +static const unsigned char sha1_digest[] = { + 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, 0x25, 0x71, + 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D +}; + +static const unsigned char sha512_pt[] = "abc"; +static const unsigned char sha512_digest[] = { + 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, 0xCC, 0x41, 0x73, 0x49, + 0xAE, 0x20, 0x41, 0x31, 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, 0x21, 0x92, 0x99, 0x2A, + 0x27, 0x4F, 0xC1, 0xA8, 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, 0x2A, 0x9A, 0xC9, 0x4F, + 0xA5, 0x4C, 0xA4, 0x9F +}; +static const unsigned char sha3_256_pt[] = { 0xe7, 0x37, 0x21, 0x05 }; +static const unsigned char sha3_256_digest[] = { + 0x3a, 0x42, 0xb6, 0x8a, 0xb0, 0x79, 0xf2, 0x8c, 0x4c, 0xa3, 0xc7, 0x52, + 0x29, 0x6f, 0x27, 0x90, 0x06, 0xc4, 0xfe, 0x78, 0xb1, 0xeb, 0x79, 0xd9, + 0x89, 0x77, 0x7f, 0x05, 0x1e, 0x40, 0x46, 0xae +}; + +static const ST_KAT_DIGEST st_kat_digest_tests[] = +{ + { + OSSL_SELF_TEST_DESC_MD_SHA1, + "SHA1", + ITM_STR(sha1_pt), + ITM(sha1_digest), + }, + { + OSSL_SELF_TEST_DESC_MD_SHA2, + "SHA512", + ITM_STR(sha512_pt), + ITM(sha512_digest), + }, + { + OSSL_SELF_TEST_DESC_MD_SHA3, + "SHA3-256", + ITM(sha3_256_pt), + ITM(sha3_256_digest), + }, +}; + + +/*- CIPHER TEST DATA */ + +/* DES3 test data */ +static const unsigned char des_ede3_cbc_pt[] = { + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, 0xE9, 0x3D, 0x7E, 0x11, + 0x73, 0x93, 0x17, 0x2A, 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 +}; + +static const unsigned char des_ede3_cbc_key[] = { + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; +static const unsigned char des_ede3_cbc_iv[] = { + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17 +}; +static const unsigned char des_ede3_cbc_ct[] = { + 0x20, 0x79, 0xC3, 0xD5, 0x3A, 0xA7, 0x63, 0xE1, 0x93, 0xB7, 0x9E, 0x25, + 0x69, 0xAB, 0x52, 0x62, 0x51, 0x65, 0x70, 0x48, 0x1F, 0x25, 0xB5, 0x0F, + 0x73, 0xC0, 0xBD, 0xA8, 0x5C, 0x8E, 0x0D, 0xA7 +}; + +static const unsigned char aes_256_gcm_key[] = { + 0x92,0xe1,0x1d,0xcd,0xaa,0x86,0x6f,0x5c,0xe7,0x90,0xfd,0x24, + 0x50,0x1f,0x92,0x50,0x9a,0xac,0xf4,0xcb,0x8b,0x13,0x39,0xd5, + 0x0c,0x9c,0x12,0x40,0x93,0x5d,0xd0,0x8b +}; +static const unsigned char aes_256_gcm_iv[] = { + 0xac,0x93,0xa1,0xa6,0x14,0x52,0x99,0xbd,0xe9,0x02,0xf2,0x1a +}; +static const unsigned char aes_256_gcm_pt[] = { + 0x2d,0x71,0xbc,0xfa,0x91,0x4e,0x4a,0xc0,0x45,0xb2,0xaa,0x60, + 0x95,0x5f,0xad,0x24 +}; +static const unsigned char aes_256_gcm_aad[] = { + 0x1e,0x08,0x89,0x01,0x6f,0x67,0x60,0x1c,0x8e,0xbe,0xa4,0x94, + 0x3b,0xc2,0x3a,0xd6 +}; +static const unsigned char aes_256_gcm_ct[] = { + 0x89,0x95,0xae,0x2e,0x6d,0xf3,0xdb,0xf9,0x6f,0xac,0x7b,0x71, + 0x37,0xba,0xe6,0x7f +}; +static const unsigned char aes_256_gcm_tag[] = { + 0xec,0xa5,0xaa,0x77,0xd5,0x1d,0x4a,0x0a,0x14,0xd9,0xc5,0x1e, + 0x1d,0xa4,0x74,0xab +}; + +static const ST_KAT_CIPHER st_kat_cipher_tests[] = { + { + { + OSSL_SELF_TEST_DESC_CIPHER_TDES, + "DES-EDE3-CBC", + ITM(des_ede3_cbc_pt), + ITM(des_ede3_cbc_ct) + }, + ITM(des_ede3_cbc_key), + ITM(des_ede3_cbc_iv), + }, + { + { + OSSL_SELF_TEST_DESC_CIPHER_AES_GCM, + "AES-256-GCM", + ITM(aes_256_gcm_pt), + ITM(aes_256_gcm_ct), + }, + ITM(aes_256_gcm_key), + ITM(aes_256_gcm_iv), + ITM(aes_256_gcm_aad), + ITM(aes_256_gcm_tag) + } +}; + +/*- KDF TEST DATA */ + +static const ST_KAT_NVP hkdf_ctrl[] = +{ + { "digest", "SHA256" }, + { "key", "secret" }, + { "salt", "salt" }, + { "info", "label" }, + { NULL, NULL } +}; +static const unsigned char hkdf_expected[] = { + 0x2a, 0xc4, 0x36, 0x9f, 0x52, 0x59, 0x96, 0xf8, 0xde, 0x13 +}; + +static const ST_KAT_KDF st_kat_kdf_tests[] = +{ + { + OSSL_SELF_TEST_DESC_KDF_HKDF, + "HKDF", + hkdf_ctrl, + ITM(hkdf_expected) + } +}; + diff --git a/providers/fips/self_test_event.c b/providers/fips/self_test_event.c new file mode 100644 index 0000000000..887b9dd17d --- /dev/null +++ b/providers/fips/self_test_event.c @@ -0,0 +1,93 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/core_names.h> +#include <openssl/params.h> +#include "self_test.h" + +static void self_test_event_setparams(OSSL_ST_EVENT *ev) +{ + size_t n = 0; + + if (ev->cb != NULL) { + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_PHASE, + (char *)ev->phase, 0); + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_TYPE, + (char *)ev->type, 0); + ev->params[n++] = + OSSL_PARAM_construct_utf8_string(OSSL_PROV_PARAM_SELF_TEST_DESC, + (char *)ev->desc, 0); + } + ev->params[n++] = OSSL_PARAM_construct_end(); +} + +void SELF_TEST_EVENT_init(OSSL_ST_EVENT *ev, OSSL_CALLBACK *cb, void *cbarg) +{ + if (ev == NULL) + return; + + ev->cb = cb; + ev->cb_arg = cbarg; + ev->phase = ""; + ev->type = ""; + ev->desc = ""; + self_test_event_setparams(ev); +} + +/* Can be used during application testing to log that a test has started. */ +void SELF_TEST_EVENT_onbegin(OSSL_ST_EVENT *ev, const char *type, + const char *desc) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = OSSL_SELF_TEST_PHASE_START; + ev->type = type; + ev->desc = desc; + self_test_event_setparams(ev); + (void)ev->cb(ev->params, ev->cb_arg); + } +} + +/* + * Can be used during application testing to log that a test has either + * passed or failed. + */ +void SELF_TEST_EVENT_onend(OSSL_ST_EVENT *ev, int ret) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = + (ret == 1 ? OSSL_SELF_TEST_PHASE_PASS : OSSL_SELF_TEST_PHASE_FAIL); + self_test_event_setparams(ev); + (void)ev->cb(ev->params, ev->cb_arg); + + ev->phase = OSSL_SELF_TEST_PHASE_NONE; + ev->type = OSSL_SELF_TEST_TYPE_NONE; + ev->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 SELF_TEST_EVENT_oncorrupt_byte(OSSL_ST_EVENT *ev, unsigned char *bytes) +{ + if (ev != NULL && ev->cb != NULL) { + ev->phase = OSSL_SELF_TEST_PHASE_CORRUPT; + self_test_event_setparams(ev); + if (!ev->cb(ev->params, ev->cb_arg)) + bytes[0] ^= 1; + } +} + diff --git a/providers/fips/self_test_kats.c b/providers/fips/self_test_kats.c new file mode 100644 index 0000000000..3ccd3f66ed --- /dev/null +++ b/providers/fips/self_test_kats.c @@ -0,0 +1,246 @@ +/* + * Copyright 2019 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <string.h> +#include <openssl/evp.h> +#include <openssl/kdf.h> +#include "internal/nelem.h" +#include "self_test.h" +#include "self_test_data.inc" + +static int self_test_digest(const ST_KAT_DIGEST *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ok = 0; + unsigned char out[EVP_MAX_MD_SIZE]; + unsigned int out_len = 0; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + EVP_MD *md = EVP_MD_fetch(libctx, t->algorithm, NULL); + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_DIGEST, t->desc); + + if (ctx == NULL + || md == NULL + || !EVP_DigestInit_ex(ctx, md, NULL) + || !EVP_DigestUpdate(ctx, t->pt, t->pt_len) + || !EVP_DigestFinal(ctx, out, &out_len)) + goto err; + + /* Optional corruption */ + SELF_TEST_EVENT_oncorrupt_byte(event, out); + + if (out_len != t->expected_len + || memcmp(out, t->expected, out_len) != 0) + goto err; + ok = 1; +err: + SELF_TEST_EVENT_onend(event, ok); + EVP_MD_free(md); + EVP_MD_CTX_free(ctx); + + return ok; +} + +/* + * Helper function to setup a EVP_CipherInit + * Used to hide the complexity of Authenticated ciphers. + */ +static int cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const ST_KAT_CIPHER *t, int enc) +{ + unsigned char *in_tag = NULL; + int pad = 0, tmp; + + /* Flag required for Key wrapping */ + EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW); + if (t->tag == NULL) { + /* Use a normal cipher init */ + return EVP_CipherInit_ex(ctx, cipher, NULL, t->key, t->iv, enc) + && EVP_CIPHER_CTX_set_padding(ctx, pad); + } + + /* The authenticated cipher init */ + if (!enc) + in_tag = (unsigned char *)t->tag; + + return EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, enc) + && EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, t->iv_len, NULL) + && (in_tag == NULL + || EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, t->tag_len, + in_tag)) + && EVP_CipherInit_ex(ctx, NULL, NULL, t->key, t->iv, enc) + && EVP_CIPHER_CTX_set_padding(ctx, pad) + && EVP_CipherUpdate(ctx, NULL, &tmp, t->aad, t->aad_len); +} + +/* Test a single KAT for encrypt/decrypt */ +static int self_test_cipher(const ST_KAT_CIPHER *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ret = 0, encrypt = 1, len, ct_len = 0, pt_len = 0; + EVP_CIPHER_CTX *ctx = NULL; + EVP_CIPHER *cipher = NULL; + unsigned char ct_buf[256] = { 0 }; + unsigned char pt_buf[256] = { 0 }; + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_CIPHER, t->base.desc); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + goto end; + cipher = EVP_CIPHER_fetch(libctx, t->base.algorithm, ""); + if (cipher == NULL) + goto end; + + /* Encrypt plain text message */ + if (!cipher_init(ctx, cipher, t, encrypt) + || !EVP_CipherUpdate(ctx, ct_buf, &len, t->base.pt, t->base.pt_len) + || !EVP_CipherFinal_ex(ctx, ct_buf + len, &ct_len)) + goto end; + + SELF_TEST_EVENT_oncorrupt_byte(event, ct_buf); + ct_len += len; + if (ct_len != (int)t->base.expected_len + || memcmp(t->base.expected, ct_buf, ct_len) != 0) + goto end; + + if (t->tag != NULL) { + unsigned char tag[16] = { 0 }; + + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, t->tag_len, tag) + || memcmp(tag, t->tag, t->tag_len) != 0) + goto end; + } + + if (!(cipher_init(ctx, cipher, t, !encrypt) + && EVP_CipherUpdate(ctx, pt_buf, &len, ct_buf, ct_len) + && EVP_CipherFinal_ex(ctx, pt_buf + len, &pt_len))) + goto end; + pt_len += len; + + if (pt_len != (int)t->base.pt_len + || memcmp(pt_buf, t->base.pt, pt_len) != 0) + goto end; + + ret = 1; +end: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + SELF_TEST_EVENT_onend(event, ret); + return ret; +} + +static int self_test_kdf(const ST_KAT_KDF *t, OSSL_ST_EVENT *event, + OPENSSL_CTX *libctx) +{ + int ret = 0; + int i; + unsigned char out[64]; + EVP_KDF *kdf = NULL; + EVP_KDF_CTX *ctx = NULL; + OSSL_PARAM params[16]; + const OSSL_PARAM *settables = NULL; + + SELF_TEST_EVENT_onbegin(event, OSSL_SELF_TEST_TYPE_KAT_KDF, t->desc); + + kdf = EVP_KDF_fetch(libctx, t->algorithm, ""); + ctx = EVP_KDF_CTX_new(kdf); + if (ctx == NULL) + goto end; + + settables = EVP_KDF_settable_ctx_params(kdf); + for (i = 0; t->ctrls[i].name != NULL; ++i) { + if (!OSSL_PARAM_allocate_from_text(¶ms[i], settables, + t->ctrls[i].name, + t->ctrls[i].value, + strlen(t->ctrls[i].value))) + goto end; + } + params[i] = OSSL_PARAM_construct_end(); + if (!EVP_KDF_CTX_set_params(ctx, params)) + goto end; + + if (t->expected_len > sizeof(out)) + goto end; + if (EVP_KDF_derive(ctx, out, t->expected_len) <= 0) + goto end; + + SELF_TEST_EVENT_oncorrupt_byte(event, out); + + if (memcmp(out, t->expected, t->expected_len) != 0) + goto end; + + ret = 1; +end: + for (i = 0; params[i].key != NULL; ++i) + OPENSSL_free(params[i].data); + EVP_KDF_free(kdf); + EVP_KDF_CTX_free(ctx); + SELF_TEST_EVENT_onend(event, ret); + return ret; +} + +/* + * Test a data driven list of KAT's for digest algorithms. + * All tests are run regardless of if they fail or not. + * Return 0 if any test fails. + */ +static int self_test_digests(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_digest_tests); ++i) { + if (!self_test_digest(&st_kat_digest_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +static int self_test_ciphers(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_cipher_tests); ++i) { + if (!self_test_cipher(&st_kat_cipher_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +static int self_test_kdfs(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int i, ret = 1; + + for (i = 0; i < (int)OSSL_NELEM(st_kat_kdf_tests); ++i) { + if (!self_test_kdf(&st_kat_kdf_tests[i], event, libctx)) + ret = 0; + } + return ret; +} + +/* + * Run the algorithm KAT's. + * Return 1 is successful, otherwise return 0. + * This runs all the tests regardless of if any fail. + * + * TODO(3.0) Add self tests for KA, DRBG, Sign/Verify when they become available + */ +int SELF_TEST_kats(OSSL_ST_EVENT *event, OPENSSL_CTX *libctx) +{ + int ret = 1; + + if (!self_test_digests(event, libctx)) + ret = 0; + if (!self_test_ciphers(event, libctx)) + ret = 0; + if (!self_test_kdfs(event, libctx)) + ret = 0; + + return ret; +} |