summaryrefslogtreecommitdiff
path: root/lib/crypto-api.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/crypto-api.c')
-rw-r--r--lib/crypto-api.c473
1 files changed, 386 insertions, 87 deletions
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index a43aaf9b89..fa4a4eb3fd 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -62,17 +62,25 @@ gnutls_cipher_init(gnutls_cipher_hd_t * handle,
api_cipher_hd_st *h;
int ret;
const cipher_entry_st* e;
+ bool not_approved = false;
- if (is_cipher_algo_forbidden(cipher))
+ if (!is_cipher_algo_allowed(cipher)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_cipher_algo_approved_in_fips(cipher)) {
+ not_approved = true;
+ }
e = cipher_to_entry(cipher);
- if (e == NULL || (e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD))
+ if (e == NULL || (e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
h = gnutls_calloc(1, sizeof(api_cipher_hd_st));
if (h == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return GNUTLS_E_MEMORY_ERROR;
}
@@ -81,6 +89,7 @@ gnutls_cipher_init(gnutls_cipher_hd_t * handle,
iv, 1);
if (ret < 0) {
gnutls_free(h);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return ret;
}
@@ -89,12 +98,19 @@ gnutls_cipher_init(gnutls_cipher_hd_t * handle,
_gnutls_cipher_init(&h->ctx_dec, e, key, iv, 0);
if (ret < 0) {
gnutls_free(h);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return ret;
}
}
*handle = h;
+ if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+
return ret;
}
@@ -145,11 +161,18 @@ gnutls_cipher_add_auth(gnutls_cipher_hd_t handle, const void *ptext,
size_t ptext_size)
{
api_cipher_hd_st *h = handle;
+ int ret;
- if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0)
+ if (_gnutls_cipher_is_aead(&h->ctx_enc) == 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
- return _gnutls_cipher_auth(&h->ctx_enc, ptext, ptext_size);
+ ret = _gnutls_cipher_auth(&h->ctx_enc, ptext, ptext_size);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ }
+ return ret;
}
/**
@@ -170,12 +193,15 @@ gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
if (_gnutls_cipher_setiv(&h->ctx_enc, iv, ivlen) < 0) {
_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
}
- if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK)
+ if (_gnutls_cipher_type(h->ctx_enc.e) == CIPHER_BLOCK) {
if (_gnutls_cipher_setiv(&h->ctx_dec, iv, ivlen) < 0) {
_gnutls_switch_lib_state(LIB_STATE_ERROR);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
}
+ }
}
/*-
@@ -227,8 +253,14 @@ int
_gnutls_cipher_set_key(gnutls_cipher_hd_t handle, void *key, size_t keylen)
{
api_cipher_hd_st *h = handle;
+ int ret;
- return _gnutls_cipher_setkey(&h->ctx_enc, key, keylen);
+ ret = _gnutls_cipher_setkey(&h->ctx_enc, key, keylen);
+
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ }
+ return ret;
}
/**
@@ -249,8 +281,15 @@ gnutls_cipher_encrypt(gnutls_cipher_hd_t handle, void *ptext,
size_t ptext_len)
{
api_cipher_hd_st *h = handle;
+ int ret;
- return _gnutls_cipher_encrypt(&h->ctx_enc, ptext, ptext_len);
+ ret = _gnutls_cipher_encrypt(&h->ctx_enc, ptext, ptext_len);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -274,13 +313,22 @@ gnutls_cipher_decrypt(gnutls_cipher_hd_t handle, void *ctext,
size_t ctext_len)
{
api_cipher_hd_st *h = handle;
+ int ret;
- if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK)
- return _gnutls_cipher_decrypt(&h->ctx_enc, ctext,
- ctext_len);
- else
- return _gnutls_cipher_decrypt(&h->ctx_dec, ctext,
- ctext_len);
+ if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) {
+ ret = _gnutls_cipher_decrypt(&h->ctx_enc, ctext,
+ ctext_len);
+ } else {
+ ret = _gnutls_cipher_decrypt(&h->ctx_dec, ctext,
+ ctext_len);
+ }
+
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -306,9 +354,16 @@ gnutls_cipher_encrypt2(gnutls_cipher_hd_t handle, const void *ptext,
size_t ctext_len)
{
api_cipher_hd_st *h = handle;
+ int ret;
- return _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len,
- ctext, ctext_len);
+ ret = _gnutls_cipher_encrypt2(&h->ctx_enc, ptext, ptext_len,
+ ctext, ctext_len);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -336,15 +391,24 @@ gnutls_cipher_decrypt2(gnutls_cipher_hd_t handle, const void *ctext,
size_t ctext_len, void *ptext, size_t ptext_len)
{
api_cipher_hd_st *h = handle;
+ int ret;
- if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK)
- return _gnutls_cipher_decrypt2(&h->ctx_enc, ctext,
- ctext_len, ptext,
- ptext_len);
- else
- return _gnutls_cipher_decrypt2(&h->ctx_dec, ctext,
- ctext_len, ptext,
- ptext_len);
+ if (_gnutls_cipher_type(h->ctx_enc.e) != CIPHER_BLOCK) {
+ ret = _gnutls_cipher_decrypt2(&h->ctx_enc, ctext,
+ ctext_len, ptext,
+ ptext_len);
+ } else {
+ ret = _gnutls_cipher_decrypt2(&h->ctx_dec, ctext,
+ ctext_len, ptext,
+ ptext_len);
+ }
+
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -394,18 +458,39 @@ gnutls_hmac_init(gnutls_hmac_hd_t * dig,
gnutls_mac_algorithm_t algorithm,
const void *key, size_t keylen)
{
+ int ret;
+ bool not_approved = false;
+
/* MD5 is only allowed internally for TLS */
- if (is_mac_algo_forbidden(algorithm))
+ if (!is_mac_algo_allowed(algorithm)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_mac_algo_approved_in_fips(algorithm)) {
+ not_approved = true;
+ }
+
+ /* Key lengthes less than 112 bits are not approved */
+ if (keylen < 14) {
+ not_approved = true;
+ }
*dig = gnutls_malloc(sizeof(mac_hd_st));
if (*dig == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return GNUTLS_E_MEMORY_ERROR;
}
- return _gnutls_mac_init(((mac_hd_st *) * dig),
- mac_to_entry(algorithm), key, keylen);
+ ret = _gnutls_mac_init(((mac_hd_st *) * dig),
+ mac_to_entry(algorithm), key, keylen);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -440,7 +525,15 @@ gnutls_hmac_set_nonce(gnutls_hmac_hd_t handle, const void *nonce,
**/
int gnutls_hmac(gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len)
{
- return _gnutls_mac((mac_hd_st *) handle, ptext, ptext_len);
+ int ret;
+
+ ret = _gnutls_mac((mac_hd_st *) handle, ptext, ptext_len);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -529,11 +622,31 @@ gnutls_hmac_fast(gnutls_mac_algorithm_t algorithm,
const void *key, size_t keylen,
const void *ptext, size_t ptext_len, void *digest)
{
- if (is_mac_algo_forbidden(algorithm))
+ int ret;
+ bool not_approved = false;
+
+ if (!is_mac_algo_allowed(algorithm)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_mac_algo_approved_in_fips(algorithm)) {
+ not_approved = true;
+ }
- return _gnutls_mac_fast(algorithm, key, keylen, ptext, ptext_len,
- digest);
+ /* Key lengthes less than 112 bits are not approved */
+ if (keylen < 14) {
+ not_approved = true;
+ }
+
+ ret = _gnutls_mac_fast(algorithm, key, keylen, ptext, ptext_len,
+ digest);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -558,12 +671,14 @@ gnutls_hmac_hd_t gnutls_hmac_copy(gnutls_hmac_hd_t handle)
dig = gnutls_malloc(sizeof(mac_hd_st));
if (dig == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return NULL;
}
if (_gnutls_mac_copy((const mac_hd_st *) handle, (mac_hd_st *)dig) != GNUTLS_E_SUCCESS) {
gnutls_assert();
gnutls_free(dig);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return NULL;
}
@@ -590,17 +705,33 @@ int
gnutls_hash_init(gnutls_hash_hd_t * dig,
gnutls_digest_algorithm_t algorithm)
{
- if (is_mac_algo_forbidden(DIG_TO_MAC(algorithm)))
+ int ret;
+ bool not_approved = false;
+
+ if (!is_mac_algo_allowed(DIG_TO_MAC(algorithm))) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_mac_algo_approved_in_fips(DIG_TO_MAC(algorithm))) {
+ not_approved = true;
+ }
*dig = gnutls_malloc(sizeof(digest_hd_st));
if (*dig == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return GNUTLS_E_MEMORY_ERROR;
}
- return _gnutls_hash_init(((digest_hd_st *) * dig),
- hash_to_entry(algorithm));
+ ret = _gnutls_hash_init(((digest_hd_st *) * dig),
+ hash_to_entry(algorithm));
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}
/**
@@ -618,7 +749,13 @@ gnutls_hash_init(gnutls_hash_hd_t * dig,
**/
int gnutls_hash(gnutls_hash_hd_t handle, const void *ptext, size_t ptext_len)
{
- return _gnutls_hash((digest_hd_st *) handle, ptext, ptext_len);
+ int ret;
+
+ ret = _gnutls_hash((digest_hd_st *) handle, ptext, ptext_len);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ }
+ return ret;
}
/**
@@ -686,10 +823,24 @@ int
gnutls_hash_fast(gnutls_digest_algorithm_t algorithm,
const void *ptext, size_t ptext_len, void *digest)
{
- if (is_mac_algo_forbidden(DIG_TO_MAC(algorithm)))
+ int ret;
+ bool not_approved = false;
+
+ if (!is_mac_algo_allowed(DIG_TO_MAC(algorithm))) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_mac_algo_approved_in_fips(DIG_TO_MAC(algorithm))) {
+ not_approved = true;
+ }
- return _gnutls_hash_fast(algorithm, ptext, ptext_len, digest);
+ ret = _gnutls_hash_fast(algorithm, ptext, ptext_len, digest);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+
+ return ret;
}
/**
@@ -714,12 +865,14 @@ gnutls_hash_hd_t gnutls_hash_copy(gnutls_hash_hd_t handle)
dig = gnutls_malloc(sizeof(digest_hd_st));
if (dig == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return NULL;
}
if (_gnutls_hash_copy((const digest_hd_st *) handle, (digest_hd_st *)dig) != GNUTLS_E_SUCCESS) {
gnutls_assert();
gnutls_free(dig);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return NULL;
}
@@ -795,28 +948,43 @@ int gnutls_aead_cipher_init(gnutls_aead_cipher_hd_t *handle,
api_aead_cipher_hd_st *h;
const cipher_entry_st *e;
int ret;
+ bool not_approved = false;
- if (is_cipher_algo_forbidden(cipher))
+ if (!is_cipher_algo_allowed(cipher)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_cipher_algo_approved_in_fips(cipher)) {
+ not_approved = true;
+ }
e = cipher_to_entry(cipher);
- if (e == NULL || e->type != CIPHER_AEAD)
+ if (e == NULL || e->type != CIPHER_AEAD) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
h = gnutls_calloc(1, sizeof(api_aead_cipher_hd_st));
if (h == NULL) {
gnutls_assert();
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return GNUTLS_E_MEMORY_ERROR;
}
ret = _gnutls_aead_cipher_init(h, cipher, key);
if (ret < 0) {
gnutls_free(h);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return ret;
}
*handle = h;
+ if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+
return ret;
}
@@ -857,11 +1025,15 @@ gnutls_aead_cipher_decrypt(gnutls_aead_cipher_hd_t handle,
if (tag_size == 0)
tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
- else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
- if (unlikely(ctext_len < tag_size))
+ if (unlikely(ctext_len < tag_size)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+ }
ret = _gnutls_aead_cipher_decrypt(&h->ctx_enc,
nonce, nonce_len,
@@ -869,8 +1041,12 @@ gnutls_aead_cipher_decrypt(gnutls_aead_cipher_hd_t handle,
tag_size,
ctext, ctext_len,
ptext, *ptext_len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
/* That assumes that AEAD ciphers are stream */
*ptext_len = ctext_len - tag_size;
@@ -913,11 +1089,15 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
if (tag_size == 0)
tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
- else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
- if (unlikely(*ctext_len < ptext_len + tag_size))
+ if (unlikely(*ctext_len < ptext_len + tag_size)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+ }
ret = _gnutls_aead_cipher_encrypt(&h->ctx_enc,
nonce, nonce_len,
@@ -925,8 +1105,12 @@ gnutls_aead_cipher_encrypt(gnutls_aead_cipher_hd_t handle,
tag_size,
ptext, ptext_len,
ctext, *ctext_len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
/* That assumes that AEAD ciphers are stream */
*ctext_len = ptext_len + tag_size;
@@ -1052,8 +1236,10 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
if (tag_size == 0)
tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
- else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
if ((handle->ctx_enc.e->flags & GNUTLS_CIPHER_FLAG_ONLY_AEAD) || handle->ctx_enc.encrypt == NULL) {
/* ciphertext cannot be produced in a piecemeal approach */
@@ -1061,12 +1247,15 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
struct iov_store_st ptext;
ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = copy_from_iov(&ptext, iov, iovcnt);
if (ret < 0) {
iov_store_free(&auth);
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
}
@@ -1078,58 +1267,77 @@ gnutls_aead_cipher_encryptv(gnutls_aead_cipher_hd_t handle,
iov_store_free(&auth);
iov_store_free(&ptext);
+ /* FIPS operation state is set by gnutls_aead_cipher_encrypt */
return ret;
}
ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
dst = ctext;
dst_size = *ctext_len;
ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
len = ret;
ret = _gnutls_cipher_encrypt2(&handle->ctx_enc,
p, len,
dst, dst_size);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
+
DECR_LEN(dst_size, len);
dst += len;
total += len;
}
- if (dst_size < tag_size)
+ if (dst_size < tag_size) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_SHORT_MEMORY_BUFFER);
+ }
_gnutls_cipher_tag(&handle->ctx_enc, dst, tag_size);
total += tag_size;
*ctext_len = total;
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return 0;
}
@@ -1172,8 +1380,10 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
else
_tag_size = *tag_size;
- if (_tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ if (_tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
/* Limitation: this function provides an optimization under the internally registered
* AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
@@ -1186,8 +1396,10 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
size_t ptext_size;
ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = copy_from_iov(&ptext, iov, iovcnt);
if (ret < 0) {
@@ -1231,25 +1443,37 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
iov_store_free(&auth);
iov_store_free(&ptext);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ }
+ /* FIPS operation state is set by gnutls_aead_cipher_encrypt */
return ret;
}
ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
@@ -1257,19 +1481,25 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
return gnutls_assert_val(ret);
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
len = ret;
ret = _gnutls_cipher_encrypt2(&handle->ctx_enc, p, len, p, len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = _gnutls_iov_iter_sync(&iter, p, len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
if (tag != NULL)
@@ -1277,6 +1507,7 @@ gnutls_aead_cipher_encryptv2(gnutls_aead_cipher_hd_t handle,
if (tag_size != NULL)
*tag_size = _tag_size;
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return 0;
}
@@ -1316,8 +1547,10 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
if (tag_size == 0)
tag_size = _gnutls_cipher_get_tag_size(h->ctx_enc.e);
- else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e))
+ else if (tag_size > (unsigned)_gnutls_cipher_get_tag_size(h->ctx_enc.e)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ }
/* Limitation: this function provides an optimization under the internally registered
* AEAD ciphers. When an AEAD cipher is used registered with gnutls_crypto_register_aead_cipher(),
@@ -1330,8 +1563,10 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
size_t ctext_size;
ret = copy_from_iov(&auth, auth_iov, auth_iovcnt);
- if (ret < 0)
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = copy_from_iov(&ctext, iov, iovcnt);
if (ret < 0) {
@@ -1369,53 +1604,76 @@ gnutls_aead_cipher_decryptv2(gnutls_aead_cipher_hd_t handle,
iov_store_free(&auth);
iov_store_free(&ctext);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ }
+ /* FIPS operation state is set by gnutls_aead_cipher_decrypt */
return ret;
}
ret = _gnutls_cipher_setiv(&handle->ctx_enc, nonce, nonce_len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = _gnutls_iov_iter_init(&iter, auth_iov, auth_iovcnt, blocksize);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
ret = _gnutls_cipher_auth(&handle->ctx_enc, p, ret);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
ret = _gnutls_iov_iter_init(&iter, iov, iovcnt, blocksize);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
while (1) {
ret = _gnutls_iov_iter_next(&iter, &p);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
if (ret == 0)
break;
len = ret;
ret = _gnutls_cipher_decrypt2(&handle->ctx_enc, p, len, p, len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
ret = _gnutls_iov_iter_sync(&iter, p, len);
- if (unlikely(ret < 0))
+ if (unlikely(ret < 0)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(ret);
+ }
}
if (tag != NULL) {
_gnutls_cipher_tag(&handle->ctx_enc, _tag, tag_size);
- if (gnutls_memcmp(_tag, tag, tag_size) != 0)
+ if (gnutls_memcmp(_tag, tag, tag_size) != 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_DECRYPTION_FAILED);
+ }
}
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
return 0;
}
@@ -1456,14 +1714,27 @@ gnutls_hkdf_extract(gnutls_mac_algorithm_t mac,
const gnutls_datum_t *salt,
void *output)
{
+ int ret;
+
/* MD5 is only allowed internally for TLS */
- if (is_mac_algo_forbidden(mac))
+ if (!is_mac_algo_allowed(mac)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ }
+
+ /* We don't check whether MAC is approved, because HKDF is
+ * only approved in TLS, which is handled separately. */
- return _gnutls_kdf_ops.hkdf_extract(mac, key->data, key->size,
- salt ? salt->data : NULL,
- salt ? salt->size : 0,
- output);
+ ret = _gnutls_kdf_ops.hkdf_extract(mac, key->data, key->size,
+ salt ? salt->data : NULL,
+ salt ? salt->size : 0,
+ output);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
/**
@@ -1488,13 +1759,26 @@ gnutls_hkdf_expand(gnutls_mac_algorithm_t mac,
const gnutls_datum_t *info,
void *output, size_t length)
{
+ int ret;
+
/* MD5 is only allowed internally for TLS */
- if (is_mac_algo_forbidden(mac))
+ if (!is_mac_algo_allowed(mac)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ }
- return _gnutls_kdf_ops.hkdf_expand(mac, key->data, key->size,
- info->data, info->size,
- output, length);
+ /* We don't check whether MAC is approved, because HKDF is
+ * only approved in TLS, which is handled separately. */
+
+ ret = _gnutls_kdf_ops.hkdf_expand(mac, key->data, key->size,
+ info->data, info->size,
+ output, length);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ }
+ return ret;
}
/**
@@ -1520,11 +1804,26 @@ gnutls_pbkdf2(gnutls_mac_algorithm_t mac,
unsigned iter_count,
void *output, size_t length)
{
+ int ret;
+ bool not_approved = false;
+
/* MD5 is only allowed internally for TLS */
- if (is_mac_algo_forbidden(mac))
+ if (!is_mac_algo_allowed(mac)) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM);
+ } else if (!is_mac_algo_approved_in_fips(mac)) {
+ not_approved = true;
+ }
- return _gnutls_kdf_ops.pbkdf2(mac, key->data, key->size,
- salt->data, salt->size, iter_count,
- output, length);
+ ret = _gnutls_kdf_ops.pbkdf2(mac, key->data, key->size,
+ salt->data, salt->size, iter_count,
+ output, length);
+ if (ret < 0) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_ERROR);
+ } else if (not_approved) {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_NOT_APPROVED);
+ } else {
+ _gnutls_switch_fips_state(GNUTLS_FIPS140_OP_APPROVED);
+ }
+ return ret;
}