]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
lib: add support for AES-GMAC
authorDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Mon, 24 Jun 2019 17:29:31 +0000 (20:29 +0300)
committerDmitry Eremin-Solenikov <dbaryshkov@gmail.com>
Fri, 28 Jun 2019 13:27:26 +0000 (16:27 +0300)
Add support for computing AES-GMAC using MAC API, as requested by Samba
for SMB3 support.

Resolves: #781

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
devel/libgnutls-latest-x86_64.abi
lib/algorithms/mac.c
lib/crypto-selftests.c
lib/fips.h
lib/includes/gnutls/gnutls.h.in
lib/nettle/mac.c

index 3fa7f452388af60135267ffb7224a54c7b9882ee..17e8d40663e65d447e452c76b433edffbe13e612 100644 (file)
       <enumerator name='GNUTLS_MAC_UMAC_128' value='202'/>
       <enumerator name='GNUTLS_MAC_AES_CMAC_128' value='203'/>
       <enumerator name='GNUTLS_MAC_AES_CMAC_256' value='204'/>
+      <enumerator name='GNUTLS_MAC_AES_GMAC_128' value='205'/>
+      <enumerator name='GNUTLS_MAC_AES_GMAC_192' value='206'/>
+      <enumerator name='GNUTLS_MAC_AES_GMAC_256' value='207'/>
     </enum-decl>
     <typedef-decl name='gnutls_mac_algorithm_t' type-id='type-id-44' id='type-id-31'/>
     <enum-decl name='__anonymous_enum__' is-anonymous='yes' id='type-id-45'>
index 11847f52466fa69922f5f57311af7b74ddf64529..ddbba2f453f0b7cc42b4a15b508237cbbee7999e 100644 (file)
@@ -162,6 +162,21 @@ mac_entry_st hash_algorithms[] = {
         .id = GNUTLS_MAC_AES_CMAC_256,
         .output_size = 16,
         .key_size = 32},
+       {.name = "AES-GMAC-128",
+        .id = GNUTLS_MAC_AES_GMAC_128,
+        .output_size = 16,
+        .key_size = 16,
+        .nonce_size = 12},
+       {.name = "AES-GMAC-192",
+        .id = GNUTLS_MAC_AES_GMAC_192,
+        .output_size = 16,
+        .key_size = 24,
+        .nonce_size = 12},
+       {.name = "AES-GMAC-256",
+        .id = GNUTLS_MAC_AES_GMAC_256,
+        .output_size = 16,
+        .key_size = 32,
+        .nonce_size = 12},
        {.name = "MAC-NULL",
         .id = GNUTLS_MAC_NULL},
        {0, 0, 0, 0, 0, 0, 0, 0, 0}
