Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KBKDF_ctr_hmac FIPS Service Indicator #1798

Merged
merged 3 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions crypto/fipsmodule/kdf/kbkdf.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
int KBKDF_ctr_hmac(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
const uint8_t *secret, size_t secret_len,
const uint8_t *info, size_t info_len) {
// We have to avoid the underlying |HMAC_Final| services updating
// the indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();

int ret = 0;

HMAC_CTX *hmac_ctx = NULL;
Expand Down Expand Up @@ -96,5 +100,9 @@ int KBKDF_ctr_hmac(uint8_t *out_key, size_t out_len, const EVP_MD *digest,
OPENSSL_cleanse(out_key, out_len);
}
HMAC_CTX_free(hmac_ctx);
FIPS_service_indicator_unlock_state();
if (ret) {
KBKDF_ctr_hmac_verify_service_indicator(digest);
}
return ret;
}
3 changes: 3 additions & 0 deletions crypto/fipsmodule/service_indicator/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void PBKDF2_verify_service_indicator(const EVP_MD *evp_md, size_t password_len,
void SSHKDF_verify_service_indicator(const EVP_MD *evp_md);
void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label,
size_t label_len);
void KBKDF_ctr_hmac_verify_service_indicator(const EVP_MD *dgst);

#else

Expand Down Expand Up @@ -116,6 +117,8 @@ OPENSSL_INLINE void TLSKDF_verify_service_indicator(
OPENSSL_UNUSED const char *label,
OPENSSL_UNUSED size_t label_len) {}

OPENSSL_INLINE void KBKDF_ctr_hmac_verify_service_indicator(OPENSSL_UNUSED const EVP_MD *dgst) {}

#endif // AWSLC_FIPS

// is_fips_build is similar to |FIPS_mode| but returns 1 including in the case
Expand Down
60 changes: 41 additions & 19 deletions crypto/fipsmodule/service_indicator/service_indicator.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
#include <openssl/service_indicator.h>
#include "internal.h"

const char* awslc_version_string(void) {
return AWSLC_VERSION_STRING;
}
const char *awslc_version_string(void) { return AWSLC_VERSION_STRING; }

int is_fips_build(void) {
#if defined(AWSLC_FIPS)
Expand Down Expand Up @@ -42,9 +40,9 @@ struct fips_service_indicator_state {
// FIPS 140-3 requires that the module should provide the service indicator
// for approved services irrespective of whether the user queries it or not.
// Hence, it is lazily initialized in any call to an approved service.
static struct fips_service_indicator_state * service_indicator_get(void) {
struct fips_service_indicator_state *indicator = CRYPTO_get_thread_local(
AWSLC_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE);
static struct fips_service_indicator_state *service_indicator_get(void) {
struct fips_service_indicator_state *indicator =
CRYPTO_get_thread_local(AWSLC_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE);

if (indicator == NULL) {
indicator = malloc(sizeof(struct fips_service_indicator_state));
Expand All @@ -56,8 +54,7 @@ static struct fips_service_indicator_state * service_indicator_get(void) {
indicator->counter = 0;

if (!CRYPTO_set_thread_local(
AWSLC_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE, indicator,
free)) {
AWSLC_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE, indicator, free)) {
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR);
return NULL;
}
Expand Down Expand Up @@ -214,7 +211,8 @@ static int is_md_fips_approved_for_verifying(int md_type, int pkey_type) {

static void evp_md_ctx_verify_service_indicator(const EVP_MD_CTX *ctx,
int rsa_1024_ok,
int (*md_ok)(int md_type, int pkey_type)) {
int (*md_ok)(int md_type,
int pkey_type)) {
if (EVP_MD_CTX_md(ctx) == NULL) {
// Signature schemes without a prehash are currently never FIPS approved.
goto err;
Expand Down Expand Up @@ -272,7 +270,7 @@ static void evp_md_ctx_verify_service_indicator(const EVP_MD_CTX *ctx,
}
}

err:
err:
// Ensure that junk errors aren't left on the queue.
ERR_clear_error();
}
Expand All @@ -292,7 +290,7 @@ void ECDH_verify_service_indicator(const EC_KEY *ec_key) {
}

void EVP_PKEY_keygen_verify_service_indicator(const EVP_PKEY *pkey) {
if (pkey->type == EVP_PKEY_RSA || pkey->type== EVP_PKEY_RSA_PSS) {
if (pkey->type == EVP_PKEY_RSA || pkey->type == EVP_PKEY_RSA_PSS) {
// 2048, 3072 and 4096 bit keys are approved for RSA key generation.
// EVP_PKEY_size returns the size of the key in bytes.
// Note: |EVP_PKEY_size| returns the length in bytes.
Expand Down Expand Up @@ -346,7 +344,7 @@ void EVP_DigestSign_verify_service_indicator(const EVP_MD_CTX *ctx) {
}

void HMAC_verify_service_indicator(const EVP_MD *evp_md) {
switch (evp_md->type){
switch (evp_md->type) {
case NID_sha1:
case NID_sha224:
case NID_sha256:
Expand All @@ -361,8 +359,8 @@ void HMAC_verify_service_indicator(const EVP_MD *evp_md) {
}
}

void HKDF_verify_service_indicator(const EVP_MD *evp_md,
const uint8_t *salt, size_t salt_len, size_t info_len) {
void HKDF_verify_service_indicator(const EVP_MD *evp_md, const uint8_t *salt,
size_t salt_len, size_t info_len) {
// HKDF with SHA1, SHA224, SHA256, SHA384, and SHA512 are approved.
//
// FIPS 140 parameter requirements, per NIST SP 800-108 Rev. 1:
Expand Down Expand Up @@ -412,7 +410,7 @@ void HKDFExpand_verify_service_indicator(const EVP_MD *evp_md) {
}
}
void PBKDF2_verify_service_indicator(const EVP_MD *evp_md, size_t password_len,
size_t salt_len, unsigned iterations) {
size_t salt_len, unsigned iterations) {
// PBKDF with SHA1, SHA224, SHA256, SHA384, and SHA512 are approved.
//
// FIPS 140 parameter requirements, per NIST SP800-132:
Expand Down Expand Up @@ -456,15 +454,15 @@ void SSHKDF_verify_service_indicator(const EVP_MD *evp_md) {
FIPS_service_indicator_update_state();
break;
default:
break;
break;
}
}

void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label,
size_t label_len) {
// HMAC-MD5/HMAC-SHA1 (both used concurrently) is approved for use in the KDF
// in TLS 1.0/1.1.
if(dgst->type == NID_md5_sha1) {
if (dgst->type == NID_md5_sha1) {
FIPS_service_indicator_update_state();
return;
}
Expand All @@ -479,14 +477,38 @@ void TLSKDF_verify_service_indicator(const EVP_MD *dgst, const char *label,
if (label_len >= TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE &&
memcmp(label, TLS_MD_EXTENDED_MASTER_SECRET_CONST,
TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE) == 0) {
FIPS_service_indicator_update_state();
FIPS_service_indicator_update_state();
}
break;
default:
break;
}
}

// "For key derivation, this Recommendation approves the use of the keyed-Hash Message
// Authentication Code (HMAC) specified in FIPS 198-1".

// * FIPS 198-1 references FIPS 180-3 which covers the SHA-1 and SHA-2* family of algorithms
// * NIST also provides ACVP vectors for SHA3-* family of algorithms but our HMAC does not support this
//
// Sourced from NIST SP 800-108r1-upd1 Section 3: Pseudorandom Function (PRF)
// https://doi.org/10.6028/NIST.SP.800-108r1-upd1
void KBKDF_ctr_hmac_verify_service_indicator(const EVP_MD *dgst) {
nebeid marked this conversation as resolved.
Show resolved Hide resolved
switch (dgst->type) {
case NID_sha1:
case NID_sha224:
case NID_sha256:
case NID_sha384:
case NID_sha512:
case NID_sha512_224:
case NID_sha512_256:
FIPS_service_indicator_update_state();
break;
default:
break;
}
}

#else

uint64_t FIPS_service_indicator_before_call(void) { return 0; }
Expand All @@ -498,4 +520,4 @@ uint64_t FIPS_service_indicator_after_call(void) {
return 1;
}

#endif // AWSLC_FIPS
#endif // AWSLC_FIPS
59 changes: 59 additions & 0 deletions crypto/fipsmodule/service_indicator/service_indicator_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4317,6 +4317,65 @@ TEST(ServiceIndicatorTest, DRBG) {
EXPECT_EQ(approved, AWSLC_APPROVED);
}

static const struct KBKDFCtrHmacTestVector {
const EVP_MD *(*md)();
const FIPSStatus expectation;
} kKBKDFCtrHmacTestVectors[] = {{
&EVP_sha1,
AWSLC_APPROVED,
},
{
&EVP_sha224,
AWSLC_APPROVED,
},
{
&EVP_sha256,
AWSLC_APPROVED,
},
{
&EVP_sha384,
AWSLC_APPROVED,
},
{
&EVP_sha512,
AWSLC_APPROVED,
},
{
&EVP_sha512_224,
AWSLC_APPROVED,
},
{
&EVP_sha512_256,
AWSLC_APPROVED,
},
{
&EVP_md5,
AWSLC_NOT_APPROVED,
}};

class KBKDFCtrHmacIndicatorTest : public TestWithNoErrors<KBKDFCtrHmacTestVector> {};

INSTANTIATE_TEST_SUITE_P(All, KBKDFCtrHmacIndicatorTest,
testing::ValuesIn(kKBKDFCtrHmacTestVectors));

TEST_P(KBKDFCtrHmacIndicatorTest, KBKDF) {
const KBKDFCtrHmacTestVector &vector = GetParam();

const uint8_t secret[20] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'K', 'B', 'K',
'D', 'F', '-', 'C', 'T', 'R', ' ', 'K', 'E', 'Y'};
const uint8_t info[16] = {'A', 'W', 'S', '-', 'L', 'C', ' ', 'K',
'B', 'K', 'D', 'F', '-', 'C', 'T', 'R'};
uint8_t output[16] = {0};

FIPSStatus approved = AWSLC_NOT_APPROVED;

CALL_SERVICE_AND_CHECK_APPROVED(
approved, ASSERT_TRUE(KBKDF_ctr_hmac(
&output[0], sizeof(output), vector.md(), &secret[0],
sizeof(secret), &info[0], sizeof(info))));
ASSERT_EQ(vector.expectation, approved);
}

// Verifies that the awslc_version_string is as expected.
// Since this is running in FIPS mode it should end in FIPS
// Update this when the AWS-LC version number is modified
Expand Down
Loading