summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaiki Ueno <dueno@redhat.com>2019-04-30 14:42:51 +0200
committerDaiki Ueno <dueno@redhat.com>2019-05-03 13:59:23 +0200
commit1401ff434fffe4420e35d996f08d52ecac41d133 (patch)
treeb60a9b9de4ea99ce635352cacf4437113913909f
parentd0571e0e934557f5fb0683cd52295b077f2969aa (diff)
downloadgnutls-tmp-getiv.tar.gz
crypto: add private API to retrieve internal IVtmp-getiv
For FIPS validation purposes, this adds a new function _gnutls_cipher_get_iv() that exposes internal IV after encryption and decryption. The function is not generally useful because the IV value can be easily calculated from the initial IV and the subsequent ciphertext but for FIPS validation purposes. Signed-off-by: Daiki Ueno <dueno@redhat.com>
-rw-r--r--lib/cipher_int.c2
-rw-r--r--lib/cipher_int.h15
-rw-r--r--lib/crypto-api.c27
-rw-r--r--lib/crypto-backend.h1
-rw-r--r--lib/crypto-selftests.c26
-rw-r--r--lib/fips.c6
-rw-r--r--lib/includes/gnutls/crypto.h1
-rw-r--r--lib/libgnutls.map1
-rw-r--r--lib/nettle/cipher.c14
9 files changed, 93 insertions, 0 deletions
diff --git a/lib/cipher_int.c b/lib/cipher_int.c
index c6032ff053..40bf64f8bc 100644
--- a/lib/cipher_int.c
+++ b/lib/cipher_int.c
@@ -101,6 +101,7 @@ _gnutls_cipher_init(cipher_hd_st *handle, const cipher_entry_st *e,
handle->auth = cc->auth;
handle->tag = cc->tag;
handle->setiv = cc->setiv;
+ handle->getiv = cc->getiv;
/* if cc->init() returns GNUTLS_E_NEED_FALLBACK we
* use the default ciphers */
@@ -126,6 +127,7 @@ _gnutls_cipher_init(cipher_hd_st *handle, const cipher_entry_st *e,
handle->auth = _gnutls_cipher_ops.auth;
handle->tag = _gnutls_cipher_ops.tag;
handle->setiv = _gnutls_cipher_ops.setiv;
+ handle->getiv = _gnutls_cipher_ops.getiv;
/* otherwise use generic cipher interface
*/
diff --git a/lib/cipher_int.h b/lib/cipher_int.h
index de83c36362..e3e010a8e7 100644
--- a/lib/cipher_int.h
+++ b/lib/cipher_int.h
@@ -50,6 +50,7 @@ typedef void (*cipher_deinit_func) (void *hd);
typedef int (*cipher_auth_func) (void *hd, const void *data, size_t);
typedef int (*cipher_setiv_func) (void *hd, const void *iv, size_t);
+typedef int (*cipher_getiv_func) (void *hd, void *iv, size_t);
typedef void (*cipher_tag_func) (void *hd, void *tag, size_t);
@@ -63,6 +64,7 @@ typedef struct {
cipher_auth_func auth;
cipher_tag_func tag;
cipher_setiv_func setiv;
+ cipher_getiv_func getiv;
cipher_deinit_func deinit;
} cipher_hd_st;
@@ -76,6 +78,16 @@ inline static int _gnutls_cipher_setiv(const cipher_hd_st * handle,
return handle->setiv(handle->handle, iv, ivlen);
}
+inline static int _gnutls_cipher_getiv(const cipher_hd_st * handle,
+ void *iv, size_t ivlen)
+{
+ if (unlikely(handle == NULL || handle->handle == NULL ||
+ handle->getiv == NULL))
+ return GNUTLS_E_INVALID_REQUEST;
+
+ return handle->getiv(handle->handle, iv, ivlen);
+}
+
inline static int
_gnutls_cipher_encrypt2(const cipher_hd_st * handle, const void *text,
size_t textlen, void *ciphertext,
@@ -158,6 +170,9 @@ inline static void _gnutls_cipher_deinit(cipher_hd_st * handle)
int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher);
+int _gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv,
+ size_t ivlen);
+
#define _gnutls_cipher_is_aead(h) _gnutls_cipher_algo_is_aead((h)->e)
/* returns the tag in AUTHENC ciphers */
diff --git a/lib/crypto-api.c b/lib/crypto-api.c
index ed1499315f..a275a7611f 100644
--- a/lib/crypto-api.c
+++ b/lib/crypto-api.c
@@ -168,6 +168,33 @@ gnutls_cipher_set_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
}
/**
+ * _gnutls_cipher_get_iv:
+ * @handle: is a #gnutls_cipher_hd_t type
+ * @iv: the IV to set
+ * @ivlen: the length of the IV
+ *
+ * This function will retrieve the internal IV value. @iv must have @ivlen
+ * length at least.
+ *
+ * This is sorely for validation purposes of our crypto
+ * implementation. For other purposes, the IV can be typically
+ * calculated from the initial IV value and the subsequent ciphertext
+ * values. As such, this function only works with the internally
+ * registered ciphers.
+ *
+ * Returns: The length of IV or a negative error code on error.
+ *
+ * Since: 3.6.8
+ **/
+int
+_gnutls_cipher_get_iv(gnutls_cipher_hd_t handle, void *iv, size_t ivlen)
+{
+ api_cipher_hd_st *h = handle;
+
+ return _gnutls_cipher_getiv(&h->ctx_enc, iv, ivlen);
+}
+
+/**
* gnutls_cipher_encrypt:
* @handle: is a #gnutls_cipher_hd_t type
* @ptext: the data to encrypt
diff --git a/lib/crypto-backend.h b/lib/crypto-backend.h
index 037241fc18..76004a7211 100644
--- a/lib/crypto-backend.h
+++ b/lib/crypto-backend.h
@@ -33,6 +33,7 @@ typedef struct {
gnutls_cipher_init_func init;
gnutls_cipher_setkey_func setkey;
gnutls_cipher_setiv_func setiv;
+ gnutls_cipher_getiv_func getiv;
gnutls_cipher_encrypt_func encrypt;
gnutls_cipher_decrypt_func decrypt;
gnutls_cipher_aead_encrypt_func aead_encrypt;
diff --git a/lib/crypto-selftests.c b/lib/crypto-selftests.c
index 5d040fb603..66f6db620d 100644
--- a/lib/crypto-selftests.c
+++ b/lib/crypto-selftests.c
@@ -52,6 +52,9 @@ struct cipher_vectors_st {
const uint8_t *iv;
unsigned int iv_size;
+
+ const uint8_t *internal_iv;
+ unsigned int internal_iv_size;
};
struct cipher_aead_vectors_st {
@@ -385,6 +388,9 @@ const struct cipher_vectors_st aes128_cfb8_vectors[] = { /* NIST 800-38a */
"\x32\xb9",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x42\x4c\x9c\x0d\xd4\x36\xba\xce\x9e\x0e\xd4\x58\x6a\x4f\x32\xb9"),
},
};
@@ -401,6 +407,9 @@ const struct cipher_vectors_st aes192_cfb8_vectors[] = { /* NIST 800-38a */
"\x67\x8a",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x52\x1e\xf0\xa9\x05\xca\x44\xcd\x05\x7c\xbf\x0d\x47\xa0\x67\x8a"),
},
};
@@ -417,6 +426,9 @@ const struct cipher_vectors_st aes256_cfb8_vectors[] = { /* NIST 800-38a */
"\x97\x00",
STR(iv, iv_size,
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"),
+ /* the least significant 16 bytes of ciphertext */
+ STR(internal_iv, internal_iv_size,
+ "\x1a\x85\x20\xa6\x4d\xb5\x5f\xcc\x8a\xc5\x54\x84\x4e\x88\x97\x00"),
},
};
@@ -607,6 +619,20 @@ static int test_cipher(gnutls_cipher_algorithm_t cipher,
}
}
+ /* check the internal IV */
+ if (vectors[i].internal_iv_size > 0) {
+ ret = _gnutls_cipher_get_iv(hd, tmp, sizeof(tmp));
+ if (ret < 0)
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+
+ if (memcmp(tmp, vectors[i].internal_iv, ret) != 0) {
+ _gnutls_debug_log("%s vector %d internal IV check failed!\n",
+ gnutls_cipher_get_name(cipher),
+ i);
+ return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
+ }
+ }
+
gnutls_cipher_deinit(hd);
}
diff --git a/lib/fips.c b/lib/fips.c
index ef1f7cbc35..b92edbbd79 100644
--- a/lib/fips.c
+++ b/lib/fips.c
@@ -329,6 +329,12 @@ int _gnutls_fips_perform_self_checks2(void)
goto error;
}
+ ret = gnutls_cipher_self_test(0, GNUTLS_CIPHER_AES_256_CFB8);
+ if (ret < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
/* Digest tests */
ret = gnutls_digest_self_test(0, GNUTLS_DIG_SHA3_224);
if (ret < 0) {
diff --git a/lib/includes/gnutls/crypto.h b/lib/includes/gnutls/crypto.h
index f6e50df86a..4f70b4a568 100644
--- a/lib/includes/gnutls/crypto.h
+++ b/lib/includes/gnutls/crypto.h
@@ -154,6 +154,7 @@ typedef int (*gnutls_cipher_init_func) (gnutls_cipher_algorithm_t, void **ctx, i
typedef int (*gnutls_cipher_setkey_func) (void *ctx, const void *key, size_t keysize);
/* old style ciphers */
typedef int (*gnutls_cipher_setiv_func) (void *ctx, const void *iv, size_t ivsize);
+typedef int (*gnutls_cipher_getiv_func) (void *ctx, void *iv, size_t ivsize);
typedef int (*gnutls_cipher_encrypt_func) (void *ctx, const void *plain, size_t plainsize,
void *encr, size_t encrsize);
typedef int (*gnutls_cipher_decrypt_func) (void *ctx, const void *encr, size_t encrsize,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index d10e22b20e..2bc33ee732 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1297,6 +1297,7 @@ GNUTLS_FIPS140_3_4 {
_gnutls_dh_generate_key;
_gnutls_ecdh_generate_key;
_gnutls_ecdh_compute_key;
+ _gnutls_cipher_get_iv;
} GNUTLS_3_4;
GNUTLS_PRIVATE_3_4 {
diff --git a/lib/nettle/cipher.c b/lib/nettle/cipher.c
index 9194fb750c..632528140a 100644
--- a/lib/nettle/cipher.c
+++ b/lib/nettle/cipher.c
@@ -841,6 +841,19 @@ wrap_nettle_cipher_setiv(void *_ctx, const void *iv, size_t iv_size)
}
static int
+wrap_nettle_cipher_getiv(void *_ctx, void *iv, size_t iv_size)
+{
+ struct nettle_cipher_ctx *ctx = _ctx;
+
+ if (iv_size < ctx->iv_size)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ memcpy(iv, ctx->iv, ctx->iv_size);
+
+ return (int) ctx->iv_size;
+}
+
+static int
wrap_nettle_cipher_decrypt(void *_ctx, const void *encr, size_t encr_size,
void *plain, size_t plain_size)
{
@@ -974,6 +987,7 @@ gnutls_crypto_cipher_st _gnutls_cipher_ops = {
.init = wrap_nettle_cipher_init,
.exists = wrap_nettle_cipher_exists,
.setiv = wrap_nettle_cipher_setiv,
+ .getiv = wrap_nettle_cipher_getiv,
.setkey = wrap_nettle_cipher_setkey,
.encrypt = wrap_nettle_cipher_encrypt,
.decrypt = wrap_nettle_cipher_decrypt,