openssl-1_1/openssl-1_1-ossl-sli-003-add-sli.patch
Pedro Monreal Gonzalez 8f01c56ec8 Accepting request 1111331 from home:ohollmann:branches:security:tls
- Update to 1.1.1w:
 * Fix POLY1305 MAC implementation corrupting XMM registers on Windows.
   The POLY1305 MAC (message authentication code) implementation in OpenSSL
   does not save the contents of non-volatile XMM registers on Windows 64
   platform when calculating the MAC of data larger than 64 bytes. Before
   returning to the caller all the XMM registers are set to zero rather than
   restoring their previous content. The vulnerable code is used only on newer
   x86_64 processors supporting the AVX512-IFMA instructions.
   The consequences of this kind of internal application state corruption can
   be various - from no consequences, if the calling application does not
   depend on the contents of non-volatile XMM registers at all, to the worst
   consequences, where the attacker could get complete control of the
   application process. However given the contents of the registers are just
   zeroized so the attacker cannot put arbitrary values inside, the most likely
   consequence, if any, would be an incorrect result of some application
   dependent calculations or a crash leading to a denial of service.
   (CVE-2023-4807)

- Add missing FIPS patches from SLE:
  * Add patches:
    - bsc1185319-FIPS-KAT-for-ECDSA.patch
    - bsc1198207-FIPS-add-hash_hmac-drbg-kat.patch
    - openssl-1.1.1-fips-fix-memory-leaks.patch
    - openssl-1_1-FIPS-PBKDF2-KAT-requirements.patch
    - openssl-1_1-FIPS_drbg-rewire.patch
    - openssl-1_1-Zeroization.patch
    - openssl-1_1-fips-drbg-selftest.patch
    - openssl-1_1-fips-list-only-approved-digest-and-pubkey-algorithms.patch
    - openssl-1_1-jitterentropy-3.4.0.patch
    - openssl-1_1-ossl-sli-000-fix-build-error.patch

OBS-URL: https://build.opensuse.org/request/show/1111331
OBS-URL: https://build.opensuse.org/package/show/security:tls/openssl-1_1?expand=0&rev=144
2023-09-14 19:44:42 +00:00

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: