Add a service indicator for FIPS 140-3.

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
Adam Langley 3 years ago committed by Boringssl LUCI CQ
parent f5d6d24bd6
commit 118a892d2d
  1. 1
      crypto/CMakeLists.txt
  2. 51
      crypto/evp/digestsign.c
  3. 12
      crypto/fipsmodule/aes/key_wrap.c
  4. 16
      crypto/fipsmodule/aes/mode_wrappers.c
  5. 1
      crypto/fipsmodule/bcm.c
  6. 10
      crypto/fipsmodule/bn/random.c
  7. 54
      crypto/fipsmodule/cipher/cipher.c
  8. 58
      crypto/fipsmodule/cipher/e_aes.c
  9. 3
      crypto/fipsmodule/cipher/e_aesccm.c
  10. 56
      crypto/fipsmodule/cmac/cmac.c
  11. 6
      crypto/fipsmodule/dh/dh.c
  12. 19
      crypto/fipsmodule/ec/ec_key.c
  13. 4
      crypto/fipsmodule/ecdh/ecdh.c
  14. 18
      crypto/fipsmodule/ecdsa/ecdsa.c
  15. 49
      crypto/fipsmodule/hmac/hmac.c
  16. 2
      crypto/fipsmodule/rand/ctrdrbg.c
  17. 41
      crypto/fipsmodule/rsa/padding.c
  18. 9
      crypto/fipsmodule/rsa/rsa_impl.c
  19. 7
      crypto/fipsmodule/self_check/self_check.c
  20. 89
      crypto/fipsmodule/service_indicator/internal.h
  21. 333
      crypto/fipsmodule/service_indicator/service_indicator.c
  22. 2410
      crypto/fipsmodule/service_indicator/service_indicator_test.cc
  23. 2
      crypto/fipsmodule/sha/sha1.c
  24. 3
      crypto/fipsmodule/sha/sha256.c
  25. 4
      crypto/fipsmodule/sha/sha512.c
  26. 16
      crypto/fipsmodule/tls/kdf.c
  27. 1
      crypto/internal.h
  28. 96
      include/openssl/service_indicator.h

@ -530,6 +530,7 @@ add_executable(
fipsmodule/modes/gcm_test.cc fipsmodule/modes/gcm_test.cc
fipsmodule/rand/ctrdrbg_test.cc fipsmodule/rand/ctrdrbg_test.cc
fipsmodule/rand/fork_detect_test.cc fipsmodule/rand/fork_detect_test.cc
fipsmodule/service_indicator/service_indicator_test.cc
fipsmodule/sha/sha_test.cc fipsmodule/sha/sha_test.cc
hkdf/hkdf_test.cc hkdf/hkdf_test.cc
hpke/hpke_test.cc hpke/hpke_test.cc

@ -59,6 +59,9 @@
#include "internal.h" #include "internal.h"
#include "../fipsmodule/digest/internal.h" #include "../fipsmodule/digest/internal.h"
#include "../fipsmodule/service_indicator/internal.h"
// TODO(agl): this will have to be moved into the FIPS module.
enum evp_sign_verify_t { enum evp_sign_verify_t {
@ -159,11 +162,17 @@ int EVP_DigestSignFinal(EVP_MD_CTX *ctx, uint8_t *out_sig,
uint8_t md[EVP_MAX_MD_SIZE]; uint8_t md[EVP_MAX_MD_SIZE];
unsigned int mdlen; unsigned int mdlen;
FIPS_service_indicator_lock_state();
EVP_MD_CTX_init(&tmp_ctx); EVP_MD_CTX_init(&tmp_ctx);
ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) &&
EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen); EVP_PKEY_sign(ctx->pctx, out_sig, out_sig_len, md, mdlen);
EVP_MD_CTX_cleanup(&tmp_ctx); EVP_MD_CTX_cleanup(&tmp_ctx);
FIPS_service_indicator_unlock_state();
if (ret) {
EVP_DigestSign_verify_service_indicator(ctx);
}
return ret; return ret;
} else { } else {
@ -184,48 +193,76 @@ int EVP_DigestVerifyFinal(EVP_MD_CTX *ctx, const uint8_t *sig,
uint8_t md[EVP_MAX_MD_SIZE]; uint8_t md[EVP_MAX_MD_SIZE];
unsigned int mdlen; unsigned int mdlen;
FIPS_service_indicator_lock_state();
EVP_MD_CTX_init(&tmp_ctx); EVP_MD_CTX_init(&tmp_ctx);
ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) && ret = EVP_MD_CTX_copy_ex(&tmp_ctx, ctx) &&
EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) && EVP_DigestFinal_ex(&tmp_ctx, md, &mdlen) &&
EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen); EVP_PKEY_verify(ctx->pctx, sig, sig_len, md, mdlen);
FIPS_service_indicator_unlock_state();
EVP_MD_CTX_cleanup(&tmp_ctx); EVP_MD_CTX_cleanup(&tmp_ctx);
if (ret) {
EVP_DigestVerify_verify_service_indicator(ctx);
}
return ret; return ret;
} }
int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len, int EVP_DigestSign(EVP_MD_CTX *ctx, uint8_t *out_sig, size_t *out_sig_len,
const uint8_t *data, size_t data_len) { const uint8_t *data, size_t data_len) {
FIPS_service_indicator_lock_state();
int ret = 0;
if (uses_prehash(ctx, evp_sign)) { if (uses_prehash(ctx, evp_sign)) {
// If |out_sig| is NULL, the caller is only querying the maximum output // If |out_sig| is NULL, the caller is only querying the maximum output
// length. |data| should only be incorporated in the final call. // length. |data| should only be incorporated in the final call.
if (out_sig != NULL && if (out_sig != NULL &&
!EVP_DigestSignUpdate(ctx, data, data_len)) { !EVP_DigestSignUpdate(ctx, data, data_len)) {
return 0; goto end;
} }
return EVP_DigestSignFinal(ctx, out_sig, out_sig_len); ret = EVP_DigestSignFinal(ctx, out_sig, out_sig_len);
goto end;
} }
if (ctx->pctx->pmeth->sign_message == NULL) { if (ctx->pctx->pmeth->sign_message == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0; goto end;
} }
return ctx->pctx->pmeth->sign_message(ctx->pctx, out_sig, out_sig_len, data, ret = ctx->pctx->pmeth->sign_message(ctx->pctx, out_sig, out_sig_len, data,
data_len); data_len);
end:
FIPS_service_indicator_unlock_state();
if (ret) {
EVP_DigestSign_verify_service_indicator(ctx);
}
return ret;
} }
int EVP_DigestVerify(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len, int EVP_DigestVerify(EVP_MD_CTX *ctx, const uint8_t *sig, size_t sig_len,
const uint8_t *data, size_t len) { const uint8_t *data, size_t len) {
FIPS_service_indicator_lock_state();
int ret = 0;
if (uses_prehash(ctx, evp_verify)) { if (uses_prehash(ctx, evp_verify)) {
return EVP_DigestVerifyUpdate(ctx, data, len) && ret = EVP_DigestVerifyUpdate(ctx, data, len) &&
EVP_DigestVerifyFinal(ctx, sig, sig_len); EVP_DigestVerifyFinal(ctx, sig, sig_len);
goto end;
} }
if (ctx->pctx->pmeth->verify_message == NULL) { if (ctx->pctx->pmeth->verify_message == NULL) {
OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE); OPENSSL_PUT_ERROR(EVP, EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
return 0; goto end;
} }
return ctx->pctx->pmeth->verify_message(ctx->pctx, sig, sig_len, data, len); ret = ctx->pctx->pmeth->verify_message(ctx->pctx, sig, sig_len, data, len);
end:
FIPS_service_indicator_unlock_state();
if (ret) {
EVP_DigestVerify_verify_service_indicator(ctx);
}
return ret;
} }

@ -55,6 +55,7 @@
#include <openssl/mem.h> #include <openssl/mem.h>
#include "../../internal.h" #include "../../internal.h"
#include "../service_indicator/internal.h"
// kDefaultIV is the default IV value given in RFC 3394, 2.2.3.1. // kDefaultIV is the default IV value given in RFC 3394, 2.2.3.1.
@ -98,6 +99,7 @@ int AES_wrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
} }
OPENSSL_memcpy(out, A, 8); OPENSSL_memcpy(out, A, 8);
FIPS_service_indicator_update_state();
return (int)in_len + 8; return (int)in_len + 8;
} }
@ -151,6 +153,7 @@ int AES_unwrap_key(const AES_KEY *key, const uint8_t *iv, uint8_t *out,
return -1; return -1;
} }
FIPS_service_indicator_update_state();
return (int)in_len - 8; return (int)in_len - 8;
} }
@ -190,12 +193,15 @@ int AES_wrap_key_padded(const AES_KEY *key, uint8_t *out, size_t *out_len,
assert(padded_len >= 8); assert(padded_len >= 8);
memset(padded_in + padded_len - 8, 0, 8); memset(padded_in + padded_len - 8, 0, 8);
memcpy(padded_in, in, in_len); memcpy(padded_in, in, in_len);
FIPS_service_indicator_lock_state();
const int ret = AES_wrap_key(key, block, out, padded_in, padded_len); const int ret = AES_wrap_key(key, block, out, padded_in, padded_len);
FIPS_service_indicator_unlock_state();
OPENSSL_free(padded_in); OPENSSL_free(padded_in);
if (ret < 0) { if (ret < 0) {
return 0; return 0;
} }
*out_len = ret; *out_len = ret;
FIPS_service_indicator_update_state();
return 1; return 1;
} }
@ -232,5 +238,9 @@ int AES_unwrap_key_padded(const AES_KEY *key, uint8_t *out, size_t *out_len,
} }
*out_len = constant_time_select_w(ok, claimed_len, 0); *out_len = constant_time_select_w(ok, claimed_len, 0);
return ok & 1; const int ret = ok & 1;
if (ret) {
FIPS_service_indicator_update_state();
}
return ret;
} }

@ -52,6 +52,7 @@
#include "../aes/internal.h" #include "../aes/internal.h"
#include "../modes/internal.h" #include "../modes/internal.h"
#include "../service_indicator/internal.h"
void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len, void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
@ -74,6 +75,8 @@ void AES_ctr128_encrypt(const uint8_t *in, uint8_t *out, size_t len,
CRYPTO_ctr128_encrypt_ctr32(in, out, len, key, ivec, ecount_buf, num, CRYPTO_ctr128_encrypt_ctr32(in, out, len, key, ivec, ecount_buf, num,
aes_nohw_ctr32_encrypt_blocks); aes_nohw_ctr32_encrypt_blocks);
} }
FIPS_service_indicator_update_state();
} }
void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key, void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key,
@ -86,24 +89,23 @@ void AES_ecb_encrypt(const uint8_t *in, uint8_t *out, const AES_KEY *key,
} else { } else {
AES_decrypt(in, out, key); AES_decrypt(in, out, key);
} }
FIPS_service_indicator_update_state();
} }
void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len, void AES_cbc_encrypt(const uint8_t *in, uint8_t *out, size_t len,
const AES_KEY *key, uint8_t *ivec, const int enc) { const AES_KEY *key, uint8_t *ivec, const int enc) {
if (hwaes_capable()) { if (hwaes_capable()) {
aes_hw_cbc_encrypt(in, out, len, key, ivec, enc); aes_hw_cbc_encrypt(in, out, len, key, ivec, enc);
return; } else if (!vpaes_capable()) {
}
if (!vpaes_capable()) {
aes_nohw_cbc_encrypt(in, out, len, key, ivec, enc); aes_nohw_cbc_encrypt(in, out, len, key, ivec, enc);
return; } else if (enc) {
}
if (enc) {
CRYPTO_cbc128_encrypt(in, out, len, key, ivec, AES_encrypt); CRYPTO_cbc128_encrypt(in, out, len, key, ivec, AES_encrypt);
} else { } else {
CRYPTO_cbc128_decrypt(in, out, len, key, ivec, AES_decrypt); CRYPTO_cbc128_decrypt(in, out, len, key, ivec, AES_decrypt);
} }
FIPS_service_indicator_update_state();
} }
void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length, void AES_ofb128_encrypt(const uint8_t *in, uint8_t *out, size_t length,

@ -99,6 +99,7 @@
#include "rsa/rsa_impl.c" #include "rsa/rsa_impl.c"
#include "self_check/fips.c" #include "self_check/fips.c"
#include "self_check/self_check.c" #include "self_check/self_check.c"
#include "service_indicator/service_indicator.c"
#include "sha/sha1-altivec.c" #include "sha/sha1-altivec.c"
#include "sha/sha1.c" #include "sha/sha1.c"
#include "sha/sha256.c" #include "sha/sha256.c"

@ -115,9 +115,10 @@
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/type_check.h> #include <openssl/type_check.h>
#include "internal.h"
#include "../../internal.h" #include "../../internal.h"
#include "../rand/internal.h" #include "../rand/internal.h"
#include "../service_indicator/internal.h"
#include "internal.h"
int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) { int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
@ -155,7 +156,10 @@ int BN_rand(BIGNUM *rnd, int bits, int top, int bottom) {
return 0; return 0;
} }
FIPS_service_indicator_lock_state();
RAND_bytes((uint8_t *)rnd->d, words * sizeof(BN_ULONG)); RAND_bytes((uint8_t *)rnd->d, words * sizeof(BN_ULONG));
FIPS_service_indicator_unlock_state();
rnd->d[words - 1] &= mask; rnd->d[words - 1] &= mask;
if (top != BN_RAND_TOP_ANY) { if (top != BN_RAND_TOP_ANY) {
if (top == BN_RAND_TOP_TWO && bits > 1) { if (top == BN_RAND_TOP_TWO && bits > 1) {
@ -270,8 +274,10 @@ int bn_rand_range_words(BN_ULONG *out, BN_ULONG min_inclusive,
// Steps 4 and 5. Use |words| and |mask| together to obtain a string of N // Steps 4 and 5. Use |words| and |mask| together to obtain a string of N
// bits, where N is the bit length of |max_exclusive|. // bits, where N is the bit length of |max_exclusive|.
FIPS_service_indicator_lock_state();
RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG), RAND_bytes_with_additional_data((uint8_t *)out, words * sizeof(BN_ULONG),
additional_data); additional_data);
FIPS_service_indicator_unlock_state();
out[words - 1] &= mask; out[words - 1] &= mask;
// If out >= max_exclusive or out < min_inclusive, retry. This implements // If out >= max_exclusive or out < min_inclusive, retry. This implements
@ -313,7 +319,9 @@ int bn_rand_secret_range(BIGNUM *r, int *out_is_uniform, BN_ULONG min_inclusive,
} }
// Select a uniform random number with num_bits(max_exclusive) bits. // Select a uniform random number with num_bits(max_exclusive) bits.
FIPS_service_indicator_lock_state();
RAND_bytes((uint8_t *)r->d, words * sizeof(BN_ULONG)); RAND_bytes((uint8_t *)r->d, words * sizeof(BN_ULONG));
FIPS_service_indicator_unlock_state();
r->d[words - 1] &= mask; r->d[words - 1] &= mask;
// Check, in constant-time, if the value is in range. // Check, in constant-time, if the value is in range.

@ -65,6 +65,7 @@
#include <openssl/nid.h> #include <openssl/nid.h>
#include "internal.h" #include "internal.h"
#include "../service_indicator/internal.h"
#include "../../internal.h" #include "../../internal.h"
@ -322,24 +323,26 @@ int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
} }
int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) { int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
int n, ret; int n;
unsigned int i, b, bl; unsigned int i, b, bl;
if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) { if (ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) {
ret = ctx->cipher->cipher(ctx, out, NULL, 0); // When EVP_CIPH_FLAG_CUSTOM_CIPHER is set, the return value of |cipher| is
if (ret < 0) { // the number of bytes written, or -1 on error. Otherwise the return value
// is one on success and zero on error.
const int num_bytes = ctx->cipher->cipher(ctx, out, NULL, 0);
if (num_bytes < 0) {
return 0; return 0;
} else {
*out_len = ret;
} }
return 1; *out_len = num_bytes;
goto out;
} }
b = ctx->cipher->block_size; b = ctx->cipher->block_size;
assert(b <= sizeof(ctx->buf)); assert(b <= sizeof(ctx->buf));
if (b == 1) { if (b == 1) {
*out_len = 0; *out_len = 0;
return 1; goto out;
} }
bl = ctx->buf_len; bl = ctx->buf_len;
@ -349,20 +352,21 @@ int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len) {
return 0; return 0;
} }
*out_len = 0; *out_len = 0;
return 1; goto out;
} }
n = b - bl; n = b - bl;
for (i = bl; i < b; i++) { for (i = bl; i < b; i++) {
ctx->buf[i] = n; ctx->buf[i] = n;
} }
ret = ctx->cipher->cipher(ctx, out, ctx->buf, b); if (!ctx->cipher->cipher(ctx, out, ctx->buf, b)) {
return 0;
if (ret) {
*out_len = b;
} }
*out_len = b;
return ret; out:
EVP_Cipher_verify_service_indicator(ctx);
return 1;
} }
int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,
@ -436,7 +440,7 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
} else { } else {
*out_len = i; *out_len = i;
} }
return 1; goto out;
} }
b = ctx->cipher->block_size; b = ctx->cipher->block_size;
@ -446,7 +450,7 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
return 0; return 0;
} }
*out_len = 0; *out_len = 0;
return 1; goto out;
} }
if (b > 1) { if (b > 1) {
@ -480,12 +484,30 @@ int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) {
*out_len = 0; *out_len = 0;
} }
out:
EVP_Cipher_verify_service_indicator(ctx);
return 1; return 1;
} }
int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in, int EVP_Cipher(EVP_CIPHER_CTX *ctx, uint8_t *out, const uint8_t *in,
size_t in_len) { size_t in_len) {
return ctx->cipher->cipher(ctx, out, in, in_len); const int ret = ctx->cipher->cipher(ctx, out, in, in_len);
// |EVP_CIPH_FLAG_CUSTOM_CIPHER| never sets the FIPS indicator via
// |EVP_Cipher| because it's complicated whether the operation has completed
// or not. E.g. AES-GCM with a non-NULL |in| argument hasn't completed an
// operation. Callers should use the |EVP_AEAD| API or, at least,
// |EVP_CipherUpdate| etc.
//
// This call can't be pushed into |EVP_Cipher_verify_service_indicator|
// because whether |ret| indicates success or not depends on whether
// |EVP_CIPH_FLAG_CUSTOM_CIPHER| is set. (This unreasonable, but matches
// OpenSSL.)
if (!(ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) && ret) {
EVP_Cipher_verify_service_indicator(ctx);
}
return ret;
} }
int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len, int EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, uint8_t *out, int *out_len,

