Merge pull request #382 from devnexen/openssl3_silencing

openssl 3 build fix proposal.
diff --git a/include/picotls.h b/include/picotls.h
index aadd671..cad1206 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -337,6 +337,8 @@
 /**
  * AEAD context. AEAD implementations are allowed to stuff data at the end of the struct. The size of the memory allocated for the
  * struct is governed by ptls_aead_algorithm_t::context_size.
+ * Ciphers for TLS over TCP MUST implement `do_encrypt`, `do_encrypt_v`, `do_decrypt`. `do_encrypt_init`, `~update`, `~final` are
+ * obsolete, and therefore may not be available.
  */
 typedef struct st_ptls_aead_context_t {
     const struct st_ptls_aead_algorithm_t *algo;
@@ -348,6 +350,8 @@
     size_t (*do_encrypt_final)(struct st_ptls_aead_context_t *ctx, void *output);
     void (*do_encrypt)(struct st_ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                        const void *aad, size_t aadlen, ptls_aead_supplementary_encryption_t *supp);
+    void (*do_encrypt_v)(struct st_ptls_aead_context_t *ctx, void *output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                         const void *aad, size_t aadlen);
     size_t (*do_decrypt)(struct st_ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                          const void *aad, size_t aadlen);
 } ptls_aead_context_t;
@@ -1149,6 +1153,12 @@
  */
 ptls_cipher_suite_t *ptls_get_cipher(ptls_t *tls);
 /**
+ * Returns current state of traffic keys. The cipher-suite being used, as well as the length of the traffic keys, can be obtained
+ * via `ptls_get_cipher`.
+ * TODO: Even in case of offloading just the TX side, there should be API for handling key updates, sending Close aleart.
+ */
+int ptls_get_traffic_keys(ptls_t *tls, int is_enc, uint8_t *key, uint8_t *iv, uint64_t *seq);
+/**
  * returns the server-name (NULL if SNI is not used or failed to negotiate)
  */
 const char *ptls_get_server_name(ptls_t *tls);
@@ -1296,24 +1306,31 @@
  */
 static void ptls_aead_xor_iv(ptls_aead_context_t *ctx, const void *bytes, size_t len);
 /**
- *
+ * Encrypts one AEAD block, given input and output vectors.
  */
 static size_t ptls_aead_encrypt(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                                 const void *aad, size_t aadlen);
+/**
+ * Encrypts one AEAD block, as well as one block of ECB (for QUIC / DTLS packet number encryption). Depending on the AEAD engine
+ * being used, the two operations might run simultaneously.
+ */
 static void ptls_aead_encrypt_s(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                                 const void *aad, size_t aadlen, ptls_aead_supplementary_encryption_t *supp);
 /**
- * initializes the internal state of the encryptor
+ * Encrypts one AEAD block, given a vector of vectors.
+ */
+static void ptls_aead_encrypt_v(ptls_aead_context_t *ctx, void *output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                                const void *aad, size_t aadlen);
+/**
+ * Obsolete; new applications should use one of: `ptls_aead_encrypt`, `ptls_aead_encrypt_s`, `ptls_aead_encrypt_v`.
  */
 static void ptls_aead_encrypt_init(ptls_aead_context_t *ctx, uint64_t seq, const void *aad, size_t aadlen);
 /**
- * encrypts the input and updates the GCM state
- * @return number of bytes emitted to output
+ * Obsolete; see `ptls_aead_encrypt_init`.
  */
 static size_t ptls_aead_encrypt_update(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen);
 /**
- * emits buffered data (if any) and the GCM tag
- * @return number of bytes emitted to output
+ * Obsolete; see `ptls_aead_encrypt_init`.
  */
 static size_t ptls_aead_encrypt_final(ptls_aead_context_t *ctx, void *output);
 /**
@@ -1359,6 +1376,11 @@
 static void ptls_aead__do_encrypt(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                                   const void *aad, size_t aadlen, ptls_aead_supplementary_encryption_t *supp);
 /**
+ *
+ */
+static void ptls_aead__do_encrypt_v(ptls_aead_context_t *ctx, void *_output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                                    const void *aad, size_t aadlen);
+/**
  * internal
  */
 void ptls__key_schedule_update_hash(ptls_key_schedule_t *sched, const uint8_t *msg, size_t msglen);
@@ -1494,6 +1516,12 @@
     ctx->do_encrypt(ctx, output, input, inlen, seq, aad, aadlen, supp);
 }
 
+inline void ptls_aead_encrypt_v(ptls_aead_context_t *ctx, void *output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                                const void *aad, size_t aadlen)
+{
+    ctx->do_encrypt_v(ctx, output, input, incnt, seq, aad, aadlen);
+}
+
 inline void ptls_aead_encrypt_init(ptls_aead_context_t *ctx, uint64_t seq, const void *aad, size_t aadlen)
 {
     ctx->do_encrypt_init(ctx, seq, aad, aadlen);
@@ -1512,9 +1540,8 @@
 inline void ptls_aead__do_encrypt(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                                   const void *aad, size_t aadlen, ptls_aead_supplementary_encryption_t *supp)
 {
-    ctx->do_encrypt_init(ctx, seq, aad, aadlen);
-    ctx->do_encrypt_update(ctx, output, input, inlen);
-    ctx->do_encrypt_final(ctx, (uint8_t *)output + inlen);
+    ptls_iovec_t invec = ptls_iovec_init(input, inlen);
+    ctx->do_encrypt_v(ctx, output, &invec, 1, seq, aad, aadlen);
 
     if (supp != NULL) {
         ptls_cipher_init(supp->ctx, supp->input);
@@ -1523,6 +1550,17 @@
     }
 }
 
+inline void ptls_aead__do_encrypt_v(ptls_aead_context_t *ctx, void *_output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                                    const void *aad, size_t aadlen)
+{
+    uint8_t *output = (uint8_t *)_output;
+
+    ctx->do_encrypt_init(ctx, seq, aad, aadlen);
+    for (size_t i = 0; i < incnt; ++i)
+        output += ctx->do_encrypt_update(ctx, output, input[i].base, input[i].len);
+    ctx->do_encrypt_final(ctx, output);
+}
+
 inline size_t ptls_aead_decrypt(ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                                 const void *aad, size_t aadlen)
 {
diff --git a/lib/cifra/aes-common.h b/lib/cifra/aes-common.h
index dfb620a..234e647 100644
--- a/lib/cifra/aes-common.h
+++ b/lib/cifra/aes-common.h
@@ -174,11 +174,14 @@
         ctx->super.do_encrypt_update = aesgcm_encrypt_update;
         ctx->super.do_encrypt_final = aesgcm_encrypt_final;
         ctx->super.do_encrypt = ptls_aead__do_encrypt;
+        ctx->super.do_encrypt_v = ptls_aead__do_encrypt_v;
         ctx->super.do_decrypt = NULL;
     } else {
         ctx->super.do_encrypt_init = NULL;
         ctx->super.do_encrypt_update = NULL;
         ctx->super.do_encrypt_final = NULL;
+        ctx->super.do_encrypt = NULL;
+        ctx->super.do_encrypt_v = NULL;
         ctx->super.do_decrypt = aesgcm_decrypt;
     }
 
diff --git a/lib/cifra/chacha20.c b/lib/cifra/chacha20.c
index 8db3a18..2e35843 100644
--- a/lib/cifra/chacha20.c
+++ b/lib/cifra/chacha20.c
@@ -199,11 +199,14 @@
         ctx->super.do_encrypt_update = chacha20poly1305_encrypt_update;
         ctx->super.do_encrypt_final = chacha20poly1305_encrypt_final;
         ctx->super.do_encrypt = ptls_aead__do_encrypt;
+        ctx->super.do_encrypt_v = ptls_aead__do_encrypt_v;
         ctx->super.do_decrypt = NULL;
     } else {
         ctx->super.do_encrypt_init = NULL;
         ctx->super.do_encrypt_update = NULL;
         ctx->super.do_encrypt_final = NULL;
+        ctx->super.do_encrypt = NULL;
+        ctx->super.do_encrypt_v = NULL;
         ctx->super.do_decrypt = chacha20poly1305_decrypt;
     }
 
diff --git a/lib/fusion.c b/lib/fusion.c
index e77e8ba..e0d977c 100644
--- a/lib/fusion.c
+++ b/lib/fusion.c
@@ -914,6 +914,12 @@
     ptls_fusion_aesgcm_encrypt(ctx->aesgcm, output, input, inlen, calc_counter(ctx, seq), aad, aadlen, supp);
 }
 
+static void aead_do_encrypt_v(struct st_ptls_aead_context_t *ctx, void *output, ptls_iovec_t *input, size_t incnt, uint64_t seq,
+                              const void *aad, size_t aadlen)
+{
+    assert(!"FIXME");
+}
+
 static size_t aead_do_decrypt(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, uint64_t seq,
                               const void *aad, size_t aadlen)
 {
@@ -954,6 +960,7 @@
     ctx->super.do_encrypt_update = aead_do_encrypt_update;
     ctx->super.do_encrypt_final = aead_do_encrypt_final;
     ctx->super.do_encrypt = aead_do_encrypt;
+    ctx->super.do_encrypt_v = aead_do_encrypt_v;
     ctx->super.do_decrypt = aead_do_decrypt;
 
     ctx->aesgcm = ptls_fusion_aesgcm_new(key, key_size, 1500 /* assume ordinary packet size */);
diff --git a/lib/openssl.c b/lib/openssl.c
index 93a74d3..f891e04 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -981,11 +981,14 @@
         ctx->super.do_encrypt_update = aead_do_encrypt_update;
         ctx->super.do_encrypt_final = aead_do_encrypt_final;
         ctx->super.do_encrypt = ptls_aead__do_encrypt;
+        ctx->super.do_encrypt_v = ptls_aead__do_encrypt_v;
         ctx->super.do_decrypt = NULL;
     } else {
         ctx->super.do_encrypt_init = NULL;
         ctx->super.do_encrypt_update = NULL;
         ctx->super.do_encrypt_final = NULL;
+        ctx->super.do_encrypt = NULL;
+        ctx->super.do_encrypt_v = NULL;
         ctx->super.do_decrypt = aead_do_decrypt;
     }
     ctx->evp_ctx = NULL;
diff --git a/lib/picotls.c b/lib/picotls.c
index 8ea30b6..8bb5b13 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -638,16 +638,13 @@
 static size_t aead_encrypt(struct st_ptls_traffic_protection_t *ctx, void *output, const void *input, size_t inlen,
                            uint8_t content_type)
 {
+    ptls_iovec_t invec[2] = {ptls_iovec_init(input, inlen), ptls_iovec_init(&content_type, 1)};
     uint8_t aad[5];
-    size_t off = 0;
 
     build_aad(aad, inlen + 1 + ctx->aead->algo->tag_size);
-    ptls_aead_encrypt_init(ctx->aead, ctx->seq++, aad, sizeof(aad));
-    off += ptls_aead_encrypt_update(ctx->aead, ((uint8_t *)output) + off, input, inlen);
-    off += ptls_aead_encrypt_update(ctx->aead, ((uint8_t *)output) + off, &content_type, 1);
-    off += ptls_aead_encrypt_final(ctx->aead, ((uint8_t *)output) + off);
+    ptls_aead_encrypt_v(ctx->aead, output, invec, PTLS_ELEMENTSOF(invec), ctx->seq++, aad, sizeof(aad));
 
-    return off;
+    return inlen + 1 + ctx->aead->algo->tag_size;
 }
 
 static int aead_decrypt(struct st_ptls_traffic_protection_t *ctx, void *output, size_t *outlen, const void *input, size_t inlen)
@@ -1195,6 +1192,20 @@
                                   label_prefix);
 }
 
+static int get_traffic_keys(ptls_aead_algorithm_t *aead, ptls_hash_algorithm_t *hash, void *key, void *iv, const void *secret,
+                            ptls_iovec_t hash_value, const char *label_prefix)
+{
+    int ret;
+
+    if ((ret = get_traffic_key(hash, key, aead->key_size, 0, secret, hash_value, label_prefix)) != 0 ||
+        (ret = get_traffic_key(hash, iv, aead->iv_size, 1, secret, hash_value, label_prefix)) != 0) {
+        ptls_clear_memory(key, aead->key_size);
+        ptls_clear_memory(iv, aead->iv_size);
+    }
+
+    return ret;
+}
+
 static int setup_traffic_protection(ptls_t *tls, int is_enc, const char *secret_label, size_t epoch, int skip_notify)
 {
     static const char *log_labels[2][4] = {
@@ -4425,6 +4436,18 @@
     return tls->cipher_suite;
 }
 
+int ptls_get_traffic_keys(ptls_t *tls, int is_enc, uint8_t *key, uint8_t *iv, uint64_t *seq)
+{
+    struct st_ptls_traffic_protection_t *ctx = is_enc ? &tls->traffic_protection.enc : &tls->traffic_protection.dec;
+    int ret;
+
+    if ((ret = get_traffic_keys(tls->cipher_suite->aead, tls->cipher_suite->hash, key, iv, ctx->secret, ptls_iovec_init(NULL, 0),
+                                NULL)) != 0)
+        return ret;
+    *seq = ctx->seq;
+    return 0;
+}
+
 const char *ptls_get_server_name(ptls_t *tls)
 {
     return tls->server_name;
@@ -5218,17 +5241,18 @@
                               ptls_iovec_t hash_value, const char *label_prefix)
 {
     ptls_aead_context_t *ctx = NULL;
-    uint8_t key_iv[PTLS_MAX_SECRET_SIZE + PTLS_MAX_IV_SIZE];
+    struct {
+        uint8_t key[PTLS_MAX_SECRET_SIZE];
+        uint8_t iv[PTLS_MAX_IV_SIZE];
+    } key_iv;
     int ret;
 
-    if ((ret = get_traffic_key(hash, key_iv, aead->key_size, 0, secret, hash_value, label_prefix)) != 0)
+    if ((ret = get_traffic_keys(aead, hash, key_iv.key, key_iv.iv, secret, hash_value, label_prefix)) != 0)
         goto Exit;
-    if ((ret = get_traffic_key(hash, key_iv + aead->key_size, aead->iv_size, 1, secret, hash_value, label_prefix)) != 0)
-        goto Exit;
-    ctx = ptls_aead_new_direct(aead, is_enc, key_iv, key_iv + aead->key_size);
+    ctx = ptls_aead_new_direct(aead, is_enc, key_iv.key, key_iv.iv);
 
 Exit:
-    ptls_clear_memory(key_iv, sizeof(key_iv));
+    ptls_clear_memory(&key_iv, sizeof(key_iv));
     return ctx;
 }
 
diff --git a/lib/ptlsbcrypt.c b/lib/ptlsbcrypt.c
index 92e26fd..41e6a73 100644
--- a/lib/ptlsbcrypt.c
+++ b/lib/ptlsbcrypt.c
@@ -545,12 +545,15 @@
             ctx->super.do_encrypt_update = ptls_bcrypt_aead_do_encrypt_update;
             ctx->super.do_encrypt_final = ptls_bcrypt_aead_do_encrypt_final;
             ctx->super.do_encrypt = ptls_bcrypt_do_encrypt;
+            ctx->super.do_encrypt_v = ptls_aead__do_encrypt_v;
         } else {
             ctx->super.dispose_crypto = ptls_bcrypt_aead_dispose_crypto;
             ctx->super.do_decrypt = ptls_bcrypt_aead_do_decrypt;
             ctx->super.do_encrypt_init = NULL;
             ctx->super.do_encrypt_update = NULL;
             ctx->super.do_encrypt_final = NULL;
+            ctx->super.do_encrypt = NULL;
+            ctx->super.do_encrypt_v = NULL;
         }
         return 0;
     } else {
@@ -830,4 +833,4 @@
 ptls_key_exchange_algorithm_t *ptls_bcrypt_key_exchanges[] = {&ptls_bcrypt_secp256r1, NULL};
 #endif
 
-#endif /* _WINDOWS */
\ No newline at end of file
+#endif /* _WINDOWS */
diff --git a/picotlsvs/bcrypt-test/bcrypt-test.c b/picotlsvs/bcrypt-test/bcrypt-test.c
index 513a344..f45c497 100644
--- a/picotlsvs/bcrypt-test/bcrypt-test.c
+++ b/picotlsvs/bcrypt-test/bcrypt-test.c
@@ -374,6 +374,78 @@
     return ret;
 }
 
+int test_encrypt_vector(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz)
+{
+    BYTE key[32];
+    BYTE iv[PTLS_MAX_IV_SIZE];
+    BYTE data[123];
+    uint64_t nonce;
+    BYTE authData[9];
+    BYTE encryptedRef[256];
+    ULONG encryptedRefLength;
+    BYTE encrypted[256];
+    size_t encryptedLength;
+    ULONG authTagLength = (ULONG)aead->tag_size;
+    ptls_aead_context_t *ctx = NULL;
+    int ret = 0;
+
+    assert(sizeof(key) >= aead->key_size);
+    assert(sizeof(iv) >= aead->iv_size);
+    assert(sizeof(data) + authTagLength <= sizeof(encrypted));
+    assert(sizeof(data) + authTagLength <= sizeof(encryptedRef));
+
+    memset(key, 'k', sizeof(key));
+    memset(iv, 'n', sizeof(iv));
+    memset(data, 'd', sizeof(data));
+    nonce = 0;
+    memset(authData, 'a', sizeof(authData));
+
+    /* Create an encryption context */
+    ctx = new_test_aead_context(aead, 1, key, iv);
+    if (ctx == NULL) {
+        ret = -1;
+    }
+
+    if (ret == 0) {
+        ret = EncodeOneShot(aead, name, chain_mode, chain_mode_sz, key, (ULONG)aead->key_size, iv, (ULONG)aead->iv_size, data, 123,
+                            nonce, authData, 9, authTagLength, encryptedRef, 256, &encryptedRefLength);
+    }
+
+    /* Try encrypt with vector procedure */
+    if (ret == 0) {
+        ptls_iovec_t input_vec[2];
+
+        input_vec[0].base = data;
+        input_vec[0].len = 23;
+        input_vec[1].base = data + 23;
+        input_vec[1].len = 100;
+
+        ptls_aead_encrypt_v(ctx, encrypted, input_vec, 2, nonce, authData, 9);
+        encryptedLength = 123 + authTagLength;
+
+        if (encryptedLength != encryptedRefLength) {
+            printf("For %s, encrypt_v returns %d instead of %d\n", aead->name, (int)encryptedLength, encryptedRefLength);
+            ret = -1;
+        } else if (memcmp(encryptedRef, encrypted, encryptedRefLength) != 0) {
+            printf("For %s, vector encrypted does not match ref\n", aead->name);
+            for (ULONG i = 0; i < encryptedRefLength; i++) {
+                if (encryptedRef[i] != encrypted[i]) {
+                    printf("For %s, vector encrypted[%d] = 0x%02x vs encryptedRef[%d] = 0x%02x\n", aead->name, i, encrypted[i], i,
+                           encryptedRef[i]);
+                    break;
+                }
+            }
+            ret = -1;
+        } else {
+            printf("For %s, vector encrypting test passes.\n", aead->name);
+        }
+    }
+
+    delete_test_aead_context(ctx);
+
+    return ret;
+}
+
 int test_for_size(ptls_aead_algorithm_t *aead, wchar_t *name, wchar_t *chain_mode, size_t chain_mode_sz)
 {
     BYTE key[32];
@@ -482,6 +554,13 @@
     }
 
     if (ret == 0) {
+        ret = test_encrypt_vector(aead, name, chain_mode, chain_mode_sz);
+
+        printf("For %s, test encrypt returns %d\n", aead->name, ret);
+    }
+
+
+    if (ret == 0) {
         ret = test_for_size(aead, name, chain_mode, chain_mode_sz);
 
         printf("For %s, test packet sizes returns %d\n", aead->name, ret);