Merge pull request #323

Confidentiality and integrity limits for AEAD
diff --git a/include/picotls.h b/include/picotls.h
index 3012ab8..0ffe7d7 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -78,11 +78,17 @@
 #define PTLS_AES_IV_SIZE 16
 #define PTLS_AESGCM_IV_SIZE 12
 #define PTLS_AESGCM_TAG_SIZE 16
+#define PTLS_AESGCM_CONFIDENTIALITY_LIMIT 0x2000000            /* 2^25 */
+#define PTLS_AESGCM_INTEGRITY_LIMIT UINT64_C(0x40000000000000) /* 2^54 */
+#define PTLS_AESCCM_CONFIDENTIALITY_LIMIT 0xB504F3             /* 2^23.5 */
+#define PTLS_AESCCM_INTEGRITY_LIMIT 0xB504F3                   /* 2^23.5 */
 
 #define PTLS_CHACHA20_KEY_SIZE 32
 #define PTLS_CHACHA20_IV_SIZE 16
 #define PTLS_CHACHA20POLY1305_IV_SIZE 12
 #define PTLS_CHACHA20POLY1305_TAG_SIZE 16
+#define PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT UINT64_MAX       /* at least 2^64 */
+#define PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT UINT64_C(0x1000000000) /* 2^36 */
 
 #define PTLS_BLOWFISH_KEY_SIZE 16
 #define PTLS_BLOWFISH_BLOCK_SIZE 8
@@ -336,6 +342,14 @@
      */
     const char *name;
     /**
+     * confidentiality_limit (max records / packets sent before re-key)
+     */
+    const uint64_t confidentiality_limit;
+    /**
+     * integrity_limit (max decryption failure records / packets before re-key)
+     */
+    const uint64_t integrity_limit;
+    /**
      * the underlying key stream
      */
     ptls_cipher_algorithm_t *ctr_cipher;
diff --git a/lib/cifra/aes128.c b/lib/cifra/aes128.c
index 7f6817f..26bd9e4 100644
--- a/lib/cifra/aes128.c
+++ b/lib/cifra/aes128.c
@@ -47,8 +47,15 @@
 ptls_cipher_algorithm_t ptls_minicrypto_aes128ctr = {
     "AES128-CTR",          PTLS_AES128_KEY_SIZE, 1 /* block size */, PTLS_AES_IV_SIZE, sizeof(struct aesctr_context_t),
     aes128ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_minicrypto_aes128gcm = {
-    "AES128-GCM",        &ptls_minicrypto_aes128ctr, &ptls_minicrypto_aes128ecb,      PTLS_AES128_KEY_SIZE,
-    PTLS_AESGCM_IV_SIZE, PTLS_AESGCM_TAG_SIZE,       sizeof(struct aesgcm_context_t), aead_aes128gcm_setup_crypto};
+ptls_aead_algorithm_t ptls_minicrypto_aes128gcm = {"AES128-GCM",
+                                                   PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                                   PTLS_AESGCM_INTEGRITY_LIMIT,
+                                                   &ptls_minicrypto_aes128ctr,
+                                                   &ptls_minicrypto_aes128ecb,
+                                                   PTLS_AES128_KEY_SIZE,
+                                                   PTLS_AESGCM_IV_SIZE,
+                                                   PTLS_AESGCM_TAG_SIZE,
+                                                   sizeof(struct aesgcm_context_t),
+                                                   aead_aes128gcm_setup_crypto};
 ptls_cipher_suite_t ptls_minicrypto_aes128gcmsha256 = {PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, &ptls_minicrypto_aes128gcm,
                                                        &ptls_minicrypto_sha256};
diff --git a/lib/cifra/aes256.c b/lib/cifra/aes256.c
index 5b925be..d0568d5 100644
--- a/lib/cifra/aes256.c
+++ b/lib/cifra/aes256.c
@@ -47,8 +47,15 @@
 ptls_cipher_algorithm_t ptls_minicrypto_aes256ctr = {
     "AES256-CTR",          PTLS_AES256_KEY_SIZE, 1 /* block size */, PTLS_AES_IV_SIZE, sizeof(struct aesctr_context_t),
     aes256ctr_setup_crypto};
-ptls_aead_algorithm_t ptls_minicrypto_aes256gcm = {
-    "AES256-GCM",        &ptls_minicrypto_aes256ctr, &ptls_minicrypto_aes256ecb,      PTLS_AES256_KEY_SIZE,
-    PTLS_AESGCM_IV_SIZE, PTLS_AESGCM_TAG_SIZE,       sizeof(struct aesgcm_context_t), aead_aes256gcm_setup_crypto};
+ptls_aead_algorithm_t ptls_minicrypto_aes256gcm = {"AES256-GCM",
+                                                   PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                                   PTLS_AESGCM_INTEGRITY_LIMIT,
+                                                   &ptls_minicrypto_aes256ctr,
+                                                   &ptls_minicrypto_aes256ecb,
+                                                   PTLS_AES256_KEY_SIZE,
+                                                   PTLS_AESGCM_IV_SIZE,
+                                                   PTLS_AESGCM_TAG_SIZE,
+                                                   sizeof(struct aesgcm_context_t),
+                                                   aead_aes256gcm_setup_crypto};
 ptls_cipher_suite_t ptls_minicrypto_aes256gcmsha384 = {PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, &ptls_minicrypto_aes256gcm,
                                                        &ptls_minicrypto_sha384};
diff --git a/lib/cifra/chacha20.c b/lib/cifra/chacha20.c
index a5f302f..57a6c39 100644
--- a/lib/cifra/chacha20.c
+++ b/lib/cifra/chacha20.c
@@ -206,6 +206,8 @@
     "CHACHA20",           PTLS_CHACHA20_KEY_SIZE, 1 /* block size */, PTLS_CHACHA20_IV_SIZE, sizeof(struct chacha20_context_t),
     chacha20_setup_crypto};
 ptls_aead_algorithm_t ptls_minicrypto_chacha20poly1305 = {"CHACHA20-POLY1305",
+                                                          PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT,
+                                                          PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT,
                                                           &ptls_minicrypto_chacha20,
                                                           NULL,
                                                           PTLS_CHACHA20_KEY_SIZE,
diff --git a/lib/fusion.c b/lib/fusion.c
index b86205f..1610447 100644
--- a/lib/fusion.c
+++ b/lib/fusion.c
@@ -38,7 +38,7 @@
  * IN THE SOFTWARE.
  */
 #include <stdint.h>
-    
+
 #include <stdlib.h>
 #include <string.h>
 #include <immintrin.h>
@@ -294,7 +294,7 @@
 
     __m128i ek0, bits0, bits1, bits2, bits3, bits4, bits5 = _mm_setzero_si128();
     const __m128i *bits4keys = ctx->ecb.keys; /* is changed to supp->ctx.keys when calcurating suppout */
-    struct ptls_fusion_gfmul_state gstate = { 0 };
+    struct ptls_fusion_gfmul_state gstate = {0};
     __m128i gdatabuf[6];
     __m128i ac = _mm_shuffle_epi8(_mm_set_epi32(0, (int)aadlen * 8, 0, (int)inlen * 8), bswap8);
 
@@ -492,7 +492,7 @@
 {
     __m128i ek0 = _mm_setzero_si128(), bits0, bits1 = _mm_setzero_si128(), bits2 = _mm_setzero_si128(), bits3 = _mm_setzero_si128(),
             bits4 = _mm_setzero_si128(), bits5 = _mm_setzero_si128();
-    struct ptls_fusion_gfmul_state gstate = { 0 };
+    struct ptls_fusion_gfmul_state gstate = {0};
     __m128i gdatabuf[6];
     __m128i ac = _mm_shuffle_epi8(_mm_set_epi32(0, (int)aadlen * 8, 0, (int)inlen * 8), bswap8);
     struct ptls_fusion_aesgcm_ghash_precompute *ghash_precompute = ctx->ghash + (aadlen + 15) / 16 + (inlen + 15) / 16 + 1;
@@ -968,6 +968,8 @@
                                                  sizeof(struct ctr_context),
                                                  aes256ctr_setup};
 ptls_aead_algorithm_t ptls_fusion_aes128gcm = {"AES128-GCM",
+                                               PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                               PTLS_AESGCM_INTEGRITY_LIMIT,
                                                &ptls_fusion_aes128ctr,
                                                NULL, // &ptls_fusion_aes128ecb,
                                                PTLS_AES128_KEY_SIZE,
@@ -976,6 +978,8 @@
                                                sizeof(struct aesgcm_context),
                                                aes128gcm_setup};
 ptls_aead_algorithm_t ptls_fusion_aes256gcm = {"AES256-GCM",
+                                               PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                               PTLS_AESGCM_INTEGRITY_LIMIT,
                                                &ptls_fusion_aes256ctr,
                                                NULL, // &ptls_fusion_aes256ecb,
                                                PTLS_AES256_KEY_SIZE,
@@ -1005,7 +1009,7 @@
         uint32_t leaf1_ecx;
         __cpuid(cpu_info, 1);
         leaf1_ecx = cpu_info[2];
-        
+
         if (/* PCLMUL */ (leaf1_ecx & (1 << 5)) != 0 && /* AES */ (leaf1_ecx & (1 << 25)) != 0) {
             uint32_t leaf7_ebx;
             __cpuid(cpu_info, 7);
diff --git a/lib/openssl.c b/lib/openssl.c
index c55ba93..c7ba115 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -1429,6 +1429,8 @@
 ptls_cipher_algorithm_t ptls_openssl_aes128ctr = {
     "AES128-CTR", PTLS_AES128_KEY_SIZE, 1, PTLS_AES_IV_SIZE, sizeof(struct cipher_context_t), aes128ctr_setup_crypto};
 ptls_aead_algorithm_t ptls_openssl_aes128gcm = {"AES128-GCM",
+                                                PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                                PTLS_AESGCM_INTEGRITY_LIMIT,
                                                 &ptls_openssl_aes128ctr,
                                                 &ptls_openssl_aes128ecb,
                                                 PTLS_AES128_KEY_SIZE,
@@ -1443,6 +1445,8 @@
     "AES256-CTR",          PTLS_AES256_KEY_SIZE, 1 /* block size */, PTLS_AES_IV_SIZE, sizeof(struct cipher_context_t),
     aes256ctr_setup_crypto};
 ptls_aead_algorithm_t ptls_openssl_aes256gcm = {"AES256-GCM",
+                                                PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                                PTLS_AESGCM_INTEGRITY_LIMIT,
                                                 &ptls_openssl_aes256ctr,
                                                 &ptls_openssl_aes256ecb,
                                                 PTLS_AES256_KEY_SIZE,
@@ -1463,6 +1467,8 @@
     "CHACHA20",           PTLS_CHACHA20_KEY_SIZE, 1 /* block size */, PTLS_CHACHA20_IV_SIZE, sizeof(struct cipher_context_t),
     chacha20_setup_crypto};
 ptls_aead_algorithm_t ptls_openssl_chacha20poly1305 = {"CHACHA20-POLY1305",
+                                                       PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT,
+                                                       PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT,
                                                        &ptls_openssl_chacha20,
                                                        NULL,
                                                        PTLS_CHACHA20_KEY_SIZE,
diff --git a/lib/ptlsbcrypt.c b/lib/ptlsbcrypt.c
index 1035c69..2a9a4d0 100644
--- a/lib/ptlsbcrypt.c
+++ b/lib/ptlsbcrypt.c
@@ -65,7 +65,7 @@
 
 /*
  * Support for symmetric ciphers
-*/
+ */
 
 struct ptls_bcrypt_symmetric_param_t {
     HANDLE hKey;
@@ -215,7 +215,7 @@
             ctx->super.do_init = ptls_bcrypt_cipher_init_ctr;
             ctx->super.do_transform = ptls_bcrypt_cipher_transform_ctr;
         } else {
-            ctx->super.do_init = NULL; 
+            ctx->super.do_init = NULL;
             ctx->super.do_transform = ptls_bcrypt_cipher_transform_ecb;
         }
         ctx->bctx.is_enc = is_enc;
@@ -236,7 +236,6 @@
     return ptls_bcrypt_cipher_setup_crypto(_ctx, is_enc, key, BCRYPT_AES_ALGORITHM, 1);
 }
 
-
 /* Picotls assumes that AEAD encryption works as:
  * - an "init" call that prepares the encryption context.
  * - a series of "update" calls that encrypt segments of the message
@@ -248,7 +247,7 @@
  *  - the "padding info" points to a BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO
  *    structure
  *  - the "IV" parameter points to a buffer holding intermediate updates
- *    of the IV. That buffer shall be initialize to zero before the 
+ *    of the IV. That buffer shall be initialize to zero before the
  *    first call.
  * The documentation of the AEAD mode on MSDN is slightly obscure, and
  * also slightly wrong. After trial and errors and web searches, we find
@@ -266,10 +265,10 @@
  *    initialized to zero before first call.
  *  - The Mac Context parameter (pbMacContext, cbMacContext) contains
  *    a working buffer for the computation of the tag. The size
- *    must be the maxLength parameter returned retrieved in the 
+ *    must be the maxLength parameter returned retrieved in the
  *    BCRYPT_AUTH_TAG_LENGTH property of the algorithm. It must be
  *    initialized to zero before first call.
- *  - The dwflag parameters must be set to 
+ *  - The dwflag parameters must be set to
  *    BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG on first call. (The
  *    MSDN documentation says BCRYPT_AUTH_MODE_IN_PROGRESS_FLAG,
  *    but that's an error.)
@@ -284,7 +283,7 @@
  * error STATUS_INVALID_BUFFER_SIZE if the length passed in the
  * chained calls is not an integer multiple of block size. This forces
  * us to maintain an intermediate buffer of "extra bytes".
- *    
+ *
  */
 
 struct ptls_bcrypt_aead_param_t {
@@ -347,9 +346,9 @@
     ctx->bctx.aead_params.pbAuthData = (PUCHAR)aad;
     ctx->bctx.aead_params.cbAuthData = (ULONG)aadlen;
     ctx->bctx.aead_params.pbTag = (PUCHAR)ctx->bctx.tag;
-    ctx->bctx.aead_params.cbTag = (ULONG) ctx->super.algo->tag_size;
+    ctx->bctx.aead_params.cbTag = (ULONG)ctx->super.algo->tag_size;
     // ctx->bctx.aead_params.cbAAD = (ULONG)aadlen;
-    ctx->bctx.aead_params.pbMacContext = (PUCHAR) ctx->bctx.auth_tag;
+    ctx->bctx.aead_params.pbMacContext = (PUCHAR)ctx->bctx.auth_tag;
     ctx->bctx.aead_params.cbMacContext = (ULONG)ctx->bctx.maxTagLength;
     ctx->bctx.aead_params.dwFlags = BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
 }
@@ -368,14 +367,15 @@
 
         if (inlen < requiredBytes) {
             memcpy(&ctx->bctx.extraBytes[ctx->bctx.nbExtraBytes], input, inlen);
-            ctx->bctx.nbExtraBytes += (ULONG) inlen;
+            ctx->bctx.nbExtraBytes += (ULONG)inlen;
             inlen = 0;
         } else {
             memcpy(&ctx->bctx.extraBytes[ctx->bctx.nbExtraBytes], input, requiredBytes);
             inlen -= requiredBytes;
-            input = (void*)(((uint8_t *)input) + requiredBytes);
+            input = (void *)(((uint8_t *)input) + requiredBytes);
             ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.extraBytes, (ULONG)ctx->super.algo->ecb_cipher->block_size,
-                                (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf, (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult1, 0);
+                                (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf, (ULONG)ctx->super.algo->iv_size, output,
+                                (ULONG)outlenMax, &cbResult1, 0);
 
             assert(BCRYPT_SUCCESS(ret));
             if (!BCRYPT_SUCCESS(ret)) {
@@ -414,8 +414,8 @@
 
     ctx->bctx.aead_params.dwFlags &= ~BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG;
 
-    ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.extraBytes, (ULONG)ctx->bctx.nbExtraBytes, (void *)&ctx->bctx.aead_params, ctx->bctx.ivbuf,
-                        (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult, 0);
+    ret = BCryptEncrypt(ctx->bctx.hKey, (PUCHAR)ctx->bctx.extraBytes, (ULONG)ctx->bctx.nbExtraBytes, (void *)&ctx->bctx.aead_params,
+                        ctx->bctx.ivbuf, (ULONG)ctx->super.algo->iv_size, output, (ULONG)outlenMax, &cbResult, 0);
     assert(BCRYPT_SUCCESS(ret));
 
     if (BCRYPT_SUCCESS(ret)) {
@@ -450,8 +450,8 @@
     ctx->bctx.aead_params.cbTag = (ULONG)(ULONG)ctx->super.algo->tag_size;
 
     /* Call the decryption */
-    ret = BCryptDecrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)textLen, (void *)&ctx->bctx.aead_params,
-                        NULL, 0, (PUCHAR)output, (ULONG)textLen, &cbResult, 0);
+    ret = BCryptDecrypt(ctx->bctx.hKey, (PUCHAR)input, (ULONG)textLen, (void *)&ctx->bctx.aead_params, NULL, 0, (PUCHAR)output,
+                        (ULONG)textLen, &cbResult, 0);
 
     if (BCRYPT_SUCCESS(ret)) {
         return (size_t)cbResult;
@@ -460,8 +460,8 @@
     }
 }
 
-static int ptls_bcrypt_aead_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, 
-    const void * iv, wchar_t const *bcrypt_name, wchar_t const *bcrypt_mode, size_t bcrypt_mode_size)
+static int ptls_bcrypt_aead_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv,
+                                         wchar_t const *bcrypt_name, wchar_t const *bcrypt_mode, size_t bcrypt_mode_size)
 {
     struct ptls_bcrypt_aead_context_t *ctx = (struct ptls_bcrypt_aead_context_t *)_ctx;
     HANDLE hAlgorithm = NULL;
@@ -533,7 +533,7 @@
     }
 }
 
-static int ptls_bcrypt_aead_setup_crypto_aesgcm(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void * iv)
+static int ptls_bcrypt_aead_setup_crypto_aesgcm(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv)
 {
     return ptls_bcrypt_aead_setup_crypto(_ctx, is_enc, key, iv, BCRYPT_AES_ALGORITHM, BCRYPT_CHAIN_MODE_GCM,
                                          sizeof(BCRYPT_CHAIN_MODE_GCM));
@@ -619,7 +619,7 @@
             }
             assert(BCRYPT_SUCCESS(ret));
             if (!BCRYPT_SUCCESS(ret)) {
-                ctx->ctx.hHash = NULL;   
+                ctx->ctx.hHash = NULL;
             }
             break;
         }
@@ -750,6 +750,8 @@
                                                  ptls_bcrypt_cipher_setup_crypto_aes_ctr};
 
 ptls_aead_algorithm_t ptls_bcrypt_aes128gcm = {"AES128-GCM",
+                                               PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                               PTLS_AESGCM_INTEGRITY_LIMIT,
                                                &ptls_bcrypt_aes128ecb,
                                                &ptls_bcrypt_aes128ctr,
                                                PTLS_AES128_KEY_SIZE,
@@ -759,6 +761,8 @@
                                                ptls_bcrypt_aead_setup_crypto_aesgcm};
 
 ptls_aead_algorithm_t ptls_bcrypt_aes256gcm = {"AES256-GCM",
+                                               PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+                                               PTLS_AESGCM_INTEGRITY_LIMIT,
                                                &ptls_bcrypt_aes256ecb,
                                                &ptls_bcrypt_aes256ctr,
                                                PTLS_AES256_KEY_SIZE,