@ -61,6 +61,7 @@
#include "../../internal.h" #include "../../internal.h"
#include "../aes/internal.h" #include "../aes/internal.h"
#include "../modes/internal.h" #include "../modes/internal.h"
#include "../service_indicator/internal.h"
#include "../delocate.h" #include "../delocate.h"
@ -485,8 +486,13 @@ static int aes_gcm_ctrl(EVP_CIPHER_CTX *c, int type, int arg, void *ptr) {
if (arg) { if (arg) {
OPENSSL_memcpy(gctx->iv, ptr, arg); OPENSSL_memcpy(gctx->iv, ptr, arg);
} }
if (c->encrypt && !RAND_bytes(gctx->iv + arg, gctx->ivlen - arg)) { if (c->encrypt) {
return 0; // |RAND_bytes| calls within the fipsmodule should be wrapped with state
// lock functions to avoid updating the service indicator with the DRBG
// functions.
FIPS_service_indicator_lock_state();
RAND_bytes(gctx->iv + arg, gctx->ivlen - arg);
FIPS_service_indicator_unlock_state();
} }
gctx->iv_gen = 1; gctx->iv_gen = 1;
return 1; return 1;
@ -1099,9 +1105,14 @@ static int aead_aes_gcm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
const uint8_t *in_tag, size_t in_tag_len, const uint8_t *in_tag, size_t in_tag_len,
const uint8_t *ad, size_t ad_len) { const uint8_t *ad, size_t ad_len) {
struct aead_aes_gcm_ctx *gcm_ctx = (struct aead_aes_gcm_ctx *)&ctx->state; struct aead_aes_gcm_ctx *gcm_ctx = (struct aead_aes_gcm_ctx *)&ctx->state;
return aead_aes_gcm_open_gather_impl(gcm_ctx, out, nonce, nonce_len, in, if (!aead_aes_gcm_open_gather_impl(gcm_ctx, out, nonce, nonce_len, in, in_len,
in_len, in_tag, in_tag_len, ad, ad_len, in_tag, in_tag_len, ad, ad_len,
ctx->tag_len); ctx->tag_len)) {
return 0;
}
AEAD_GCM_verify_service_indicator(ctx);
return 1;
} }
DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm) { DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm) {
@ -1186,7 +1197,12 @@ static int aead_aes_gcm_seal_scatter_randnonce(
return 0; return 0;
} }
// |RAND_bytes| calls within the fipsmodule should be wrapped with state lock
// functions to avoid updating the service indicator with the DRBG functions.
FIPS_service_indicator_lock_state();
RAND_bytes(nonce, sizeof(nonce)); RAND_bytes(nonce, sizeof(nonce));
FIPS_service_indicator_unlock_state();
const struct aead_aes_gcm_ctx *gcm_ctx = const struct aead_aes_gcm_ctx *gcm_ctx =
(const struct aead_aes_gcm_ctx *)&ctx->state; (const struct aead_aes_gcm_ctx *)&ctx->state;
if (!aead_aes_gcm_seal_scatter_impl(gcm_ctx, out, out_tag, out_tag_len, if (!aead_aes_gcm_seal_scatter_impl(gcm_ctx, out, out_tag, out_tag_len,
@ -1201,6 +1217,7 @@ static int aead_aes_gcm_seal_scatter_randnonce(
memcpy(out_tag + *out_tag_len, nonce, sizeof(nonce)); memcpy(out_tag + *out_tag_len, nonce, sizeof(nonce));
*out_tag_len += sizeof(nonce); *out_tag_len += sizeof(nonce);
AEAD_GCM_verify_service_indicator(ctx);
return 1; return 1;
} }
@ -1223,10 +1240,15 @@ static int aead_aes_gcm_open_gather_randnonce(
const struct aead_aes_gcm_ctx *gcm_ctx = const struct aead_aes_gcm_ctx *gcm_ctx =
(const struct aead_aes_gcm_ctx *)&ctx->state; (const struct aead_aes_gcm_ctx *)&ctx->state;
return aead_aes_gcm_open_gather_impl( if (!aead_aes_gcm_open_gather_impl(
gcm_ctx, out, nonce, AES_GCM_NONCE_LENGTH, in, in_len, in_tag, gcm_ctx, out, nonce, AES_GCM_NONCE_LENGTH, in, in_len, in_tag,
in_tag_len - AES_GCM_NONCE_LENGTH, ad, ad_len, in_tag_len - AES_GCM_NONCE_LENGTH, ad, ad_len,
ctx->tag_len - AES_GCM_NONCE_LENGTH); ctx->tag_len - AES_GCM_NONCE_LENGTH)) {
return 0;
}
AEAD_GCM_verify_service_indicator(ctx);
return 1;
} }
DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_randnonce) { DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_randnonce) {
@ -1316,9 +1338,14 @@ static int aead_aes_gcm_tls12_seal_scatter(
gcm_ctx->min_next_nonce = given_counter + 1; gcm_ctx->min_next_nonce = given_counter + 1;
return aead_aes_gcm_seal_scatter(ctx, out, out_tag, out_tag_len, if (!aead_aes_gcm_seal_scatter(ctx, out, out_tag, out_tag_len,
max_out_tag_len, nonce, nonce_len, in, max_out_tag_len, nonce, nonce_len, in, in_len,
in_len, extra_in, extra_in_len, ad, ad_len); extra_in, extra_in_len, ad, ad_len)) {
return 0;
}
AEAD_GCM_verify_service_indicator(ctx);
return 1;
} }
DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_tls12) { DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_tls12) {
@ -1422,9 +1449,14 @@ static int aead_aes_gcm_tls13_seal_scatter(
gcm_ctx->min_next_nonce = given_counter + 1; gcm_ctx->min_next_nonce = given_counter + 1;
return aead_aes_gcm_seal_scatter(ctx, out, out_tag, out_tag_len, if (!aead_aes_gcm_seal_scatter(ctx, out, out_tag, out_tag_len,
max_out_tag_len, nonce, nonce_len, in, max_out_tag_len, nonce, nonce_len, in, in_len,
in_len, extra_in, extra_in_len, ad, ad_len); extra_in, extra_in_len, ad, ad_len)) {
return 0;
}
AEAD_GCM_verify_service_indicator(ctx);
return 1;
} }
DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_tls13) { DEFINE_METHOD_FUNCTION(EVP_AEAD, EVP_aead_aes_128_gcm_tls13) {

@ -55,6 +55,7 @@
#include <openssl/mem.h> #include <openssl/mem.h>
#include "internal.h" #include "internal.h"
#include "../service_indicator/internal.h"
struct ccm128_context { struct ccm128_context {
@ -350,6 +351,7 @@ static int aead_aes_ccm_seal_scatter(
} }
*out_tag_len = ctx->tag_len; *out_tag_len = ctx->tag_len;
AEAD_CCM_verify_service_indicator(ctx);
return 1; return 1;
} }
@ -390,6 +392,7 @@ static int aead_aes_ccm_open_gather(const EVP_AEAD_CTX *ctx, uint8_t *out,
return 0; return 0;
} }
AEAD_CCM_verify_service_indicator(ctx);
return 1; return 1;
} }

@ -56,6 +56,7 @@
#include <openssl/mem.h> #include <openssl/mem.h>
#include "../../internal.h" #include "../../internal.h"
#include "../service_indicator/internal.h"
struct cmac_ctx_st { struct cmac_ctx_st {
@ -85,6 +86,8 @@ int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len,
const uint8_t *in, size_t in_len) { const uint8_t *in, size_t in_len) {
const EVP_CIPHER *cipher; const EVP_CIPHER *cipher;
switch (key_len) { switch (key_len) {
// WARNING: this code assumes that all supported key sizes are FIPS
// Approved.
case 16: case 16:
cipher = EVP_aes_128_cbc(); cipher = EVP_aes_128_cbc();
break; break;
@ -99,10 +102,17 @@ int AES_CMAC(uint8_t out[16], const uint8_t *key, size_t key_len,
CMAC_CTX ctx; CMAC_CTX ctx;
CMAC_CTX_init(&ctx); CMAC_CTX_init(&ctx);
// We have to verify that all the CMAC services actually succeed before
// updating the indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
const int ok = CMAC_Init(&ctx, key, key_len, cipher, NULL /* engine */) && const int ok = CMAC_Init(&ctx, key, key_len, cipher, NULL /* engine */) &&
CMAC_Update(&ctx, in, in_len) && CMAC_Update(&ctx, in, in_len) &&
CMAC_Final(&ctx, out, &scratch_out_len); CMAC_Final(&ctx, out, &scratch_out_len);
FIPS_service_indicator_unlock_state();
if (ok) {
FIPS_service_indicator_update_state();
}
CMAC_CTX_cleanup(&ctx); CMAC_CTX_cleanup(&ctx);
return ok; return ok;
} }
@ -173,8 +183,13 @@ static const uint8_t kZeroIV[AES_BLOCK_SIZE] = {0};
int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len, int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len,
const EVP_CIPHER *cipher, ENGINE *engine) { const EVP_CIPHER *cipher, ENGINE *engine) {
int ret = 0;
uint8_t scratch[AES_BLOCK_SIZE]; uint8_t scratch[AES_BLOCK_SIZE];
// We have to avoid the underlying AES-CBC |EVP_CIPHER| services updating the
// indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
size_t block_size = EVP_CIPHER_block_size(cipher); size_t block_size = EVP_CIPHER_block_size(cipher);
if ((block_size != AES_BLOCK_SIZE && block_size != 8 /* 3-DES */) || if ((block_size != AES_BLOCK_SIZE && block_size != 8 /* 3-DES */) ||
EVP_CIPHER_key_length(cipher) != key_len || EVP_CIPHER_key_length(cipher) != key_len ||
@ -182,7 +197,7 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len,
!EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, block_size) || !EVP_Cipher(&ctx->cipher_ctx, scratch, kZeroIV, block_size) ||
// Reset context again ready for first data. // Reset context again ready for first data.
!EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV)) { !EVP_EncryptInit_ex(&ctx->cipher_ctx, NULL, NULL, NULL, kZeroIV)) {
return 0; goto out;
} }
if (block_size == AES_BLOCK_SIZE) { if (block_size == AES_BLOCK_SIZE) {
@ -193,8 +208,11 @@ int CMAC_Init(CMAC_CTX *ctx, const void *key, size_t key_len,
binary_field_mul_x_64(ctx->k2, ctx->k1); binary_field_mul_x_64(ctx->k2, ctx->k1);
} }
ctx->block_used = 0; ctx->block_used = 0;
ret = 1;
return 1; out:
FIPS_service_indicator_unlock_state();
return ret;
} }
int CMAC_Reset(CMAC_CTX *ctx) { int CMAC_Reset(CMAC_CTX *ctx) {
@ -203,6 +221,12 @@ int CMAC_Reset(CMAC_CTX *ctx) {
} }
int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) { int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
int ret = 0;
// We have to avoid the underlying AES-CBC |EVP_Cipher| services updating the
// indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx); size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx);
assert(block_size <= AES_BLOCK_SIZE); assert(block_size <= AES_BLOCK_SIZE);
uint8_t scratch[AES_BLOCK_SIZE]; uint8_t scratch[AES_BLOCK_SIZE];
@ -224,20 +248,21 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
// case we don't want to process this block now because it might be the last // case we don't want to process this block now because it might be the last
// block and that block is treated specially. // block and that block is treated specially.
if (in_len == 0) { if (in_len == 0) {
return 1; ret = 1;
goto out;
} }
assert(ctx->block_used == block_size); assert(ctx->block_used == block_size);
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, block_size)) { if (!EVP_Cipher(&ctx->cipher_ctx, scratch, ctx->block, block_size)) {
return 0; goto out;
} }
} }
// Encrypt all but one of the remaining blocks. // Encrypt all but one of the remaining blocks.
while (in_len > block_size) { while (in_len > block_size) {
if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, block_size)) { if (!EVP_Cipher(&ctx->cipher_ctx, scratch, in, block_size)) {
return 0; goto out;
} }
in += block_size; in += block_size;
in_len -= block_size; in_len -= block_size;
@ -245,17 +270,26 @@ int CMAC_Update(CMAC_CTX *ctx, const uint8_t *in, size_t in_len) {
OPENSSL_memcpy(ctx->block, in, in_len); OPENSSL_memcpy(ctx->block, in, in_len);
ctx->block_used = in_len; ctx->block_used = in_len;
ret = 1;
return 1; out:
FIPS_service_indicator_unlock_state();
return ret;
} }
int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) { int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) {
int ret = 0;
size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx); size_t block_size = EVP_CIPHER_CTX_block_size(&ctx->cipher_ctx);
assert(block_size <= AES_BLOCK_SIZE); assert(block_size <= AES_BLOCK_SIZE);
// We have to avoid the underlying AES-CBC |EVP_Cipher| services updating the
// indicator state, so we lock the state here.
FIPS_service_indicator_lock_state();
*out_len = block_size; *out_len = block_size;
if (out == NULL) { if (out == NULL) {
return 1; ret = 1;
goto out;
} }
const uint8_t *mask = ctx->k1; const uint8_t *mask = ctx->k1;
@ -273,6 +307,12 @@ int CMAC_Final(CMAC_CTX *ctx, uint8_t *out, size_t *out_len) {
for (unsigned i = 0; i < block_size; i++) { for (unsigned i = 0; i < block_size; i++) {
out[i] = ctx->block[i] ^ mask[i]; out[i] = ctx->block[i] ^ mask[i];
} }
ret = EVP_Cipher(&ctx->cipher_ctx, out, out, block_size);
return EVP_Cipher(&ctx->cipher_ctx, out, out, block_size); out:
FIPS_service_indicator_unlock_state();
if (ret) {
FIPS_service_indicator_update_state();
}
return ret;
} }

@ -64,9 +64,10 @@
#include <openssl/mem.h> #include <openssl/mem.h>
#include <openssl/thread.h> #include <openssl/thread.h>
#include "internal.h"
#include "../../internal.h" #include "../../internal.h"
#include "../bn/internal.h" #include "../bn/internal.h"
#include "../service_indicator/internal.h"
#include "internal.h"
#define OPENSSL_DH_MAX_MODULUS_BITS 10000 #define OPENSSL_DH_MAX_MODULUS_BITS 10000
@ -383,6 +384,8 @@ int DH_compute_key_hashed(DH *dh, uint8_t *out, size_t *out_len,
return 0; return 0;
} }
FIPS_service_indicator_lock_state();
int ret = 0; int ret = 0;
const size_t dh_len = DH_size(dh); const size_t dh_len = DH_size(dh);
uint8_t *shared_bytes = OPENSSL_malloc(dh_len); uint8_t *shared_bytes = OPENSSL_malloc(dh_len);
@ -404,6 +407,7 @@ int DH_compute_key_hashed(DH *dh, uint8_t *out, size_t *out_len,
ret = 1; ret = 1;
err: err:
FIPS_service_indicator_unlock_state();
OPENSSL_free(shared_bytes); OPENSSL_free(shared_bytes);
return ret; return ret;
} }

@ -329,14 +329,17 @@ int EC_KEY_check_key(const EC_KEY *eckey) {
} }
int EC_KEY_check_fips(const EC_KEY *key) { int EC_KEY_check_fips(const EC_KEY *key) {
int ret = 0;
FIPS_service_indicator_lock_state();
if (EC_KEY_is_opaque(key)) { if (EC_KEY_is_opaque(key)) {
// Opaque keys can't be checked. // Opaque keys can't be checked.
OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED); OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED);
return 0; goto end;
} }
if (!EC_KEY_check_key(key)) { if (!EC_KEY_check_key(key)) {
return 0; goto end;
} }
if (key->priv_key) { if (key->priv_key) {
@ -350,11 +353,19 @@ int EC_KEY_check_fips(const EC_KEY *key) {
ECDSA_SIG_free(sig); ECDSA_SIG_free(sig);
if (!ok) { if (!ok) {
OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED); OPENSSL_PUT_ERROR(EC, EC_R_PUBLIC_KEY_VALIDATION_FAILED);
return 0; goto end;
} }
} }
return 1; ret = 1;
end:
FIPS_service_indicator_unlock_state();
if (ret) {
EC_KEY_keygen_verify_service_indicator(key);
}
return ret;
} }
int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, const BIGNUM *x, int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, const BIGNUM *x,

@ -103,6 +103,7 @@ int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
return 0; return 0;
} }
FIPS_service_indicator_lock_state();
switch (out_len) { switch (out_len) {
case SHA224_DIGEST_LENGTH: case SHA224_DIGEST_LENGTH:
SHA224(buf, buflen, out); SHA224(buf, buflen, out);
@ -118,8 +119,11 @@ int ECDH_compute_key_fips(uint8_t *out, size_t out_len, const EC_POINT *pub_key,
break; break;
default: default:
OPENSSL_PUT_ERROR(ECDH, ECDH_R_UNKNOWN_DIGEST_LENGTH); OPENSSL_PUT_ERROR(ECDH, ECDH_R_UNKNOWN_DIGEST_LENGTH);
FIPS_service_indicator_unlock_state();
return 0; return 0;
} }
FIPS_service_indicator_unlock_state();
ECDH_verify_service_indicator(priv_key);
return 1; return 1;
} }

@ -323,6 +323,9 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
// into the RBG. This is a hardening measure against entropy failure. // into the RBG. This is a hardening measure against entropy failure.
OPENSSL_STATIC_ASSERT(SHA512_DIGEST_LENGTH >= 32, OPENSSL_STATIC_ASSERT(SHA512_DIGEST_LENGTH >= 32,
"additional_data is too large for SHA-512"); "additional_data is too large for SHA-512");
FIPS_service_indicator_lock_state();
SHA512_CTX sha; SHA512_CTX sha;
uint8_t additional_data[SHA512_DIGEST_LENGTH]; uint8_t additional_data[SHA512_DIGEST_LENGTH];
SHA512_Init(&sha); SHA512_Init(&sha);
@ -330,17 +333,22 @@ ECDSA_SIG *ECDSA_do_sign(const uint8_t *digest, size_t digest_len,
SHA512_Update(&sha, digest, digest_len); SHA512_Update(&sha, digest, digest_len);
SHA512_Final(additional_data, &sha); SHA512_Final(additional_data, &sha);
ECDSA_SIG *ret = NULL;
for (;;) { for (;;) {
EC_SCALAR k; EC_SCALAR k;
if (!ec_random_nonzero_scalar(group, &k, additional_data)) { if (!ec_random_nonzero_scalar(group, &k, additional_data)) {
return NULL; ret = NULL;
goto out;
} }
int retry; int retry;
ECDSA_SIG *sig = ret = ecdsa_sign_impl(group, &retry, priv_key, &k, digest, digest_len);
ecdsa_sign_impl(group, &retry, priv_key, &k, digest, digest_len); if (ret != NULL || !retry) {
if (sig != NULL || !retry) { goto out;
return sig;
} }
} }
out:
FIPS_service_indicator_unlock_state();
return ret;
} }

@ -70,13 +70,22 @@ uint8_t *HMAC(const EVP_MD *evp_md, const void *key, size_t key_len,
unsigned int *out_len) { unsigned int *out_len) {
HMAC_CTX ctx; HMAC_CTX ctx;
HMAC_CTX_init(&ctx); HMAC_CTX_init(&ctx);
if (!HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) ||
!HMAC_Update(&ctx, data, data_len) || // The underlying hash functions should not set the FIPS service indicator
!HMAC_Final(&ctx, out, out_len)) { // until all operations have completed.
out = NULL; FIPS_service_indicator_lock_state();
} const int ok = HMAC_Init_ex(&ctx, key, key_len, evp_md, NULL) &&
HMAC_Update(&ctx, data, data_len) &&
HMAC_Final(&ctx, out, out_len);
FIPS_service_indicator_unlock_state();
HMAC_CTX_cleanup(&ctx); HMAC_CTX_cleanup(&ctx);
if (!ok) {
return NULL;
}
HMAC_verify_service_indicator(evp_md);
return out; return out;
} }
@ -120,6 +129,9 @@ void HMAC_CTX_free(HMAC_CTX *ctx) {
int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len, int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
const EVP_MD *md, ENGINE *impl) { const EVP_MD *md, ENGINE *impl) {
int ret = 0;
FIPS_service_indicator_lock_state();
if (md == NULL) { if (md == NULL) {
md = ctx->md; md = ctx->md;
} }
@ -143,7 +155,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) || if (!EVP_DigestInit_ex(&ctx->md_ctx, md, impl) ||
!EVP_DigestUpdate(&ctx->md_ctx, key, key_len) || !EVP_DigestUpdate(&ctx->md_ctx, key, key_len) ||
!EVP_DigestFinal_ex(&ctx->md_ctx, key_block, &key_block_len)) { !EVP_DigestFinal_ex(&ctx->md_ctx, key_block, &key_block_len)) {
return 0; goto out;
} }
} else { } else {
assert(key_len <= sizeof(key_block)); assert(key_len <= sizeof(key_block));
@ -160,7 +172,7 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
} }
if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) || if (!EVP_DigestInit_ex(&ctx->i_ctx, md, impl) ||
!EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) { !EVP_DigestUpdate(&ctx->i_ctx, pad, EVP_MD_block_size(md))) {
return 0; goto out;
} }
for (size_t i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) { for (size_t i = 0; i < EVP_MAX_MD_BLOCK_SIZE; i++) {
@ -168,17 +180,17 @@ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, size_t key_len,
} }
if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) || if (!EVP_DigestInit_ex(&ctx->o_ctx, md, impl) ||
!EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) { !EVP_DigestUpdate(&ctx->o_ctx, pad, EVP_MD_block_size(md))) {
return 0; goto out;
} }
ctx->md = md; ctx->md = md;
} }
if (!EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx)) { ret = EVP_MD_CTX_copy_ex(&ctx->md_ctx, &ctx->i_ctx);
return 0;
}
return 1; out:
FIPS_service_indicator_unlock_state();
return ret;
} }
int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) { int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) {
@ -186,9 +198,11 @@ int HMAC_Update(HMAC_CTX *ctx, const uint8_t *data, size_t data_len) {
} }
int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) { int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) {
int ret = 0;
unsigned int i; unsigned int i;
uint8_t buf[EVP_MAX_MD_SIZE]; uint8_t buf[EVP_MAX_MD_SIZE];
FIPS_service_indicator_lock_state();
// TODO(davidben): The only thing that can officially fail here is // TODO(davidben): The only thing that can officially fail here is
// |EVP_MD_CTX_copy_ex|, but even that should be impossible in this case. // |EVP_MD_CTX_copy_ex|, but even that should be impossible in this case.
if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) || if (!EVP_DigestFinal_ex(&ctx->md_ctx, buf, &i) ||
@ -196,10 +210,17 @@ int HMAC_Final(HMAC_CTX *ctx, uint8_t *out, unsigned int *out_len) {
!EVP_DigestUpdate(&ctx->md_ctx, buf, i) || !EVP_DigestUpdate(&ctx->md_ctx, buf, i) ||
!EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) { !EVP_DigestFinal_ex(&ctx->md_ctx, out, out_len)) {
*out_len = 0; *out_len = 0;
return 0; goto out;
} }
return 1; ret = 1;
out:
FIPS_service_indicator_unlock_state();
if (ret) {
HMAC_verify_service_indicator(ctx->md);
}
return ret;
} }
size_t HMAC_size(const HMAC_CTX *ctx) { size_t HMAC_size(const HMAC_CTX *ctx) {

@ -19,6 +19,7 @@
#include "internal.h" #include "internal.h"
#include "../cipher/internal.h" #include "../cipher/internal.h"
#include "../service_indicator/internal.h"
// Section references in this file refer to SP 800-90Ar1: // Section references in this file refer to SP 800-90Ar1:
@ -194,6 +195,7 @@ int CTR_DRBG_generate(CTR_DRBG_STATE *drbg, uint8_t *out, size_t out_len,
} }
drbg->reseed_counter++; drbg->reseed_counter++;
FIPS_service_indicator_update_state();
return 1; return 1;
} }

@ -67,6 +67,7 @@
#include <openssl/sha.h> #include <openssl/sha.h>
#include "internal.h" #include "internal.h"
#include "../service_indicator/internal.h"
#include "../../internal.h" #include "../../internal.h"
@ -145,20 +146,17 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *out, size_t *out_len,
return 1; return 1;
} }
static int rand_nonzero(uint8_t *out, size_t len) { static void rand_nonzero(uint8_t *out, size_t len) {
if (!RAND_bytes(out, len)) { FIPS_service_indicator_lock_state();
return 0; RAND_bytes(out, len);
}
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
while (out[i] == 0) { while (out[i] == 0) {
if (!RAND_bytes(out + i, 1)) { RAND_bytes(out + i, 1);
return 0;
}
} }
} }
return 1; FIPS_service_indicator_unlock_state();
} }
int RSA_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len, int RSA_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
@ -178,10 +176,7 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
to[1] = 2; to[1] = 2;
size_t padding_len = to_len - 3 - from_len; size_t padding_len = to_len - 3 - from_len;
if (!rand_nonzero(to + 2, padding_len)) { rand_nonzero(to + 2, padding_len);
return 0;
}
to[2 + padding_len] = 0; to[2 + padding_len] = 0;
OPENSSL_memcpy(to + to_len - from_len, from, from_len); OPENSSL_memcpy(to + to_len - from_len, from, from_len);
return 1; return 1;
@ -275,6 +270,7 @@ static int PKCS1_MGF1(uint8_t *out, size_t len, const uint8_t *seed,
int ret = 0; int ret = 0;
EVP_MD_CTX ctx; EVP_MD_CTX ctx;
EVP_MD_CTX_init(&ctx); EVP_MD_CTX_init(&ctx);
FIPS_service_indicator_lock_state();
size_t md_len = EVP_MD_size(md); size_t md_len = EVP_MD_size(md);
@ -310,6 +306,7 @@ static int PKCS1_MGF1(uint8_t *out, size_t len, const uint8_t *seed,
err: err:
EVP_MD_CTX_cleanup(&ctx); EVP_MD_CTX_cleanup(&ctx);
FIPS_service_indicator_unlock_state();
return ret; return ret;
} }
@ -346,23 +343,25 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, size_t to_len,
uint8_t *seed = to + 1; uint8_t *seed = to + 1;
uint8_t *db = to + mdlen + 1; uint8_t *db = to + mdlen + 1;
uint8_t *dbmask = NULL;
int ret = 0;
FIPS_service_indicator_lock_state();
if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) { if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) {
return 0; goto out;
} }
OPENSSL_memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1); OPENSSL_memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1);
db[emlen - from_len - mdlen - 1] = 0x01; db[emlen - from_len - mdlen - 1] = 0x01;
OPENSSL_memcpy(db + emlen - from_len - mdlen, from, from_len); OPENSSL_memcpy(db + emlen - from_len - mdlen, from, from_len);
if (!RAND_bytes(seed, mdlen)) { if (!RAND_bytes(seed, mdlen)) {
return 0; goto out;
} }
uint8_t *dbmask = OPENSSL_malloc(emlen - mdlen); dbmask = OPENSSL_malloc(emlen - mdlen);
if (dbmask == NULL) { if (dbmask == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0; goto out;
} }
int ret = 0;
if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) { if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) {
goto out; goto out;
} }
@ -381,6 +380,7 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, size_t to_len,
out: out:
OPENSSL_free(dbmask); OPENSSL_free(dbmask);
FIPS_service_indicator_unlock_state();
return ret; return ret;
} }
@ -410,6 +410,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len,
} }
size_t dblen = from_len - mdlen - 1; size_t dblen = from_len - mdlen - 1;
FIPS_service_indicator_lock_state();
db = OPENSSL_malloc(dblen); db = OPENSSL_malloc(dblen);
if (db == NULL) { if (db == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE); OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
@ -470,6 +471,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len,
OPENSSL_memcpy(out, db + one_index, mlen); OPENSSL_memcpy(out, db + one_index, mlen);
*out_len = mlen; *out_len = mlen;
OPENSSL_free(db); OPENSSL_free(db);
FIPS_service_indicator_unlock_state();
return 1; return 1;
decoding_err: decoding_err:
@ -478,6 +480,7 @@ decoding_err:
OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR); OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR);
err: err:
OPENSSL_free(db); OPENSSL_free(db);
FIPS_service_indicator_unlock_state();
return 0; return 0;
} }
@ -501,6 +504,7 @@ int RSA_verify_PKCS1_PSS_mgf1(const RSA *rsa, const uint8_t *mHash,
} }
hLen = EVP_MD_size(Hash); hLen = EVP_MD_size(Hash);
FIPS_service_indicator_lock_state();
// Negative sLen has special meanings: // Negative sLen has special meanings:
// -1 sLen == hLen // -1 sLen == hLen
@ -578,6 +582,7 @@ int RSA_verify_PKCS1_PSS_mgf1(const RSA *rsa, const uint8_t *mHash,
err: err:
OPENSSL_free(DB); OPENSSL_free(DB);
EVP_MD_CTX_cleanup(&ctx); EVP_MD_CTX_cleanup(&ctx);
FIPS_service_indicator_unlock_state();
return ret; return ret;
} }
@ -595,6 +600,7 @@ int RSA_padding_add_PKCS1_PSS_mgf1(const RSA *rsa, unsigned char *EM,
mgf1Hash = Hash; mgf1Hash = Hash;
} }
FIPS_service_indicator_lock_state();
hLen = EVP_MD_size(Hash); hLen = EVP_MD_size(Hash);
if (BN_is_zero(rsa->n)) { if (BN_is_zero(rsa->n)) {
@ -690,6 +696,7 @@ int RSA_padding_add_PKCS1_PSS_mgf1(const RSA *rsa, unsigned char *EM,
err: err:
OPENSSL_free(salt); OPENSSL_free(salt);
FIPS_service_indicator_unlock_state();
return ret; return ret;
} }

@ -66,11 +66,12 @@
#include <openssl/thread.h> #include <openssl/thread.h>
#include <openssl/type_check.h> #include <openssl/type_check.h>
#include "internal.h"
#include "../bn/internal.h"
#include "../../internal.h" #include "../../internal.h"
#include "../bn/internal.h"
#include "../delocate.h" #include "../delocate.h"
#include "../rand/fork_detect.h" #include "../rand/fork_detect.h"
#include "../service_indicator/internal.h"
#include "internal.h"
int rsa_check_public_key(const RSA *rsa) { int rsa_check_public_key(const RSA *rsa) {
@ -1419,6 +1420,10 @@ int RSA_generate_key_fips(RSA *rsa, int bits, BN_GENCB *cb) {
BN_set_word(e, RSA_F4) && BN_set_word(e, RSA_F4) &&
RSA_generate_key_ex_maybe_fips(rsa, bits, e, cb, /*check_fips=*/1); RSA_generate_key_ex_maybe_fips(rsa, bits, e, cb, /*check_fips=*/1);
BN_free(e); BN_free(e);
if (ret) {
FIPS_service_indicator_update_state();
}
return ret; return ret;
} }

@ -36,6 +36,7 @@
#include "../ecdsa/internal.h" #include "../ecdsa/internal.h"
#include "../rand/internal.h" #include "../rand/internal.h"
#include "../rsa/internal.h" #include "../rsa/internal.h"
#include "../service_indicator/internal.h"
#include "../tls/internal.h" #include "../tls/internal.h"
@ -616,9 +617,11 @@ err:
#if defined(BORINGSSL_FIPS) #if defined(BORINGSSL_FIPS)
static void run_self_test_rsa(void) { static void run_self_test_rsa(void) {
FIPS_service_indicator_lock_state();
if (!boringssl_self_test_rsa()) { if (!boringssl_self_test_rsa()) {
BORINGSSL_FIPS_abort(); BORINGSSL_FIPS_abort();
} }
FIPS_service_indicator_unlock_state();
} }
DEFINE_STATIC_ONCE(g_self_test_once_rsa); DEFINE_STATIC_ONCE(g_self_test_once_rsa);
@ -628,9 +631,11 @@ void boringssl_ensure_rsa_self_test(void) {
} }
static void run_self_test_ecc(void) { static void run_self_test_ecc(void) {
FIPS_service_indicator_lock_state();
if (!boringssl_self_test_ecc()) { if (!boringssl_self_test_ecc()) {
BORINGSSL_FIPS_abort(); BORINGSSL_FIPS_abort();
} }
FIPS_service_indicator_unlock_state();
} }
DEFINE_STATIC_ONCE(g_self_test_once_ecc); DEFINE_STATIC_ONCE(g_self_test_once_ecc);
@ -640,9 +645,11 @@ void boringssl_ensure_ecc_self_test(void) {
} }
static void run_self_test_ffdh(void) { static void run_self_test_ffdh(void) {
FIPS_service_indicator_lock_state();
if (!boringssl_self_test_ffdh()) { if (!boringssl_self_test_ffdh()) {
BORINGSSL_FIPS_abort(); BORINGSSL_FIPS_abort();
} }
FIPS_service_indicator_unlock_state();
} }
DEFINE_STATIC_ONCE(g_self_test_once_ffdh); DEFINE_STATIC_ONCE(g_self_test_once_ffdh);

@ -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

@ -62,6 +62,7 @@
#include "../../internal.h" #include "../../internal.h"
#include "../digest/md32_common.h" #include "../digest/md32_common.h"
#include "../service_indicator/internal.h"
#include "internal.h" #include "internal.h"
@ -108,6 +109,7 @@ int SHA1_Final(uint8_t out[SHA_DIGEST_LENGTH], SHA_CTX *c) {
CRYPTO_store_u32_be(out + 8, c->h[2]); CRYPTO_store_u32_be(out + 8, c->h[2]);
CRYPTO_store_u32_be(out + 12, c->h[3]); CRYPTO_store_u32_be(out + 12, c->h[3]);
CRYPTO_store_u32_be(out + 16, c->h[4]); CRYPTO_store_u32_be(out + 16, c->h[4]);
FIPS_service_indicator_update_state();
return 1; return 1;
} }

@ -62,6 +62,7 @@
#include "../../internal.h" #include "../../internal.h"
#include "../digest/md32_common.h" #include "../digest/md32_common.h"
#include "../service_indicator/internal.h"
#include "internal.h" #include "internal.h"
@ -150,6 +151,8 @@ static int sha256_final_impl(uint8_t *out, SHA256_CTX *c) {
CRYPTO_store_u32_be(out, c->h[i]); CRYPTO_store_u32_be(out, c->h[i]);
out += 4; out += 4;
} }
FIPS_service_indicator_update_state();
return 1; return 1;
} }

@ -60,8 +60,9 @@
#include <openssl/mem.h> #include <openssl/mem.h>
#include "internal.h"
#include "../../internal.h" #include "../../internal.h"
#include "../service_indicator/internal.h"
#include "internal.h"
// The 32-bit hash algorithms share a common byte-order neutral collector and // The 32-bit hash algorithms share a common byte-order neutral collector and
@ -274,6 +275,7 @@ static int sha512_final_impl(uint8_t *out, SHA512_CTX *sha) {
out += 8; out += 8;
} }
FIPS_service_indicator_update_state();
return 1; return 1;
} }

@ -58,6 +58,7 @@
#include "internal.h" #include "internal.h"
#include "../../internal.h" #include "../../internal.h"
#include "../service_indicator/internal.h"
// tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246, // tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246,
@ -146,12 +147,16 @@ int CRYPTO_tls1_prf(const EVP_MD *digest,
OPENSSL_memset(out, 0, out_len); OPENSSL_memset(out, 0, out_len);
const EVP_MD *const original_digest = digest;
FIPS_service_indicator_lock_state();
int ret = 0;
if (digest == EVP_md5_sha1()) { if (digest == EVP_md5_sha1()) {
// If using the MD5/SHA1 PRF, |secret| is partitioned between MD5 and SHA-1. // If using the MD5/SHA1 PRF, |secret| is partitioned between MD5 and SHA-1.
size_t secret_half = secret_len - (secret_len / 2); size_t secret_half = secret_len - (secret_len / 2);
if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, label, if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, label,
label_len, seed1, seed1_len, seed2, seed2_len)) { label_len, seed1, seed1_len, seed2, seed2_len)) {
return 0; goto end;
} }
// Note that, if |secret_len| is odd, the two halves share a byte. // Note that, if |secret_len| is odd, the two halves share a byte.
@ -160,6 +165,13 @@ int CRYPTO_tls1_prf(const EVP_MD *digest,
digest = EVP_sha1(); digest = EVP_sha1();
} }
return tls1_P_hash(out, out_len, digest, secret, secret_len, label, label_len, ret = tls1_P_hash(out, out_len, digest, secret, secret_len, label, label_len,
seed1, seed1_len, seed2, seed2_len); seed1, seed1_len, seed2, seed2_len);
end:
FIPS_service_indicator_unlock_state();
if (ret) {
TLSKDF_verify_service_indicator(original_digest);
}
return ret;
} }

@ -648,6 +648,7 @@ typedef enum {
OPENSSL_THREAD_LOCAL_ERR = 0, OPENSSL_THREAD_LOCAL_ERR = 0,
OPENSSL_THREAD_LOCAL_RAND, OPENSSL_THREAD_LOCAL_RAND,
OPENSSL_THREAD_LOCAL_FIPS_COUNTERS, OPENSSL_THREAD_LOCAL_FIPS_COUNTERS,
OPENSSL_THREAD_LOCAL_FIPS_SERVICE_INDICATOR_STATE,
OPENSSL_THREAD_LOCAL_TEST, OPENSSL_THREAD_LOCAL_TEST,
NUM_OPENSSL_THREAD_LOCALS, NUM_OPENSSL_THREAD_LOCALS,
} thread_local_data_t; } thread_local_data_t;

@ -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…
Cancel
Save