--- crypto/cmac/cm_pmeth.c | 5 crypto/cmac/cmac.c | 16 crypto/dh/dh_pmeth.c | 4 crypto/dsa/dsa_pmeth.c | 5 crypto/ec/ec_pmeth.c | 13 crypto/ec/ecx_meth.c | 2 crypto/evp/digest.c | 2 crypto/evp/e_aes.c | 70 +++ crypto/evp/evp_enc.c | 3 crypto/evp/evp_local.h | 4 crypto/evp/kdf_lib.c | 11 crypto/evp/m_sigver.c | 54 ++ crypto/evp/p5_crpt2.c | 38 + crypto/evp/p_open.c | 3 crypto/evp/p_seal.c | 3 crypto/evp/p_sign.c | 5 crypto/evp/p_verify.c | 4 crypto/evp/pkey_kdf.c | 5 crypto/evp/pmeth_lib.c | 2 crypto/fips/build.info | 2 crypto/fips/fips_sli.c | 371 ++++++++++++++++ crypto/hmac/hm_pmeth.c | 5 crypto/hmac/hmac.c | 49 +- crypto/hmac/hmac_local.h | 4 crypto/kdf/hkdf.c | 8 crypto/kdf/pbkdf2.c | 14 crypto/kdf/scrypt.c | 7 crypto/kdf/sshkdf.c | 13 crypto/kdf/tls1_prf.c | 12 crypto/poly1305/poly1305_pmeth.c | 4 crypto/rand/rand_lib.c | 12 crypto/rsa/rsa_pmeth.c | 61 ++ crypto/sha/sha1_one.c | 5 crypto/siphash/siphash_pmeth.c | 4 crypto/sm2/sm2_pmeth.c | 5 doc/man3/FIPS_service_level_indicator.pod | 110 +++++ include/crypto/evp.h | 5 include/crypto/fipserr.h | 121 +++++ include/internal/fips_sli_local.h | 96 ++++ include/openssl/fips_sli.h | 32 + test/build.info | 6 test/fips_slitest.c | 659 ++++++++++++++++++++++++++++++ test/fips_slitest_helper.c | 489 ++++++++++++++++++++++ test/fips_slitest_helper.h | 29 + test/recipes/30-test_fips_sli.t | 4 util/libcrypto.num | 11 46 files changed, 2345 insertions(+), 42 deletions(-) --- a/crypto/cmac/cm_pmeth.c +++ b/crypto/cmac/cm_pmeth.c @@ -72,7 +72,10 @@ static int cmac_signctx_init(EVP_PKEY_CT static int cmac_signctx(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen, EVP_MD_CTX *mctx) { - return CMAC_Final(ctx->data, sig, siglen); + const int r = CMAC_Final(ctx->data, sig, siglen); + if (!fips_sli_is_approved_CMAC_CTX(ctx->data)) + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + return r; } static int pkey_cmac_ctrl(EVP_PKEY_CTX *ctx, int type, int p1, void *p2) --- a/crypto/cmac/cmac.c +++ b/crypto/cmac/cmac.c @@ -13,6 +13,7 @@ #include "internal/cryptlib.h" #include #include +#include "internal/fips_sli_local.h" struct CMAC_CTX_st { /* Cipher context to use */ @@ -26,8 +27,11 @@ struct CMAC_CTX_st { unsigned char last_block[EVP_MAX_BLOCK_LENGTH]; /* Number of bytes in last block: -1 means context not initialised */ int nlast_block; + FIPS_STATUS sli; /* Service Level Indicator */ }; +fips_sli_define_for(CMAC_CTX) + /* Make temporary keys K1 and K2 */ static void make_kn(unsigned char *k1, const unsigned char *l, int bl) @@ -62,6 +66,7 @@ CMAC_CTX *CMAC_CTX_new(void) void CMAC_CTX_cleanup(CMAC_CTX *ctx) { + ctx->sli = FIPS_UNSET; EVP_CIPHER_CTX_reset(ctx->cctx); OPENSSL_cleanse(ctx->tbl, EVP_MAX_BLOCK_LENGTH); OPENSSL_cleanse(ctx->k1, EVP_MAX_BLOCK_LENGTH); @@ -97,6 +102,7 @@ int CMAC_CTX_copy(CMAC_CTX *out, const C memcpy(out->tbl, in->tbl, bl); memcpy(out->last_block, in->last_block, bl); out->nlast_block = in->nlast_block; + out->sli = in->sli; return 1; } @@ -104,6 +110,7 @@ int CMAC_Init(CMAC_CTX *ctx, const void const EVP_CIPHER *cipher, ENGINE *impl) { static const unsigned char zero_iv[EVP_MAX_BLOCK_LENGTH] = { 0 }; + ctx->sli = FIPS_UNSET; /* All zeros means restart */ if (!key && !cipher && !impl && keylen == 0) { /* Not initialised */ @@ -215,6 +222,15 @@ int CMAC_Final(CMAC_CTX *ctx, unsigned c OPENSSL_cleanse(out, bl); return 0; } + switch (EVP_CIPHER_nid(EVP_CIPHER_CTX_cipher(ctx->cctx))) { + case NID_aes_128_cbc: + case NID_aes_192_cbc: + case NID_aes_256_cbc: + fips_sli_approve_CMAC_CTX(ctx); + break; + default: + fips_sli_disapprove_CMAC_CTX(ctx); + } return 1; } --- a/crypto/dh/dh_pmeth.c +++ b/crypto/dh/dh_pmeth.c @@ -466,6 +466,8 @@ static int pkey_dh_derive(EVP_PKEY_CTX * if (ret < 0) return ret; *keylen = ret; + fips_sli_check_key_dh_EVP_PKEY_CTX(ctx, ctx->peerkey->pkey.dh); + fips_sli_check_key_dh_EVP_PKEY_CTX(ctx, dh); return 1; } #ifndef OPENSSL_NO_CMS @@ -493,6 +495,8 @@ static int pkey_dh_derive(EVP_PKEY_CTX * dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md)) goto err; *keylen = dctx->kdf_outlen; + fips_sli_check_key_dh_EVP_PKEY_CTX(ctx, ctx->peerkey->pkey.dh); + fips_sli_check_key_dh_EVP_PKEY_CTX(ctx, dh); ret = 1; err: OPENSSL_clear_free(Z, Zlen); --- a/crypto/dsa/dsa_pmeth.c +++ b/crypto/dsa/dsa_pmeth.c @@ -77,6 +77,8 @@ static int pkey_dsa_sign(EVP_PKEY_CTX *c DSA_PKEY_CTX *dctx = ctx->data; DSA *dsa = ctx->pkey->pkey.dsa; + fips_sli_check_key_dsa_siggen_EVP_PKEY_CTX(ctx, dsa); + if (dctx->md != NULL && tbslen != (size_t)EVP_MD_size(dctx->md)) return 0; @@ -96,6 +98,8 @@ static int pkey_dsa_verify(EVP_PKEY_CTX DSA_PKEY_CTX *dctx = ctx->data; DSA *dsa = ctx->pkey->pkey.dsa; + fips_sli_check_key_dsa_sigver_EVP_PKEY_CTX(ctx, dsa); + if (dctx->md != NULL && tbslen != (size_t)EVP_MD_size(dctx->md)) return 0; @@ -224,6 +228,7 @@ static int pkey_dsa_paramgen(EVP_PKEY_CT static int pkey_dsa_keygen(EVP_PKEY_CTX *ctx, EVP_PKEY *pkey) { DSA *dsa = NULL; + fips_sli_disapprove_EVP_PKEY_CTX(ctx); if (ctx->pkey == NULL) { DSAerr(DSA_F_PKEY_DSA_KEYGEN, DSA_R_NO_PARAMETERS_SET); --- a/crypto/ec/ec_pmeth.c +++ b/crypto/ec/ec_pmeth.c @@ -122,6 +122,7 @@ static int pkey_ec_sign(EVP_PKEY_CTX *ct type = (dctx->md != NULL) ? EVP_MD_type(dctx->md) : NID_sha1; + fips_sli_check_curve_siggen_EVP_PKEY_CTX(ctx, EC_KEY_get0_group(ec)); ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec); if (ret <= 0) @@ -143,6 +144,7 @@ static int pkey_ec_verify(EVP_PKEY_CTX * else type = NID_sha1; + fips_sli_check_curve_sigver_EVP_PKEY_CTX(ctx, EC_KEY_get0_group(ec)); ret = ECDSA_verify(type, tbs, tbslen, sig, siglen, ec); return ret; @@ -182,6 +184,8 @@ static int pkey_ec_derive(EVP_PKEY_CTX * if (ret <= 0) return 0; *keylen = ret; + fips_sli_check_key_ecdh_EVP_PKEY_CTX(ctx, eckey); + fips_sli_check_key_ecdh_EVP_PKEY_CTX(ctx, ctx->peerkey->pkey.ec); return 1; } @@ -208,6 +212,8 @@ static int pkey_ec_kdf_derive(EVP_PKEY_C } if (!pkey_ec_derive(ctx, ktmp, &ktmplen)) goto err; + /* ANSI-X9.63-KDF (X9_62) is FIPS-approved, but we don't have a selftest */ + fips_sli_disapprove_EVP_PKEY_CTX(ctx); /* Do KDF stuff */ if (!ecdh_KDF_X9_63(key, *keylen, ktmp, ktmplen, dctx->kdf_ukm, dctx->kdf_ukmlen, dctx->kdf_md)) @@ -433,7 +439,12 @@ static int pkey_ec_keygen(EVP_PKEY_CTX * else ret = EC_KEY_set_group(ec, dctx->gen_group); - return ret ? EC_KEY_generate_key(ec) : 0; + if (ret) { + fips_sli_check_key_ec_keygen_EVP_PKEY_CTX(ctx, ec); + return EC_KEY_generate_key(ec); + } else { + return 0; + } } static const EVP_PKEY_METHOD ec_pkey_meth = { --- a/crypto/ec/ecx_meth.c +++ b/crypto/ec/ecx_meth.c @@ -691,6 +691,7 @@ static int pkey_ecx_derive25519(EVP_PKEY && X25519(key, privkey, pubkey) == 0)) return 0; *keylen = X25519_KEYLEN; + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return 1; } @@ -704,6 +705,7 @@ static int pkey_ecx_derive448(EVP_PKEY_C && X448(key, privkey, pubkey) == 0)) return 0; *keylen = X448_KEYLEN; + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return 1; } --- a/crypto/evp/digest.c +++ b/crypto/evp/digest.c @@ -40,6 +40,7 @@ int EVP_MD_CTX_reset(EVP_MD_CTX *ctx) if (ctx == NULL) return 1; + ctx->sli = FIPS_UNSET; /* * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, because * sometimes only copies of the context are ever finalised. @@ -80,6 +81,7 @@ int EVP_DigestInit(EVP_MD_CTX *ctx, cons int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) { EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + ctx->sli = FIPS_UNSET; #ifdef OPENSSL_FIPS if (FIPS_selftest_failed()) { FIPSerr(FIPS_F_EVP_DIGESTINIT_EX, FIPS_R_FIPS_SELFTEST_FAILED); --- a/crypto/evp/e_aes.c +++ b/crypto/evp/e_aes.c @@ -4303,3 +4303,73 @@ BLOCK_CIPHER_custom(NID_aes, 192, 16, 12 BLOCK_CIPHER_custom(NID_aes, 256, 16, 12, ocb, OCB, EVP_CIPH_FLAG_AEAD_CIPHER | CUSTOM_FLAGS) #endif /* OPENSSL_NO_OCB */ + +/* Use an explicit whitelist here (due to the number of ciphers and modes) */ +FIPS_STATUS EVP_CIPHER_get_fips_status(const EVP_CIPHER *cipher) { + /* switch on pointers is not entirely portable */ + if (cipher->do_cipher == aes_cbc_cipher + || cipher->do_cipher == aes_ecb_cipher + || cipher->do_cipher == aes_xts_cipher + || cipher->do_cipher == aes_ofb_cipher + || cipher->do_cipher == aes_cfb_cipher + || cipher->do_cipher == aes_cfb1_cipher + || cipher->do_cipher == aes_cfb8_cipher + || cipher->do_cipher == aes_ctr_cipher + || cipher->do_cipher == aes_gcm_cipher + || cipher->do_cipher == aes_gcm_tls_cipher + || cipher->do_cipher == aes_ccm_cipher + #if defined(OPENSSL_CPUID_OBJ) && ( \ + ((defined(__i386) || defined(__i386__) || defined(_M_IX86))\ + && defined(OPENSSL_IA32_SSE2)) \ + || defined(__x86_64) || defined(__x86_64__) \ + || defined(_M_AMD64) || defined(_M_X64)) + || cipher->do_cipher == aesni_cbc_cipher /* AES-NI */ + || cipher->do_cipher == aesni_ecb_cipher + || cipher->do_cipher == aesni_xts_cipher + || cipher->do_cipher == aesni_ofb_cipher + || cipher->do_cipher == aesni_cfb_cipher + || cipher->do_cipher == aesni_cfb1_cipher + || cipher->do_cipher == aesni_cfb8_cipher + || cipher->do_cipher == aesni_ctr_cipher + || cipher->do_cipher == aesni_gcm_cipher + || cipher->do_cipher == aesni_ccm_cipher + #elif defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + || cipher->do_cipher == s390x_aes_cbc_cipher /* System/390 */ + || cipher->do_cipher == s390x_aes_ecb_cipher + || cipher->do_cipher == s390x_aes_xts_cipher + || cipher->do_cipher == s390x_aes_ofb_cipher + || cipher->do_cipher == s390x_aes_cfb_cipher + || cipher->do_cipher == s390x_aes_cfb1_cipher + || cipher->do_cipher == s390x_aes_cfb8_cipher + || cipher->do_cipher == s390x_aes_ctr_cipher + || cipher->do_cipher == s390x_aes_gcm_cipher + || cipher->do_cipher == s390x_aes_gcm_tls_cipher + || cipher->do_cipher == s390x_aes_ccm_cipher + #endif + || cipher->do_cipher == aes_wrap_cipher /* key wrapping */ + ) { + switch (EVP_CIPHER_key_length(cipher) * 8) { + case 128: + case 192: + if (cipher->do_cipher == aes_xts_cipher + #if defined(OPENSSL_CPUID_OBJ) && ( \ + ((defined(__i386) || defined(__i386__) || defined(_M_IX86))\ + && defined(OPENSSL_IA32_SSE2)) \ + || defined(__x86_64) || defined(__x86_64__) \ + || defined(_M_AMD64) || defined(_M_X64)) + || cipher->do_cipher == aesni_xts_cipher + #elif defined(OPENSSL_CPUID_OBJ) && defined(__s390__) + || cipher->do_cipher == s390x_aes_xts_cipher + #endif + ) + return FIPS_NONAPPROVED; + /* intended fall-through */ + case 256: + return FIPS_APPROVED; + } + } + /* disapproved for enc and dec: all others, including + * 3DES and AES modes + * aes_ocb_cipher */ + return FIPS_NONAPPROVED; +} --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -32,6 +32,7 @@ int EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX #endif if (c == NULL) return 1; + c->sli = FIPS_UNSET; if (c->cipher != NULL) { if (c->cipher->cleanup && !c->cipher->cleanup(c)) return 0; @@ -116,6 +117,7 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ct /* Restore encrypt and flags */ ctx->encrypt = enc; ctx->flags = flags; + ctx->sli = FIPS_UNSET; } #ifndef OPENSSL_NO_ENGINE if (impl) { @@ -237,6 +239,7 @@ int EVP_CipherInit_ex(EVP_CIPHER_CTX *ct ctx->buf_len = 0; ctx->final_used = 0; ctx->block_mask = ctx->cipher->block_size - 1; + fips_sli_check_cipher_EVP_CIPHER_CTX(ctx, ctx->cipher); return 1; } --- a/crypto/evp/evp_local.h +++ b/crypto/evp/evp_local.h @@ -1,3 +1,4 @@ +#include "internal/fips_sli_local.h" /* * Copyright 2000-2022 The OpenSSL Project Authors. All Rights Reserved. * @@ -19,6 +20,7 @@ struct evp_md_ctx_st { EVP_PKEY_CTX *pctx; /* Update function: usually copied from EVP_MD */ int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); + FIPS_STATUS sli; /* Service Level Indicator */ } /* EVP_MD_CTX */ ; struct evp_cipher_ctx_st { @@ -39,11 +41,13 @@ struct evp_cipher_ctx_st { int final_used; int block_mask; unsigned char final[EVP_MAX_BLOCK_LENGTH]; /* possible final block */ + FIPS_STATUS sli; /* Service Level Indicator */ } /* EVP_CIPHER_CTX */ ; struct evp_kdf_ctx_st { const EVP_KDF_METHOD *kmeth; EVP_KDF_IMPL *impl; /* Algorithm-specific data */ + FIPS_STATUS sli; /* Service Level Indicator */ } /* EVP_KDF_CTX */ ; int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, const char *pass, --- a/crypto/evp/kdf_lib.c +++ b/crypto/evp/kdf_lib.c @@ -17,6 +17,7 @@ #include #include "crypto/asn1.h" #include "crypto/evp.h" +#include "internal/fips_sli_local.h" #include "internal/numbers.h" #include "evp_local.h" @@ -82,6 +83,7 @@ EVP_KDF_CTX *EVP_KDF_CTX_new_id(int id) } ret->kmeth = kmeth; + ret->sli = FIPS_UNSET; return ret; } @@ -101,6 +103,7 @@ void EVP_KDF_reset(EVP_KDF_CTX *ctx) if (ctx->kmeth->reset != NULL) ctx->kmeth->reset(ctx->impl); + ctx->sli = FIPS_UNSET; } int EVP_KDF_ctrl(EVP_KDF_CTX *ctx, int cmd, ...) @@ -161,6 +164,12 @@ int EVP_KDF_derive(EVP_KDF_CTX *ctx, uns if (ctx == NULL) return 0; - return ctx->kmeth->derive(ctx->impl, key, keylen); + int ret = ctx->kmeth->derive(ctx->impl, key, keylen); + if (ctx->kmeth->fips_sli_is_approved(ctx->impl)) + fips_sli_approve_EVP_KDF_CTX(ctx); + else + fips_sli_disapprove_EVP_KDF_CTX(ctx); + + return ret; } --- a/crypto/evp/m_sigver.c +++ b/crypto/evp/m_sigver.c @@ -105,15 +105,21 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, if (pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM) { if (!sigret) return pctx->pmeth->signctx(pctx, sigret, siglen, ctx); - if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) + if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) { r = pctx->pmeth->signctx(pctx, sigret, siglen, ctx); - else { + if (!fips_sli_is_approved_EVP_PKEY_CTX(pctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); + } else { EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_dup(ctx->pctx); if (!dctx) return 0; r = dctx->pmeth->signctx(dctx, sigret, siglen, ctx); + if (!fips_sli_is_approved_EVP_PKEY_CTX(dctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); EVP_PKEY_CTX_free(dctx); } + /* stricter than necessary, ctx->digest might be set but unused */ + fips_sli_check_hash_siggen_EVP_MD_CTX(ctx, ctx->digest); return r; } if (pctx->pmeth->signctx) @@ -124,8 +130,11 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char md[EVP_MAX_MD_SIZE]; unsigned int mdlen = 0; if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) { - if (sctx) + if (sctx) { r = ctx->pctx->pmeth->signctx(ctx->pctx, sigret, siglen, ctx); + if (!fips_sli_is_approved_EVP_PKEY_CTX(ctx->pctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); + } else r = EVP_DigestFinal_ex(ctx, md, &mdlen); } else { @@ -136,16 +145,25 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, EVP_MD_CTX_free(tmp_ctx); return 0; } - if (sctx) + if (sctx) { r = tmp_ctx->pctx->pmeth->signctx(tmp_ctx->pctx, sigret, siglen, tmp_ctx); + if (!fips_sli_is_approved_EVP_PKEY_CTX(tmp_ctx->pctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); + } else r = EVP_DigestFinal_ex(tmp_ctx, md, &mdlen); EVP_MD_CTX_free(tmp_ctx); } + /* stricter than necessary, ctx->digest might be set but unused */ + fips_sli_check_hash_siggen_EVP_MD_CTX(ctx, ctx->digest); + if (sctx || !r) return r; - if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0) + r = EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen); + if (!fips_sli_is_approved_EVP_PKEY_CTX(ctx->pctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); + if (r <= 0) return 0; } else { if (sctx) { @@ -163,8 +181,12 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen, const unsigned char *tbs, size_t tbslen) { - if (ctx->pctx->pmeth->digestsign != NULL) + if (ctx->pctx->pmeth->digestsign != NULL) { + /* digestsign is only used for ed25519 and ed448 signatures, so should + * be safe to disapprove it completely */ + fips_sli_disapprove_EVP_MD_CTX(ctx); return ctx->pctx->pmeth->digestsign(ctx, sigret, siglen, tbs, tbslen); + } if (sigret != NULL && EVP_DigestSignUpdate(ctx, tbs, tbslen) <= 0) return 0; return EVP_DigestSignFinal(ctx, sigret, siglen); @@ -178,9 +200,14 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ct unsigned int mdlen = 0; int vctx = 0; - if (ctx->pctx->pmeth->verifyctx) + fips_sli_check_hash_sigver_EVP_MD_CTX(ctx, EVP_MD_CTX_md(ctx)); + + if (ctx->pctx->pmeth->verifyctx) { vctx = 1; - else + /* verifyctx seems to be unused by openssl, so should be safe to + * disapprove it */ + fips_sli_disapprove_EVP_MD_CTX(ctx); + } else vctx = 0; if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) { if (vctx) @@ -204,14 +231,21 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ct } if (vctx || !r) return r; - return EVP_PKEY_verify(ctx->pctx, sig, siglen, md, mdlen); + const int res = EVP_PKEY_verify(ctx->pctx, sig, siglen, md, mdlen); + if (!fips_sli_is_approved_EVP_PKEY_CTX(ctx->pctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); + return res; } int EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen, const unsigned char *tbs, size_t tbslen) { - if (ctx->pctx->pmeth->digestverify != NULL) + if (ctx->pctx->pmeth->digestverify != NULL) { + /* digestverify is only used for ed25519 and ed448 signatures, so should + * be safe to disapprove it completely */ + fips_sli_disapprove_EVP_MD_CTX(ctx); return ctx->pctx->pmeth->digestverify(ctx, sigret, siglen, tbs, tbslen); + } if (EVP_DigestVerifyUpdate(ctx, tbs, tbslen) <= 0) return -1; return EVP_DigestVerifyFinal(ctx, sigret, siglen); --- a/crypto/evp/p5_crpt2.c +++ b/crypto/evp/p5_crpt2.c @@ -10,6 +10,7 @@ #include #include #include "internal/cryptlib.h" +#include "internal/fips_sli_local.h" #include #include #include @@ -24,13 +25,13 @@ static void h__dump(const unsigned char *p, int len); #endif -int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, +static int PKCS5_PBKDF2_HMAC_internal(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, - const EVP_MD *digest, int keylen, unsigned char *out) + const EVP_MD *digest, int keylen, unsigned char *out, + EVP_KDF_CTX *kctx) { const char *empty = ""; int rv = 1; - EVP_KDF_CTX *kctx; /* Keep documented behaviour. */ if (pass == NULL) { @@ -42,9 +43,6 @@ int PKCS5_PBKDF2_HMAC(const char *pass, if (salt == NULL && saltlen == 0) salt = (unsigned char *)empty; - kctx = EVP_KDF_CTX_new_id(EVP_KDF_PBKDF2); - if (kctx == NULL) - return 0; if (EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_PASS, pass, (size_t)passlen) != 1 || EVP_KDF_ctrl(kctx, EVP_KDF_CTRL_SET_SALT, salt, (size_t)saltlen) != 1 @@ -53,8 +51,6 @@ int PKCS5_PBKDF2_HMAC(const char *pass, || EVP_KDF_derive(kctx, out, keylen) != 1) rv = 0; - EVP_KDF_CTX_free(kctx); - # ifdef OPENSSL_DEBUG_PKCS5V2 fprintf(stderr, "Password:\n"); h__dump(pass, passlen); @@ -67,6 +63,32 @@ int PKCS5_PBKDF2_HMAC(const char *pass, return rv; } +int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out) +{ + EVP_KDF_CTX *kctx; + kctx = EVP_KDF_CTX_new_id(EVP_KDF_PBKDF2); + if (kctx == NULL) + return 0; + int ret = PKCS5_PBKDF2_HMAC_internal(pass, passlen, salt, saltlen, iter, digest, keylen, out, kctx); + EVP_KDF_CTX_free(kctx); + return ret; +} + +int fips_sli_PKCS5_PBKDF2_HMAC_is_approved(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out) +{ + EVP_KDF_CTX *kctx = EVP_KDF_CTX_new_id(EVP_KDF_PBKDF2); + if (kctx == NULL) + return 0; + PKCS5_PBKDF2_HMAC_internal(pass, passlen, salt, saltlen, iter, digest, keylen, out, kctx); + int ret = fips_sli_is_approved_EVP_KDF_CTX(kctx); + EVP_KDF_CTX_free(kctx); + return ret; +} + int PKCS5_PBKDF2_HMAC_SHA1(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, int keylen, unsigned char *out) --- a/crypto/evp/p_open.c +++ b/crypto/evp/p_open.c @@ -8,6 +8,7 @@ */ #include "internal/cryptlib.h" +#include "internal/fips_sli_local.h" #ifdef OPENSSL_NO_RSA NON_EMPTY_TRANSLATION_UNIT #else @@ -47,6 +48,8 @@ int EVP_OpenInit(EVP_CIPHER_CTX *ctx, co goto err; } + // EVP_PKEY_decrypt_old always uses RSA dec + fips_sli_disapprove_EVP_CIPHER_CTX(ctx); i = EVP_PKEY_decrypt_old(key, ek, ekl, priv); if ((i <= 0) || !EVP_CIPHER_CTX_set_key_length(ctx, i)) { /* ERROR */ --- a/crypto/evp/p_seal.c +++ b/crypto/evp/p_seal.c @@ -9,6 +9,7 @@ #include #include "internal/cryptlib.h" +#include "internal/fips_sli_local.h" #include #include #include @@ -44,6 +45,8 @@ int EVP_SealInit(EVP_CIPHER_CTX *ctx, co ekl[i] = EVP_PKEY_encrypt_old(ek[i], key, EVP_CIPHER_CTX_key_length(ctx), pubk[i]); + // EVP_PKEY_encrypt_old always uses RSA encryption + fips_sli_disapprove_EVP_CIPHER_CTX(ctx); if (ekl[i] <= 0) { rv = -1; goto err; --- a/crypto/evp/p_sign.c +++ b/crypto/evp/p_sign.c @@ -23,6 +23,8 @@ int EVP_SignFinal(EVP_MD_CTX *ctx, unsig size_t sltmp; EVP_PKEY_CTX *pkctx = NULL; + fips_sli_check_hash_sigver_EVP_MD_CTX(ctx, EVP_MD_CTX_md(ctx)); + *siglen = 0; if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) { if (!EVP_DigestFinal_ex(ctx, m, &m_len)) @@ -37,6 +39,7 @@ int EVP_SignFinal(EVP_MD_CTX *ctx, unsig rv = EVP_MD_CTX_copy_ex(tmp_ctx, ctx); if (rv) rv = EVP_DigestFinal_ex(tmp_ctx, m, &m_len); + EVP_MD_CTX_free(tmp_ctx); if (!rv) return 0; @@ -53,6 +56,8 @@ int EVP_SignFinal(EVP_MD_CTX *ctx, unsig goto err; if (EVP_PKEY_sign(pkctx, sigret, &sltmp, m, m_len) <= 0) goto err; + if (!fips_sli_is_approved_EVP_PKEY_CTX(pkctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); *siglen = sltmp; i = 1; err: --- a/crypto/evp/p_verify.c +++ b/crypto/evp/p_verify.c @@ -22,6 +22,8 @@ int EVP_VerifyFinal(EVP_MD_CTX *ctx, con int i = 0; EVP_PKEY_CTX *pkctx = NULL; + fips_sli_check_hash_sigver_EVP_MD_CTX(ctx, EVP_MD_CTX_md(ctx)); + if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_FINALISE)) { if (!EVP_DigestFinal_ex(ctx, m, &m_len)) goto err; @@ -49,6 +51,8 @@ int EVP_VerifyFinal(EVP_MD_CTX *ctx, con if (EVP_PKEY_CTX_set_signature_md(pkctx, EVP_MD_CTX_md(ctx)) <= 0) goto err; i = EVP_PKEY_verify(pkctx, sigbuf, siglen, m, m_len); + if (!fips_sli_is_approved_EVP_PKEY_CTX(pkctx)) + fips_sli_disapprove_EVP_MD_CTX(ctx); err: EVP_PKEY_CTX_free(pkctx); return i; --- a/crypto/evp/pkey_kdf.c +++ b/crypto/evp/pkey_kdf.c @@ -158,7 +158,10 @@ static int pkey_kdf_derive(EVP_PKEY_CTX if (key == NULL) return 1; } - return EVP_KDF_derive(kctx, key, *keylen); + int ret = EVP_KDF_derive(kctx, key, *keylen); + if (!fips_sli_is_approved_EVP_KDF_CTX(kctx)) + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + return ret; } #ifndef OPENSSL_NO_SCRYPT --- a/crypto/evp/pmeth_lib.c +++ b/crypto/evp/pmeth_lib.c @@ -162,6 +162,7 @@ static EVP_PKEY_CTX *int_ctx_new(EVP_PKE EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE); return NULL; } + ret->sli = FIPS_UNSET; ret->engine = e; ret->pmeth = pmeth; ret->operation = EVP_PKEY_OP_UNDEFINED; @@ -299,6 +300,7 @@ EVP_PKEY_CTX *EVP_PKEY_CTX_dup(EVP_PKEY_ rctx->data = NULL; rctx->app_data = NULL; rctx->operation = pctx->operation; + rctx->sli = pctx->sli; if (pctx->pmeth->copy(rctx, pctx) > 0) return rctx; --- a/crypto/fips/build.info +++ b/crypto/fips/build.info @@ -5,7 +5,7 @@ SOURCE[../../libcrypto]=\ fips_post.c drbgtest.c fips_drbg_ctr.c fips_drbg_hash.c fips_drbg_hmac.c \ fips_drbg_lib.c fips_drbg_rand.c fips_drbg_selftest.c fips_rand_lib.c \ fips_cmac_selftest.c fips_ecdh_selftest.c fips_ecdsa_selftest.c \ - fips_dh_selftest.c fips_kdf_selftest.c fips_ers.c + fips_dh_selftest.c fips_kdf_selftest.c fips_ers.c fips_sli.c PROGRAMS=\ fips_standalone_hmac --- /dev/null +++ b/crypto/fips/fips_sli.c @@ -0,0 +1,371 @@ +#include +#include +#include +#include "crypto/evp.h" +#include "../evp/evp_local.h" +#include "../hmac/hmac_local.h" +#include "internal/fips_sli_local.h" + +/* Main part of the FIPS Service Level Indicator + If you want to quickly change its behaviour, you most likely want to start here + - beware of some exceptions, though... */ + +FIPS_STATUS fips_sli_fsm_transition(FIPS_STATUS state, FIPS_STATUS input) { + switch (state) { + case FIPS_UNSET: + switch (input) { + case FIPS_UNSET: /* ignore */ + return state; + case FIPS_APPROVED: + case FIPS_NONAPPROVED: + case FIPS_ERROR: + return input; + } + break; + case FIPS_APPROVED: + switch (input) { + case FIPS_UNSET: /* ignore */ + case FIPS_APPROVED: + return state; + case FIPS_NONAPPROVED: + case FIPS_ERROR: + return input; + } + break; + case FIPS_NONAPPROVED: + return state; + case FIPS_ERROR: + switch (input) { + case FIPS_UNSET: /* ignore */ + case FIPS_APPROVED: + case FIPS_ERROR: + return state; + case FIPS_NONAPPROVED: + return input; + } + } + abort(); +} + +fips_sli_define_for(EVP_CIPHER_CTX) +fips_sli_define_for(EVP_KDF_CTX) +fips_sli_define_for(EVP_MD_CTX) +fips_sli_define_for(EVP_PKEY_CTX) +fips_sli_define_for(HMAC_CTX) + +typedef enum curve_usage_e { + CURVE_KEYGEN, + CURVE_SIGGEN, + CURVE_SIGVER, + CURVE_DH +} CURVE_USAGE; + +/* Check whether a curve is okay for some type of usage */ +static FIPS_STATUS get_fips_curve_status(const EC_GROUP *group, CURVE_USAGE u) { + if (group == NULL) { + return FIPS_ERROR; + } + + switch (u) { + case CURVE_KEYGEN: + switch (EC_GROUP_get_curve_name(group)) { + /* ACVP-tested curves for keygen: */ + case NID_secp224r1: + /* SECG secp256r1 is the same as X9.62 prime256v1 (P-256) and hence omitted */ + case NID_X9_62_prime256v1: + case NID_secp384r1: + case NID_secp521r1: + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + case CURVE_SIGVER: + switch (EC_GROUP_get_curve_name(group)) { + case NID_X9_62_prime192v1: /* NIST P-192 */ + case NID_secp224r1: + /* SECG secp256r1 is the same as X9.62 prime256v1 (P-256) and hence omitted */ + case NID_X9_62_prime256v1: + case NID_secp384r1: + case NID_secp521r1: + /* nist k curves */ + case NID_sect233k1: + case NID_sect283k1: + case NID_sect409k1: + case NID_sect571k1: + /* nist b curves */ + case NID_sect233r1: + case NID_sect283r1: + case NID_sect409r1: + case NID_sect571r1: + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + case CURVE_SIGGEN: + case CURVE_DH: + switch (EC_GROUP_get_curve_name(group)) { + /* see crypto/ec/ec_curve.c:2800 */ + /* nist P curves*/ + case NID_secp224r1: + /* SECG secp256r1 is the same as X9.62 prime256v1 and hence omitted */ + case NID_X9_62_prime256v1: + case NID_secp384r1: + case NID_secp521r1: + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + } + return FIPS_NONAPPROVED; +} + +#define make_fips_sli_check_curve(CTXTYPE, fn, usage) \ +void fips_sli_check_curve_##fn##_##CTXTYPE(CTXTYPE *ctx, const EC_GROUP *group)\ +{ \ + fips_sli_fsm_##CTXTYPE(ctx, get_fips_curve_status(group, usage)); \ +} + +make_fips_sli_check_curve(EVP_MD_CTX, siggen, CURVE_SIGGEN) +make_fips_sli_check_curve(EVP_MD_CTX, sigver, CURVE_SIGVER) +/* keygen missing because in this case we need more info than available here*/ +make_fips_sli_check_curve(EVP_PKEY_CTX, siggen, CURVE_SIGGEN) +make_fips_sli_check_curve(EVP_PKEY_CTX, sigver, CURVE_SIGVER) + +typedef enum hash_usage_e { + HASH_SIGGEN, + HASH_SIGVER, + HASH_KDF_SSHKDF, + HASH_KDF_PBKDF2, + HASH_KDF_TLS, + HASH_RNG, + HASH_MAC +} HASH_USAGE; + +static FIPS_STATUS get_fips_hash_status(const EVP_MD *md, HASH_USAGE u) { + if (md == NULL) { + return FIPS_ERROR; + } + + switch (u) { + case HASH_KDF_TLS: + switch (EVP_MD_type(md)) { + case NID_sha256: /* TLSv1.2 */ + case NID_sha384: + case NID_sha512: + case NID_md5_sha1: /* used in TLS v1.0 / v1.1 */ + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + case HASH_KDF_PBKDF2: + case HASH_KDF_SSHKDF: + case HASH_MAC: + switch (EVP_MD_type(md)) { + case NID_sha1: + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha512_224: + case NID_sha512_256: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + case NID_shake128: + case NID_shake256: + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + case HASH_RNG: + case HASH_SIGGEN: + case HASH_SIGVER: + switch (EVP_MD_type(md)) { + case NID_sha224: + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha512_224: + case NID_sha512_256: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + case NID_shake128: + case NID_shake256: + return FIPS_APPROVED; + default: + return FIPS_NONAPPROVED; + } + } + return FIPS_ERROR; +} + +#define make_fips_sli_check_hash(CTXTYPE, fn, usage) \ +void fips_sli_check_hash_##fn##_##CTXTYPE(CTXTYPE *ctx, const EVP_MD *md) \ +{ \ + fips_sli_fsm_##CTXTYPE(ctx, get_fips_hash_status(md, usage)); \ +} + +make_fips_sli_check_hash(EVP_MD_CTX, siggen, HASH_SIGGEN) +make_fips_sli_check_hash(EVP_MD_CTX, sigver, HASH_SIGVER) +make_fips_sli_check_hash(EVP_PKEY_CTX, siggen, HASH_SIGGEN) +make_fips_sli_check_hash(EVP_PKEY_CTX, sigver, HASH_SIGVER) +make_fips_sli_check_hash(HMAC_CTX, mac, HASH_MAC) +/* KDF impl is a bit special - avoid changing everything just because of that */ +FIPS_STATUS fips_sli_get_hash_status_sshkdf(const EVP_MD * md) { + return get_fips_hash_status(md, HASH_KDF_SSHKDF); +} +FIPS_STATUS fips_sli_get_hash_status_pbkdf2(const EVP_MD * md) { + return get_fips_hash_status(md, HASH_KDF_PBKDF2); +} +FIPS_STATUS fips_sli_get_hash_status_kdf_tls1_prf(const EVP_MD * md) { + return get_fips_hash_status(md, HASH_KDF_TLS); +} + +FIPS_STATUS fips_sli_get_kdf_keylen_status(size_t keylen_bytes) { + if (keylen_bytes >= 112/8) + return FIPS_APPROVED; + else + return FIPS_NONAPPROVED; +} + +void fips_sli_check_key_rsa_keygen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa) { + fips_sli_check_key_rsa_siggen_EVP_PKEY_CTX(ctx, rsa); +} + +void fips_sli_check_key_rsa_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa) { + if (RSA_bits(rsa) >= 2048) + fips_sli_approve_EVP_PKEY_CTX(ctx); + else + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_rsa_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa) { + const int len_n = RSA_bits(rsa); + + if (1024 <= len_n && len_n < 2048) + fips_sli_approve_EVP_PKEY_CTX(ctx); // legacy use + else if (2048 <= len_n) + fips_sli_approve_EVP_PKEY_CTX(ctx); + else + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_rsa_enc_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa) { + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_rsa_dec_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa) { + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_dsa_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const DSA * dsa) { + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_dsa_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const DSA * dsa) { + fips_sli_disapprove_EVP_PKEY_CTX(ctx); +} + +void fips_sli_check_key_dh_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const DH *dh) { + switch (DH_get_nid(dh)) { + /* RFC 3526 */ + case NID_modp_2048: + case NID_modp_3072: + case NID_modp_4096: + case NID_modp_6144: + case NID_modp_8192: + /* RFC 7919 */ + case NID_ffdhe2048: + case NID_ffdhe3072: + case NID_ffdhe4096: + case NID_ffdhe6144: + case NID_ffdhe8192: + fips_sli_approve_EVP_PKEY_CTX(ctx); + break; + default: + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + } +} + +void fips_sli_check_key_ecdh_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const EC_KEY *ecdh) { + fips_sli_fsm_EVP_PKEY_CTX(ctx, get_fips_curve_status(EC_KEY_get0_group(ecdh), CURVE_DH)); +} + +void fips_sli_check_cipher_EVP_CIPHER_CTX(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher) { + fips_sli_fsm_EVP_CIPHER_CTX(ctx, EVP_CIPHER_get_fips_status(cipher)); +} + +/** According to FIPS PUB 186-5. + * Not really helpful because nist P curves are the only allowed curves for + * KeyGen, and have h=1 anyway - but allow for future extensibility */ +static FIPS_STATUS get_fips_keygen_ecdsa_order_status(const EC_KEY *ec) { + BN_CTX *ctx = BN_CTX_new(); + BIGNUM *pwr14, *pwr16, *pwr24, *pwr32; + const BIGNUM * cofactor = EC_GROUP_get0_cofactor(EC_KEY_get0_group(ec)); + const int n = EC_GROUP_order_bits(EC_KEY_get0_group(ec)); + FIPS_STATUS ret = FIPS_NONAPPROVED; + + if (ctx == NULL) { + ret = FIPS_ERROR; + goto end; + } + + BN_CTX_start(ctx); + pwr14 = BN_CTX_get(ctx); + pwr16 = BN_CTX_get(ctx); + pwr24 = BN_CTX_get(ctx); + pwr32 = BN_CTX_get(ctx); + if (pwr32 == NULL) { + /* Sufficient to check the return value of the last BN_CTX_get() */ + ret = FIPS_ERROR; + goto end; + } + BN_set_bit(pwr14, 14); + BN_set_bit(pwr16, 16); + BN_set_bit(pwr24, 24); + BN_set_bit(pwr32, 32); + + if (224 < n && n <= 255) { + if (BN_cmp(cofactor, pwr14) != 1) + ret = FIPS_APPROVED; + } else if (256 < n && n <= 383) { + if (BN_cmp(cofactor, pwr16) != 1) + ret = FIPS_APPROVED; + + } else if (384 < n && n <= 511) { + if (BN_cmp(cofactor, pwr24) != 1) + ret = FIPS_APPROVED; + + } else if (n >= 512) { + if (BN_cmp(cofactor, pwr32) != 1) + ret = FIPS_APPROVED; + } + +end: + BN_CTX_end(ctx); + BN_CTX_free(ctx); + return ret; +} + +void fips_sli_check_key_ec_keygen_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, + const EC_KEY *ec) { + fips_sli_fsm_EVP_PKEY_CTX(ctx, get_fips_curve_status( + EC_KEY_get0_group(ec), CURVE_KEYGEN)); + fips_sli_fsm_EVP_PKEY_CTX(ctx, get_fips_keygen_ecdsa_order_status(ec)); +} + +/* MINOR: refactor for sign/verify, too. See crypto/rsa/rsa_pmeth.c */ +static FIPS_STATUS get_fips_padding_rsa_encdec_status(int pad_mode/*,usg: enc/dec*/) { + return FIPS_NONAPPROVED; +} + +void fips_sli_check_padding_rsa_enc_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, int pad_mode) { + fips_sli_fsm_EVP_PKEY_CTX(ctx, get_fips_padding_rsa_encdec_status(pad_mode)); +} + +void fips_sli_check_padding_rsa_dec_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, int pad_mode) { + fips_sli_check_padding_rsa_enc_EVP_PKEY_CTX(ctx, pad_mode); +} --- a/crypto/hmac/hm_pmeth.c +++ b/crypto/hmac/hm_pmeth.c @@ -128,8 +128,11 @@ static int hmac_signctx(EVP_PKEY_CTX *ct if (!sig) return 1; - if (!HMAC_Final(hctx->ctx, sig, &hlen)) + if (!HMAC_Final(hctx->ctx, sig, &hlen)) { + if (!fips_sli_is_approved_HMAC_CTX(hctx->ctx)) + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return 0; + } *siglen = (size_t)hlen; return 1; } --- a/crypto/hmac/hmac.c +++ b/crypto/hmac/hmac.c @@ -23,6 +23,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const vo unsigned char pad[HMAC_MAX_MD_CBLOCK_SIZE]; unsigned int keytmp_length; unsigned char keytmp[HMAC_MAX_MD_CBLOCK_SIZE]; + ctx->sli = FIPS_UNSET; /* If we are changing MD then we must have a key */ if (md != NULL && md != ctx->md && (key == NULL || len < 0)) @@ -83,9 +84,17 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const vo if (!EVP_DigestInit_ex(ctx->o_ctx, md, impl) || !EVP_DigestUpdate(ctx->o_ctx, pad, EVP_MD_block_size(md))) goto err; + ctx->sli_key_len = len; } if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->i_ctx)) goto err; + /* On reuse, key/key_len might be NULL. Use cached value. */ + if (ctx->sli_key_len >= 112/8) { + fips_sli_approve_HMAC_CTX(ctx); + } else { + fips_sli_disapprove_HMAC_CTX(ctx); + } + fips_sli_check_hash_mac_HMAC_CTX(ctx, md); rv = 1; err: if (reset) { @@ -190,6 +199,7 @@ static int hmac_ctx_alloc_mds(HMAC_CTX * int HMAC_CTX_reset(HMAC_CTX *ctx) { + ctx->sli = FIPS_UNSET; hmac_ctx_cleanup(ctx); if (!hmac_ctx_alloc_mds(ctx)) { hmac_ctx_cleanup(ctx); @@ -209,24 +219,22 @@ int HMAC_CTX_copy(HMAC_CTX *dctx, HMAC_C if (!EVP_MD_CTX_copy_ex(dctx->md_ctx, sctx->md_ctx)) goto err; dctx->md = sctx->md; + dctx->sli = sctx->sli; return 1; err: hmac_ctx_cleanup(dctx); return 0; } -unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, +static unsigned char *HMAC_internal(const EVP_MD *evp_md, const void *key, int key_len, const unsigned char *d, size_t n, unsigned char *md, - unsigned int *md_len) + unsigned int *md_len, HMAC_CTX *c) { - HMAC_CTX *c = NULL; static unsigned char m[EVP_MAX_MD_SIZE]; static const unsigned char dummy_key[1] = {'\0'}; if (md == NULL) md = m; - if ((c = HMAC_CTX_new()) == NULL) - goto err; /* For HMAC_Init_ex, NULL key signals reuse. */ if (key == NULL && key_len == 0) { @@ -239,13 +247,40 @@ unsigned char *HMAC(const EVP_MD *evp_md goto err; if (!HMAC_Final(c, md, md_len)) goto err; - HMAC_CTX_free(c); return md; err: - HMAC_CTX_free(c); return NULL; } +unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len) +{ + HMAC_CTX *c = HMAC_CTX_new(); + unsigned char *ret = NULL; + if (c == NULL) + goto err; + ret = HMAC_internal(evp_md, key, key_len, d, n, md, md_len, c); + HMAC_CTX_free(c); + err: + return ret; +} + +int fips_sli_HMAC_is_approved(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len) +{ + HMAC_CTX *c = HMAC_CTX_new(); + int ret = 0; + if (c == NULL) + goto err; + HMAC_internal(evp_md, key, key_len, d, n, md, md_len, c); + ret = fips_sli_is_approved_HMAC_CTX(c); + HMAC_CTX_free(c); + err: + return ret; +} + void HMAC_CTX_set_flags(HMAC_CTX *ctx, unsigned long flags) { EVP_MD_CTX_set_flags(ctx->i_ctx, flags); --- a/crypto/hmac/hmac_local.h +++ b/crypto/hmac/hmac_local.h @@ -10,6 +10,8 @@ #ifndef OSSL_CRYPTO_HMAC_LOCAL_H # define OSSL_CRYPTO_HMAC_LOCAL_H +#include "internal/fips_sli_local.h" + /* The current largest case is for SHA3-224 */ #define HMAC_MAX_MD_CBLOCK_SIZE 144 @@ -18,6 +20,8 @@ struct hmac_ctx_st { EVP_MD_CTX *md_ctx; EVP_MD_CTX *i_ctx; EVP_MD_CTX *o_ctx; + FIPS_STATUS sli; /* Service Level Indicator */ + size_t sli_key_len; /* SLI needs to cache keylen in case of context reuse */ }; #endif --- a/crypto/kdf/hkdf.c +++ b/crypto/kdf/hkdf.c @@ -222,6 +222,11 @@ static int kdf_hkdf_derive(EVP_KDF_IMPL } } +static int kdf_hkdf_fips_sli_is_approved(ossl_unused const EVP_KDF_IMPL *impl) { + return 0; /* can't check whether this is only used for DH / TLS1.3 because + this is handled by the application. Thus label HKDF as non-approved. */ +} + const EVP_KDF_METHOD hkdf_kdf_meth = { EVP_KDF_HKDF, kdf_hkdf_new, @@ -230,7 +235,8 @@ const EVP_KDF_METHOD hkdf_kdf_meth = { kdf_hkdf_ctrl, kdf_hkdf_ctrl_str, kdf_hkdf_size, - kdf_hkdf_derive + kdf_hkdf_derive, + kdf_hkdf_fips_sli_is_approved }; static int HKDF(const EVP_MD *evp_md, --- a/crypto/kdf/pbkdf2.c +++ b/crypto/kdf/pbkdf2.c @@ -31,8 +31,16 @@ struct evp_kdf_impl_st { size_t salt_len; int iter; const EVP_MD *md; + FIPS_STATUS sli; /* Service Level Indicator */ }; +static ossl_unused int fips_sli_is_approved_struct_evp_kdf_impl_st(const struct evp_kdf_impl_st *ctx); +fips_sli_define_basic_for(static, struct_evp_kdf_impl_st, struct evp_kdf_impl_st) + +static void fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(struct evp_kdf_impl_st *ctx) { + fips_sli_fsm_struct_evp_kdf_impl_st(ctx, fips_sli_get_hash_status_pbkdf2(ctx->md)); +} + static EVP_KDF_IMPL *kdf_pbkdf2_new(void) { EVP_KDF_IMPL *impl; @@ -64,6 +72,7 @@ static void kdf_pbkdf2_init(EVP_KDF_IMPL { impl->iter = PKCS5_DEFAULT_ITER; impl->md = EVP_sha1(); + impl->sli = FIPS_UNSET; } static int pbkdf2_set_membuf(unsigned char **buffer, size_t *buflen, @@ -175,6 +184,8 @@ static int kdf_pbkdf2_derive(EVP_KDF_IMP return 0; } + fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(impl); + return pkcs5_pbkdf2_alg((char *)impl->pass, impl->pass_len, impl->salt, impl->salt_len, impl->iter, impl->md, key, keylen); @@ -188,7 +199,8 @@ const EVP_KDF_METHOD pbkdf2_kdf_meth = { kdf_pbkdf2_ctrl, kdf_pbkdf2_ctrl_str, NULL, - kdf_pbkdf2_derive + kdf_pbkdf2_derive, + fips_sli_is_approved_struct_evp_kdf_impl_st }; /* --- a/crypto/kdf/scrypt.c +++ b/crypto/kdf/scrypt.c @@ -266,6 +266,10 @@ static int kdf_scrypt_derive(EVP_KDF_IMP impl->maxmem_bytes, key, keylen); } +static int kdf_scrypt_fips_sli_is_approved(ossl_unused const EVP_KDF_IMPL *impl) { + return 0; /* not FIPS-approved */ +} + const EVP_KDF_METHOD scrypt_kdf_meth = { EVP_KDF_SCRYPT, kdf_scrypt_new, @@ -274,7 +278,8 @@ const EVP_KDF_METHOD scrypt_kdf_meth = { kdf_scrypt_ctrl, kdf_scrypt_ctrl_str, NULL, - kdf_scrypt_derive + kdf_scrypt_derive, + kdf_scrypt_fips_sli_is_approved }; #define R(a,b) (((a) << (b)) | ((a) >> (32 - (b)))) --- a/crypto/kdf/sshkdf.c +++ b/crypto/kdf/sshkdf.c @@ -34,8 +34,19 @@ struct evp_kdf_impl_st { char type; /* X */ unsigned char *session_id; size_t session_id_len; + FIPS_STATUS sli; /* Service Level Indicator */ }; + +fips_sli_define_basic_for(static, struct_evp_kdf_impl_st, struct evp_kdf_impl_st) + +static void fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(struct evp_kdf_impl_st *ctx) { + fips_sli_fsm_struct_evp_kdf_impl_st(ctx, + fips_sli_get_hash_status_sshkdf(ctx->md)); + fips_sli_fsm_struct_evp_kdf_impl_st(ctx, + fips_sli_get_kdf_keylen_status(ctx->key_len)); +} + static EVP_KDF_IMPL *kdf_sshkdf_new(void) { EVP_KDF_IMPL *impl; @@ -196,6 +207,7 @@ static int kdf_sshkdf_derive(EVP_KDF_IMP KDFerr(KDF_F_KDF_SSHKDF_DERIVE, KDF_R_MISSING_TYPE); return 0; } + fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(impl); return SSHKDF(impl->md, impl->key, impl->key_len, impl->xcghash, impl->xcghash_len, impl->session_id, impl->session_id_len, @@ -211,6 +223,7 @@ const EVP_KDF_METHOD sshkdf_kdf_meth = { kdf_sshkdf_ctrl_str, kdf_sshkdf_size, kdf_sshkdf_derive, + fips_sli_is_approved_struct_evp_kdf_impl_st }; static int SSHKDF(const EVP_MD *evp_md, --- a/crypto/kdf/tls1_prf.c +++ b/crypto/kdf/tls1_prf.c @@ -35,8 +35,16 @@ struct evp_kdf_impl_st { /* Buffer of concatenated seed data */ unsigned char seed[TLS1_PRF_MAXBUF]; size_t seedlen; + FIPS_STATUS sli; /* Service Level Indicator */ }; +fips_sli_define_basic_for(static, struct_evp_kdf_impl_st, struct evp_kdf_impl_st) + +static void fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(struct evp_kdf_impl_st *ctx) { + fips_sli_fsm_struct_evp_kdf_impl_st(ctx, + fips_sli_get_hash_status_kdf_tls1_prf(ctx->md)); +} + static EVP_KDF_IMPL *kdf_tls1_prf_new(void) { EVP_KDF_IMPL *impl; @@ -152,6 +160,7 @@ static int kdf_tls1_prf_derive(EVP_KDF_I KDFerr(KDF_F_KDF_TLS1_PRF_DERIVE, KDF_R_MISSING_SEED); return 0; } + fips_sli_check_hash_kdf_struct_evp_kdf_impl_st(impl); return tls1_prf_alg(impl->md, impl->sec, impl->seclen, impl->seed, impl->seedlen, key, keylen); @@ -165,7 +174,8 @@ const EVP_KDF_METHOD tls1_prf_kdf_meth = kdf_tls1_prf_ctrl, kdf_tls1_prf_ctrl_str, NULL, - kdf_tls1_prf_derive + kdf_tls1_prf_derive, + fips_sli_is_approved_struct_evp_kdf_impl_st }; static int tls1_prf_P_hash(const EVP_MD *md, --- a/crypto/poly1305/poly1305_pmeth.c +++ b/crypto/poly1305/poly1305_pmeth.c @@ -108,8 +108,10 @@ static int poly1305_signctx(EVP_PKEY_CTX POLY1305_PKEY_CTX *pctx = ctx->data; *siglen = POLY1305_DIGEST_SIZE; - if (sig != NULL) + if (sig != NULL) { Poly1305_Final(&pctx->ctx, sig); + fips_sli_disapprove_EVP_PKEY_CTX(ctx); // Poly1305 isn't an approved MAC + } return 1; } --- a/crypto/rand/rand_lib.c +++ b/crypto/rand/rand_lib.c @@ -937,6 +937,13 @@ int RAND_priv_bytes(unsigned char *buf, return 0; } +int fips_sli_RAND_priv_bytes_is_approved(unsigned char *buf, int num) { + const RAND_METHOD *meth = RAND_get_rand_method(); + if (meth != NULL && meth != RAND_OpenSSL()) + return 0; + return 1; +} + int RAND_bytes(unsigned char *buf, int num) { const RAND_METHOD *meth = RAND_get_rand_method(); @@ -947,6 +954,11 @@ int RAND_bytes(unsigned char *buf, int n return -1; } +int fips_sli_RAND_bytes_is_approved(unsigned char *buf, int num) { + const RAND_METHOD *meth = RAND_get_rand_method(); + return meth == RAND_OpenSSL(); +} + #if OPENSSL_API_COMPAT < 0x10100000L int RAND_pseudo_bytes(unsigned char *buf, int num) { --- a/crypto/rsa/rsa_pmeth.c +++ b/crypto/rsa/rsa_pmeth.c @@ -129,6 +129,7 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *c RSA_PKEY_CTX *rctx = ctx->data; RSA *rsa = ctx->pkey->pkey.rsa; + fips_sli_check_key_rsa_siggen_EVP_PKEY_CTX(ctx, rsa); if (rctx->md) { if (tbslen != (size_t)EVP_MD_size(rctx->md)) { RSAerr(RSA_F_PKEY_RSA_SIGN, RSA_R_INVALID_DIGEST_LENGTH); @@ -139,6 +140,8 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *c unsigned int sltmp; if (rctx->pad_mode != RSA_PKCS1_PADDING) return -1; + /* PKCS1-v1.5 padding is disallowed after 2023 */ + fips_sli_disapprove_EVP_PKEY_CTX(ctx); ret = RSA_sign_ASN1_OCTET_STRING(0, tbs, tbslen, sig, &sltmp, rsa); @@ -154,11 +157,30 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *c RSAerr(RSA_F_PKEY_RSA_SIGN, ERR_R_MALLOC_FAILURE); return -1; } + /* MINOR fips: refactor out? May have to read rctx->pad_mode (RSA_PKEY_CTX), though */ + /* ANSI X9.31 */ + switch (EVP_MD_type(rctx->md)) { + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + case NID_shake128: + case NID_shake256: + fips_sli_approve_EVP_PKEY_CTX(ctx); + break; + default: + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + } memcpy(rctx->tbuf, tbs, tbslen); rctx->tbuf[tbslen] = RSA_X931_hash_id(EVP_MD_type(rctx->md)); ret = RSA_private_encrypt(tbslen + 1, rctx->tbuf, sig, rsa, RSA_X931_PADDING); } else if (rctx->pad_mode == RSA_PKCS1_PADDING) { + /* PKCS1-v1.5 padding is disallowed after 2023 */ + fips_sli_disapprove_EVP_PKEY_CTX(ctx); unsigned int sltmp; ret = RSA_sign(EVP_MD_type(rctx->md), tbs, tbslen, sig, &sltmp, rsa); @@ -173,12 +195,14 @@ static int pkey_rsa_sign(EVP_PKEY_CTX *c rctx->md, rctx->mgf1md, rctx->saltlen)) return -1; + fips_sli_check_hash_siggen_EVP_PKEY_CTX(ctx, rctx->md); ret = RSA_private_encrypt(RSA_size(rsa), rctx->tbuf, sig, rsa, RSA_NO_PADDING); } else { return -1; } } else { + fips_sli_approve_EVP_PKEY_CTX(ctx); /* plain sig without hash */ ret = RSA_private_encrypt(tbslen, tbs, sig, ctx->pkey->pkey.rsa, rctx->pad_mode); } @@ -199,6 +223,23 @@ static int pkey_rsa_verifyrecover(EVP_PK if (rctx->pad_mode == RSA_X931_PADDING) { if (!setup_tbuf(rctx, ctx)) return -1; + /* MINOR fips: refactor out? May have to read rctx->pad_mode (RSA_PKEY_CTX), though */ + /* ANSI X9.31 */ + switch (EVP_MD_type(rctx->md)) { + case NID_sha256: + case NID_sha384: + case NID_sha512: + case NID_sha3_224: + case NID_sha3_256: + case NID_sha3_384: + case NID_sha3_512: + case NID_shake128: + case NID_shake256: + fips_sli_approve_EVP_PKEY_CTX(ctx); + break; + default: + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + } ret = RSA_public_decrypt(siglen, sig, rctx->tbuf, ctx->pkey->pkey.rsa, RSA_X931_PADDING); @@ -245,11 +286,15 @@ static int pkey_rsa_verify(EVP_PKEY_CTX RSA_PKEY_CTX *rctx = ctx->data; RSA *rsa = ctx->pkey->pkey.rsa; size_t rslen; + fips_sli_check_key_rsa_sigver_EVP_PKEY_CTX(ctx, rsa); if (rctx->md) { - if (rctx->pad_mode == RSA_PKCS1_PADDING) + if (rctx->pad_mode == RSA_PKCS1_PADDING) { + /* PKCS1-v1.5 padding is disallowed after 2023 */ + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return RSA_verify(EVP_MD_type(rctx->md), tbs, tbslen, sig, siglen, rsa); + } if (tbslen != (size_t)EVP_MD_size(rctx->md)) { RSAerr(RSA_F_PKEY_RSA_VERIFY, RSA_R_INVALID_DIGEST_LENGTH); return -1; @@ -270,6 +315,7 @@ static int pkey_rsa_verify(EVP_PKEY_CTX rctx->tbuf, rctx->saltlen); if (ret <= 0) return 0; + fips_sli_check_hash_sigver_EVP_PKEY_CTX(ctx, rctx->md); return 1; } else { return -1; @@ -277,6 +323,7 @@ static int pkey_rsa_verify(EVP_PKEY_CTX } else { if (!setup_tbuf(rctx, ctx)) return -1; + fips_sli_approve_EVP_PKEY_CTX(ctx); /* plain sig without hash */ rslen = RSA_public_decrypt(siglen, sig, rctx->tbuf, rsa, rctx->pad_mode); if (rslen == 0) @@ -313,6 +360,8 @@ static int pkey_rsa_encrypt(EVP_PKEY_CTX ret = RSA_public_encrypt(inlen, in, out, ctx->pkey->pkey.rsa, rctx->pad_mode); } + fips_sli_check_padding_rsa_enc_EVP_PKEY_CTX(ctx, rctx->pad_mode); + fips_sli_check_key_rsa_enc_EVP_PKEY_CTX(ctx, ctx->pkey->pkey.rsa); if (ret < 0) return ret; *outlen = ret; @@ -342,6 +391,8 @@ static int pkey_rsa_decrypt(EVP_PKEY_CTX ret = RSA_private_decrypt(inlen, in, out, ctx->pkey->pkey.rsa, rctx->pad_mode); } + fips_sli_check_padding_rsa_dec_EVP_PKEY_CTX(ctx, rctx->pad_mode); + fips_sli_check_key_rsa_dec_EVP_PKEY_CTX(ctx, ctx->pkey->pkey.rsa); *outlen = constant_time_select_s(constant_time_msb_s(ret), *outlen, ret); ret = constant_time_select_int(constant_time_msb(ret), ret, 1); return ret; @@ -747,9 +798,13 @@ static int pkey_rsa_keygen(EVP_PKEY_CTX RSA_free(rsa); return 0; } - if (ret > 0) + if (rctx->primes != 2) + fips_sli_disapprove_EVP_PKEY_CTX(ctx); + + if (ret > 0) { + fips_sli_check_key_rsa_keygen_EVP_PKEY_CTX(ctx, rsa); EVP_PKEY_assign(pkey, ctx->pmeth->pkey_id, rsa); - else + } else RSA_free(rsa); return ret; } --- a/crypto/sha/sha1_one.c +++ b/crypto/sha/sha1_one.c @@ -26,3 +26,8 @@ unsigned char *SHA1(const unsigned char OPENSSL_cleanse(&c, sizeof(c)); return md; } + +int fips_sli_SHA1_is_approved(const unsigned char *d, size_t n, unsigned char *md) { + /* Only approved depending on usage context, so default to false */ + return 0; +} --- a/crypto/siphash/siphash_pmeth.c +++ b/crypto/siphash/siphash_pmeth.c @@ -109,8 +109,10 @@ static int siphash_signctx(EVP_PKEY_CTX SIPHASH_PKEY_CTX *pctx = ctx->data; *siglen = SipHash_hash_size(&pctx->ctx); - if (sig != NULL) + if (sig != NULL) { + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return SipHash_Final(&pctx->ctx, sig, *siglen); + } return 1; } --- a/crypto/sm2/sm2_pmeth.c +++ b/crypto/sm2/sm2_pmeth.c @@ -107,6 +107,7 @@ static int pkey_sm2_sign(EVP_PKEY_CTX *c return 0; } + fips_sli_disapprove_EVP_PKEY_CTX(ctx); ret = sm2_sign(tbs, tbslen, sig, &sltmp, ec); if (ret <= 0) @@ -120,7 +121,7 @@ static int pkey_sm2_verify(EVP_PKEY_CTX const unsigned char *tbs, size_t tbslen) { EC_KEY *ec = ctx->pkey->pkey.ec; - + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return sm2_verify(tbs, tbslen, sig, siglen, ec); } @@ -139,6 +140,7 @@ static int pkey_sm2_encrypt(EVP_PKEY_CTX return 1; } + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return sm2_encrypt(ec, md, in, inlen, out, outlen); } @@ -157,6 +159,7 @@ static int pkey_sm2_decrypt(EVP_PKEY_CTX return 1; } + fips_sli_disapprove_EVP_PKEY_CTX(ctx); return sm2_decrypt(ec, md, in, inlen, out, outlen); } --- /dev/null +++ b/doc/man3/FIPS_service_level_indicator.pod @@ -0,0 +1,110 @@ +=pod + +=head1 NAME + +C - get status of the FIPS Service Level Indicator (SLI) for context operations + +C - get status of the FIPS SLI for standalone operations + +=head1 SYNOPSIS + + #include + + int fips_sli_is_approved_EVP_CIPHER_CTX(const EVP_CIPHER_CTX *ctx); + + int fips_sli_is_approved_EVP_KDF_CTX(const EVP_KDF_CTX *ctx); + + int fips_sli_is_approved_EVP_MD_CTX(const EVP_MD_CTX *ctx); + + int fips_sli_is_approved_EVP_PKEY_CTX(const EVP_PKEY_CTX *ctx); + + int fips_sli_is_approved_CMAC_CTX(const CMAC_CTX *ctx); + + int fips_sli_is_approved_HMAC_CTX(const HMAC_CTX *ctx); + + int fips_sli_SHA1_is_approved(const unsigned char *d, size_t n, unsigned char *md); + + int fips_sli_HMAC_is_approved(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len); + + int fips_sli_PKCS5_PBKDF2_HMAC_is_approved(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out); + + int fips_sli_RAND_bytes_is_approved(unsigned char *buf, int num); + + int fips_sli_RAND_priv_bytes_is_approved(unsigned char *buf, int num); + +=head1 DESCRIPTION + +The service level indicator has two different usage scenarios. + +=over 1 + +=item C + +Most operations happen on some form of a context, which also holds the SLI. +This function returns whether the FIPS SLI indicates an approved operation or not. + +After a disapproved operation is encountered, the SLI will continue to indicate this disapproved state. The SLI can only +be reset by the various existing resetting functions such as C or reinitializing the +context, e.g. via L. + +=item C + +Operations without a context (standalone functions) have a separate SLI with the name fips_sli_FNNAME_is_approved(). +These indicator functions take the same parameters as their corresponding operation +and may modify them just like their corresponding function might do. + +In order to check the SLI status of an operation C, the function +C must be called with the same set of parameters as C. +Note that applications must check the return value of C according to its documentation B the return value of the SLI (see below for L). +Both are orthogonal: the former reports about success and failure of C, and the latter whether a disapproved operation happened or not. +Well-behaving applications check for both. + +The following explicit indicators exist: + +C + +C + +C + +C + +C + +=back + +=head1 Notes on the RNG + +OpenSSL 1.1.1l implements a CTR DRBG with AES 128/192/256 (defaults to AES-256). +See L/RAND_priv_bytes(). + +Swapping out OPENSSL's RNG implementation (e.g. via L) is NOT allowed. + +=head1 RETURN VALUES + +C returns 0 if the previous operation(s) was unapproved or B was B, and returns 1 +if the previous operation(s) were approved (or rather, no non-approved operations happened). + +C returns 0 if an operation with a given set of parameters was unapproved, and returns 1 +if the operation is approved with the given set of parameters. + +These functions can be invoked at any time. + +=head1 HISTORY + +The FIPS SLI was added in OpenSSL 1.1.1.l. + +=head1 COPYRIGHT + +Copyright 2022 + +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 +L. + +=cut --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -9,6 +9,7 @@ #include #include "internal/refcount.h" +#include "internal/fips_sli_local.h" /* * Don't free up md_ctx->pctx in EVP_MD_CTX_reset, use the reserved flag @@ -36,6 +37,7 @@ struct evp_pkey_ctx_st { /* implementation specific keygen data */ int *keygen_info; int keygen_info_count; + FIPS_STATUS sli; /* Service Level Indicator */ } /* EVP_PKEY_CTX */ ; #define EVP_PKEY_FLAG_DYNAMIC 1 @@ -123,6 +125,9 @@ typedef struct { int (*ctrl_str) (EVP_KDF_IMPL *impl, const char *type, const char *value); size_t (*size) (EVP_KDF_IMPL *impl); int (*derive) (EVP_KDF_IMPL *impl, unsigned char *key, size_t keylen); + /* KDFs are handled differently by the SLI because the EVP_KDF_IMPL, which + holds the required information, is defined implementation-dependent */ + int (*fips_sli_is_approved) (const EVP_KDF_IMPL *impl); } EVP_KDF_METHOD; extern const EVP_KDF_METHOD pbkdf2_kdf_meth; --- /dev/null +++ b/include/crypto/fipserr.h @@ -0,0 +1,121 @@ +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-2022 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 + */ + +#ifndef HEADER_FIPSERR_H +# define HEADER_FIPSERR_H + +# include + +# ifdef __cplusplus +extern "C" +# endif +int ERR_load_FIPS_strings(void); + +/* + * FIPS function codes. + */ +# define FIPS_F_DRBG_RESEED 100 +# define FIPS_F_DSA_BUILTIN_PARAMGEN2 101 +# define FIPS_F_DSA_DO_SIGN 102 +# define FIPS_F_DSA_DO_VERIFY 103 +# define FIPS_F_ECDSA_SIMPLE_SIGN_SIG 104 +# define FIPS_F_ECDSA_SIMPLE_VERIFY_SIG 105 +# define FIPS_F_EVP_CIPHERINIT_EX 106 +# define FIPS_F_EVP_CIPHER_CTX_NEW 107 +# define FIPS_F_EVP_CIPHER_CTX_RESET 108 +# define FIPS_F_EVP_DIGESTINIT_EX 109 +# define FIPS_F_FIPS_CHECK_DSA 110 +# define FIPS_F_FIPS_CHECK_EC 111 +# define FIPS_F_FIPS_CHECK_RSA 112 +# define FIPS_F_FIPS_DRBG_BYTES 113 +# define FIPS_F_FIPS_DRBG_CHECK 114 +# define FIPS_F_FIPS_DRBG_ERROR_CHECK 115 +# define FIPS_F_FIPS_DRBG_GENERATE 116 +# define FIPS_F_FIPS_DRBG_INIT 117 +# define FIPS_F_FIPS_DRBG_INSTANTIATE 118 +# define FIPS_F_FIPS_DRBG_NEW 119 +# define FIPS_F_FIPS_DRBG_SINGLE_KAT 120 +# define FIPS_F_FIPS_GET_ENTROPY 121 +# define FIPS_F_FIPS_MODULE_MODE_SET 122 +# define FIPS_F_FIPS_PKEY_SIGNATURE_TEST 123 +# define FIPS_F_FIPS_RAND_BYTES 124 +# define FIPS_F_FIPS_RAND_SEED 125 +# define FIPS_F_FIPS_RAND_SET_METHOD 126 +# define FIPS_F_FIPS_RAND_STATUS 127 +# define FIPS_F_FIPS_RSA_BUILTIN_KEYGEN 128 +# define FIPS_F_FIPS_SELFTEST_AES 129 +# define FIPS_F_FIPS_SELFTEST_AES_CCM 130 +# define FIPS_F_FIPS_SELFTEST_AES_GCM 131 +# define FIPS_F_FIPS_SELFTEST_AES_XTS 132 +# define FIPS_F_FIPS_SELFTEST_CMAC 133 +# define FIPS_F_FIPS_SELFTEST_DES 134 +# define FIPS_F_FIPS_SELFTEST_ECDSA 135 +# define FIPS_F_FIPS_SELFTEST_HKDF 136 +# define FIPS_F_FIPS_SELFTEST_HMAC 137 +# define FIPS_F_FIPS_SELFTEST_PBKDF2 138 +# define FIPS_F_FIPS_SELFTEST_SHA1 139 +# define FIPS_F_FIPS_SELFTEST_SHA2 140 +# define FIPS_F_FIPS_SELFTEST_SHA3 141 +# define FIPS_F_FIPS_SELFTEST_SSH 142 +# define FIPS_F_FIPS_SELFTEST_TLS 143 +# define FIPS_F_OSSL_ECDH_COMPUTE_KEY 144 +# define FIPS_F_RSA_OSSL_PRIVATE_DECRYPT 145 +# define FIPS_F_RSA_OSSL_PRIVATE_ENCRYPT 146 +# define FIPS_F_RSA_OSSL_PUBLIC_DECRYPT 147 +# define FIPS_F_RSA_OSSL_PUBLIC_ENCRYPT 148 + +/* + * FIPS reason codes. + */ +# define FIPS_R_ADDITIONAL_INPUT_ERROR_UNDETECTED 100 +# define FIPS_R_ADDITIONAL_INPUT_TOO_LONG 101 +# define FIPS_R_ALREADY_INSTANTIATED 102 +# define FIPS_R_DRBG_NOT_INITIALISED 103 +# define FIPS_R_ENTROPY_ERROR_UNDETECTED 104 +# define FIPS_R_ENTROPY_NOT_REQUESTED_FOR_RESEED 105 +# define FIPS_R_ENTROPY_SOURCE_STUCK 106 +# define FIPS_R_ERROR_INITIALISING_DRBG 107 +# define FIPS_R_ERROR_INSTANTIATING_DRBG 108 +# define FIPS_R_ERROR_RETRIEVING_ADDITIONAL_INPUT 109 +# define FIPS_R_ERROR_RETRIEVING_ENTROPY 110 +# define FIPS_R_ERROR_RETRIEVING_NONCE 111 +# define FIPS_R_FINGERPRINT_DOES_NOT_MATCH 112 +# define FIPS_R_FIPS_MODE_ALREADY_SET 113 +# define FIPS_R_FIPS_SELFTEST_FAILED 114 +# define FIPS_R_FUNCTION_ERROR 115 +# define FIPS_R_GENERATE_ERROR 116 +# define FIPS_R_GENERATE_ERROR_UNDETECTED 117 +# define FIPS_R_INSTANTIATE_ERROR 118 +# define FIPS_R_INVALID_KEY_LENGTH 119 +# define FIPS_R_IN_ERROR_STATE 120 +# define FIPS_R_KEY_TOO_SHORT 121 +# define FIPS_R_NONCE_ERROR_UNDETECTED 122 +# define FIPS_R_NON_FIPS_METHOD 123 +# define FIPS_R_NOPR_TEST1_FAILURE 124 +# define FIPS_R_NOPR_TEST2_FAILURE 125 +# define FIPS_R_NOT_INSTANTIATED 126 +# define FIPS_R_PAIRWISE_TEST_FAILED 127 +# define FIPS_R_PERSONALISATION_ERROR_UNDETECTED 128 +# define FIPS_R_PERSONALISATION_STRING_TOO_LONG 129 +# define FIPS_R_PR_TEST1_FAILURE 130 +# define FIPS_R_PR_TEST2_FAILURE 131 +# define FIPS_R_REQUEST_LENGTH_ERROR_UNDETECTED 132 +# define FIPS_R_REQUEST_TOO_LARGE_FOR_DRBG 133 +# define FIPS_R_RESEED_COUNTER_ERROR 134 +# define FIPS_R_RESEED_ERROR 135 +# define FIPS_R_SELFTEST_FAILED 136 +# define FIPS_R_SELFTEST_FAILURE 137 +# define FIPS_R_TEST_FAILURE 138 +# define FIPS_R_UNINSTANTIATE_ERROR 139 +# define FIPS_R_UNINSTANTIATE_ZEROISE_ERROR 140 +# define FIPS_R_UNSUPPORTED_DRBG_TYPE 141 +# define FIPS_R_UNSUPPORTED_PLATFORM 142 + +#endif --- /dev/null +++ b/include/internal/fips_sli_local.h @@ -0,0 +1,96 @@ +#ifndef FIPS_SLI_LOCAL_H_INCLUDED +#define FIPS_SLI_LOCAL_H_INCLUDED + +#include +#include +#include + +/* status for SLI */ +typedef enum fips_status_e { + FIPS_UNSET, + FIPS_APPROVED, + FIPS_NONAPPROVED, + FIPS_ERROR, +} FIPS_STATUS; + + +void fips_sli_approve_EVP_KDF_CTX(EVP_KDF_CTX *ctx); +void fips_sli_approve_EVP_MD_CTX(EVP_MD_CTX *ctx); +void fips_sli_approve_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx); +void fips_sli_approve_HMAC_CTX(HMAC_CTX *ctx); + +/* Unused: + * void fips_sli_approve_EVP_CIPHER_CTX(EVP_CIPHER_CTX *ctx); + */ +void fips_sli_disapprove_EVP_CIPHER_CTX(EVP_CIPHER_CTX *ctx); +void fips_sli_disapprove_EVP_KDF_CTX(EVP_KDF_CTX *ctx); +void fips_sli_disapprove_EVP_MD_CTX(EVP_MD_CTX *ctx); +void fips_sli_disapprove_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx); +void fips_sli_disapprove_HMAC_CTX(HMAC_CTX *ctx); + +//void fips_sli_error_EVP_KDF_CTX(EVP_KDF_CTX *ctx); /* unused */ +//void fips_sli_error_HMAC_CTX(HMAC_CTX *ctx); +//void fips_sli_error_EVP_CIPHER_CTX(EVP_CIPHER_CTX *ctx); +void fips_sli_error_EVP_MD_CTX(EVP_MD_CTX *ctx); +void fips_sli_error_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx); + +FIPS_STATUS fips_sli_fsm_transition(FIPS_STATUS state, FIPS_STATUS input); + +#define fips_sli_define_basic_for(LNKG, FNNAME, CTXTYPE) \ +static void fips_sli_fsm_##FNNAME(CTXTYPE *ctx, FIPS_STATUS input) { \ + if (ctx == NULL) \ + return; \ + ctx->sli = fips_sli_fsm_transition(ctx->sli, input); \ +} \ +LNKG int fips_sli_is_approved_##FNNAME(const CTXTYPE *ctx) { \ + if (ctx == NULL) \ + return 0; \ + return (ctx->sli == FIPS_UNSET) || (ctx->sli == FIPS_APPROVED); \ +} + +#define fips_sli_define_for(CTXTYPE) \ +fips_sli_define_basic_for(, CTXTYPE, CTXTYPE) \ +void fips_sli_approve_##CTXTYPE(CTXTYPE *ctx) { \ + fips_sli_fsm_##CTXTYPE(ctx, FIPS_APPROVED); \ +} \ +void fips_sli_disapprove_##CTXTYPE(CTXTYPE *ctx) { \ + fips_sli_fsm_##CTXTYPE(ctx, FIPS_NONAPPROVED); \ +} \ +void fips_sli_error_##CTXTYPE(CTXTYPE *ctx) { \ + fips_sli_fsm_##CTXTYPE(ctx, FIPS_ERROR); \ +} + +void fips_sli_check_hash_siggen_EVP_MD_CTX(EVP_MD_CTX * ctx, const EVP_MD * md); +void fips_sli_check_hash_sigver_EVP_MD_CTX(EVP_MD_CTX * ctx, const EVP_MD * md); +void fips_sli_check_hash_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const EVP_MD * md); +void fips_sli_check_hash_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const EVP_MD * md); +void fips_sli_check_hash_mac_HMAC_CTX(HMAC_CTX * ctx, const EVP_MD * md); + +FIPS_STATUS fips_sli_get_hash_status_sshkdf(const EVP_MD * md); +FIPS_STATUS fips_sli_get_hash_status_pbkdf2(const EVP_MD * md); +FIPS_STATUS fips_sli_get_hash_status_kdf_tls1_prf(const EVP_MD * md); +FIPS_STATUS fips_sli_get_kdf_keylen_status(size_t keylen_bytes); + +/* Check if used curve is okay for and in this context */ +void fips_sli_check_curve_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const EC_GROUP *group); +void fips_sli_check_curve_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const EC_GROUP *group); + +void fips_sli_check_key_ec_keygen_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const EC_KEY *ec); +void fips_sli_check_key_rsa_keygen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa); +void fips_sli_check_key_rsa_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa); +void fips_sli_check_key_rsa_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa); +void fips_sli_check_key_rsa_enc_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa); +void fips_sli_check_key_rsa_dec_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const RSA * rsa); +void fips_sli_check_key_dsa_siggen_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const DSA * dsa); +void fips_sli_check_key_dsa_sigver_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, const DSA * dsa); + +void fips_sli_check_key_dh_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const DH *dh); +void fips_sli_check_key_ecdh_EVP_PKEY_CTX(EVP_PKEY_CTX *ctx, const EC_KEY *ecdh); + +void fips_sli_check_padding_rsa_enc_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, int pad_mode); +void fips_sli_check_padding_rsa_dec_EVP_PKEY_CTX(EVP_PKEY_CTX * ctx, int pad_mode); + +FIPS_STATUS EVP_CIPHER_get_fips_status(const EVP_CIPHER *cipher); +void fips_sli_check_cipher_EVP_CIPHER_CTX(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher); + +#endif /* FIPS_SLI_LOCAL_H_INCLUDED */ --- /dev/null +++ b/include/openssl/fips_sli.h @@ -0,0 +1,32 @@ +#ifndef FIPS_SLI_H_INCLUDED +#define FIPS_SLI_H_INCLUDED + +#include +#include +# ifdef __cplusplus +extern "C" { +# endif + +/* Interface for consumers to check if their usage of the services offered by + * this ctx was approved */ +int fips_sli_is_approved_EVP_CIPHER_CTX(const EVP_CIPHER_CTX *ctx); +int fips_sli_is_approved_EVP_KDF_CTX(const EVP_KDF_CTX *ctx); +int fips_sli_is_approved_EVP_MD_CTX(const EVP_MD_CTX *ctx); +int fips_sli_is_approved_EVP_PKEY_CTX(const EVP_PKEY_CTX *ctx); +int fips_sli_is_approved_CMAC_CTX(const CMAC_CTX *ctx); +int fips_sli_is_approved_HMAC_CTX(const HMAC_CTX *ctx); + +int fips_sli_SHA1_is_approved(const unsigned char *d, size_t n, unsigned char *md); +int fips_sli_HMAC_is_approved(const EVP_MD *evp_md, const void *key, int key_len, + const unsigned char *d, size_t n, unsigned char *md, + unsigned int *md_len); +int fips_sli_PKCS5_PBKDF2_HMAC_is_approved(const char *pass, int passlen, + const unsigned char *salt, int saltlen, int iter, + const EVP_MD *digest, int keylen, unsigned char *out); +int fips_sli_RAND_bytes_is_approved(unsigned char *buf, int num); +int fips_sli_RAND_priv_bytes_is_approved(unsigned char *buf, int num); + +# ifdef __cplusplus +} +# endif +#endif // FIPS_SLI_H_INCLUDED --- a/test/build.info +++ b/test/build.info @@ -52,7 +52,7 @@ INCLUDE_MAIN___test_libtestutil_OLB = /I recordlentest drbgtest drbg_cavs_test sslbuffertest \ time_offset_test pemtest ssl_cert_table_internal_test ciphername_test \ servername_test ocspapitest rsa_mp_test fatalerrtest tls13ccstest \ - sysdefaulttest errtest ssl_ctx_test gosttest + sysdefaulttest errtest ssl_ctx_test gosttest fips_slitest SOURCE[versions]=versions.c INCLUDE[versions]=../include @@ -575,6 +575,10 @@ INCLUDE_MAIN___test_libtestutil_OLB = /I INCLUDE[gosttest]=../include .. DEPEND[gosttest]=../libcrypto ../libssl libtestutil.a + SOURCE[fips_slitest]=fips_slitest.c fips_slitest_helper.c + INCLUDE[fips_slitest]=../include + DEPEND[fips_slitest]=../libcrypto libtestutil.a + SOURCE[ssl_ctx_test]=ssl_ctx_test.c INCLUDE[ssl_ctx_test]=../include DEPEND[ssl_ctx_test]=../libcrypto ../libssl libtestutil.a --- /dev/null +++ b/test/fips_slitest.c @@ -0,0 +1,659 @@ +#include +#include +#include +#include /* To see if OPENSSL_NO_EC is defined */ +#ifndef OPENSSL_NO_EC +# include +#endif +#ifndef OPENSSL_NO_RSA +# include +#endif +#include + +#include "testutil.h" +#include "fips_slitest_helper.h" + +static int test_sli_noop(void) { + int res = 0; /* 0 means test failure */ + EVP_MD_CTX* ctx = NULL; + if (!TEST_ptr(ctx = EVP_MD_CTX_new())) + goto end; + if (!TEST_true(fips_sli_is_approved_EVP_MD_CTX(ctx))) + goto end; + if (!TEST_false(fips_sli_is_approved_EVP_MD_CTX(NULL))) + goto end; + res = 1; /* test case successful */ +end: + EVP_MD_CTX_free(ctx); + return res; +} + +static int cmac_aes_cbc(void) { + int success = 0; + CMAC_CTX *ctx = NULL; + size_t maclen = 0; + + if (!TEST_ptr(ctx = CMAC_CTX_new())) + return 0; + if (!TEST_true(CMAC_Init(ctx, get_key_16(), 16, EVP_aes_128_cbc(), NULL)) + || !TEST_true(CMAC_Final(ctx, NULL, &maclen)) + ) { + CMAC_CTX_free(ctx); + return 0; + } + + uint8_t mac[maclen]; + + if (!TEST_true(maclen > 0) + || !TEST_true(CMAC_Update(ctx, get_msg_16(), 16)) + || !TEST_true(CMAC_Final(ctx, mac, &maclen)) + || !TEST_true(fips_sli_is_approved_CMAC_CTX(ctx)) + ) + goto end; + success = 1; +end: + CMAC_CTX_free(ctx); + return success; +} + +static int cmac_no_des(void) { + int success = 0; + CMAC_CTX *ctx = NULL; + size_t maclen = 0; + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) { + TEST_note("Skipping test because DES is disabled in FIPS mode"); + return 1; + } +#endif + + if (!TEST_ptr(ctx = CMAC_CTX_new())) + return 0; + if (!TEST_true(CMAC_Init(ctx, get_key_16(), 16, EVP_des_ede_cbc(), NULL)) + || !TEST_true(CMAC_Final(ctx, NULL, &maclen)) + ) { + CMAC_CTX_free(ctx); + return 0; + } + + uint8_t mac[maclen]; + + if (!TEST_true(maclen > 0) + || !TEST_int_eq(16, EVP_CIPHER_key_length(EVP_des_ede_cbc())) + || !TEST_true(CMAC_Update(ctx, get_msg_16(), 16)) + || !TEST_true(CMAC_Final(ctx, mac, &maclen)) + || !TEST_false(fips_sli_is_approved_CMAC_CTX(ctx)) + ) + goto end; + success = 1; +end: + CMAC_CTX_free(ctx); + return success; +} + +typedef struct { + int fips_approved; + int cipher_nid; +} SLI_CMAC_TEST; + +static const SLI_CMAC_TEST cmac_tests[] = { + // Cipher must fit to key length of 32 B + {1, NID_aes_256_cbc}, + {0, NID_camellia_256_cbc}, +}; +static const size_t cmac_tests_len = sizeof(cmac_tests) / sizeof(cmac_tests[0]); + +static int cmac_via_md_ctx(int cmac_test_index) { + int success = 0; + EVP_MD_CTX *ctx = NULL; + const EVP_MD* md = NULL; + unsigned char* mac = NULL; + size_t maclen = 0; + + EVP_PKEY *key = NULL; + +#ifdef OPENSSL_FIPS + if (FIPS_mode() + && cmac_tests[cmac_test_index].cipher_nid == NID_camellia_256_cbc) { + TEST_note("Skipping test because Camellia is disabled in FIPS mode"); + success = 1; + goto end; + } +#endif + + if (!TEST_true(get_cmac_key(cmac_tests[cmac_test_index].cipher_nid, + &key) == 1)) + goto end; + if (!TEST_ptr(ctx = EVP_MD_CTX_new())) + goto end; + // hash doesn't matter here but must be present... + if (!TEST_true(EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))) + goto end; + if (!TEST_true(EVP_DigestSignInit(ctx, NULL, md, NULL, key))) + goto end; + if (!TEST_true(EVP_DigestSignUpdate(ctx, get_msg_16(), 16))) + goto end; + size_t req = 0; + if (!TEST_true(EVP_DigestSignFinal(ctx, NULL, &req))) + goto end; + if (!TEST_true(req > 0)) + goto end; + if (!TEST_ptr(mac = OPENSSL_malloc(req))) + goto end; + maclen = req; + if (!TEST_true(EVP_DigestSignFinal(ctx, mac, &maclen))) + goto end; + if (cmac_tests[cmac_test_index].fips_approved) { + if (!TEST_true(fips_sli_is_approved_EVP_MD_CTX(ctx))) + goto end; + } else { + if (!TEST_false(fips_sli_is_approved_EVP_MD_CTX(ctx))) + goto end; + } + + success = 1; +end: + if (mac) + OPENSSL_free(mac); + EVP_MD_CTX_free(ctx); + return success; +} + +#ifndef OPENSSL_NO_EC +typedef struct { + int fips_approved; + int curve_nid; +} SLI_ECDSA_TEST; + +static const SLI_ECDSA_TEST ecdsa_tests[] = { + {0, NID_secp112r2}, + {1, NID_secp521r1}, +#ifndef OPENSSL_NO_EC2M + {0, NID_sect163r1}, +#endif + {0, NID_brainpoolP512r1}, +}; +static const size_t ecdsa_tests_len = sizeof(ecdsa_tests) / sizeof(ecdsa_tests[0]); + +/* Adapted from openssl/test/ecdsatest.c */ +static int ecdsa_via_EVP_DigestSign(int ecdsa_test_index) { + unsigned char *sig = NULL; + EC_KEY *eckey = NULL; + EVP_PKEY *pkey = NULL; + EVP_MD_CTX *mctx = NULL; + size_t sig_len; + const int nid = ecdsa_tests[ecdsa_test_index].curve_nid; + int success = 0; + const uint8_t* tbs = get_msg_128(); + + TEST_note("testing ECDSA for curve %s", OBJ_nid2sn(nid)); + + if (!TEST_ptr(mctx = EVP_MD_CTX_new()) + || !TEST_ptr(eckey = EC_KEY_new_by_curve_name(nid)) + || !TEST_true(EC_KEY_generate_key(eckey)) + || !TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_true(EVP_PKEY_assign_EC_KEY(pkey, eckey))) + goto err; + + sig_len = ECDSA_size(eckey); + + if (!TEST_ptr(sig = OPENSSL_malloc(sig_len)) + /* create a signature */ + || !TEST_true(EVP_DigestSignInit(mctx, NULL, NULL, NULL, pkey)) + || !TEST_true(EVP_DigestSign(mctx, sig, &sig_len, tbs, sizeof(tbs))) + || !TEST_int_le(sig_len, ECDSA_size(eckey))) + goto err; + + // SLI shows proper status for sign() + if (ecdsa_tests[ecdsa_test_index].fips_approved) { + if (!TEST_true(fips_sli_is_approved_EVP_MD_CTX(mctx))) + goto err; + } else { + if (!TEST_false(fips_sli_is_approved_EVP_MD_CTX(mctx))) + goto err; + } + + /* positive test, verify with correct key, 1 return */ + if (!TEST_true(EVP_MD_CTX_reset(mctx)) + || !TEST_true(EVP_DigestVerifyInit(mctx, NULL, NULL, NULL, pkey))) + goto err; + + /* a resetted and initialised ctx should be okay again */ + if (!TEST_true(fips_sli_is_approved_EVP_MD_CTX(mctx))) + goto err; + + if (!TEST_int_eq(EVP_DigestVerify(mctx, sig, sig_len, tbs, sizeof(tbs)), 1)) + goto err; + + // SLI shows proper status for verify() + if (ecdsa_tests[ecdsa_test_index].fips_approved) { + if (!TEST_true(fips_sli_is_approved_EVP_MD_CTX(mctx))) + goto err; + } else { + if (!TEST_false(fips_sli_is_approved_EVP_MD_CTX(mctx))) + goto err; + } + + success = 1; +err: + EVP_PKEY_free(pkey); + if (mctx != NULL) + EVP_MD_CTX_free(mctx); + if (sig != NULL) + OPENSSL_free(sig); + return success; +} +#endif + +typedef struct { + int fips_approved; + int cipher_nid; +} SLI_CIPHER_TEST; + +static const SLI_CIPHER_TEST cipher_tests[] = { + {1, NID_aes_128_cfb128}, + {1, NID_aes_256_gcm}, + {0, NID_des_ede3_cbc}, + {0, NID_des_ede3_cfb8}, + {0, NID_des_ofb64}, + {0, NID_des_ede_ecb}, + {0, NID_des_ede_ofb64}, + {0, NID_idea_cbc}, +}; +static const size_t cipher_tests_len = sizeof(cipher_tests) / sizeof(cipher_tests[0]); + +static size_t get_ciphertext_len(size_t plaintextlen, const EVP_CIPHER *cipher) { + /* maximum value according to manpage */ + return plaintextlen + EVP_CIPHER_block_size(cipher); +} + +static int cipher(int cipher_test_index) { + int success = 0; + unsigned char *key = NULL, *iv = NULL, *ctext = NULL; + int ctext_written_len = 0; + const EVP_CIPHER *cipher = NULL; + EVP_CIPHER_CTX *ctx = NULL; + const uint8_t* const ptext = get_msg_16(); + const size_t ptext_len = 16; + const int cipher_nid = cipher_tests[cipher_test_index].cipher_nid; + + TEST_note("testing SLI for cipher %s", OBJ_nid2sn(cipher_nid)); + +#ifdef OPENSSL_NO_IDEA + switch (cipher_nid) { + case NID_idea_cbc: + TEST_note("Skipping test since IDEA is not supported in this build"); + success = 1; + goto end; + } +#endif + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) { + switch (cipher_nid) { + case NID_des_ofb64: + case NID_des_ede_ecb: + case NID_des_ede_ofb64: + case NID_idea_cbc: + TEST_note("Skipping test since DES/IDEA are disabled in FIPS mode"); + success = 1; + goto end; + } + } +#endif + + if (!TEST_ptr(cipher = EVP_get_cipherbynid(cipher_nid))) { + goto end; + } + + const size_t key_len = EVP_CIPHER_key_length(cipher); + const size_t iv_len = EVP_CIPHER_iv_length(cipher); + TEST_note("have keylen = %zd, ivlen = %zd", key_len, iv_len); + + if (!TEST_ptr(key = OPENSSL_malloc(key_len)) + || !TEST_ptr(ctext = OPENSSL_malloc(get_ciphertext_len(ptext_len, cipher))) + || !TEST_true(RAND_bytes(key, key_len) == 1)) + goto end; + + if (iv_len != 0) { + if (!TEST_ptr(iv = OPENSSL_malloc(iv_len)) + || !TEST_true(RAND_bytes(iv, iv_len) == 1)) + goto end; + } + + int tmp_len = 0; + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv) == 1) + || !TEST_true(EVP_EncryptUpdate(ctx, ctext, &ctext_written_len, ptext, ptext_len) == 1) + || !TEST_true(ctext_written_len <= get_ciphertext_len(ptext_len, cipher)) + || !TEST_true(EVP_EncryptFinal_ex(ctx, ctext + ctext_written_len, &tmp_len) == 1)) + goto end; + + if (!TEST_true(ctext_written_len + tmp_len <= get_ciphertext_len(ptext_len, cipher))) + goto end; + + if (cipher_tests[cipher_test_index].fips_approved) { + if (!TEST_true(fips_sli_is_approved_EVP_CIPHER_CTX(ctx))) + goto end; + } else { + if (!TEST_false(fips_sli_is_approved_EVP_CIPHER_CTX(ctx))) + goto end; + } + + success = 1; +end: + EVP_CIPHER_CTX_free(ctx); + if (key != NULL) + OPENSSL_free(key); + if (iv != NULL) + OPENSSL_free(iv); + if (ctext != NULL) + OPENSSL_free(ctext); + return success; +} + +#ifndef OPENSSL_NO_RSA +typedef struct { + int fips_approved; + int cipher_nid; + uint8_t rsa_key_id; +} SLI_SEALENV_TEST; + +static const SLI_SEALENV_TEST sealenv_tests[] = { + // consider RSA enc/dec as always disapproved + {0, NID_aes_128_cfb128, 0}, + {0, NID_aes_256_gcm, 1}, + {0, NID_idea_cbc, 0}, + {0, NID_des_ede3_cbc, 2}, + {0, NID_aes_128_ecb, 0}, + {0, NID_aes_128_ecb, 3}, + {0, NID_aes_128_ccm, 3}, +}; +static const size_t sealenv_tests_len = sizeof(sealenv_tests) / sizeof(sealenv_tests[0]); + +/* Asymmetric enc/dec */ +static int sealenv(int sealenv_test_index) { + int success = 0; + RSA *rsa_pkey = RSA_new(); + EVP_PKEY *pkey = NULL; + const EVP_CIPHER *cipher = NULL; + const int cipher_nid = sealenv_tests[sealenv_test_index].cipher_nid; + EVP_CIPHER_CTX *ctx = NULL; + + uint8_t* enc_sym_key = NULL; + int enc_sym_key_len = 0; + + const uint8_t* const ptext = get_msg_128(); + const size_t ptext_len = 128; + unsigned char *iv = NULL, *ctext = NULL; + size_t ctext_len = 0; + int ctext_written_len = 0; + + switch (sealenv_tests[sealenv_test_index].rsa_key_id) { + case 0: + get_rsa_key1(rsa_pkey); + break; + case 1: + get_rsa_key2(rsa_pkey); + break; + case 2: + get_rsa_key3(rsa_pkey); + break; + case 3: + if (!TEST_int_eq(256, get_rsa_key2048p3(rsa_pkey))) + goto end; + break; + default: + goto end; + } + + TEST_note("RSA enc with key #%d, cipher %s", + sealenv_tests[sealenv_test_index].rsa_key_id, + OBJ_nid2sn(cipher_nid)); + +#ifdef OPENSSL_NO_IDEA + switch (cipher_nid) { + case NID_idea_cbc: + TEST_note("Skipping test since IDEA is not supported in this build"); + success = 1; + goto end; + } +#endif + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) { + switch (cipher_nid) { + case NID_idea_cbc: + TEST_note("Skipping test since IDEA is disabled in FIPS mode"); + success = 1; + goto end; + } + } +#endif + + if (!TEST_ptr(pkey = EVP_PKEY_new()) + || !TEST_true(EVP_PKEY_assign_RSA(pkey, rsa_pkey)) + || !TEST_ptr(cipher = EVP_get_cipherbynid(cipher_nid)) + || !TEST_ptr(enc_sym_key = OPENSSL_malloc(EVP_PKEY_size(pkey))) + || !TEST_ptr(ctext = OPENSSL_malloc(get_ciphertext_len(ptext_len, cipher))) + ) + goto end; + + const size_t iv_len = EVP_CIPHER_iv_length(cipher); + if (iv_len != 0) { + if (!TEST_ptr(iv = OPENSSL_malloc(iv_len))) + goto end; + } + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_true(1 == EVP_SealInit(ctx, cipher, &enc_sym_key, &enc_sym_key_len, iv, &pkey, 1)) + || !TEST_true(enc_sym_key_len > 0 && enc_sym_key_len <= EVP_PKEY_size(pkey)) + || !TEST_true(1 == EVP_SealUpdate(ctx, ctext, &ctext_written_len, ptext, ptext_len)) + ) + goto end; + ctext_len += ctext_written_len; + if (!TEST_true(1 == EVP_SealFinal(ctx, ctext + ctext_len, &ctext_written_len))) + goto end; + ctext_len += ctext_written_len; + if (!TEST_true(ctext_len <= get_ciphertext_len(ptext_len, cipher))) + goto end; + + if (sealenv_tests[sealenv_test_index].fips_approved) { + if (!TEST_true(fips_sli_is_approved_EVP_CIPHER_CTX(ctx))) + goto end; + } else { + if (!TEST_false(fips_sli_is_approved_EVP_CIPHER_CTX(ctx))) + goto end; + } + + success = 1; +end: + EVP_PKEY_free(pkey); /* also frees rsa_pkey */ + if (ctx != NULL) + EVP_CIPHER_CTX_free(ctx); + if (enc_sym_key != NULL) + OPENSSL_free(enc_sym_key); + if (iv != NULL) + OPENSSL_free(iv); + if (ctext != NULL) + OPENSSL_free(ctext); + return success; +} +#endif + +typedef struct { + int fips_approved; + int iterations; + int nid_digest; + const uint8_t key_expected[32]; // length has to be 32 +} SLI_PBKDF2_TEST; + +static const SLI_PBKDF2_TEST pbkdf2_tests[] = { + { + 1, 4200, NID_sha256, { + 0xE7, 0xBE, 0x37, 0x75, 0x9D, 0x53, 0x3E, 0x5A, 0x06, 0x20, 0xC9, 0xA5, 0x3A, 0x8D, 0xA2, 0x9E, + 0x9C, 0x27, 0xDF, 0x26, 0x24, 0xAB, 0xD8, 0x8E, 0x56, 0xE5, 0xB9, 0xF5, 0xA0, 0xD6, 0xD5, 0xEE + } + }, + { + 1, 1347, NID_sha256, { + 0xFB, 0xBB, 0xEC, 0x28, 0x5B, 0x48, 0xE7, 0xC2, 0x54, 0x4E, 0x65, 0x0F, 0x1E, 0xC8, 0xB5, 0x1C, + 0xF5, 0xAD, 0xAE, 0x2A, 0x21, 0x56, 0x94, 0xD2, 0xE1, 0xB7, 0xC8, 0x7D, 0x7A, 0x0D, 0x63, 0x86 + } + }, + { + 1, 4200, NID_sha1, { + 0x45, 0x96, 0x78, 0xF3, 0x92, 0x74, 0xAC, 0x5B, 0x1F, 0x2B, 0xD3, 0x75, 0x1A, 0xBA, 0x5D, 0xBE, + 0xF2, 0xDE, 0xE9, 0x88, 0x16, 0x4B, 0x0B, 0x84, 0x94, 0xD9, 0xC2, 0x2D, 0xC1, 0xB9, 0xB0, 0x8A + } + }, + { + 1, 4200, NID_sha3_512, { + 0x1E, 0x77, 0xC8, 0x28, 0x9A, 0x79, 0x2E, 0x25, 0x85, 0x8D, 0x73, 0xB3, 0x0D, 0xA1, 0x26, 0x65, + 0xC0, 0x04, 0x7D, 0x91, 0xB6, 0x5F, 0x89, 0x5E, 0x01, 0x82, 0x23, 0x35, 0x19, 0x2E, 0x5C, 0x09 + } + }, + { + 0, 1347, NID_md5, { + 0xC2, 0x78, 0x16, 0xDC, 0xD1, 0xC5, 0x71, 0xBD, 0x4A, 0x06, 0x2B, 0x38, 0x50, 0xE7, 0x4E, 0xC2, + 0x0E, 0x74, 0x9D, 0xB1, 0x59, 0xA8, 0xFF, 0x11, 0x24, 0x68, 0xD0, 0xCF, 0x69, 0xE5, 0x30, 0x36 + } + } +}; +static const size_t pbkdf2_tests_len = sizeof(pbkdf2_tests) / sizeof(pbkdf2_tests[0]); + +static int test_PKCS5_PBKDF2_HMAC(int pbkdf2_tests_idx) { + int success = 0; + const char password[] = "password"; + const unsigned char salt[] = {'s', 'a', 'l', 't'}; + const size_t password_len = sizeof(password) / sizeof(password[0]); + const size_t salt_len = sizeof(salt) / sizeof(salt[0]); + + int iter = pbkdf2_tests[pbkdf2_tests_idx].iterations; + const EVP_MD *digest = EVP_get_digestbynid(pbkdf2_tests[pbkdf2_tests_idx].nid_digest); + const size_t key_len = 32; + const size_t key_expected_len = key_len; + uint8_t* key = NULL; + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) { + switch (pbkdf2_tests[pbkdf2_tests_idx].nid_digest) { + case NID_md5: + TEST_note("Skipping test since MD5 is disabled in FIPS mode"); + success = 1; + goto end; + } + } +#endif + + if (!TEST_ptr(key = OPENSSL_malloc(key_len)) + || !TEST_true(1 == PKCS5_PBKDF2_HMAC(password, password_len, salt, salt_len, + iter, digest, + key_len, key)) + || !TEST_true(fips_sli_PKCS5_PBKDF2_HMAC_is_approved(password, password_len, + salt, salt_len, + iter, digest, + key_len, key) == pbkdf2_tests[pbkdf2_tests_idx].fips_approved) + || !TEST_mem_eq(key, key_len, pbkdf2_tests[pbkdf2_tests_idx].key_expected, key_expected_len)) + goto end; + success = 1; +end: + return success; +} + +typedef struct { + int fips_approved; + int digest_nid; +} SLI_SSHKDF_TEST; + +static const SLI_SSHKDF_TEST sshkdf_tests[] = { + {1, NID_sha256}, + {0, NID_md5}, +}; +static const size_t sshkdf_tests_len = sizeof(sshkdf_tests) / sizeof(sshkdf_tests[0]); + +static int sshkdf(int sshkdf_test_idx) { + int success = 0; + const uint8_t *key = get_key_32(); + const uint8_t *xcghash = get_msg_128(); + const uint8_t *session_id = get_key_32(); + uint8_t kdfout[16]; + size_t kdfoutlen = sizeof(kdfout) / sizeof(kdfout[0]); + const int digest_nid = sshkdf_tests[sshkdf_test_idx].digest_nid; + EVP_KDF_CTX *ctx = NULL; + + TEST_note("SSHKDF with %s", OBJ_nid2sn(digest_nid)); + +#ifdef OPENSSL_FIPS + if (FIPS_mode()) { + switch (digest_nid) { + case NID_md5: + TEST_note("Skipping test since MD5 is disabled in FIPS mode"); + success = 1; + goto end; + } + } +#endif + + if (!TEST_ptr(ctx = EVP_KDF_CTX_new_id(NID_sshkdf)) + || !TEST_true(EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_MD, EVP_get_digestbynid(digest_nid)) == 1) + || !TEST_true(EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_KEY, key, 32) == 1) + || !TEST_true(EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_SESSION_ID, session_id, 32) == 1) + || !TEST_true(EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_TYPE, EVP_KDF_SSHKDF_TYPE_ENCRYPTION_KEY_CLI_TO_SRV) == 1) + || !TEST_true(EVP_KDF_ctrl(ctx, EVP_KDF_CTRL_SET_SSHKDF_XCGHASH, xcghash, 128) == 1) + || !TEST_true(fips_sli_is_approved_EVP_KDF_CTX(ctx)) + || !TEST_true(EVP_KDF_derive(ctx, kdfout, kdfoutlen) == 1) + || !TEST_true(fips_sli_is_approved_EVP_KDF_CTX(ctx) == sshkdf_tests[sshkdf_test_idx].fips_approved) + ) + goto end; + + EVP_KDF_reset(ctx); + + if (!TEST_true(fips_sli_is_approved_EVP_KDF_CTX(ctx))) + goto end; + + success = 1; +end: + EVP_KDF_CTX_free(ctx); + return success; +} + +static int rand_bytes() { + int success = 0; + unsigned char r[1]; + size_t rlen = sizeof(r) / sizeof(r[0]); + if (!TEST_true(fips_sli_RAND_bytes_is_approved(r, rlen) == 1) + || !TEST_true(RAND_bytes(r, rlen) == 1) + || !TEST_true(fips_sli_RAND_priv_bytes_is_approved(r, rlen) == 1) + || !TEST_true(RAND_priv_bytes(r, rlen) == 1) + || !TEST_true(fips_sli_RAND_priv_bytes_is_approved(r, rlen) == 1) + ) + goto end; + success = 1; +end: + return success; +} + +int setup_tests(void) { + ADD_TEST(test_sli_noop); + ADD_TEST(cmac_aes_cbc); + ADD_TEST(cmac_no_des); + ADD_ALL_TESTS(cmac_via_md_ctx, cmac_tests_len); +#ifdef OPENSSL_NO_EC + TEST_note("Elliptic curves are disabled."); +#else + ADD_ALL_TESTS(ecdsa_via_EVP_DigestSign, ecdsa_tests_len); +#endif + ADD_ALL_TESTS(cipher, cipher_tests_len); +#ifdef OPENSSL_NO_RSA + TEST_note("RSA is disabled."); +#else + ADD_ALL_TESTS(sealenv, sealenv_tests_len); +#endif + ADD_ALL_TESTS(test_PKCS5_PBKDF2_HMAC, pbkdf2_tests_len); + ADD_ALL_TESTS(sshkdf, sshkdf_tests_len); + ADD_TEST(rand_bytes); + + return 1; /* success */ +} --- /dev/null +++ b/test/fips_slitest_helper.c @@ -0,0 +1,489 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "testutil.h" +#include "fips_slitest_helper.h" + +int make_hmac_keys(EVP_PKEY** skey, EVP_PKEY** vkey) { + byte hkey[EVP_MAX_MD_SIZE]; + + int result = -1; + + if (!skey || !vkey) + return -1; + + if (*skey != NULL) { + EVP_PKEY_free(*skey); + *skey = NULL; + } + + if (*vkey != NULL) { + EVP_PKEY_free(*vkey); + *vkey = NULL; + } + + do { + const EVP_MD* md = EVP_sha256(); + int size = EVP_MD_size(md); + assert(size >= 16); + if (!(size >= 16)) { + printf("EVP_MD_size failed, error 0x%lx\n", ERR_get_error()); + break; /* failed */ + } + + assert(size <= sizeof(hkey)); + if (!(size <= sizeof(hkey))) { + printf("EVP_MD_size is too large\n"); + break; /* failed */ + } + + /* Generate bytes */ + int rc = RAND_bytes(hkey, size); + assert(rc == 1); + if (rc != 1) { + printf("RAND_bytes failed, error 0x%lx\n", ERR_get_error()); + break; + } + + //print_it("HMAC key", hkey, size); + + *skey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, hkey, size); + assert(*skey != NULL); + if (*skey == NULL) { + printf("EVP_PKEY_new_mac_key 1st failed, error 0x%lx\n", ERR_get_error()); + break; + } + + *vkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, hkey, size); + assert(*vkey != NULL); + if (*vkey == NULL) { + printf("EVP_PKEY_new_mac_key 2nd failed, error 0x%lx\n", ERR_get_error()); + break; + } + + result = 0; + + } while (0); + + OPENSSL_cleanse(hkey, sizeof(hkey)); + + /* Convert to 0/1 result */ + return !!result; +} +static const uint8_t msg[16] = { 0x71, 0x50, 0x00, 0x00, + 0xc0, 0xff, 0xee, 0x00, + 0xde, 0xad, 0xbe, 0xef, + 0x01, 0x02, 0x03, 0x04 + }; +static const uint8_t msg128[128] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127 + }; + +static const uint8_t key16[16] = { 0xaa, 0xbb, 0xcc, 0xdd, + 0x01, 0x02, 0x03, 0x04, + 0xaa, 0xbb, 0xcc, 0xdd, + 0xde, 0xad, 0xbe, 0xef + }; +static const uint8_t key32[32] = { 0xaa, 0xbb, 0xcc, 0xdd, + 0x01, 0x02, 0x03, 0x04, + 0xaa, 0xbb, 0xcc, 0xdd, + 0xde, 0xad, 0xbe, 0xef, + 0xaa, 0xbb, 0xcc, 0xdd, + 0x01, 0x02, 0x03, 0x04, + 0xaa, 0xbb, 0xcc, 0xdd, + 0xde, 0xad, 0xbe, 0xef + }; + +const uint8_t* get_msg_16() { + return msg; +} + +const uint8_t* get_msg_128() { + return msg128; +} + +const uint8_t* get_key_16() { + return key16; +} + +const uint8_t* get_key_32() { + return key32; +} + +void print_it(const char* label, const byte* buff, size_t len) { + if (!buff || !len) + return; + + if (label) + printf("%s: ", label); + + for (size_t i = 0; i < len; ++i) + printf("%02X", buff[i]); + + printf("\n"); +} + +int get_cmac_key(int cipher_nid, EVP_PKEY** out) { + int success = 0; + EVP_PKEY_CTX *ctx = NULL; + const size_t key_len = 32; + const uint8_t *key = get_key_32(); + const EVP_CIPHER *cipher = EVP_get_cipherbynid(cipher_nid); + + if (!(ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_CMAC, NULL))) + goto end; + if (EVP_PKEY_keygen_init(ctx) != 1) + goto end; + if (cipher == NULL) + goto end; + if (EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_CIPHER, 0, (void*)cipher) <= 0) + goto end; + if (EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_KEYGEN, EVP_PKEY_CTRL_SET_MAC_KEY, key_len, (void*)key) <= 0) + goto end; + if (!EVP_PKEY_keygen(ctx, out)) + goto end; + + success = 1; +end: + + if (ctx) + EVP_PKEY_CTX_free(ctx); + return success; +} + +#ifndef OPENSSL_NO_RSA +# include + +/* adapted from openssl/test/rsa_test.c */ +# define SetKey \ + RSA_set0_key(key, \ + BN_bin2bn(n, sizeof(n)-1, NULL), \ + BN_bin2bn(e, sizeof(e)-1, NULL), \ + BN_bin2bn(d, sizeof(d)-1, NULL)); \ + RSA_set0_factors(key, \ + BN_bin2bn(p, sizeof(p)-1, NULL), \ + BN_bin2bn(q, sizeof(q)-1, NULL)); \ + RSA_set0_crt_params(key, \ + BN_bin2bn(dmp1, sizeof(dmp1)-1, NULL), \ + BN_bin2bn(dmq1, sizeof(dmq1)-1, NULL), \ + BN_bin2bn(iqmp, sizeof(iqmp)-1, NULL)); + +void get_rsa_key1(RSA *key) { + static unsigned char n[] = + "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F" + "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5" + "\xAD\xB3\x00\xA0\x28\x5E\x53\x01\x93\x0E\x0C\x70\xFB\x68\x76\x93" + "\x9C\xE6\x16\xCE\x62\x4A\x11\xE0\x08\x6D\x34\x1E\xBC\xAC\xA0\xA1" + "\xF5"; + + static unsigned char e[] = "\x11"; + + static unsigned char d[] = + "\x0A\x03\x37\x48\x62\x64\x87\x69\x5F\x5F\x30\xBC\x38\xB9\x8B\x44" + "\xC2\xCD\x2D\xFF\x43\x40\x98\xCD\x20\xD8\xA1\x38\xD0\x90\xBF\x64" + "\x79\x7C\x3F\xA7\xA2\xCD\xCB\x3C\xD1\xE0\xBD\xBA\x26\x54\xB4\xF9" + "\xDF\x8E\x8A\xE5\x9D\x73\x3D\x9F\x33\xB3\x01\x62\x4A\xFD\x1D\x51"; + + static unsigned char p[] = + "\x00\xD8\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5" + "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x12" + "\x0D"; + + static unsigned char q[] = + "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9" + "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D" + "\x89"; + + static unsigned char dmp1[] = + "\x59\x0B\x95\x72\xA2\xC2\xA9\xC4\x06\x05\x9D\xC2\xAB\x2F\x1D\xAF" + "\xEB\x7E\x8B\x4F\x10\xA7\x54\x9E\x8E\xED\xF5\xB4\xFC\xE0\x9E\x05"; + + static unsigned char dmq1[] = + "\x00\x8E\x3C\x05\x21\xFE\x15\xE0\xEA\x06\xA3\x6F\xF0\xF1\x0C\x99" + "\x52\xC3\x5B\x7A\x75\x14\xFD\x32\x38\xB8\x0A\xAD\x52\x98\x62\x8D" + "\x51"; + + static unsigned char iqmp[] = + "\x36\x3F\xF7\x18\x9D\xA8\xE9\x0B\x1D\x34\x1F\x71\xD0\x9B\x76\xA8" + "\xA9\x43\xE1\x1D\x10\xB2\x4D\x24\x9F\x2D\xEA\xFE\xF8\x0C\x18\x26"; + + SetKey; +} + +void get_rsa_key2(RSA *key) { + static unsigned char n[] = + "\x00\xA3\x07\x9A\x90\xDF\x0D\xFD\x72\xAC\x09\x0C\xCC\x2A\x78\xB8" + "\x74\x13\x13\x3E\x40\x75\x9C\x98\xFA\xF8\x20\x4F\x35\x8A\x0B\x26" + "\x3C\x67\x70\xE7\x83\xA9\x3B\x69\x71\xB7\x37\x79\xD2\x71\x7B\xE8" + "\x34\x77\xCF"; + + static unsigned char e[] = "\x3"; + + static unsigned char d[] = + "\x6C\xAF\xBC\x60\x94\xB3\xFE\x4C\x72\xB0\xB3\x32\xC6\xFB\x25\xA2" + "\xB7\x62\x29\x80\x4E\x68\x65\xFC\xA4\x5A\x74\xDF\x0F\x8F\xB8\x41" + "\x3B\x52\xC0\xD0\xE5\x3D\x9B\x59\x0F\xF1\x9B\xE7\x9F\x49\xDD\x21" + "\xE5\xEB"; + + static unsigned char p[] = + "\x00\xCF\x20\x35\x02\x8B\x9D\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92" + "\xEA\x0D\xA3\xB4\x32\x04\xB5\xCF\xCE\x91"; + + static unsigned char q[] = + "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9" + "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5F"; + + static unsigned char dmp1[] = + "\x00\x8A\x15\x78\xAC\x5D\x13\xAF\x10\x2B\x22\xB9\x99\xCD\x74\x61" + "\xF1\x5E\x6D\x22\xCC\x03\x23\xDF\xDF\x0B"; + + static unsigned char dmq1[] = + "\x00\x86\x55\x21\x4A\xC5\x4D\x8D\x4E\xCD\x61\x77\xF1\xC7\x36\x90" + "\xCE\x2A\x48\x2C\x8B\x05\x99\xCB\xE0\x3F"; + + static unsigned char iqmp[] = + "\x00\x83\xEF\xEF\xB8\xA9\xA4\x0D\x1D\xB6\xED\x98\xAD\x84\xED\x13" + "\x35\xDC\xC1\x08\xF3\x22\xD0\x57\xCF\x8D"; + + SetKey; +} + +void get_rsa_key3(RSA *key) { + static unsigned char n[] = + "\x00\xBB\xF8\x2F\x09\x06\x82\xCE\x9C\x23\x38\xAC\x2B\x9D\xA8\x71" + "\xF7\x36\x8D\x07\xEE\xD4\x10\x43\xA4\x40\xD6\xB6\xF0\x74\x54\xF5" + "\x1F\xB8\xDF\xBA\xAF\x03\x5C\x02\xAB\x61\xEA\x48\xCE\xEB\x6F\xCD" + "\x48\x76\xED\x52\x0D\x60\xE1\xEC\x46\x19\x71\x9D\x8A\x5B\x8B\x80" + "\x7F\xAF\xB8\xE0\xA3\xDF\xC7\x37\x72\x3E\xE6\xB4\xB7\xD9\x3A\x25" + "\x84\xEE\x6A\x64\x9D\x06\x09\x53\x74\x88\x34\xB2\x45\x45\x98\x39" + "\x4E\xE0\xAA\xB1\x2D\x7B\x61\xA5\x1F\x52\x7A\x9A\x41\xF6\xC1\x68" + "\x7F\xE2\x53\x72\x98\xCA\x2A\x8F\x59\x46\xF8\xE5\xFD\x09\x1D\xBD" + "\xCB"; + + static unsigned char e[] = "\x11"; + + static unsigned char d[] = + "\x00\xA5\xDA\xFC\x53\x41\xFA\xF2\x89\xC4\xB9\x88\xDB\x30\xC1\xCD" + "\xF8\x3F\x31\x25\x1E\x06\x68\xB4\x27\x84\x81\x38\x01\x57\x96\x41" + "\xB2\x94\x10\xB3\xC7\x99\x8D\x6B\xC4\x65\x74\x5E\x5C\x39\x26\x69" + "\xD6\x87\x0D\xA2\xC0\x82\xA9\x39\xE3\x7F\xDC\xB8\x2E\xC9\x3E\xDA" + "\xC9\x7F\xF3\xAD\x59\x50\xAC\xCF\xBC\x11\x1C\x76\xF1\xA9\x52\x94" + "\x44\xE5\x6A\xAF\x68\xC5\x6C\x09\x2C\xD3\x8D\xC3\xBE\xF5\xD2\x0A" + "\x93\x99\x26\xED\x4F\x74\xA1\x3E\xDD\xFB\xE1\xA1\xCE\xCC\x48\x94" + "\xAF\x94\x28\xC2\xB7\xB8\x88\x3F\xE4\x46\x3A\x4B\xC8\x5B\x1C\xB3" + "\xC1"; + + static unsigned char p[] = + "\x00\xEE\xCF\xAE\x81\xB1\xB9\xB3\xC9\x08\x81\x0B\x10\xA1\xB5\x60" + "\x01\x99\xEB\x9F\x44\xAE\xF4\xFD\xA4\x93\xB8\x1A\x9E\x3D\x84\xF6" + "\x32\x12\x4E\xF0\x23\x6E\x5D\x1E\x3B\x7E\x28\xFA\xE7\xAA\x04\x0A" + "\x2D\x5B\x25\x21\x76\x45\x9D\x1F\x39\x75\x41\xBA\x2A\x58\xFB\x65" + "\x99"; + + static unsigned char q[] = + "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9" + "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D" + "\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5" + "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x15" + "\x03"; + + static unsigned char dmp1[] = + "\x54\x49\x4C\xA6\x3E\xBA\x03\x37\xE4\xE2\x40\x23\xFC\xD6\x9A\x5A" + "\xEB\x07\xDD\xDC\x01\x83\xA4\xD0\xAC\x9B\x54\xB0\x51\xF2\xB1\x3E" + "\xD9\x49\x09\x75\xEA\xB7\x74\x14\xFF\x59\xC1\xF7\x69\x2E\x9A\x2E" + "\x20\x2B\x38\xFC\x91\x0A\x47\x41\x74\xAD\xC9\x3C\x1F\x67\xC9\x81"; + + static unsigned char dmq1[] = + "\x47\x1E\x02\x90\xFF\x0A\xF0\x75\x03\x51\xB7\xF8\x78\x86\x4C\xA9" + "\x61\xAD\xBD\x3A\x8A\x7E\x99\x1C\x5C\x05\x56\xA9\x4C\x31\x46\xA7" + "\xF9\x80\x3F\x8F\x6F\x8A\xE3\x42\xE9\x31\xFD\x8A\xE4\x7A\x22\x0D" + "\x1B\x99\xA4\x95\x84\x98\x07\xFE\x39\xF9\x24\x5A\x98\x36\xDA\x3D"; + + static unsigned char iqmp[] = + "\x00\xB0\x6C\x4F\xDA\xBB\x63\x01\x19\x8D\x26\x5B\xDB\xAE\x94\x23" + "\xB3\x80\xF2\x71\xF7\x34\x53\x88\x50\x93\x07\x7F\xCD\x39\xE2\x11" + "\x9F\xC9\x86\x32\x15\x4F\x58\x83\xB1\x67\xA9\x67\xBF\x40\x2B\x4E" + "\x9E\x2E\x0F\x96\x56\xE6\x98\xEA\x36\x66\xED\xFB\x25\x79\x80\x39" + "\xF7"; + + SetKey; +} + +/* taken from openssl/test/rsa_mp_test.c */ +#define NUM_EXTRA_PRIMES 1 +/* Returns the public key length (256) on success */ +int get_rsa_key2048p3(RSA *key) { + /* C90 requires string should <= 509 bytes */ + static const unsigned char n[] = + "\x92\x60\xd0\x75\x0a\xe1\x17\xee\xe5\x5c\x3f\x3d\xea\xba\x74\x91" + "\x75\x21\xa2\x62\xee\x76\x00\x7c\xdf\x8a\x56\x75\x5a\xd7\x3a\x15" + "\x98\xa1\x40\x84\x10\xa0\x14\x34\xc3\xf5\xbc\x54\xa8\x8b\x57\xfa" + "\x19\xfc\x43\x28\xda\xea\x07\x50\xa4\xc4\x4e\x88\xcf\xf3\xb2\x38" + "\x26\x21\xb8\x0f\x67\x04\x64\x43\x3e\x43\x36\xe6\xd0\x03\xe8\xcd" + "\x65\xbf\xf2\x11\xda\x14\x4b\x88\x29\x1c\x22\x59\xa0\x0a\x72\xb7" + "\x11\xc1\x16\xef\x76\x86\xe8\xfe\xe3\x4e\x4d\x93\x3c\x86\x81\x87" + "\xbd\xc2\x6f\x7b\xe0\x71\x49\x3c\x86\xf7\xa5\x94\x1c\x35\x10\x80" + "\x6a\xd6\x7b\x0f\x94\xd8\x8f\x5c\xf5\xc0\x2a\x09\x28\x21\xd8\x62" + "\x6e\x89\x32\xb6\x5c\x5b\xd8\xc9\x20\x49\xc2\x10\x93\x2b\x7a\xfa" + "\x7a\xc5\x9c\x0e\x88\x6a\xe5\xc1\xed\xb0\x0d\x8c\xe2\xc5\x76\x33" + "\xdb\x26\xbd\x66\x39\xbf\xf7\x3c\xee\x82\xbe\x92\x75\xc4\x02\xb4" + "\xcf\x2a\x43\x88\xda\x8c\xf8\xc6\x4e\xef\xe1\xc5\xa0\xf5\xab\x80" + "\x57\xc3\x9f\xa5\xc0\x58\x9c\x3e\x25\x3f\x09\x60\x33\x23\x00\xf9" + "\x4b\xea\x44\x87\x7b\x58\x8e\x1e\xdb\xde\x97\xcf\x23\x60\x72\x7a" + "\x09\xb7\x75\x26\x2d\x7e\xe5\x52\xb3\x31\x9b\x92\x66\xf0\x5a\x25"; + + static const unsigned char e[] = "\x01\x00\x01"; + + static const unsigned char d[] = + "\x6a\x7d\xf2\xca\x63\xea\xd4\xdd\xa1\x91\xd6\x14\xb6\xb3\x85\xe0" + "\xd9\x05\x6a\x3d\x6d\x5c\xfe\x07\xdb\x1d\xaa\xbe\xe0\x22\xdb\x08" + "\x21\x2d\x97\x61\x3d\x33\x28\xe0\x26\x7c\x9d\xd2\x3d\x78\x7a\xbd" + "\xe2\xaf\xcb\x30\x6a\xeb\x7d\xfc\xe6\x92\x46\xcc\x73\xf5\xc8\x7f" + "\xdf\x06\x03\x01\x79\xa2\x11\x4b\x76\x7d\xb1\xf0\x83\xff\x84\x1c" + "\x02\x5d\x7d\xc0\x0c\xd8\x24\x35\xb9\xa9\x0f\x69\x53\x69\xe9\x4d" + "\xf2\x3d\x2c\xe4\x58\xbc\x3b\x32\x83\xad\x8b\xba\x2b\x8f\xa1\xba" + "\x62\xe2\xdc\xe9\xac\xcf\xf3\x79\x9a\xae\x7c\x84\x00\x16\xf3\xba" + "\x8e\x00\x48\xc0\xb6\xcc\x43\x39\xaf\x71\x61\x00\x3a\x5b\xeb\x86" + "\x4a\x01\x64\xb2\xc1\xc9\x23\x7b\x64\xbc\x87\x55\x69\x94\x35\x1b" + "\x27\x50\x6c\x33\xd4\xbc\xdf\xce\x0f\x9c\x49\x1a\x7d\x6b\x06\x28" + "\xc7\xc8\x52\xbe\x4f\x0a\x9c\x31\x32\xb2\xed\x3a\x2c\x88\x81\xe9" + "\xaa\xb0\x7e\x20\xe1\x7d\xeb\x07\x46\x91\xbe\x67\x77\x76\xa7\x8b" + "\x5c\x50\x2e\x05\xd9\xbd\xde\x72\x12\x6b\x37\x38\x69\x5e\x2d\xd1" + "\xa0\xa9\x8a\x14\x24\x7c\x65\xd8\xa7\xee\x79\x43\x2a\x09\x2c\xb0" + "\x72\x1a\x12\xdf\x79\x8e\x44\xf7\xcf\xce\x0c\x49\x81\x47\xa9\xb1"; + + static const unsigned char p[] = + "\x06\x77\xcd\xd5\x46\x9b\xc1\xd5\x58\x00\x81\xe2\xf3\x0a\x36\xb1" + "\x6e\x29\x89\xd5\x2f\x31\x5f\x92\x22\x3b\x9b\x75\x30\x82\xfa\xc5" + "\xf5\xde\x8a\x36\xdb\xc6\xe5\x8f\xef\x14\x37\xd6\x00\xf9\xab\x90" + "\x9b\x5d\x57\x4c\xf5\x1f\x77\xc4\xbb\x8b\xdd\x9b\x67\x11\x45\xb2" + "\x64\xe8\xac\xa8\x03\x0f\x16\x0d\x5d\x2d\x53\x07\x23\xfb\x62\x0d" + "\xe6\x16\xd3\x23\xe8\xb3"; + + static const unsigned char q[] = + "\x06\x66\x9a\x70\x53\xd6\x72\x74\xfd\xea\x45\xc3\xc0\x17\xae\xde" + "\x79\x17\xae\x79\xde\xfc\x0e\xf7\xa4\x3a\x8c\x43\x8f\xc7\x8a\xa2" + "\x2c\x51\xc4\xd0\x72\x89\x73\x5c\x61\xbe\xfd\x54\x3f\x92\x65\xde" + "\x4d\x65\x71\x70\xf6\xf2\xe5\x98\xb9\x0f\xd1\x0b\xe6\x95\x09\x4a" + "\x7a\xdf\xf3\x10\x16\xd0\x60\xfc\xa5\x10\x34\x97\x37\x6f\x0a\xd5" + "\x5d\x8f\xd4\xc3\xa0\x5b"; + + static const unsigned char dmp1[] = + "\x05\x7c\x9e\x1c\xbd\x90\x25\xe7\x40\x86\xf5\xa8\x3b\x7a\x3f\x99" + "\x56\x95\x60\x3a\x7b\x95\x4b\xb8\xa0\xd7\xa5\xf1\xcc\xdc\x5f\xb5" + "\x8c\xf4\x62\x95\x54\xed\x2e\x12\x62\xc2\xe8\xf6\xde\xce\xed\x8e" + "\x77\x6d\xc0\x40\x25\x74\xb3\x5a\x2d\xaa\xe1\xac\x11\xcb\xe2\x2f" + "\x0a\x51\x23\x1e\x47\xb2\x05\x88\x02\xb2\x0f\x4b\xf0\x67\x30\xf0" + "\x0f\x6e\xef\x5f\xf7\xe7"; + + static const unsigned char dmq1[] = + "\x01\xa5\x6b\xbc\xcd\xe3\x0e\x46\xc6\x72\xf5\x04\x56\x28\x01\x22" + "\x58\x74\x5d\xbc\x1c\x3c\x29\x41\x49\x6c\x81\x5c\x72\xe2\xf7\xe5" + "\xa3\x8e\x58\x16\xe0\x0e\x37\xac\x1f\xbb\x75\xfd\xaf\xe7\xdf\xe9" + "\x1f\x70\xa2\x8f\x52\x03\xc0\x46\xd9\xf9\x96\x63\x00\x27\x7e\x5f" + "\x38\x60\xd6\x6b\x61\xe2\xaf\xbe\xea\x58\xd3\x9d\xbc\x75\x03\x8d" + "\x42\x65\xd6\x6b\x85\x97"; + + static const unsigned char iqmp[] = + "\x03\xa1\x8b\x80\xe4\xd8\x87\x25\x17\x5d\xcc\x8d\xa9\x8a\x22\x2b" + "\x6c\x15\x34\x6f\x80\xcc\x1c\x44\x04\x68\xbc\x03\xcd\x95\xbb\x69" + "\x37\x61\x48\xb4\x23\x13\x08\x16\x54\x6a\xa1\x7c\xf5\xd4\x3a\xe1" + "\x4f\xa4\x0c\xf5\xaf\x80\x85\x27\x06\x0d\x70\xc0\xc5\x19\x28\xfe" + "\xee\x8e\x86\x21\x98\x8a\x37\xb7\xe5\x30\x25\x70\x93\x51\x2d\x49" + "\x85\x56\xb3\x0c\x2b\x96"; + + static const unsigned char ex_prime[] = + "\x03\x89\x22\xa0\xb7\x3a\x91\xcb\x5e\x0c\xfd\x73\xde\xa7\x38\xa9" + "\x47\x43\xd6\x02\xbf\x2a\xb9\x3c\x48\xf3\x06\xd6\x58\x35\x50\x56" + "\x16\x5c\x34\x9b\x61\x87\xc8\xaa\x0a\x5d\x8a\x0a\xcd\x9c\x41\xd9" + "\x96\x24\xe0\xa9\x9b\x26\xb7\xa8\x08\xc9\xea\xdc\xa7\x15\xfb\x62" + "\xa0\x2d\x90\xe6\xa7\x55\x6e\xc6\x6c\xff\xd6\x10\x6d\xfa\x2e\x04" + "\x50\xec\x5c\x66\xe4\x05"; + + static const unsigned char ex_exponent[] = + "\x02\x0a\xcd\xc3\x82\xd2\x03\xb0\x31\xac\xd3\x20\x80\x34\x9a\x57" + "\xbc\x60\x04\x57\x25\xd0\x29\x9a\x16\x90\xb9\x1c\x49\x6a\xd1\xf2" + "\x47\x8c\x0e\x9e\xc9\x20\xc2\xd8\xe4\x8f\xce\xd2\x1a\x9c\xec\xb4" + "\x1f\x33\x41\xc8\xf5\x62\xd1\xa5\xef\x1d\xa1\xd8\xbd\x71\xc6\xf7" + "\xda\x89\x37\x2e\xe2\xec\x47\xc5\xb8\xe3\xb4\xe3\x5c\x82\xaa\xdd" + "\xb7\x58\x2e\xaf\x07\x79"; + + static const unsigned char ex_coefficient[] = + "\x00\x9c\x09\x88\x9b\xc8\x57\x08\x69\x69\xab\x2d\x9e\x29\x1c\x3c" + "\x6d\x59\x33\x12\x0d\x2b\x09\x2e\xaf\x01\x2c\x27\x01\xfc\xbd\x26" + "\x13\xf9\x2d\x09\x22\x4e\x49\x11\x03\x82\x88\x87\xf4\x43\x1d\xac" + "\xca\xec\x86\xf7\x23\xf1\x64\xf3\xf5\x81\xf0\x37\x36\xcf\x67\xff" + "\x1a\xff\x7a\xc7\xf9\xf9\x67\x2d\xa0\x9d\x61\xf8\xf6\x47\x5c\x2f" + "\xe7\x66\xe8\x3c\x3a\xe8"; + + BIGNUM **pris = NULL, **exps = NULL, **coeffs = NULL; + int rv = 256; /* public key length */ + + if (!TEST_int_eq(RSA_set0_key(key, + BN_bin2bn(n, sizeof(n) - 1, NULL), + BN_bin2bn(e, sizeof(e) - 1, NULL), + BN_bin2bn(d, sizeof(d) - 1, NULL)), 1)) + goto err; + + if (!TEST_int_eq(RSA_set0_factors(key, + BN_bin2bn(p, sizeof(p) - 1, NULL), + BN_bin2bn(q, sizeof(q) - 1, NULL)), 1)) + goto err; + + if (!TEST_int_eq(RSA_set0_crt_params(key, + BN_bin2bn(dmp1, sizeof(dmp1) - 1, NULL), + BN_bin2bn(dmq1, sizeof(dmq1) - 1, NULL), + BN_bin2bn(iqmp, sizeof(iqmp) - 1, + NULL)), 1)) + return 0; + + pris = OPENSSL_zalloc(sizeof(BIGNUM *)); + exps = OPENSSL_zalloc(sizeof(BIGNUM *)); + coeffs = OPENSSL_zalloc(sizeof(BIGNUM *)); + if (!TEST_ptr(pris) || !TEST_ptr(exps) || !TEST_ptr(coeffs)) + goto err; + + pris[0] = BN_bin2bn(ex_prime, sizeof(ex_prime) - 1, NULL); + exps[0] = BN_bin2bn(ex_exponent, sizeof(ex_exponent) - 1, NULL); + coeffs[0] = BN_bin2bn(ex_coefficient, sizeof(ex_coefficient) - 1, NULL); + if (!TEST_ptr(pris[0]) || !TEST_ptr(exps[0]) || !TEST_ptr(coeffs[0])) + goto err; + + if (!TEST_true(RSA_set0_multi_prime_params(key, pris, exps, + coeffs, NUM_EXTRA_PRIMES))) + goto err; + +ret: + OPENSSL_free(pris); + OPENSSL_free(exps); + OPENSSL_free(coeffs); + return rv; +err: + if (pris != NULL) + BN_free(pris[0]); + if (exps != NULL) + BN_free(exps[0]); + if (coeffs != NULL) + BN_free(coeffs[0]); + rv = 0; + goto ret; +} + +#endif --- /dev/null +++ b/test/fips_slitest_helper.h @@ -0,0 +1,29 @@ +#ifndef __FIPS_SLITEST_HELPER_H__ +#define __FIPS_SLITEST_HELPER_H__ + +#include + +typedef unsigned char byte; + +/** Create a MAC key: one copy for macgen, one for macver (verification) + * Adapted from https://wiki.openssl.org/images/1/1b/T-hmac.c.tar.gz + */ +int make_hmac_keys(EVP_PKEY** skey, EVP_PKEY** vkey); + +/* Adapted from https://wiki.openssl.org/images/1/1b/T-hmac.c.tar.gz */ +void print_it(const char* label, const byte* buff, size_t len); + +int get_cmac_key(int cipher_nid, EVP_PKEY** out); + +const uint8_t* get_msg_16(); +const uint8_t* get_msg_128(); +/* Get constant keys of specified length */ +const uint8_t* get_key_16(); +const uint8_t* get_key_32(); + +void get_rsa_key1(RSA *key); +void get_rsa_key2(RSA *key); +void get_rsa_key3(RSA *key); +int get_rsa_key2048p3(RSA *key); + +#endif /* __FIPS_SLITEST_HELPER_H__ */ --- /dev/null +++ b/test/recipes/30-test_fips_sli.t @@ -0,0 +1,4 @@ +#!/usr/bin/env perl +use OpenSSL::Test::Simple; + +simple_test("test_fips_sli", "fips_slitest", "fips_sli"); --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4636,3 +4636,14 @@ EVP_KDF_size EVP_KDF_derive 6597 1_1_1d EXIST::FUNCTION: EC_GROUP_get0_field 6598 1_1_1l EXIST::FUNCTION:EC NONFIPS_selftest_check 6599 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_EVP_MD_CTX 6600 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_CMAC_CTX 6601 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_HMAC_CTX 6602 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_EVP_PKEY_CTX 6603 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_EVP_CIPHER_CTX 6604 1_1_1l EXIST::FUNCTION: +fips_sli_is_approved_EVP_KDF_CTX 6605 1_1_1l EXIST::FUNCTION: +fips_sli_SHA1_is_approved 6606 1_1_1l EXIST::FUNCTION: +fips_sli_PKCS5_PBKDF2_HMAC_is_approved 6607 1_1_1l EXIST::FUNCTION: +fips_sli_HMAC_is_approved 6608 1_1_1l EXIST::FUNCTION: +fips_sli_RAND_bytes_is_approved 6609 1_1_1l EXIST::FUNCTION: +fips_sli_RAND_priv_bytes_is_approved 6610 1_1_1l EXIST::FUNCTION: