]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
crypto: add private API to retrieve internal IV
authorDaiki Ueno <dueno@redhat.com>
Tue, 30 Apr 2019 12:42:51 +0000 (14:42 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 3 May 2019 17:07:25 +0000 (19:07 +0200)
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>
lib/cipher_int.c
lib/cipher_int.h
lib/crypto-api.c
lib/crypto-backend.h
lib/crypto-selftests.c
lib/fips.c
lib/includes/gnutls/crypto.h
lib/libgnutls.map
lib/nettle/cipher.c

index c6032ff0532d8d66430c71d3fb9e801641359e05..40bf64f8bc1f33d7f458a4995228e9132739b835 100644 (file)
@@ -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
         */
index de83c36362a7ee064e4bdc00c26f9bd82a99af4c..e3e010a8e7f1b7efae43de8158c30d9c201b2ccc 100644 (file)
@@ -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 */
index ed1499315f91e8557ae695e8320cd4f8028bba1d..0b6be4eed22d83c558faaf8ce2c5c34ea1eef531 100644 (file)
@@ -167,6 +167,34 @@ 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 internally calculated IV value. It is
+ * intended to be used  for modes like CFB. @iv must have @ivlen length
+ * at least.
+ *
+ * This is solely 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
index 037241fc181f1bbcd4e7e2cbe40f2901af0a7402..76004a72114d625e1417c2a2da33e37714f4ac33 100644 (file)
@@ -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;
index 5d040fb603fc446863c5423c17ed2fc8ab8e3d34..66f6db620d6baace0da59da14b2f4ea98ca6c894 100644 (file)
@@ -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);
        }
 
index ef1f7cbc3557d3a47731233cb8db17c831da855c..b92edbbd7978b1a967f47ef5d3ceb355d7040c29 100644 (file)
@@ -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) {
index f6e50df86ae4163459d94f918237fa6e994007e1..4f70b4a56873c85c3bbcb66272246e28a47843cd 100644 (file)
@@ -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,
index d10e22b20ef2f89177ae999b7e87db6101b13bd6..2bc33ee732129136f43f19ad3a4734c45312cb2f 100644 (file)
@@ -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 {
index 9194fb750c32f203ca473a41c16a69cfbbef5dc6..632528140af08052a5dffc43e14f948939df451f 100644 (file)
@@ -840,6 +840,19 @@ wrap_nettle_cipher_setiv(void *_ctx, const void *iv, size_t iv_size)
        return 0;
 }
 
+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,