Merge pull request #467 from h2o/kazuho/boring
add support for boringssl
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8b538ad..02cd626 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -23,6 +23,8 @@
command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204
- name: "Linux / OpenSSL 1.1.1 + ASan & UBSan"
command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address,undefined -DCMAKE_CXX_FLAGS=-fsanitize=address,undefined' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1'
+ - name: "Linux / boringssl"
+ command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 CMAKE_ARGS='-DOPENSSL_ROOT_DIR=/opt/boringssl'
timeout-minutes: 20
steps:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3af816d..5ad42d8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -11,6 +11,7 @@
FIND_PACKAGE(PkgConfig REQUIRED)
INCLUDE(cmake/dtrace-utils.cmake)
+INCLUDE(cmake/boringssl-adjust.cmake)
CHECK_DTRACE(${PROJECT_SOURCE_DIR}/picotls-probes.d)
IF ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND
@@ -120,6 +121,8 @@
picotls-minicrypto picotls-core)
FIND_PACKAGE(OpenSSL)
+BORINGSSL_ADJUST()
+
IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
MESSAGE(STATUS " Enabling OpenSSL support")
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
diff --git a/cmake/boringssl-adjust.cmake b/cmake/boringssl-adjust.cmake
new file mode 100644
index 0000000..4a2aef6
--- /dev/null
+++ b/cmake/boringssl-adjust.cmake
@@ -0,0 +1,16 @@
+FUNCTION (BORINGSSL_ADJUST)
+ IF (OPENSSL_FOUND AND OPENSSL_VERSION STREQUAL "" AND EXISTS "${OPENSSL_INCLUDE_DIR}/openssl/base.h")
+ MESSAGE(STATUS " BoringSSL found; assuming OpenSSL 1.1.1 compatibility")
+ SET(OPENSSL_VERSION "1.1.1" PARENT_SCOPE)
+ LIST(GET OPENSSL_CRYPTO_LIBRARIES 0 OPENSSL_ONE_LIB_PATH)
+ GET_FILENAME_COMPONENT(OPENSSL_LIBDIR "${OPENSSL_ONE_LIB_PATH}" DIRECTORY)
+ SET(LIBDECREPIT_PATH "${OPENSSL_LIBDIR}/libdecrepit.a")
+ IF (NOT EXISTS "${LIBDECREPIT_PATH}")
+ MESSAGE(FATAL_ERROR "libdecrepit.a was not found under ${OPENSSL_LIBDIR}; maybe you need to manually copy the file there")
+ ENDIF ()
+ LIST(APPEND OPENSSL_CRYPTO_LIBRARIES "${LIBDECREPIT_PATH}")
+ SET(OPENSSL_CRYPTO_LIBRARIES "${OPENSSL_CRYPTO_LIBRARIES}" PARENT_SCOPE)
+ LIST(APPEND OPENSSL_LIBRARIES "${LIBDECREPIT_PATH}")
+ SET(OPENSSL_LIBRARIES "${OPENSSL_LIBRARIES}" PARENT_SCOPE)
+ ENDIF ()
+ENDFUNCTION ()
diff --git a/include/picotls.h b/include/picotls.h
index 420861f..0cadb17 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -85,7 +85,7 @@
#define PTLS_AESCCM_INTEGRITY_LIMIT 0xB504F3 /* 2^23.5 */
#define PTLS_CHACHA20_KEY_SIZE 32
-#define PTLS_CHACHA20_IV_SIZE 16
+#define PTLS_CHACHA20_IV_SIZE 16 /* contrary to RFC 7539, follow OpenSSL way of using first 32 bits as ctr and latter 96 as IV */
#define PTLS_CHACHA20POLY1305_IV_SIZE 12
#define PTLS_CHACHA20POLY1305_TAG_SIZE 16
#define PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT UINT64_MAX /* at least 2^64 */
diff --git a/include/picotls/openssl.h b/include/picotls/openssl.h
index a892f9b..e0761ed 100644
--- a/include/picotls/openssl.h
+++ b/include/picotls/openssl.h
@@ -65,7 +65,9 @@
#define PTLS_OPENSSL_HAS_X25519 1 /* deprecated; use HAVE_ */
extern ptls_key_exchange_algorithm_t ptls_openssl_x25519;
#endif
-#ifndef OPENSSL_NO_BF
+
+/* when boringssl is used, existence of libdecrepit is assumed */
+#if !defined(OPENSSL_NO_BF) || defined(OPENSSL_IS_BORINGSSL)
#define PTLS_OPENSSL_HAVE_BF 1
#endif
diff --git a/lib/chacha20poly1305.h b/lib/chacha20poly1305.h
new file mode 100644
index 0000000..ad2d7fe
--- /dev/null
+++ b/lib/chacha20poly1305.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2016-2023 DeNA Co., Ltd., Kazuho Oku, Lars Eggert, Christian
+ Huitema, Fastly
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <stddef.h>
+#include "picotls.h"
+
+#define CHACHA20POLY1305_BLOCKSIZE 64
+
+struct chacha20poly1305_context_t {
+ ptls_aead_context_t super;
+ ptls_cipher_context_t *chacha;
+ uint8_t static_iv[PTLS_CHACHA20POLY1305_IV_SIZE];
+ size_t aadlen;
+ size_t textlen;
+ void (*poly1305_init)(struct chacha20poly1305_context_t *, const void *);
+ void (*poly1305_update)(struct chacha20poly1305_context_t *, const void *, size_t);
+ void (*poly1305_finish)(struct chacha20poly1305_context_t *, void *);
+};
+
+static void chacha20poly1305_write_u64(uint8_t *buf, uint64_t v)
+{
+ *buf++ = v & 0xff;
+ *buf++ = (v >> 8) & 0xff;
+ *buf++ = (v >> 16) & 0xff;
+ *buf++ = (v >> 24) & 0xff;
+ *buf++ = (v >> 32) & 0xff;
+ *buf++ = (v >> 40) & 0xff;
+ *buf++ = (v >> 48) & 0xff;
+ *buf = (v >> 56) & 0xff;
+}
+
+static void chacha20poly1305_encrypt_pad(struct chacha20poly1305_context_t *ctx, size_t n)
+{
+ static const uint8_t zeros[16] = {0};
+ if (n % 16 != 0)
+ ctx->poly1305_update(ctx, zeros, 16 - (n % 16));
+}
+
+static void chacha20poly1305_finalize(struct chacha20poly1305_context_t *ctx, uint8_t *tag)
+{
+ uint8_t lenbuf[16];
+
+ chacha20poly1305_encrypt_pad(ctx, ctx->textlen);
+
+ chacha20poly1305_write_u64(lenbuf, ctx->aadlen);
+ chacha20poly1305_write_u64(lenbuf + 8, ctx->textlen);
+ ctx->poly1305_update(ctx, lenbuf, sizeof(lenbuf));
+
+ ctx->poly1305_finish(ctx, tag);
+}
+
+static void chacha20poly1305_dispose_crypto(ptls_aead_context_t *_ctx)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+ ptls_cipher_free(ctx->chacha);
+}
+
+static void chacha20poly1305_init(ptls_aead_context_t *_ctx, uint64_t seq, const void *aad, size_t aadlen)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+ uint8_t tmpbuf[CHACHA20POLY1305_BLOCKSIZE];
+
+ /* init chacha */
+ memset(tmpbuf, 0, 16 - PTLS_CHACHA20POLY1305_IV_SIZE);
+ ptls_aead__build_iv(ctx->super.algo, tmpbuf + 16 - PTLS_CHACHA20POLY1305_IV_SIZE, ctx->static_iv, seq);
+ ptls_cipher_init(ctx->chacha, tmpbuf);
+
+ /* init poly1305 */
+ memset(tmpbuf, 0, sizeof(tmpbuf));
+ ptls_cipher_encrypt(ctx->chacha, tmpbuf, tmpbuf, CHACHA20POLY1305_BLOCKSIZE);
+ ctx->poly1305_init(ctx, tmpbuf);
+
+ ptls_clear_memory(tmpbuf, sizeof(tmpbuf));
+
+ /* aad */
+ if (aadlen != 0) {
+ ctx->poly1305_update(ctx, aad, aadlen);
+ chacha20poly1305_encrypt_pad(ctx, aadlen);
+ }
+
+ ctx->aadlen = aadlen;
+ ctx->textlen = 0;
+}
+
+static size_t chacha20poly1305_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+
+ ptls_cipher_encrypt(ctx->chacha, output, input, inlen);
+ ctx->poly1305_update(ctx, output, inlen);
+ ctx->textlen += inlen;
+
+ return inlen;
+}
+
+static size_t chacha20poly1305_encrypt_final(ptls_aead_context_t *_ctx, void *output)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+
+ chacha20poly1305_finalize(ctx, output);
+
+ return PTLS_CHACHA20POLY1305_TAG_SIZE;
+}
+
+static size_t chacha20poly1305_decrypt(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, uint64_t seq,
+ const void *aad, size_t aadlen)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+ uint8_t tag[PTLS_CHACHA20POLY1305_TAG_SIZE];
+ size_t ret;
+
+ if (inlen < sizeof(tag))
+ return SIZE_MAX;
+
+ chacha20poly1305_init(&ctx->super, seq, aad, aadlen);
+
+ ctx->poly1305_update(ctx, input, inlen - sizeof(tag));
+ ctx->textlen = inlen - sizeof(tag);
+
+ chacha20poly1305_finalize(ctx, tag);
+ if (ptls_mem_equal(tag, (const uint8_t *)input + inlen - sizeof(tag), sizeof(tag))) {
+ ptls_cipher_encrypt(ctx->chacha, output, input, inlen - sizeof(tag));
+ ret = inlen - sizeof(tag);
+ } else {
+ ret = SIZE_MAX;
+ }
+
+ ptls_clear_memory(tag, sizeof(tag));
+
+ return ret;
+}
+
+static void chacha20poly1305_get_iv(ptls_aead_context_t *_ctx, void *iv)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+
+ memcpy(iv, ctx->static_iv, sizeof(ctx->static_iv));
+}
+
+static void chacha20poly1305_set_iv(ptls_aead_context_t *_ctx, const void *iv)
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+
+ memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv));
+ }
+
+static int chacha20poly1305_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv,
+ ptls_cipher_algorithm_t *chacha,
+ void (*poly1305_init)(struct chacha20poly1305_context_t *, const void *),
+ void (*poly1305_update)(struct chacha20poly1305_context_t *, const void *, size_t),
+ void (*poly1305_finish)(struct chacha20poly1305_context_t *, void *))
+{
+ struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
+
+ ctx->super.dispose_crypto = chacha20poly1305_dispose_crypto;
+ ctx->super.do_get_iv = chacha20poly1305_get_iv;
+ ctx->super.do_set_iv = chacha20poly1305_set_iv;
+ if (is_enc) {
+ ctx->super.do_encrypt_init = chacha20poly1305_init;
+ 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;
+ }
+
+ if ((ctx->chacha = ptls_cipher_new(chacha, is_enc, key)) == NULL)
+ return PTLS_ERROR_LIBRARY;
+
+ memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv));
+ ctx->poly1305_init = poly1305_init;
+ ctx->poly1305_update = poly1305_update;
+ ctx->poly1305_finish = poly1305_finish;
+
+ return 0;
+}
diff --git a/lib/cifra/chacha20.c b/lib/cifra/chacha20.c
index 95a9e56..d56a8ca 100644
--- a/lib/cifra/chacha20.c
+++ b/lib/cifra/chacha20.c
@@ -27,6 +27,7 @@
#include "sha2.h"
#include "picotls.h"
#include "picotls/minicrypto.h"
+#include "../chacha20poly1305.h"
struct chacha20_context_t {
ptls_cipher_context_t super;
@@ -64,161 +65,33 @@
return 0;
}
-struct chacha20poly1305_context_t {
- ptls_aead_context_t super;
- uint8_t key[PTLS_CHACHA20_KEY_SIZE];
- uint8_t static_iv[PTLS_CHACHA20POLY1305_IV_SIZE];
- cf_chacha20_ctx chacha;
+struct cifra_chacha20poly1305_context_t {
+ struct chacha20poly1305_context_t super;
cf_poly1305 poly;
- size_t aadlen;
- size_t textlen;
};
-static void chacha20poly1305_dispose_crypto(ptls_aead_context_t *_ctx)
+static void cifra_poly1305_init(struct chacha20poly1305_context_t *_ctx, const void *rs)
{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- /* clear all memory except super */
- ptls_clear_memory(&ctx->key, sizeof(*ctx) - offsetof(struct chacha20poly1305_context_t, key));
+ struct cifra_chacha20poly1305_context_t *ctx = (struct cifra_chacha20poly1305_context_t *)_ctx;
+ cf_poly1305_init(&ctx->poly, rs, (const uint8_t *)rs + 16);
}
-static const uint8_t zeros64[64] = {0};
-
-static void chacha20poly1305_encrypt_pad(cf_poly1305 *poly, size_t n)
+static void cifra_poly1305_update(struct chacha20poly1305_context_t *_ctx, const void *input, size_t len)
{
- if (n % 16 != 0)
- cf_poly1305_update(poly, zeros64, 16 - (n % 16));
+ struct cifra_chacha20poly1305_context_t *ctx = (struct cifra_chacha20poly1305_context_t *)_ctx;
+ cf_poly1305_update(&ctx->poly, input, len);
}
-static void chacha20poly1305_finalize(struct chacha20poly1305_context_t *ctx, uint8_t *tag)
+static void cifra_poly1305_finish(struct chacha20poly1305_context_t *_ctx, void *tag)
{
- uint8_t lenbuf[16];
-
- chacha20poly1305_encrypt_pad(&ctx->poly, ctx->textlen);
-
- write64_le(ctx->aadlen, lenbuf);
- write64_le(ctx->textlen, lenbuf + 8);
- cf_poly1305_update(&ctx->poly, lenbuf, sizeof(lenbuf));
-
+ struct cifra_chacha20poly1305_context_t *ctx = (struct cifra_chacha20poly1305_context_t *)_ctx;
cf_poly1305_finish(&ctx->poly, tag);
}
-static void chacha20poly1305_init(ptls_aead_context_t *_ctx, uint64_t seq, const void *aad, size_t aadlen)
+static int cifra_chacha20poly1305_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key, const void *iv)
{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
- uint8_t tmpbuf[64];
-
- /* init chacha */
- memset(tmpbuf, 0, 16 - PTLS_CHACHA20POLY1305_IV_SIZE);
- ptls_aead__build_iv(ctx->super.algo, tmpbuf + 16 - PTLS_CHACHA20POLY1305_IV_SIZE, ctx->static_iv, seq);
- cf_chacha20_init_custom(&ctx->chacha, ctx->key, sizeof(ctx->key), tmpbuf, 4);
-
- /* init poly1305 (by using first 16 bytes of the key stream of the first block) */
- cf_chacha20_cipher(&ctx->chacha, zeros64, tmpbuf, 64);
- cf_poly1305_init(&ctx->poly, tmpbuf, tmpbuf + 16);
-
- ptls_clear_memory(tmpbuf, sizeof(tmpbuf));
-
- /* aad */
- if (aadlen != 0) {
- cf_poly1305_update(&ctx->poly, aad, aadlen);
- chacha20poly1305_encrypt_pad(&ctx->poly, aadlen);
- }
-
- ctx->aadlen = aadlen;
- ctx->textlen = 0;
-}
-
-static size_t chacha20poly1305_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- cf_chacha20_cipher(&ctx->chacha, input, output, inlen);
- cf_poly1305_update(&ctx->poly, output, inlen);
- ctx->textlen += inlen;
-
- return inlen;
-}
-
-static size_t chacha20poly1305_encrypt_final(ptls_aead_context_t *_ctx, void *output)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- chacha20poly1305_finalize(ctx, output);
-
- ptls_clear_memory(&ctx->chacha, sizeof(ctx->chacha));
- return PTLS_CHACHA20POLY1305_TAG_SIZE;
-}
-
-static size_t chacha20poly1305_decrypt(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, uint64_t seq,
- const void *aad, size_t aadlen)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
- uint8_t tag[PTLS_CHACHA20POLY1305_TAG_SIZE];
- size_t ret;
-
- if (inlen < sizeof(tag))
- return SIZE_MAX;
-
- chacha20poly1305_init(&ctx->super, seq, aad, aadlen);
-
- cf_poly1305_update(&ctx->poly, input, inlen - sizeof(tag));
- ctx->textlen = inlen - sizeof(tag);
-
- chacha20poly1305_finalize(ctx, tag);
- if (mem_eq(tag, (const uint8_t *)input + inlen - sizeof(tag), sizeof(tag))) {
- cf_chacha20_cipher(&ctx->chacha, input, output, inlen - sizeof(tag));
- ret = inlen - sizeof(tag);
- } else {
- ret = SIZE_MAX;
- }
-
- ptls_clear_memory(tag, sizeof(tag));
- ptls_clear_memory(&ctx->poly, sizeof(ctx->poly));
-
- return ret;
-}
-
-static void chacha20poly1305_get_iv(ptls_aead_context_t *_ctx, void *iv)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- memcpy(iv, ctx->static_iv, sizeof(ctx->static_iv));
-}
-
-static void chacha20poly1305_set_iv(ptls_aead_context_t *_ctx, const void *iv)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv));
-}
-
-static int aead_chacha20poly1305_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv)
-{
- struct chacha20poly1305_context_t *ctx = (struct chacha20poly1305_context_t *)_ctx;
-
- ctx->super.dispose_crypto = chacha20poly1305_dispose_crypto;
- ctx->super.do_get_iv = chacha20poly1305_get_iv;
- ctx->super.do_set_iv = chacha20poly1305_set_iv;
- if (is_enc) {
- ctx->super.do_encrypt_init = chacha20poly1305_init;
- 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;
- }
-
- memcpy(ctx->key, key, sizeof(ctx->key));
- memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv));
- return 0;
+ return chacha20poly1305_setup_crypto(ctx, is_enc, key, iv, &ptls_minicrypto_chacha20, cifra_poly1305_init,
+ cifra_poly1305_update, cifra_poly1305_finish);
}
ptls_cipher_algorithm_t ptls_minicrypto_chacha20 = {
@@ -236,8 +109,8 @@
{PTLS_TLS12_CHACHAPOLY_FIXED_IV_SIZE, PTLS_TLS12_CHACHAPOLY_RECORD_IV_SIZE},
0,
0,
- sizeof(struct chacha20poly1305_context_t),
- aead_chacha20poly1305_setup_crypto};
+ sizeof(struct cifra_chacha20poly1305_context_t),
+ cifra_chacha20poly1305_setup_crypto};
ptls_cipher_suite_t ptls_minicrypto_chacha20poly1305sha256 = {.id = PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256,
.name = PTLS_CIPHER_SUITE_NAME_CHACHA20_POLY1305_SHA256,
.aead = &ptls_minicrypto_chacha20poly1305,
diff --git a/lib/openssl.c b/lib/openssl.c
index b710e88..0cd3976 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -32,6 +32,11 @@
#define OPENSSL_API_COMPAT 0x00908000L
#include <openssl/bn.h>
#include <openssl/crypto.h>
+#ifdef OPENSSL_IS_BORINGSSL
+#include <openssl/curve25519.h>
+#include <openssl/chacha.h>
+#include <openssl/poly1305.h>
+#endif
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/err.h>
@@ -44,6 +49,9 @@
#include <openssl/x509_vfy.h>
#include "picotls.h"
#include "picotls/openssl.h"
+#ifdef OPENSSL_IS_BORINGSSL
+#include "./chacha20poly1305.h"
+#endif
#ifdef _WINDOWS
#ifndef _CRT_SECURE_NO_WARNINGS
@@ -513,6 +521,25 @@
goto Exit;
}
+#ifdef OPENSSL_IS_BORINGSSL
+ if (ctx->super.algo->id == PTLS_GROUP_X25519) {
+ secret->len = peerkey.len;
+ if ((secret->base = malloc(secret->len)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
+ uint8_t sk_raw[32];
+ size_t sk_raw_len = sizeof(sk_raw);
+ if (EVP_PKEY_get_raw_private_key(ctx->privkey, sk_raw, &sk_raw_len) != 1) {
+ ret = PTLS_ERROR_LIBRARY;
+ goto Exit;
+ }
+ X25519(secret->base, sk_raw, peerkey.base);
+ ret = 0;
+ goto Exit;
+ }
+#endif
+
if ((evppeer = EVP_PKEY_new()) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
goto Exit;
@@ -975,6 +1002,100 @@
}
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
+#ifdef OPENSSL_IS_BORINGSSL
+
+struct boringssl_chacha20_context_t {
+ ptls_cipher_context_t super;
+ uint8_t key[PTLS_CHACHA20_KEY_SIZE];
+ uint8_t iv[12];
+ struct {
+ uint32_t ctr;
+ uint8_t bytes[64];
+ size_t len;
+ } keystream;
+};
+
+static void boringssl_chacha20_dispose(ptls_cipher_context_t *_ctx)
+{
+ struct boringssl_chacha20_context_t *ctx = (struct boringssl_chacha20_context_t *)_ctx;
+
+ ptls_clear_memory(ctx->key, sizeof(ctx->key));
+ ptls_clear_memory(ctx->iv, sizeof(ctx->iv));
+ ptls_clear_memory(ctx->keystream.bytes, sizeof(ctx->keystream.bytes));
+}
+
+static void boringssl_chacha20_init(ptls_cipher_context_t *_ctx, const void *_iv)
+{
+ struct boringssl_chacha20_context_t *ctx = (struct boringssl_chacha20_context_t *)_ctx;
+ const uint8_t *iv = _iv;
+
+ memcpy(ctx->iv, iv + 4, sizeof(ctx->iv));
+ ctx->keystream.ctr = iv[0] | ((uint32_t)iv[1] << 8) | ((uint32_t)iv[2] << 16) | ((uint32_t)iv[3] << 24);
+ ctx->keystream.len = 0;
+}
+
+static inline void boringssl_chacha20_transform_buffered(struct boringssl_chacha20_context_t *ctx, uint8_t **output,
+ const uint8_t **input, size_t *len)
+{
+ size_t apply_len = *len < ctx->keystream.len ? *len : ctx->keystream.len;
+ const uint8_t *ks = ctx->keystream.bytes + sizeof(ctx->keystream.bytes) - ctx->keystream.len;
+ ctx->keystream.len -= apply_len;
+
+ *len -= apply_len;
+ for (size_t i = 0; i < apply_len; ++i)
+ *(*output)++ = *(*input)++ ^ *ks++;
+}
+
+static void boringssl_chacha20_transform(ptls_cipher_context_t *_ctx, void *_output, const void *_input, size_t len)
+{
+ struct boringssl_chacha20_context_t *ctx = (struct boringssl_chacha20_context_t *)_ctx;
+ uint8_t *output = _output;
+ const uint8_t *input = _input;
+
+ if (len == 0)
+ return;
+
+ if (ctx->keystream.len != 0) {
+ boringssl_chacha20_transform_buffered(ctx, &output, &input, &len);
+ if (len == 0)
+ return;
+ }
+
+ assert(ctx->keystream.len == 0);
+
+ if (len >= sizeof(ctx->keystream.bytes)) {
+ size_t blocks = len / CHACHA20POLY1305_BLOCKSIZE;
+ CRYPTO_chacha_20(output, input, blocks * CHACHA20POLY1305_BLOCKSIZE, ctx->key, ctx->iv, ctx->keystream.ctr);
+ ctx->keystream.ctr += blocks;
+ output += blocks * CHACHA20POLY1305_BLOCKSIZE;
+ input += blocks * CHACHA20POLY1305_BLOCKSIZE;
+ len -= blocks * CHACHA20POLY1305_BLOCKSIZE;
+ if (len == 0)
+ return;
+ }
+
+ memset(ctx->keystream.bytes, 0, CHACHA20POLY1305_BLOCKSIZE);
+ CRYPTO_chacha_20(ctx->keystream.bytes, ctx->keystream.bytes, CHACHA20POLY1305_BLOCKSIZE, ctx->key, ctx->iv,
+ ctx->keystream.ctr++);
+ ctx->keystream.len = sizeof(ctx->keystream.bytes);
+
+ boringssl_chacha20_transform_buffered(ctx, &output, &input, &len);
+ assert(len == 0);
+}
+
+static int boringssl_chacha20_setup_crypto(ptls_cipher_context_t *_ctx, int is_enc, const void *key)
+{
+ struct boringssl_chacha20_context_t *ctx = (struct boringssl_chacha20_context_t *)_ctx;
+
+ ctx->super.do_dispose = boringssl_chacha20_dispose;
+ ctx->super.do_init = boringssl_chacha20_init;
+ ctx->super.do_transform = boringssl_chacha20_transform;
+ memcpy(ctx->key, key, sizeof(ctx->key));
+
+ return 0;
+}
+
+#else
static int chacha20_setup_crypto(ptls_cipher_context_t *ctx, int is_enc, const void *key)
{
@@ -982,6 +1103,7 @@
}
#endif
+#endif
#if PTLS_OPENSSL_HAVE_BF
@@ -1160,10 +1282,45 @@
}
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
+#ifdef OPENSSL_IS_BORINGSSL
+
+struct boringssl_chacha20poly1305_context_t {
+ struct chacha20poly1305_context_t super;
+ poly1305_state poly1305;
+};
+
+static void boringssl_poly1305_init(struct chacha20poly1305_context_t *_ctx, const void *key)
+{
+ struct boringssl_chacha20poly1305_context_t *ctx = (struct boringssl_chacha20poly1305_context_t *)_ctx;
+ CRYPTO_poly1305_init(&ctx->poly1305, key);
+}
+
+static void boringssl_poly1305_update(struct chacha20poly1305_context_t *_ctx, const void *input, size_t len)
+{
+ struct boringssl_chacha20poly1305_context_t *ctx = (struct boringssl_chacha20poly1305_context_t *)_ctx;
+ CRYPTO_poly1305_update(&ctx->poly1305, input, len);
+}
+
+static void boringssl_poly1305_finish(struct chacha20poly1305_context_t *_ctx, void *tag)
+{
+ struct boringssl_chacha20poly1305_context_t *ctx = (struct boringssl_chacha20poly1305_context_t *)_ctx;
+ CRYPTO_poly1305_finish(&ctx->poly1305, tag);
+}
+
+static int boringssl_chacha20poly1305_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key, const void *iv)
+{
+ return chacha20poly1305_setup_crypto(ctx, is_enc, key, iv, &ptls_openssl_chacha20, boringssl_poly1305_init,
+ boringssl_poly1305_update, boringssl_poly1305_finish);
+}
+
+#else
+
static int aead_chacha20poly1305_setup_crypto(ptls_aead_context_t *ctx, int is_enc, const void *key, const void *iv)
{
return aead_setup_crypto(ctx, is_enc, key, iv, EVP_chacha20_poly1305());
}
+
+#endif
#endif
#define _sha256_final(ctx, md) SHA256_Final((md), (ctx))
@@ -1388,7 +1545,7 @@
if (ptls_server_name_is_ipaddr(server_name)) {
X509_VERIFY_PARAM_set1_ip_asc(params, server_name);
} else {
- X509_VERIFY_PARAM_set1_host(params, server_name, 0);
+ X509_VERIFY_PARAM_set1_host(params, server_name, strlen(server_name));
X509_VERIFY_PARAM_set_hostflags(params, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
}
}
@@ -1558,7 +1715,7 @@
*verifier = verify_sign;
ret = 0;
Exit:
- free(expected_pubkey.base);
+ OPENSSL_free(expected_pubkey.base);
return ret;
}
@@ -1957,21 +2114,38 @@
.hash = &ptls_openssl_sha384};
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
ptls_cipher_algorithm_t ptls_openssl_chacha20 = {
- "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,
- PTLS_CHACHA20POLY1305_IV_SIZE,
- PTLS_CHACHA20POLY1305_TAG_SIZE,
- {PTLS_TLS12_CHACHAPOLY_FIXED_IV_SIZE, PTLS_TLS12_CHACHAPOLY_RECORD_IV_SIZE},
- 0,
- 0,
- sizeof(struct aead_crypto_context_t),
- aead_chacha20poly1305_setup_crypto};
+ .name = "CHACHA20",
+ .key_size = PTLS_CHACHA20_KEY_SIZE,
+ .block_size = 1,
+ .iv_size = PTLS_CHACHA20_IV_SIZE,
+#ifdef OPENSSL_IS_BORINGSSL
+ .context_size = sizeof(struct boringssl_chacha20_context_t),
+ .setup_crypto = boringssl_chacha20_setup_crypto,
+#else
+ .context_size = sizeof(struct cipher_context_t),
+ .setup_crypto = chacha20_setup_crypto,
+#endif
+};
+ptls_aead_algorithm_t ptls_openssl_chacha20poly1305 = {
+ .name = "CHACHA20-POLY1305",
+ .confidentiality_limit = PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT,
+ .integrity_limit = PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT,
+ .ctr_cipher = &ptls_openssl_chacha20,
+ .ecb_cipher = NULL,
+ .key_size = PTLS_CHACHA20_KEY_SIZE,
+ .iv_size = PTLS_CHACHA20POLY1305_IV_SIZE,
+ .tag_size = PTLS_CHACHA20POLY1305_TAG_SIZE,
+ .tls12 = {.fixed_iv_size = PTLS_TLS12_CHACHAPOLY_FIXED_IV_SIZE, .record_iv_size = PTLS_TLS12_CHACHAPOLY_RECORD_IV_SIZE},
+ .non_temporal = 0,
+ .align_bits = 0,
+#ifdef OPENSSL_IS_BORINGSSL
+ .context_size = sizeof(struct boringssl_chacha20poly1305_context_t),
+ .setup_crypto = boringssl_chacha20poly1305_setup_crypto,
+#else
+ .context_size = sizeof(struct aead_crypto_context_t),
+ .setup_crypto = aead_chacha20poly1305_setup_crypto,
+#endif
+};
ptls_cipher_suite_t ptls_openssl_chacha20poly1305sha256 = {.id = PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256,
.name = PTLS_CIPHER_SUITE_NAME_CHACHA20_POLY1305_SHA256,
.aead = &ptls_openssl_chacha20poly1305,
diff --git a/picotls.xcodeproj/project.pbxproj b/picotls.xcodeproj/project.pbxproj
index 9a917b3..6882e19 100644
--- a/picotls.xcodeproj/project.pbxproj
+++ b/picotls.xcodeproj/project.pbxproj
@@ -8,6 +8,8 @@
/* Begin PBXBuildFile section */
081F00CA2918823200534A86 /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 081F00C92918823200534A86 /* hpke.c */; };
+ 08A835E22995E04100D872CE /* chacha20poly1305.h in Headers */ = {isa = PBXBuildFile; fileRef = 08A835E12995E04100D872CE /* chacha20poly1305.h */; };
+ 08A835E32995E04100D872CE /* chacha20poly1305.h in Headers */ = {isa = PBXBuildFile; fileRef = 08A835E12995E04100D872CE /* chacha20poly1305.h */; };
08F0FDF62910F67A00EE657D /* hpke.c in Sources */ = {isa = PBXBuildFile; fileRef = 08F0FDF52910F67A00EE657D /* hpke.c */; };
105900431DC8D57000FB4085 /* picotls.c in Sources */ = {isa = PBXBuildFile; fileRef = 106530E91D9B7C13005B2C60 /* picotls.c */; };
105900441DC8D57000FB4085 /* picotest.c in Sources */ = {isa = PBXBuildFile; fileRef = 106530E31D9B4021005B2C60 /* picotest.c */; };
@@ -203,6 +205,8 @@
081F00CC291A358800534A86 /* asn1.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = asn1.h; sourceTree = "<group>"; };
081F00CD291A358800534A86 /* pembase64.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pembase64.h; sourceTree = "<group>"; };
081F00CE291A358800534A86 /* ptlsbcrypt.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ptlsbcrypt.h; sourceTree = "<group>"; };
+ 08A835E12995E04100D872CE /* chacha20poly1305.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = chacha20poly1305.h; sourceTree = "<group>"; };
+ 08A835EB2996971300D872CE /* boringssl-adjust.cmake */ = {isa = PBXFileReference; lastKnownFileType = text; path = "boringssl-adjust.cmake"; sourceTree = "<group>"; };
08B3298229419DFC009D6766 /* ech-live.t */ = {isa = PBXFileReference; lastKnownFileType = text; path = "ech-live.t"; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.perl; };
08F0FDF52910F67A00EE657D /* hpke.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = hpke.c; sourceTree = "<group>"; };
105900241DC8D37500FB4085 /* aes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = aes.c; path = src/aes.c; sourceTree = "<group>"; };
@@ -434,6 +438,7 @@
E99B75DE1F5CDDB500CF503E /* asn1.c */,
E9E4B12A2180530400514B47 /* certificate_compression.c */,
E9F20BDF22E34B210018D260 /* cifra */,
+ 08A835E12995E04100D872CE /* chacha20poly1305.h */,
1059003F1DC8D53200FB4085 /* cifra.c */,
E97577022212405D00D1EF74 /* ffx.c */,
E9B43DBF24619D1700824E51 /* fusion.c */,
@@ -520,6 +525,7 @@
E95EBCC9227E9FF30022C32D /* cmake */ = {
isa = PBXGroup;
children = (
+ 08A835EB2996971300D872CE /* boringssl-adjust.cmake */,
E95EBCCA227EA0180022C32D /* dtrace-utils.cmake */,
);
path = cmake;
@@ -560,6 +566,7 @@
buildActionMask = 2147483647;
files = (
105900A21DC8E20D00FB4085 /* openssl.h in Headers */,
+ 08A835E32995E04100D872CE /* chacha20poly1305.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -608,6 +615,7 @@
10EACB0E1DCEAF0F00CA0341 /* chash.h in Headers */,
10EACB0F1DCEAF0F00CA0341 /* sha2.h in Headers */,
E9BC76DE1EF3CCD100EB7A09 /* poly1305.h in Headers */,
+ 08A835E22995E04100D872CE /* chacha20poly1305.h in Headers */,
10EACB101DCEAF0F00CA0341 /* aes.h in Headers */,
10EACB111DCEAF0F00CA0341 /* minicrypto.h in Headers */,
10EACB121DCEAF0F00CA0341 /* gf128.h in Headers */,
diff --git a/t/picotls.c b/t/picotls.c
index 14fa849..db7ee76 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -210,6 +210,53 @@
ptls_aead_free(c);
}
+static void test_ciphersuite_stream(ptls_cipher_suite_t *cs1, ptls_cipher_suite_t *cs2)
+{
+ const char *traffic_secret = "012345678901234567890123456789012345678901234567",
+ *text[] = {
+ "CHAPTER I.\n",
+ "Down the Rabbit-Hole\n",
+ "Alice was beginning to get very tired of sitting by her sister on the bank, and of having nothing to do: once "
+ "or twice she had peeped into the book her sister was reading, but it had no pictures or conversations in it, "
+ "“and what is the use of a book,” thought Alice “without pictures or conversations?”\n",
+ "So she was considering in her own mind (as well as she could, for the hot day made her feel very sleepy and "
+ "stupid), whether the pleasure of making a daisy-chain would be worth the trouble of getting up and picking the "
+ "daisies, when suddenly a White Rabbit with pink eyes ran close by her.\n",
+ NULL,
+ };
+ ptls_aead_context_t *c;
+ char enc[1024], dec[1024];
+ size_t enclen, declen;
+
+ /* encrypt */
+ c = ptls_aead_new(cs1->aead, cs1->hash, 1, traffic_secret, NULL);
+ assert(c != NULL);
+ ptls_aead_encrypt_init(c, 0, NULL, 0);
+ enclen = 0;
+ for (size_t i = 0; text[i] != NULL; ++i)
+ enclen += ptls_aead_encrypt_update(c, enc + enclen, text[i], strlen(text[i]));
+ enclen += ptls_aead_encrypt_final(c, enc + enclen);
+ ptls_aead_free(c);
+
+ /* decrypt */
+ c = ptls_aead_new(cs2->aead, cs2->hash, 0, traffic_secret, NULL);
+ declen = ptls_aead_decrypt(c, dec, enc, enclen, 0, NULL, 0);
+ ok(declen != SIZE_MAX);
+ ok(declen == enclen - cs1->aead->tag_size);
+ ptls_aead_free(c);
+
+ /* check text */
+ for (size_t i = 0, decoff = 0;; ++i) {
+ if (text[i] == NULL) {
+ ok(decoff == declen);
+ break;
+ }
+ ok(decoff + strlen(text[i]) <= declen);
+ ok(memcmp(dec + decoff, text[i], strlen(text[i])) == 0);
+ decoff += strlen(text[i]);
+ }
+}
+
static void test_aad_ciphersuite(ptls_cipher_suite_t *cs1, ptls_cipher_suite_t *cs2)
{
const char *traffic_secret = "012345678901234567890123456789012345678901234567", *src = "hello world", *aad = "my true aad";
@@ -372,6 +419,7 @@
*cs_peer = find_cipher(ctx_peer, PTLS_CIPHER_SUITE_AES_128_GCM_SHA256);
test_ciphersuite(cs, cs_peer);
+ test_ciphersuite_stream(cs, cs_peer);
test_aad_ciphersuite(cs, cs_peer);
test_aad96_ciphersuite(cs, cs_peer);
}
@@ -383,6 +431,7 @@
if (cs != NULL && cs_peer != NULL) {
test_ciphersuite(cs, cs_peer);
+ test_ciphersuite_stream(cs, cs_peer);
test_aad_ciphersuite(cs, cs_peer);
test_aad96_ciphersuite(cs, cs_peer);
}
@@ -395,6 +444,7 @@
if (cs != NULL && cs_peer != NULL) {
test_ciphersuite(cs, cs_peer);
+ test_ciphersuite_stream(cs, cs_peer);
test_aad_ciphersuite(cs, cs_peer);
test_aad96_ciphersuite(cs, cs_peer);
}