This is cribbed, with perimssion, from AWS-LC. The FIPS service indicator[1] signals when an approved service has been completed. [1] FIPS 140-3 IG 2.4.C Change-Id: Ib40210d69b3823f4d2a500b23a1606f8d6942f81 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/52568 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: Adam Langley <agl@google.com>fips-20220613
parent
f5d6d24bd6
commit
118a892d2d
28 changed files with 3275 additions and 102 deletions
@ -0,0 +1,89 @@ |
|||||||
|
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* |
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||||
|
* copyright notice and this permission notice appear in all copies. |
||||||
|
* |
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_SERVICE_INDICATOR_INTERNAL_H |
||||||
|
#define OPENSSL_HEADER_SERVICE_INDICATOR_INTERNAL_H |
||||||
|
|
||||||
|
#include <openssl/base.h> |
||||||
|
#include <openssl/service_indicator.h> |
||||||
|
|
||||||
|
#if defined(BORINGSSL_FIPS) |
||||||
|
|
||||||
|
// FIPS_service_indicator_update_state records that an approved service has been
|
||||||
|
// invoked.
|
||||||
|
void FIPS_service_indicator_update_state(void); |
||||||
|
|
||||||
|
// FIPS_service_indicator_lock_state and |FIPS_service_indicator_unlock_state|
|
||||||
|
// stop |FIPS_service_indicator_update_state| from actually updating the service
|
||||||
|
// indicator. This is used when a primitive calls a potentially approved
|
||||||
|
// primitive to avoid false positives. For example, just because a key
|
||||||
|
// generation calls |RAND_bytes| (and thus the approved DRBG) doesn't mean that
|
||||||
|
// the key generation operation itself is approved.
|
||||||
|
//
|
||||||
|
// This lock nests: i.e. locking twice is fine so long as each lock is paired
|
||||||
|
// with an unlock. If the (64-bit) counter overflows, the process aborts.
|
||||||
|
void FIPS_service_indicator_lock_state(void); |
||||||
|
void FIPS_service_indicator_unlock_state(void); |
||||||
|
|
||||||
|
// The following functions may call |FIPS_service_indicator_update_state| if
|
||||||
|
// their parameter specifies an approved operation.
|
||||||
|
|
||||||
|
void AEAD_GCM_verify_service_indicator(const EVP_AEAD_CTX *ctx); |
||||||
|
void AEAD_CCM_verify_service_indicator(const EVP_AEAD_CTX *ctx); |
||||||
|
void EC_KEY_keygen_verify_service_indicator(const EC_KEY *eckey); |
||||||
|
void ECDH_verify_service_indicator(const EC_KEY *ec_key); |
||||||
|
void EVP_Cipher_verify_service_indicator(const EVP_CIPHER_CTX *ctx); |
||||||
|
void EVP_DigestSign_verify_service_indicator(const EVP_MD_CTX *ctx); |
||||||
|
void EVP_DigestVerify_verify_service_indicator(const EVP_MD_CTX *ctx); |
||||||
|
void HMAC_verify_service_indicator(const EVP_MD *evp_md); |
||||||
|
void TLSKDF_verify_service_indicator(const EVP_MD *dgst); |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
// Service indicator functions are no-ops in non-FIPS builds.
|
||||||
|
|
||||||
|
OPENSSL_INLINE void FIPS_service_indicator_update_state(void) {} |
||||||
|
OPENSSL_INLINE void FIPS_service_indicator_lock_state(void) {} |
||||||
|
OPENSSL_INLINE void FIPS_service_indicator_unlock_state(void) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void AEAD_GCM_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_AEAD_CTX *ctx) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void AEAD_CCM_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_AEAD_CTX *ctx) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void EC_KEY_keygen_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EC_KEY *eckey) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void ECDH_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EC_KEY *ec_key) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void EVP_Cipher_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_CIPHER_CTX *ctx) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void EVP_DigestSign_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_MD_CTX *ctx) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void EVP_DigestVerify_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_MD_CTX *ctx) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void HMAC_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_MD *evp_md) {} |
||||||
|
|
||||||
|
OPENSSL_INLINE void TLSKDF_verify_service_indicator( |
||||||
|
OPENSSL_UNUSED const EVP_MD *dgst) {} |
||||||
|
|
||||||
|
#endif // BORINGSSL_FIPS
|
||||||
|
|
||||||
|
#endif // OPENSSL_HEADER_SERVICE_INDICATOR_INTERNAL_H
|
@ -0,0 +1,333 @@ |
|||||||
|
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* |
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||||
|
* copyright notice and this permission notice appear in all copies. |
||||||
|
* |
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
||||||
|
|
||||||
|
#include <openssl/crypto.h> |
||||||
|
#include <openssl/ec.h> |
||||||
|
#include <openssl/ec_key.h> |
||||||
|
#include <openssl/evp.h> |
||||||
|
#include <openssl/service_indicator.h> |
||||||
|
|
||||||
|
#include "../../evp/internal.h" |
||||||
|
#include "../../internal.h" |
||||||
|
#include "internal.h" |
||||||
|
|
||||||
|
#if defined(BORINGSSL_FIPS) |
||||||
|
|
||||||
|
#define STATE_UNLOCKED 0 |
||||||
|
|
||||||
|
// fips_service_indicator_state is a thread-local structure that stores the
|
||||||
|
// state of the FIPS service indicator.
|
||||||
|
struct fips_service_indicator_state { |
||||||
|
// lock_state records the number of times the indicator has been locked.
|
||||||
|
// When it is zero (i.e. |STATE_UNLOCKED|) then the indicator can be updated.
|
||||||
|
uint64_t lock_state; |
||||||
|
// counter is the indicator state. It is incremented when an approved service
|
||||||
|
// completes.
|
||||||
|
uint64_t counter; |
||||||
|
}; |
||||||
|
|
||||||
|
// service_indicator_get returns a pointer to the |fips_service_indicator_state|
|
||||||
|
// for the current thread. It returns NULL on error.
|
||||||
|
//
|
||||||
|
// 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( |
||||||
|
OPENSSL_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE); |
||||||
|
|
||||||
|
if (indicator == NULL) { |
||||||
|
indicator = OPENSSL_malloc(sizeof(struct fips_service_indicator_state)); |
||||||
|
if (indicator == NULL) { |
||||||
|
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_MALLOC_FAILURE); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
|
||||||
|
indicator->lock_state = STATE_UNLOCKED; |
||||||
|
indicator->counter = 0; |
||||||
|
|
||||||
|
if (!CRYPTO_set_thread_local( |
||||||
|
OPENSSL_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE, indicator, |
||||||
|
OPENSSL_free)) { |
||||||
|
OPENSSL_PUT_ERROR(CRYPTO, ERR_R_INTERNAL_ERROR); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return indicator; |
||||||
|
} |
||||||
|
|
||||||
|
static uint64_t service_indicator_get_counter(void) { |
||||||
|
struct fips_service_indicator_state *indicator = service_indicator_get(); |
||||||
|
if (indicator == NULL) { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
return indicator->counter; |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t FIPS_service_indicator_before_call(void) { |
||||||
|
return service_indicator_get_counter(); |
||||||
|
} |
||||||
|
|
||||||
|
uint64_t FIPS_service_indicator_after_call(void) { |
||||||
|
return service_indicator_get_counter(); |
||||||
|
} |
||||||
|
|
||||||
|
void FIPS_service_indicator_update_state(void) { |
||||||
|
struct fips_service_indicator_state *indicator = service_indicator_get(); |
||||||
|
if (indicator && indicator->lock_state == STATE_UNLOCKED) { |
||||||
|
indicator->counter++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FIPS_service_indicator_lock_state(void) { |
||||||
|
struct fips_service_indicator_state *indicator = service_indicator_get(); |
||||||
|
if (indicator == NULL) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// |FIPS_service_indicator_lock_state| and
|
||||||
|
// |FIPS_service_indicator_unlock_state| should not under/overflow in normal
|
||||||
|
// operation. They are still checked and errors added to facilitate testing in
|
||||||
|
// service_indicator_test.cc. This should only happen if lock/unlock are
|
||||||
|
// called in an incorrect order or multiple times in the same function.
|
||||||
|
const uint64_t new_state = indicator->lock_state + 1; |
||||||
|
if (new_state < indicator->lock_state) { |
||||||
|
// Overflow. This would imply that our call stack length has exceeded a
|
||||||
|
// |uint64_t| which impossible on a 64-bit system.
|
||||||
|
abort(); |
||||||
|
} |
||||||
|
|
||||||
|
indicator->lock_state = new_state; |
||||||
|
} |
||||||
|
|
||||||
|
void FIPS_service_indicator_unlock_state(void) { |
||||||
|
struct fips_service_indicator_state *indicator = service_indicator_get(); |
||||||
|
if (indicator == NULL) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
if (indicator->lock_state == 0) { |
||||||
|
abort(); |
||||||
|
} |
||||||
|
|
||||||
|
indicator->lock_state--; |
||||||
|
} |
||||||
|
|
||||||
|
void AEAD_GCM_verify_service_indicator(const EVP_AEAD_CTX *ctx) { |
||||||
|
const size_t key_len = EVP_AEAD_key_length(ctx->aead); |
||||||
|
if (key_len == 16 || key_len == 32) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AEAD_CCM_verify_service_indicator(const EVP_AEAD_CTX *ctx) { |
||||||
|
if (EVP_AEAD_key_length(ctx->aead) == 16 && ctx->tag_len == 4) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// is_ec_fips_approved returns one if the curve corresponding to the given NID
|
||||||
|
// is FIPS approved, and zero otherwise.
|
||||||
|
static int is_ec_fips_approved(int curve_nid) { |
||||||
|
switch (curve_nid) { |
||||||
|
case NID_secp224r1: |
||||||
|
case NID_X9_62_prime256v1: |
||||||
|
case NID_secp384r1: |
||||||
|
case NID_secp521r1: |
||||||
|
return 1; |
||||||
|
default: |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// is_md_fips_approved_for_signing returns one if the given message digest type
|
||||||
|
// is FIPS approved for signing, and zero otherwise.
|
||||||
|
static int is_md_fips_approved_for_signing(int md_type) { |
||||||
|
switch (md_type) { |
||||||
|
case NID_sha224: |
||||||
|
case NID_sha256: |
||||||
|
case NID_sha384: |
||||||
|
case NID_sha512: |
||||||
|
case NID_sha512_256: |
||||||
|
return 1; |
||||||
|
default: |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// is_md_fips_approved_for_verifying returns one if the given message digest
|
||||||
|
// type is FIPS approved for verifying, and zero otherwise.
|
||||||
|
static int is_md_fips_approved_for_verifying(int md_type) { |
||||||
|
switch (md_type) { |
||||||
|
case NID_sha1: |
||||||
|
case NID_sha224: |
||||||
|
case NID_sha256: |
||||||
|
case NID_sha384: |
||||||
|
case NID_sha512: |
||||||
|
case NID_sha512_256: |
||||||
|
return 1; |
||||||
|
default: |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void evp_md_ctx_verify_service_indicator(const EVP_MD_CTX *ctx, |
||||||
|
int rsa_1024_ok, |
||||||
|
int (*md_ok)(int md_type)) { |
||||||
|
if (EVP_MD_CTX_md(ctx) == NULL) { |
||||||
|
// Signature schemes without a prehash are currently never FIPS approved.
|
||||||
|
goto err; |
||||||
|
} |
||||||
|
|
||||||
|
EVP_PKEY_CTX *const pctx = ctx->pctx; |
||||||
|
const EVP_PKEY *const pkey = EVP_PKEY_CTX_get0_pkey(pctx); |
||||||
|
const int pkey_type = EVP_PKEY_id(pkey); |
||||||
|
const int md_type = EVP_MD_CTX_type(ctx); |
||||||
|
|
||||||
|
// EVP_PKEY_RSA_PSS SPKIs aren't supported.
|
||||||
|
if (pkey_type == EVP_PKEY_RSA) { |
||||||
|
// Message digest used in the private key should be of the same type
|
||||||
|
// as the given one, so we extract the MD type from the |EVP_PKEY|
|
||||||
|
// and compare it with the type in |ctx|.
|
||||||
|
const EVP_MD *pctx_md; |
||||||
|
if (!EVP_PKEY_CTX_get_signature_md(pctx, &pctx_md)) { |
||||||
|
goto err; |
||||||
|
} |
||||||
|
if (EVP_MD_type(pctx_md) != md_type) { |
||||||
|
goto err; |
||||||
|
} |
||||||
|
|
||||||
|
int padding; |
||||||
|
if (!EVP_PKEY_CTX_get_rsa_padding(pctx, &padding)) { |
||||||
|
goto err; |
||||||
|
} |
||||||
|
if (padding == RSA_PKCS1_PSS_PADDING) { |
||||||
|
int salt_len; |
||||||
|
const EVP_MD *mgf1_md; |
||||||
|
if (!EVP_PKEY_CTX_get_rsa_pss_saltlen(pctx, &salt_len) || |
||||||
|
!EVP_PKEY_CTX_get_rsa_mgf1_md(pctx, &mgf1_md) || |
||||||
|
(salt_len != -1 && salt_len != (int)EVP_MD_size(pctx_md)) || |
||||||
|
EVP_MD_type(mgf1_md) != md_type) { |
||||||
|
// Only PSS where saltLen == hashLen is tested with ACVP. Cases with
|
||||||
|
// non-standard padding functions are also excluded.
|
||||||
|
goto err; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// The approved RSA key sizes for signing are 2048, 3072 and 4096 bits.
|
||||||
|
// Note: |EVP_PKEY_size| returns the size in bytes.
|
||||||
|
size_t pkey_size = EVP_PKEY_size(ctx->pctx->pkey); |
||||||
|
|
||||||
|
// Check if the MD type and the RSA key size are approved.
|
||||||
|
if (md_ok(md_type) && |
||||||
|
((rsa_1024_ok && pkey_size == 128) || pkey_size == 256 || |
||||||
|
pkey_size == 384 || pkey_size == 512)) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} else if (pkey_type == EVP_PKEY_EC) { |
||||||
|
// Check if the MD type and the elliptic curve are approved.
|
||||||
|
if (md_ok(md_type) && is_ec_fips_approved(EC_GROUP_get_curve_name( |
||||||
|
ctx->pctx->pkey->pkey.ec->group))) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
err: |
||||||
|
// Ensure that junk errors aren't left on the queue.
|
||||||
|
ERR_clear_error(); |
||||||
|
} |
||||||
|
|
||||||
|
void EC_KEY_keygen_verify_service_indicator(const EC_KEY *eckey) { |
||||||
|
if (is_ec_fips_approved(EC_GROUP_get_curve_name(eckey->group))) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void ECDH_verify_service_indicator(const EC_KEY *ec_key) { |
||||||
|
if (is_ec_fips_approved(EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key)))) { |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void EVP_Cipher_verify_service_indicator(const EVP_CIPHER_CTX *ctx) { |
||||||
|
switch (EVP_CIPHER_CTX_nid(ctx)) { |
||||||
|
case NID_aes_128_ecb: |
||||||
|
case NID_aes_192_ecb: |
||||||
|
case NID_aes_256_ecb: |
||||||
|
|
||||||
|
case NID_aes_128_cbc: |
||||||
|
case NID_aes_192_cbc: |
||||||
|
case NID_aes_256_cbc: |
||||||
|
|
||||||
|
case NID_aes_128_ctr: |
||||||
|
case NID_aes_192_ctr: |
||||||
|
case NID_aes_256_ctr: |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void EVP_DigestVerify_verify_service_indicator(const EVP_MD_CTX *ctx) { |
||||||
|
return evp_md_ctx_verify_service_indicator(ctx, /*rsa_1024_ok=*/1, |
||||||
|
is_md_fips_approved_for_verifying); |
||||||
|
} |
||||||
|
|
||||||
|
void EVP_DigestSign_verify_service_indicator(const EVP_MD_CTX *ctx) { |
||||||
|
return evp_md_ctx_verify_service_indicator(ctx, /*rsa_1024_ok=*/0, |
||||||
|
is_md_fips_approved_for_signing); |
||||||
|
} |
||||||
|
|
||||||
|
void HMAC_verify_service_indicator(const EVP_MD *evp_md) { |
||||||
|
switch (evp_md->type) { |
||||||
|
case NID_sha1: |
||||||
|
case NID_sha224: |
||||||
|
case NID_sha256: |
||||||
|
case NID_sha384: |
||||||
|
case NID_sha512: |
||||||
|
case NID_sha512_256: |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void TLSKDF_verify_service_indicator(const EVP_MD *md) { |
||||||
|
// HMAC-MD5, HMAC-SHA1, and HMAC-MD5/HMAC-SHA1 (both used concurrently) are
|
||||||
|
// approved for use in the KDF in TLS 1.0/1.1.
|
||||||
|
// HMAC-SHA{256, 384, 512} are approved for use in the KDF in TLS 1.2.
|
||||||
|
// These Key Derivation functions are to be used in the context of the TLS
|
||||||
|
// protocol.
|
||||||
|
switch (EVP_MD_type(md)) { |
||||||
|
case NID_md5: |
||||||
|
case NID_sha1: |
||||||
|
case NID_md5_sha1: |
||||||
|
case NID_sha256: |
||||||
|
case NID_sha384: |
||||||
|
case NID_sha512: |
||||||
|
FIPS_service_indicator_update_state(); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
#else |
||||||
|
|
||||||
|
uint64_t FIPS_service_indicator_before_call(void) { return 0; } |
||||||
|
|
||||||
|
uint64_t FIPS_service_indicator_after_call(void) { |
||||||
|
// One is returned so that the return value is always greater than zero, the
|
||||||
|
// return value of |FIPS_service_indicator_before_call|. This makes everything
|
||||||
|
// report as "approved" in non-FIPS builds.
|
||||||
|
return 1; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // BORINGSSL_FIPS
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,96 @@ |
|||||||
|
/* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
* |
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any |
||||||
|
* purpose with or without fee is hereby granted, provided that the above |
||||||
|
* copyright notice and this permission notice appear in all copies. |
||||||
|
* |
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
||||||
|
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||||||
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
||||||
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ |
||||||
|
|
||||||
|
#ifndef OPENSSL_HEADER_SERVICE_INDICATOR_H |
||||||
|
#define OPENSSL_HEADER_SERVICE_INDICATOR_H |
||||||
|
|
||||||
|
#include <openssl/base.h> |
||||||
|
|
||||||
|
#if defined(__cplusplus) |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
// FIPS_service_indicator_before_call and |FIPS_service_indicator_after_call|
|
||||||
|
// both currently return the same local thread counter which is slowly
|
||||||
|
// incremented whenever approved services are called. The
|
||||||
|
// |CALL_SERVICE_AND_CHECK_APPROVED| macro is strongly recommended over calling
|
||||||
|
// these functions directly.
|
||||||
|
//
|
||||||
|
// |FIPS_service_indicator_before_call| is intended to be called immediately
|
||||||
|
// before an approved service, while |FIPS_service_indicator_after_call| should
|
||||||
|
// be called immediately after. If the values returned from these two functions
|
||||||
|
// are not equal, this means that the service called inbetween is deemed to be
|
||||||
|
// approved. If the values are still the same, this means the counter has not
|
||||||
|
// been incremented, and the service called is not approved for FIPS.
|
||||||
|
//
|
||||||
|
// In non-FIPS builds, |FIPS_service_indicator_before_call| always returns zero
|
||||||
|
// and |FIPS_service_indicator_after_call| always returns one. Thus calls always
|
||||||
|
// appear to be approved. This is intended to simplify testing.
|
||||||
|
OPENSSL_EXPORT uint64_t FIPS_service_indicator_before_call(void); |
||||||
|
OPENSSL_EXPORT uint64_t FIPS_service_indicator_after_call(void); |
||||||
|
|
||||||
|
#if defined(__cplusplus) |
||||||
|
} |
||||||
|
|
||||||
|
#if !defined(BORINGSSL_NO_CXX) |
||||||
|
|
||||||
|
extern "C++" { |
||||||
|
|
||||||
|
// CALL_SERVICE_AND_CHECK_APPROVED runs |func| and sets |approved| to one of the
|
||||||
|
// |FIPSStatus*| values, above, depending on whether |func| invoked an
|
||||||
|
// approved service. The result of |func| becomes the result of this macro.
|
||||||
|
#define CALL_SERVICE_AND_CHECK_APPROVED(approved, func) \ |
||||||
|
[&] { \
|
||||||
|
bssl::FIPSIndicatorHelper fips_indicator_helper(&approved); \
|
||||||
|
return func; \
|
||||||
|
}() |
||||||
|
|
||||||
|
namespace bssl { |
||||||
|
|
||||||
|
enum class FIPSStatus { |
||||||
|
NOT_APPROVED = 0, |
||||||
|
APPROVED = 1, |
||||||
|
}; |
||||||
|
|
||||||
|
// FIPSIndicatorHelper records whether the service indicator counter advanced
|
||||||
|
// during its lifetime.
|
||||||
|
class FIPSIndicatorHelper { |
||||||
|
public: |
||||||
|
FIPSIndicatorHelper(FIPSStatus *result) |
||||||
|
: result_(result), before_(FIPS_service_indicator_before_call()) { |
||||||
|
*result_ = FIPSStatus::NOT_APPROVED; |
||||||
|
} |
||||||
|
|
||||||
|
~FIPSIndicatorHelper() { |
||||||
|
uint64_t after = FIPS_service_indicator_after_call(); |
||||||
|
if (after != before_) { |
||||||
|
*result_ = FIPSStatus::APPROVED; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
FIPSIndicatorHelper(const FIPSIndicatorHelper&) = delete; |
||||||
|
FIPSIndicatorHelper &operator=(const FIPSIndicatorHelper &) = delete; |
||||||
|
|
||||||
|
private: |
||||||
|
FIPSStatus *const result_; |
||||||
|
const uint64_t before_; |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace bssl
|
||||||
|
} // extern "C++"
|
||||||
|
|
||||||
|
#endif // !BORINGSSL_NO_CXX
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
#endif // OPENSSL_HEADER_SERVICE_INDICATOR_H
|
Loading…
Reference in new issue