index eddf93568003418bf7ecb9d9759907a829b9f171..821271f22b3f4f65b951801c2e0951fb85b008f9 100644 (file)
@@ -1427,6 +1427,8 @@ static int test_digest(gnutls_digest_algorithm_t dig,
 struct mac_vectors_st {
        const uint8_t *key;
        unsigned int key_size;
+       const uint8_t *nonce;
+       unsigned int nonce_size;
        const uint8_t *plaintext;
        unsigned int plaintext_size;
        const uint8_t *output;
@@ -1560,6 +1562,47 @@ const struct mac_vectors_st aes_cmac_256_vectors[] = { /* NIST SP800-38A */
         },
 };
 
+const struct mac_vectors_st aes_gmac_128_vectors[] = { /* NIST test vectors */
+       {
+        STR(key, key_size,
+            "\x23\x70\xe3\x20\xd4\x34\x42\x08\xe0\xff\x56\x83\xf2\x43\xb2\x13"),
+        STR(nonce, nonce_size,
+            "\x04\xdb\xb8\x2f\x04\x4d\x30\x83\x1c\x44\x12\x28"),
+        STR(plaintext, plaintext_size,
+            "\xd4\x3a\x8e\x50\x89\xee\xa0\xd0\x26\xc0\x3a\x85\x17\x8b\x27\xda"),
+        STR(output, output_size,
+            "\x2a\x04\x9c\x04\x9d\x25\xaa\x95\x96\x9b\x45\x1d\x93\xc3\x1c\x6e"),
+       },
+};
+
+const struct mac_vectors_st aes_gmac_192_vectors[] = { /* NIST test vectors */
+       {
+        STR(key, key_size,
+            "\xaa\x92\x1c\xb5\xa2\x43\xab\x08\x91\x1f\x32\x89\x26\x6b\x39\xda"
+            "\xb1\x33\xf5\xc4\x20\xa6\xc5\xcd"),
+        STR(nonce, nonce_size,
+            "\x8f\x73\xdb\x68\xda\xee\xed\x2d\x15\x5f\xb1\xa0"),
+        STR(plaintext, plaintext_size,
+            "\x48\x74\x43\xc7\xc1\x4c\xe4\x74\xcb\x3d\x29\x1f\x25\x70\x70\xa2"),
+        STR(output, output_size,
+            "\xb1\x26\x74\xfb\xea\xc6\x88\x9a\x24\x94\x8f\x27\x92\xe3\x0a\x50"),
+       },
+};
+
+const struct mac_vectors_st aes_gmac_256_vectors[] = { /* NIST test vectors */
+       {
+        STR(key, key_size,
+            "\x6d\xfd\xaf\xd6\x70\x3c\x28\x5c\x01\xf1\x4f\xd1\x0a\x60\x12\x86"
+            "\x2b\x2a\xf9\x50\xd4\x73\x3a\xbb\x40\x3b\x2e\x74\x5b\x26\x94\x5d"),
+        STR(nonce, nonce_size,
+            "\x37\x49\xd0\xb3\xd5\xba\xcb\x71\xbe\x06\xad\xe6"),
+        STR(plaintext, plaintext_size,
+            "\xc0\xd2\x49\x87\x19\x92\xe7\x03\x02\xae\x00\x81\x93\xd1\xe8\x9f"),
+        STR(output, output_size,
+            "\x4a\xa4\xcc\x69\xf8\x4e\xe6\xac\x16\xd9\xbf\xb4\xe0\x5d\xe5\x00"),
+       },
+};
+
 static int test_mac(gnutls_mac_algorithm_t mac,
                    const struct mac_vectors_st *vectors,
                    size_t vectors_size, unsigned flags)
@@ -1582,6 +1625,11 @@ static int test_mac(gnutls_mac_algorithm_t mac,
                        return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
                }
 
+               if (vectors[i].nonce_size)
+                       gnutls_hmac_set_nonce(hd,
+                                             vectors[i].nonce,
+                                             vectors[i].nonce_size);
+
                ret = gnutls_hmac(hd, vectors[i].plaintext, 1);
                if (ret < 0)
                        return gnutls_assert_val(GNUTLS_E_SELF_TEST_ERROR);
@@ -1794,6 +1842,12 @@ int gnutls_mac_self_test(unsigned flags, gnutls_mac_algorithm_t mac)
                CASE(GNUTLS_MAC_AES_CMAC_128, test_mac, aes_cmac_128_vectors);
                FALLTHROUGH;
                CASE(GNUTLS_MAC_AES_CMAC_256, test_mac, aes_cmac_256_vectors);
+               FALLTHROUGH;
+               CASE(GNUTLS_MAC_AES_GMAC_128, test_mac, aes_gmac_128_vectors);
+               FALLTHROUGH;
+               CASE(GNUTLS_MAC_AES_GMAC_192, test_mac, aes_gmac_192_vectors);
+               FALLTHROUGH;
+               CASE(GNUTLS_MAC_AES_GMAC_256, test_mac, aes_gmac_256_vectors);
 
                break;
        default:
index 7385a95de01e390eaf8e580c5c85f130a3f62767..1464c9595bc6152fe2f9555e19a713b9105a3b76 100644 (file)
@@ -107,6 +107,9 @@ static unsigned is_mac_algo_forbidden(gnutls_mac_algorithm_t algo)
                        case GNUTLS_MAC_SHA3_512:
                         case GNUTLS_MAC_AES_CMAC_128:
                         case GNUTLS_MAC_AES_CMAC_256:
+                        case GNUTLS_MAC_AES_GMAC_128:
+                        case GNUTLS_MAC_AES_GMAC_192:
+                        case GNUTLS_MAC_AES_GMAC_256:
                                return 0;
                        default:
                                if (mode == GNUTLS_FIPS140_LAX)
index 365a5828052293bf8b2cff7a281d5f61ab6afd9b..074967603a096918b6cda5b557565087aae1327a 100644 (file)
@@ -282,6 +282,9 @@ typedef enum {
  * @GNUTLS_MAC_UMAC_128: The UMAC-128 MAC algorithm.
  * @GNUTLS_MAC_AES_CMAC_128: The AES-CMAC-128 MAC algorithm.
  * @GNUTLS_MAC_AES_CMAC_256: The AES-CMAC-256 MAC algorithm.
+ * @GNUTLS_MAC_AES_GMAC_128: The AES-GMAC-128 MAC algorithm.
+ * @GNUTLS_MAC_AES_GMAC_192: The AES-GMAC-192 MAC algorithm.
+ * @GNUTLS_MAC_AES_GMAC_256: The AES-GMAC-256 MAC algorithm.
  * @GNUTLS_MAC_SHA3_224: Reserved; unimplemented.
  * @GNUTLS_MAC_SHA3_256: Reserved; unimplemented.
  * @GNUTLS_MAC_SHA3_384: Reserved; unimplemented.
@@ -316,6 +319,9 @@ typedef enum {
        GNUTLS_MAC_UMAC_128 = 202,
        GNUTLS_MAC_AES_CMAC_128 = 203,
        GNUTLS_MAC_AES_CMAC_256 = 204,
+       GNUTLS_MAC_AES_GMAC_128 = 205,
+       GNUTLS_MAC_AES_GMAC_192 = 206,
+       GNUTLS_MAC_AES_GMAC_256 = 207,
 } gnutls_mac_algorithm_t;
 
 /**
index 8107f7cea448927670ebc1dc6bdbdefbff0e2a7e..64fa7e4925973eece2a9130ebcc4b2b9ca30b237 100644 (file)
@@ -42,6 +42,7 @@
 #else
 #include "cmac.h"
 #endif /* HAVE_NETTLE_CMAC128_UPDATE */
+#include <nettle/gcm.h>
 
 typedef void (*update_func) (void *, size_t, const uint8_t *);
 typedef void (*digest_func) (void *, size_t, uint8_t *);
@@ -56,6 +57,19 @@ struct md5_sha1_ctx {
        struct sha1_ctx sha1;
 };
 
+struct gmac_ctx {
+       unsigned int pos;
+       uint8_t buffer[GCM_BLOCK_SIZE];
+       struct gcm_key key;
+       struct gcm_ctx ctx;
+       nettle_cipher_func *encrypt;
+       union {
+               struct aes128_ctx aes128;
+               struct aes192_ctx aes192;
+               struct aes256_ctx aes256;
+       } cipher;
+};
+
 struct nettle_hash_ctx {
        union {
                struct md5_ctx md5;
@@ -100,6 +114,7 @@ struct nettle_mac_ctx {
                struct umac128_ctx umac128;
                 struct cmac_aes128_ctx cmac128;
                 struct cmac_aes256_ctx cmac256;
+               struct gmac_ctx gmac;
        } ctx;
 
        void *ctx_ptr;
@@ -143,6 +158,88 @@ _wrap_cmac256_set_key(void *ctx, size_t len, const uint8_t * key)
        cmac_aes256_set_key(ctx, key);
 }
 
+static void
+_wrap_gmac_aes128_set_key(void *_ctx, size_t len, const uint8_t * key)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       if (unlikely(len != 16))
+               abort();
+       aes128_set_encrypt_key(&ctx->cipher.aes128, key);
+       gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt);
+       ctx->pos = 0;
+}
+
+static void
+_wrap_gmac_aes192_set_key(void *_ctx, size_t len, const uint8_t * key)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       if (unlikely(len != 24))
+               abort();
+       aes192_set_encrypt_key(&ctx->cipher.aes192, key);
+       gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt);
+       ctx->pos = 0;
+}
+
+static void
+_wrap_gmac_aes256_set_key(void *_ctx, size_t len, const uint8_t * key)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       if (unlikely(len != 32))
+               abort();
+       aes256_set_encrypt_key(&ctx->cipher.aes256, key);
+       gcm_set_key(&ctx->key, &ctx->cipher, ctx->encrypt);
+       ctx->pos = 0;
+}
+
+static void _wrap_gmac_set_nonce(void *_ctx, size_t nonce_length, const uint8_t *nonce)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       gcm_set_iv(&ctx->ctx, &ctx->key, nonce_length, nonce);
+}
+
+static void _wrap_gmac_update(void *_ctx, size_t length, const uint8_t *data)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       if (ctx->pos + length < GCM_BLOCK_SIZE) {
+               memcpy(&ctx->buffer[ctx->pos], data, length);
+               ctx->pos += length;
+               return;
+       }
+
+       if (ctx->pos) {
+               memcpy(&ctx->buffer[ctx->pos], data, GCM_BLOCK_SIZE - ctx->pos);
+               gcm_update(&ctx->ctx, &ctx->key, GCM_BLOCK_SIZE, ctx->buffer);
+               data += GCM_BLOCK_SIZE - ctx->pos;
+               length -= GCM_BLOCK_SIZE - ctx->pos;
+       }
+
+       if (length >= GCM_BLOCK_SIZE) {
+               gcm_update(&ctx->ctx, &ctx->key,
+                          length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE,
+                          data);
+               data += length / GCM_BLOCK_SIZE * GCM_BLOCK_SIZE;
+               length %= GCM_BLOCK_SIZE;
+       }
+
+       memcpy(ctx->buffer, data, length);
+       ctx->pos = length;
+}
+
+static void _wrap_gmac_digest(void *_ctx, size_t length, uint8_t *digest)
+{
+       struct gmac_ctx *ctx = _ctx;
+
+       if (ctx->pos)
+               gcm_update(&ctx->ctx, &ctx->key, ctx->pos, ctx->buffer);
+       gcm_digest(&ctx->ctx, &ctx->key, &ctx->cipher, ctx->encrypt, length, digest);
+       ctx->pos = 0;
+}
+
 static int _mac_ctx_init(gnutls_mac_algorithm_t algo,
                         struct nettle_mac_ctx *ctx)
 {
@@ -246,6 +343,33 @@ static int _mac_ctx_init(gnutls_mac_algorithm_t algo,
                ctx->ctx_ptr = &ctx->ctx.cmac256;
                ctx->length = CMAC128_DIGEST_SIZE;
                break;
+       case GNUTLS_MAC_AES_GMAC_128:
+               ctx->set_key = _wrap_gmac_aes128_set_key;
+               ctx->set_nonce = _wrap_gmac_set_nonce;
+               ctx->update = _wrap_gmac_update;
+               ctx->digest = _wrap_gmac_digest;
+               ctx->ctx_ptr = &ctx->ctx.gmac;
+               ctx->length = GCM_DIGEST_SIZE;
+               ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes128_encrypt;
+               break;
+       case GNUTLS_MAC_AES_GMAC_192:
+               ctx->set_key = _wrap_gmac_aes192_set_key;
+               ctx->set_nonce = _wrap_gmac_set_nonce;
+               ctx->update = _wrap_gmac_update;
+               ctx->digest = _wrap_gmac_digest;
+               ctx->ctx_ptr = &ctx->ctx.gmac;
+               ctx->length = GCM_DIGEST_SIZE;
+               ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes192_encrypt;
+               break;
+       case GNUTLS_MAC_AES_GMAC_256:
+               ctx->set_key = _wrap_gmac_aes256_set_key;
+               ctx->set_nonce = _wrap_gmac_set_nonce;
+               ctx->update = _wrap_gmac_update;
+               ctx->digest = _wrap_gmac_digest;
+               ctx->ctx_ptr = &ctx->ctx.gmac;
+               ctx->length = GCM_DIGEST_SIZE;
+               ctx->ctx.gmac.encrypt = (nettle_cipher_func *)aes256_encrypt;
+               break;
        default:
                gnutls_assert();
                return GNUTLS_E_INVALID_REQUEST;
@@ -289,6 +413,9 @@ static int wrap_nettle_mac_exists(gnutls_mac_algorithm_t algo)
        case GNUTLS_MAC_SHA512:
        case GNUTLS_MAC_UMAC_96:
        case GNUTLS_MAC_UMAC_128:
+       case GNUTLS_MAC_AES_GMAC_128:
+       case GNUTLS_MAC_AES_GMAC_192:
+       case GNUTLS_MAC_AES_GMAC_256:
 #if ENABLE_GOST
        case GNUTLS_MAC_GOSTR_94:
        case GNUTLS_MAC_STREEBOG_256: