openssl-1_1/openssl-1_1-ossl-sli-003-add-sli.patch

3334 lines
120 KiB
Diff

---
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 <openssl/cmac.h>
#include <openssl/err.h>
+#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 <openssl/kdf.h>
#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 <stdio.h>
#include <stdlib.h>
#include "internal/cryptlib.h"
+#include "internal/fips_sli_local.h"
#include <openssl/x509.h>
#include <openssl/evp.h>
#include <openssl/kdf.h>
@@ -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 <stdio.h>
#include "internal/cryptlib.h"
+#include "internal/fips_sli_local.h"
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
@@ -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 <openssl/dsa.h>
+#include <openssl/ec.h>
+#include <openssl/rsa.h>
+#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<int fips_sli_is_approved_*_CTX> - get status of the FIPS Service Level Indicator (SLI) for context operations
+
+C<int fips_sli_*_is_approved> - get status of the FIPS SLI for standalone operations
+
+=head1 SYNOPSIS
+
+ #include <openssl/fips_sli.h>
+
+ 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<int fips_sli_is_approved_*_CTX(...)>
+
+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<EVP_MD_CTX_reset(EVP_MD_CTX *ctx)> or reinitializing the
+context, e.g. via L<EVP_DigestInit(3)>.
+
+=item C<int fips_sli_*_is_approved(...)>
+
+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<FNNAME()>, the function
+C<fips_sli_FNNAME_is_approved()> must be called with the same set of parameters as C<FNNAME()>.
+Note that applications must check the return value of C<FNNAME()> according to its documentation B<as well as> the return value of the SLI (see below for L</RETURN VALUES>).
+Both are orthogonal: the former reports about success and failure of C<FNNAME()>, and the latter whether a disapproved operation happened or not.
+Well-behaving applications check for both.
+
+The following explicit indicators exist:
+
+C<int fips_sli_SHA1_is_approved(const unsigned char *d, size_t n, unsigned char *md);>
+
+C<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);>
+
+C<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);>
+
+C<int fips_sli_RAND_bytes_is_approved(unsigned char *buf, int num);>
+
+C<int fips_sli_RAND_priv_bytes_is_approved(unsigned char *buf, int num);>
+
+=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_bytes(3)>/RAND_priv_bytes().
+
+Swapping out OPENSSL's RNG implementation (e.g. via L<RAND_set_rand_method(3)>) is NOT allowed.
+
+=head1 RETURN VALUES
+
+C<fips_sli_is_approved_*_CTX()> returns 0 if the previous operation(s) was unapproved or B<ctx> was B<NULL>, and returns 1
+if the previous operation(s) were approved (or rather, no non-approved operations happened).
+
+C<fips_sli_*_is_approved()> 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<https://www.openssl.org/source/license.html>.
+
+=cut
--- a/include/crypto/evp.h
+++ b/include/crypto/evp.h
@@ -9,6 +9,7 @@
#include <openssl/evp.h>
#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 <openssl/symhacks.h>
+
+# 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 <openssl/cmac.h>
+#include <openssl/ec.h>
+#include <openssl/fips_sli.h>
+
+/* 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 <openssl/evp.h>
+#include <openssl/cmac.h>
+# 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 <openssl/evp.h>
+#include <openssl/fips_sli.h>
+#include <openssl/kdf.h>
+#include <openssl/opensslconf.h> /* To see if OPENSSL_NO_EC is defined */
+#ifndef OPENSSL_NO_EC
+# include <openssl/ec.h>
+#endif
+#ifndef OPENSSL_NO_RSA
+# include <openssl/rsa.h>
+#endif
+#include <openssl/rand.h>
+
+#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 <stdlib.h>
+#include <stdio.h>
+#include <limits.h>
+#include <string.h>
+#include <assert.h>
+
+#include <openssl/err.h>
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+
+#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 <openssl/rsa.h>
+
+/* 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 <openssl/evp.h>
+
+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: