Merge branch 'master' into kazuho/session-ticket-context
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 80b5401..1293876 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,8 +19,8 @@
command: make -f misc/docker-ci.mk CMAKE_ARGS='-DOPENSSL_ROOT_DIR=-DOPENSSL_ROOT_DIR=/opt/openssl-1.1.0 -DWITH_FUSION=OFF' CONTAINER_NAME='h2oserver/h2o-ci:ubuntu1604'
- name: "Linux / OpenSSL 1.1.1"
command: make -f misc/docker-ci.mk CMAKE_ARGS='-DWITH_AEGIS=1 -DAEGIS_INCLUDE_DIR=/usr/local/include'
- - name: "Linux / OpenSSL 3.0"
- command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204
+ - name: "Linux / OpenSSL 3.0 + mbedtls"
+ command: make -f misc/docker-ci.mk CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2204 CMAKE_ARGS='-DWITH_MBEDTLS=1'
- 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"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42692a5..dc146a8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,18 +10,13 @@
ENDIF ()
FIND_PACKAGE(PkgConfig REQUIRED)
-INCLUDE(cmake/dtrace-utils.cmake)
INCLUDE(cmake/boringssl-adjust.cmake)
+INCLUDE(cmake/dtrace-utils.cmake)
+INCLUDE(cmake/fusion.cmake)
+SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
CHECK_DTRACE(${PROJECT_SOURCE_DIR}/picotls-probes.d)
-IF ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND
- (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") OR
- (CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") OR
- (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64"))
- SET(WITH_FUSION_DEFAULT "ON")
-ELSE ()
- SET(WITH_FUSION_DEFAULT "OFF")
-ENDIF ()
+CHECK_FUSION_PREREQUISITES()
OPTION(WITH_DTRACE "use USDT (userspace Dtrace probes)" ${HAVE_DTRACE})
OPTION(WITH_FUSION "build 'fusion' AES-GCM engine" ${WITH_FUSION_DEFAULT})
@@ -32,6 +27,7 @@
MESSAGE(STATUS "Enabling 'fusion' AES-GCM engine")
ENDIF ()
OPTION(WITH_AEGIS "enable AEGIS (requires libaegis)" ${WITH_AEGIS})
+OPTION(WITH_MBEDTLS "enable MBEDTLS" ${WITH_MBEDTLS})
SET(CMAKE_C_FLAGS "-std=c99 -Wall -O2 -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}")
INCLUDE_DIRECTORIES(
@@ -196,9 +192,30 @@
ENDIF ()
SET(TEST_EXES ${TEST_EXES} test-fusion.t)
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPTLS_HAVE_FUSION=1")
LIST(APPEND PTLSBENCH_LIBS picotls-fusion)
ENDIF ()
+IF (WITH_MBEDTLS)
+ FIND_PACKAGE(MbedTLS)
+ IF (NOT MbedTLS_FOUND)
+ MESSAGE(FATAL_ERROR "-DWITH_MBEDTLS set but mbedtls not found")
+ ENDIF ()
+ message(STATUS "mbedtls/include: ${MBEDTLS_INCLUDE_DIRS}")
+ message(STATUS "mbedtls libraries: ${MBEDTLS_LIBRARIES}")
+ INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIRS})
+ ADD_LIBRARY(picotls-mbedtls lib/mbedtls.c)
+ ADD_EXECUTABLE(test-mbedtls.t
+ deps/picotest/picotest.c
+ ${CORE_TEST_FILES}
+ t/mbedtls.c)
+ TARGET_LINK_LIBRARIES(test-mbedtls.t
+ picotls-minicrypto picotls-mbedtls
+ ${MBEDTLS_LIBRARIES})
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPTLS_HAVE_MBEDTLS=1")
+ LIST(APPEND PTLSBENCH_LIBS picotls-mbedtls ${MBEDTLS_LIBRARIES})
+ENDIF ()
+
ADD_EXECUTABLE(ptlsbench t/ptlsbench.c)
SET_TARGET_PROPERTIES(ptlsbench PROPERTIES COMPILE_FLAGS "-DPTLS_MEMORY_DEBUG=1")
TARGET_LINK_LIBRARIES(ptlsbench ${PTLSBENCH_LIBS})
diff --git a/cmake/FindMbedTLS.cmake b/cmake/FindMbedTLS.cmake
new file mode 100644
index 0000000..048a1e9
--- /dev/null
+++ b/cmake/FindMbedTLS.cmake
@@ -0,0 +1,48 @@
+# Try to find MbedTLS; recognized hints are:
+# * MBEDTLS_ROOT_DIR
+# * MBEDTLS_LIBDIR
+# Upon return,
+# * MBEDTLS_INCLUDE_DIRS
+# * MBEDTLS_LIBRARIES
+# will be set.
+# Users may supply MBEDTLS_INCLUDE_DIRS or MBEDTLS_LIBRARIES directly.
+
+INCLUDE(FindPackageHandleStandardArgs)
+
+# setup default vars for the hints
+IF (NOT DEFINED MBEDTLS_ROOT_DIR)
+ SET(MBEDTLS_ROOT_DIR "/usr/local" "/usr")
+ENDIF ()
+IF (NOT DEFINED MBEDTLS_LIBDIR)
+ SET(MBEDTLS_LIBDIR)
+ FOREACH (item IN LISTS MBEDTLS_ROOT_DIR)
+ LIST(APPEND MBEDTLS_LIBDIR "${item}/lib")
+ ENDFOREACH ()
+ENDIF ()
+
+# find include directory
+IF (NOT DEFINED MBEDTLS_INCLUDE_DIRS)
+ SET(HINTS)
+ FOREACH (item IN LISTS MBEDTLS_ROOT_DIR)
+ LIST(APPEND HINTS "${item}/include")
+ ENDFOREACH ()
+ FIND_PATH(MBEDTLS_INCLUDE_DIRS
+ NAMES mbedtls/build_info.h psa/crypto.h
+ HINTS $HINTS)
+ENDIF ()
+
+# find libraries
+FIND_LIBRARY(MBEDTLS_LIBRARY mbedtls HINTS $MBEDTLS_LIBDIR)
+FIND_LIBRARY(MBEDTLS_CRYPTO mbedcrypto HINTS $MBEDTLS_LIBDIR)
+FIND_LIBRARY(MBEDTLS_X509 mbedx509 HINTS $MBEDTLS_LIBDIR)
+
+# setup
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(MbedTLS REQUIRED_VARS
+ MBEDTLS_LIBRARY
+ MBEDTLS_CRYPTO
+ MBEDTLS_X509
+ MBEDTLS_INCLUDE_DIRS)
+IF (MbedTLS_FOUND)
+ SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDTLS_CRYPTO} ${MBEDTLS_X509})
+ MARK_AS_ADVANCED(MBEDTLS_LIBRARIES MBEDTLS_INCLUDE_DIRS)
+ENDIF ()
diff --git a/cmake/fusion.cmake b/cmake/fusion.cmake
new file mode 100644
index 0000000..2b7ef1c
--- /dev/null
+++ b/cmake/fusion.cmake
@@ -0,0 +1,30 @@
+INCLUDE(CheckCSourceCompiles)
+INCLUDE(CMakePushCheckState)
+
+FUNCTION (CHECK_FUSION_PREREQUISITES)
+ MESSAGE(STATUS "Detecting fusion support")
+
+ CMAKE_PUSH_CHECK_STATE()
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -mavx2 -maes -mpclmul -mvaes -mvpclmulqdq")
+ CHECK_C_SOURCE_COMPILES("
+ #include <emmintrin.h>
+ #include <immintrin.h>
+ int main(void) {
+ __m256i ord0, ord1, ord2, ord3 = _mm256_setzero_si256();
+ ord0 = _mm256_aesenc_epi128(ord1, ord2);
+ ord3 = _mm256_aesenclast_epi128(ord0, ord1);
+ ord1 = _mm256_clmulepi64_epi128(ord3, ord2, 0x00);
+ _mm_insert_epi64(_mm_setr_epi32(0, 1, 2, 3), 0, 0);
+ return 0;
+ }
+ " CC_HAS_AESNI256)
+ CMAKE_POP_CHECK_STATE()
+
+ IF (CC_HAS_AESNI256)
+ MESSAGE(STATUS "Can use fusion")
+ SET(WITH_FUSION_DEFAULT "ON" PARENT_SCOPE)
+ ELSE ()
+ MESSAGE(STATUS "Cannot use fusion")
+ SET(WITH_FUSION_DEFAULT "OFF" PARENT_SCOPE)
+ ENDIF ()
+ENDFUNCTION ()
diff --git a/include/picotls.h b/include/picotls.h
index 04b885a..8af9da1 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -130,8 +130,8 @@
#define PTLS_CIPHER_SUITE_NAME_AES_256_GCM_SHA384 "TLS_AES_256_GCM_SHA384"
#define PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256 0x1303
#define PTLS_CIPHER_SUITE_NAME_CHACHA20_POLY1305_SHA256 "TLS_CHACHA20_POLY1305_SHA256"
-#define PTLS_CIPHER_SUITE_AEGIS256_SHA384 0x1306
-#define PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA384 "TLS_AEGIS_256_SHA384"
+#define PTLS_CIPHER_SUITE_AEGIS256_SHA512 0x1306
+#define PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA512 "TLS_AEGIS_256_SHA512"
#define PTLS_CIPHER_SUITE_AEGIS128L_SHA256 0x1307
#define PTLS_CIPHER_SUITE_NAME_AEGIS128L_SHA256 "TLS_AEGIS_128L_SHA256"
@@ -338,11 +338,14 @@
*/
const struct st_ptls_key_exchange_algorithm_t *algo;
/**
- * the public key
+ * public key of this context
*/
ptls_iovec_t pubkey;
/**
- * If `release` is set, the callee frees resources allocated to the context and set *keyex to NULL
+ * This function can be used for deriving a shared secret or for destroying the context.
+ * When `secret` is non-NULL, this callback derives the shared secret using the public key of the context and the peer key being
+ * given, and sets the value in `secret`. The memory pointed to by `secret->base` must be freed by the caller by calling `free`.
+ * When `release` is set, the callee frees resources allocated to the context and set *keyex to NULL.
*/
int (*on_exchange)(struct st_ptls_key_exchange_context_t **keyex, int release, ptls_iovec_t *secret, ptls_iovec_t peerkey);
} ptls_key_exchange_context_t;
@@ -356,12 +359,14 @@
*/
uint16_t id;
/**
- * creates a context for asynchronous key exchange. The function is called when ClientHello is generated. The on_exchange
+ * Creates a context for asynchronous key exchange. The function is called when ClientHello is generated. The on_exchange
* callback of the created context is called when the client receives ServerHello.
*/
int (*create)(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx);
/**
- * implements synchronous key exchange. Called when receiving a ServerHello.
+ * Implements synchronous key exchange. Called when receiving a ServerHello.
+ * Given a public key provided by the peer (`peerkey`), this callback returns a empheral public key (`pubkey`) and a secret
+ * (`secret) `derived from the two public keys.
*/
int (*exchange)(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
ptls_iovec_t peerkey);
@@ -398,31 +403,81 @@
int (*setup_crypto)(ptls_cipher_context_t *ctx, int is_enc, const void *key);
} ptls_cipher_algorithm_t;
+/**
+ * This object specifies symmetric cipher to be calculated alongside the AEAD encryption.
+ * QUIC stacks can use this object to apply QUIC header protection and AEAD encryption in one shot.
+ */
typedef struct st_ptls_aead_supplementary_encryption_t {
+ /**
+ * Cipher context to be used.
+ */
ptls_cipher_context_t *ctx;
+ /**
+ * Input to the cipher.
+ * This field may point to the output of AEAD encryption, in which case the input will be read after AEAD encryption is
+ * complete.
+ */
const void *input;
+ /**
+ * Output.
+ */
uint8_t output[16];
} ptls_aead_supplementary_encryption_t;
/**
- * 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.
+ * AEAD context.
+ * AEAD implementations are allowed to stuff data at the end of the struct; see `ptls_aead_algorithm_t::setup_crypto`.
+ * 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 {
+ /**
+ * Points to the algorithm. This field is governed by picotls core; backends must not alter.
+ */
const struct st_ptls_aead_algorithm_t *algo;
- /* field above this line must not be altered by the crypto binding */
+ /**
+ * Mandatory callback that disposes of all the backend-specific data.
+ */
void (*dispose_crypto)(struct st_ptls_aead_context_t *ctx);
+ /**
+ * Mandatory callback that returns the static IV. The size of IV is available as `ptls_aead_algorithm_t::iv_size`.
+ */
void (*do_get_iv)(struct st_ptls_aead_context_t *ctx, void *iv);
+ /**
+ * Mandatory callback that sets the static IV. The size of IV is available as `ptls_aead_algorithm_t::iv_size`.
+ */
void (*do_set_iv)(struct st_ptls_aead_context_t *ctx, const void *iv);
+ /**
+ * Deprecated.
+ */
void (*do_encrypt_init)(struct st_ptls_aead_context_t *ctx, uint64_t seq, const void *aad, size_t aadlen);
+ /**
+ * Deprecated.
+ */
size_t (*do_encrypt_update)(struct st_ptls_aead_context_t *ctx, void *output, const void *input, size_t inlen);
+ /**
+ * Deprecated.
+ */
size_t (*do_encrypt_final)(struct st_ptls_aead_context_t *ctx, void *output);
+ /**
+ * Mandatory callback that does "one-shot" encryption of an AEAD block.
+ * When `supp` is set to non-NULL, the callback must also encrypt the supplementary block.
+ * Backends may set this field to `ptls_aead__do_encrypt` that calls `do_encrypt_v` and `ptls_cipher_*` functions for handling
+ * the supplimentary block.
+ */
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);
+ /**
+ * Variant of `do_encrypt` that gathers input from multiple blocks. Support for this callback is also mandatory.
+ * Legacy backends may set this field to `ptls_aead__do_encrypt_v` that calls `do_encrypt_init`, `do_encrypt_update`,
+ * `do_encrypt_final`.
+ */
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);
+ /**
+ * Mandatory callback for decrypting an AEAD block.
+ * If successful, returns the amount of cleartext bytes being written to output. Otherwise, returns SIZE_MAX.
+ */
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;
@@ -479,12 +534,16 @@
*/
uint8_t align_bits;
/**
- * size of memory allocated for ptls_aead_context_t. AEAD implementations can set this value to something greater than
- * sizeof(ptls_aead_context_t) and stuff additional data at the bottom of the struct.
+ * size of memory allocated for `ptls_aead_context_t`
*/
size_t context_size;
/**
- * callback that sets up the crypto
+ * Backend callback called to setup `ptls_aead_context_t`.
+ * Backends are allowed to stuff arbitrary data at the end of `ptls_aead_context_t`; actual size of the memory chunk being
+ * allocated is that specified by `ptls_aead_algorithm_t::context_size`. When the `setup_crypto` callback is called, all the
+ * fields outside of `ptls_aead_context_t` will be in undefined state; it is the responsibility of the callback to initialize
+ * them, as well as the callbacks of `ptls_aead_context_t` that the backend supports.
+ * A non-zero return value indicates failure, in which case the error will propagate as `ptls_aead_new` returning NULL.
*/
int (*setup_crypto)(ptls_aead_context_t *ctx, int is_enc, const void *key, const void *iv);
} ptls_aead_algorithm_t;
@@ -1770,6 +1829,10 @@
* the default get_time callback
*/
extern ptls_get_time_t ptls_get_time;
+/**
+ * default hash clone function that calls memcpy
+ */
+static void ptls_hash_clone_memcpy(void *dst, const void *src, size_t size);
#if defined(PICOTLS_USE_DTRACE) && PICOTLS_USE_DTRACE
/**
*
@@ -1926,7 +1989,14 @@
return ctx->do_decrypt(ctx, output, input, inlen, seq, aad, aadlen);
}
+inline void ptls_hash_clone_memcpy(void *dst, const void *src, size_t size)
+{
+ memcpy(dst, src, size);
+}
+
#define ptls_define_hash(name, ctx_type, init_func, update_func, final_func) \
+ ptls_define_hash6(name, ctx_type, init_func, update_func, final_func, ptls_hash_clone_memcpy)
+#define ptls_define_hash6(name, ctx_type, init_func, update_func, final_func, clone_func) \
\
struct name##_context_t { \
ptls_hash_context_t super; \
@@ -1969,7 +2039,8 @@
struct name##_context_t *dst, *src = (struct name##_context_t *)_src; \
if ((dst = malloc(sizeof(*dst))) == NULL) \
return NULL; \
- *dst = *src; \
+ dst->super = src->super; \
+ clone_func(&dst->ctx, &src->ctx, sizeof(dst->ctx)); \
return &dst->super; \
} \
\
diff --git a/include/picotls/mbedtls.h b/include/picotls/mbedtls.h
new file mode 100644
index 0000000..b649246
--- /dev/null
+++ b/include/picotls/mbedtls.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2023, Christian Huitema
+ *
+ * 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.
+ */
+#ifndef picotls_mbedtls_h
+#define picotls_mbedtls_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <psa/crypto.h>
+#include "picotls.h"
+
+/* before using any of these objects, psa_crypto_init() must be called */
+
+extern ptls_hash_algorithm_t ptls_mbedtls_sha256;
+extern ptls_hash_algorithm_t ptls_mbedtls_sha512;
+#if defined(MBEDTLS_SHA384_C)
+extern ptls_hash_algorithm_t ptls_mbedtls_sha384;
+#endif
+
+extern ptls_cipher_algorithm_t ptls_mbedtls_aes128ecb;
+extern ptls_cipher_algorithm_t ptls_mbedtls_aes256ecb;
+extern ptls_cipher_algorithm_t ptls_mbedtls_aes128ctr;
+extern ptls_cipher_algorithm_t ptls_mbedtls_aes256ctr;
+extern ptls_cipher_algorithm_t ptls_mbedtls_chacha20;
+
+extern ptls_aead_algorithm_t ptls_mbedtls_aes128gcm;
+extern ptls_aead_algorithm_t ptls_mbedtls_aes256gcm;
+extern ptls_aead_algorithm_t ptls_mbedtls_chacha20poly1305;
+
+extern ptls_cipher_suite_t ptls_mbedtls_aes128gcmsha256;
+#if defined(MBEDTLS_SHA384_C)
+extern ptls_cipher_suite_t ptls_mbedtls_aes256gcmsha384;
+#endif
+extern ptls_cipher_suite_t ptls_mbedtls_chacha20poly1305sha256;
+extern ptls_cipher_suite_t *ptls_mbedtls_cipher_suites[];
+
+extern ptls_key_exchange_algorithm_t ptls_mbedtls_secp256r1;
+extern ptls_key_exchange_algorithm_t ptls_mbedtls_x25519;
+extern ptls_key_exchange_algorithm_t *ptls_mbedtls_key_exchanges[];
+
+void ptls_mbedtls_random_bytes(void *buf, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* picotls_mbedtls_h */
diff --git a/include/picotls/minicrypto.h b/include/picotls/minicrypto.h
index ca3a31d..a6202d0 100644
--- a/include/picotls/minicrypto.h
+++ b/include/picotls/minicrypto.h
@@ -51,11 +51,11 @@
extern ptls_aead_algorithm_t ptls_minicrypto_aegis128l;
extern ptls_aead_algorithm_t ptls_minicrypto_aegis256;
#endif
-extern ptls_hash_algorithm_t ptls_minicrypto_sha256, ptls_minicrypto_sha384;
+extern ptls_hash_algorithm_t ptls_minicrypto_sha256, ptls_minicrypto_sha384, ptls_minicrypto_sha512;
extern ptls_cipher_suite_t ptls_minicrypto_aes128gcmsha256, ptls_minicrypto_aes256gcmsha384, ptls_minicrypto_chacha20poly1305sha256;
#ifdef PTLS_HAVE_AEGIS
extern ptls_cipher_suite_t ptls_minicrypto_aegis128lsha256;
-extern ptls_cipher_suite_t ptls_minicrypto_aegis256sha384;
+extern ptls_cipher_suite_t ptls_minicrypto_aegis256sha512;
#endif
extern ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[];
extern ptls_cipher_suite_t *ptls_minicrypto_cipher_suites_all[];
diff --git a/include/picotls/openssl.h b/include/picotls/openssl.h
index 987b9b1..de777c8 100644
--- a/include/picotls/openssl.h
+++ b/include/picotls/openssl.h
@@ -98,7 +98,7 @@
extern ptls_aead_algorithm_t ptls_openssl_aegis128l;
extern ptls_aead_algorithm_t ptls_openssl_aegis256;
extern ptls_cipher_suite_t ptls_openssl_aegis128lsha256;
-extern ptls_cipher_suite_t ptls_openssl_aegis256sha384;
+extern ptls_cipher_suite_t ptls_openssl_aegis256sha512;
#endif
extern ptls_cipher_suite_t ptls_openssl_tls12_ecdhe_rsa_aes128gcmsha256;
diff --git a/lib/cifra.c b/lib/cifra.c
index d51f2b7..5fe9feb 100644
--- a/lib/cifra.c
+++ b/lib/cifra.c
@@ -23,7 +23,7 @@
#include "picotls.h"
#include "picotls/minicrypto.h"
-ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = {// ciphers used with sha384 (must be first)
+ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = {// ciphers used with sha512 and sha384 (must be first)
&ptls_minicrypto_aes256gcmsha384,
// ciphers used with sha256
@@ -31,9 +31,9 @@
&ptls_minicrypto_chacha20poly1305sha256,
NULL};
-ptls_cipher_suite_t *ptls_minicrypto_cipher_suites_all[] = {// ciphers used with sha384 (must be first)
+ptls_cipher_suite_t *ptls_minicrypto_cipher_suites_all[] = {// ciphers used with sha512 and sha384 (must be first)
#ifdef PTLS_HAVE_AEGIS
- &ptls_minicrypto_aegis256sha384,
+ &ptls_minicrypto_aegis256sha512,
#endif
&ptls_minicrypto_aes256gcmsha384,
diff --git a/lib/cifra/aes256.c b/lib/cifra/aes256.c
index d4cefa9..e074dea 100644
--- a/lib/cifra/aes256.c
+++ b/lib/cifra/aes256.c
@@ -41,6 +41,11 @@
ptls_hash_algorithm_t ptls_minicrypto_sha384 = {"sha384", PTLS_SHA384_BLOCK_SIZE, PTLS_SHA384_DIGEST_SIZE, sha384_create,
PTLS_ZERO_DIGEST_SHA384};
+ptls_define_hash(sha512, cf_sha512_context, cf_sha512_init, cf_sha512_update, cf_sha512_digest_final);
+
+ptls_hash_algorithm_t ptls_minicrypto_sha512 = {"sha512", PTLS_SHA512_BLOCK_SIZE, PTLS_SHA512_DIGEST_SIZE, sha512_create,
+ PTLS_ZERO_DIGEST_SHA512};
+
ptls_cipher_algorithm_t ptls_minicrypto_aes256ecb = {
"AES256-ECB", PTLS_AES256_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 0 /* iv size */, sizeof(struct aesecb_context_t),
aes256ecb_setup_crypto};
diff --git a/lib/cifra/libaegis.c b/lib/cifra/libaegis.c
index 0b4af93..76fc9e4 100644
--- a/lib/cifra/libaegis.c
+++ b/lib/cifra/libaegis.c
@@ -20,11 +20,9 @@
* IN THE SOFTWARE.
*/
+#include "picotls/minicrypto.h"
#include "../libaegis.h"
-extern ptls_hash_algorithm_t ptls_minicrypto_sha256;
-extern ptls_hash_algorithm_t ptls_minicrypto_sha384;
-
ptls_aead_algorithm_t ptls_minicrypto_aegis128l = {"AEGIS-128L",
PTLS_AEGIS128L_CONFIDENTIALITY_LIMIT,
PTLS_AEGIS128L_INTEGRITY_LIMIT,
@@ -56,7 +54,7 @@
0,
sizeof(struct aegis256_context_t),
aegis256_setup_crypto};
-ptls_cipher_suite_t ptls_minicrypto_aegis256sha384 = {.id = PTLS_CIPHER_SUITE_AEGIS256_SHA384,
- .name = PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA384,
+ptls_cipher_suite_t ptls_minicrypto_aegis256sha512 = {.id = PTLS_CIPHER_SUITE_AEGIS256_SHA512,
+ .name = PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA512,
.aead = &ptls_minicrypto_aegis256,
- .hash = &ptls_minicrypto_sha384};
+ .hash = &ptls_minicrypto_sha512};
diff --git a/lib/cifra/x25519.c b/lib/cifra/x25519.c
index 58f464f..3697d4d 100644
--- a/lib/cifra/x25519.c
+++ b/lib/cifra/x25519.c
@@ -45,6 +45,13 @@
return PTLS_ERROR_NO_MEMORY;
cf_curve25519_mul(secret->base, clientpriv != NULL ? clientpriv : serverpriv, clientpriv != NULL ? serverpub : clientpub);
+
+ static const uint8_t zeros[X25519_KEY_SIZE] = {0};
+ if (ptls_mem_equal(secret->base, zeros, sizeof(zeros))) {
+ free(secret->base);
+ return PTLS_ERROR_INCOMPATIBLE_KEY;
+ }
+
secret->len = X25519_KEY_SIZE;
return 0;
}
@@ -111,8 +118,10 @@
Exit:
ptls_clear_memory(priv, sizeof(priv));
- if (pub != NULL && ret != 0)
+ if (pub != NULL && ret != 0) {
ptls_clear_memory(pub, X25519_KEY_SIZE);
+ free(pub);
+ }
return ret;
}
diff --git a/lib/mbedtls.c b/lib/mbedtls.c
new file mode 100644
index 0000000..86fa7b0
--- /dev/null
+++ b/lib/mbedtls.c
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2023, Christian Huitema
+ *
+ * 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.
+ */
+
+#ifdef _WINDOWS
+#include "wincompat.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <psa/crypto.h>
+#include <mbedtls/chacha20.h>
+#include <mbedtls/ecdh.h>
+#include "picotls.h"
+
+#define PSA_FUNC_FAILED(fn, ret) \
+ do { \
+ fprintf(stderr, "in %s at line %d, " PTLS_TO_STR(fn) " failed (%d)\n", __FUNCTION__, __LINE__, (int)ret); \
+ abort(); \
+ } while (0)
+
+#define CALL_WITH_CHECK(fn, ...) \
+ do { \
+ psa_status_t ret; \
+ if ((ret = fn(__VA_ARGS__)) != PSA_SUCCESS) \
+ PSA_FUNC_FAILED(fn, ret); \
+ } while (0)
+
+void ptls_mbedtls_random_bytes(void *buf, size_t len)
+{
+ CALL_WITH_CHECK(psa_generate_random, buf, len);
+}
+
+#define DEFINE_HASH(name, name_upcase, psa_alg) \
+ static void name##_do_init(psa_hash_operation_t *op) \
+ { \
+ *op = psa_hash_operation_init(); \
+ CALL_WITH_CHECK(psa_hash_setup, op, psa_alg); \
+ } \
+ static void name##_do_update(psa_hash_operation_t *op, const void *src, size_t len) \
+ { \
+ CALL_WITH_CHECK(psa_hash_update, op, src, len); \
+ } \
+ static void name##_do_final(psa_hash_operation_t *op, void *md) \
+ { \
+ size_t unused; \
+ CALL_WITH_CHECK(psa_hash_finish, op, md, PTLS_##name_upcase##_DIGEST_SIZE, &unused); \
+ } \
+ static void name##_do_clone(psa_hash_operation_t *dst, psa_hash_operation_t *src, size_t unused) \
+ { \
+ CALL_WITH_CHECK(psa_hash_clone, src, dst); \
+ } \
+ ptls_define_hash6(name, psa_hash_operation_t, name##_do_init, name##_do_update, name##_do_final, name##_do_clone); \
+ ptls_hash_algorithm_t ptls_mbedtls_##name = {PTLS_TO_STR(name), PTLS_##name_upcase##_BLOCK_SIZE, \
+ PTLS_##name_upcase##_DIGEST_SIZE, name##_create, PTLS_ZERO_DIGEST_##name_upcase};
+DEFINE_HASH(sha256, SHA256, PSA_ALG_SHA_256);
+DEFINE_HASH(sha512, SHA512, PSA_ALG_SHA_512);
+#if defined(MBEDTLS_SHA384_C)
+DEFINE_HASH(sha384, SHA384, PSA_ALG_SHA_384);
+#endif
+
+/**
+ * Generic implementation of a cipher using the PSA API
+ */
+struct st_ptls_mbedtls_cipher_context_t {
+ ptls_cipher_context_t super;
+ psa_algorithm_t alg;
+ unsigned is_enc : 1;
+ unsigned is_op_in_progress : 1;
+ mbedtls_svc_key_id_t key;
+ psa_cipher_operation_t op;
+};
+
+static void cipher_init(ptls_cipher_context_t *_ctx, const void *iv)
+{
+ struct st_ptls_mbedtls_cipher_context_t *ctx = (struct st_ptls_mbedtls_cipher_context_t *)_ctx;
+
+ if (ctx->is_op_in_progress) {
+ psa_cipher_abort(&ctx->op);
+ ctx->is_op_in_progress = 0;
+ }
+
+ ctx->op = psa_cipher_operation_init();
+ if (ctx->is_enc) {
+ CALL_WITH_CHECK(psa_cipher_encrypt_setup, &ctx->op, ctx->key, ctx->alg);
+ } else {
+ CALL_WITH_CHECK(psa_cipher_decrypt_setup, &ctx->op, ctx->key, ctx->alg);
+ }
+ ctx->is_op_in_progress = 1;
+ if (ctx->super.algo->iv_size > 0)
+ CALL_WITH_CHECK(psa_cipher_set_iv, &ctx->op, iv, ctx->super.algo->iv_size);
+}
+
+static void cipher_transform(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
+{
+ struct st_ptls_mbedtls_cipher_context_t *ctx = (struct st_ptls_mbedtls_cipher_context_t *)_ctx;
+ size_t unused = 0;
+
+ CALL_WITH_CHECK(psa_cipher_update, &ctx->op, input, len, output, len, &unused);
+}
+
+static void cipher_dispose(ptls_cipher_context_t *_ctx)
+{
+ struct st_ptls_mbedtls_cipher_context_t *ctx = (struct st_ptls_mbedtls_cipher_context_t *)_ctx;
+
+ if (ctx->is_op_in_progress)
+ psa_cipher_abort(&ctx->op);
+ psa_destroy_key(ctx->key);
+}
+
+static int cipher_setup(ptls_cipher_context_t *_ctx, int is_enc, const void *key_bytes, psa_algorithm_t alg,
+ psa_key_type_t key_type)
+{
+ struct st_ptls_mbedtls_cipher_context_t *ctx = (struct st_ptls_mbedtls_cipher_context_t *)_ctx;
+
+ { /* import key or fail immediately */
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_set_key_usage_flags(&attributes, is_enc ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT);
+ psa_set_key_algorithm(&attributes, alg);
+ psa_set_key_type(&attributes, key_type);
+ psa_set_key_bits(&attributes, ctx->super.algo->key_size * 8);
+ if (psa_import_key(&attributes, key_bytes, ctx->super.algo->key_size, &ctx->key) != PSA_SUCCESS)
+ return PTLS_ERROR_LIBRARY;
+ }
+
+ /* init the rest that are guaranteed to succeed */
+ ctx->super.do_dispose = cipher_dispose;
+ ctx->super.do_init = cipher_init;
+ ctx->super.do_transform = cipher_transform;
+ ctx->alg = alg;
+ ctx->is_enc = is_enc;
+ ctx->is_op_in_progress = 0;
+ ctx->op = psa_cipher_operation_init();
+
+ return 0;
+}
+
+static int ecb_setup(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes, psa_key_type_t key_type)
+{
+ int ret;
+
+ if ((ret = cipher_setup(ctx, is_enc, key_bytes, PSA_ALG_ECB_NO_PADDING, key_type)) != 0)
+ return ret;
+ /* ECB mode does not necessary call `ptls_cipher_init` */
+ cipher_init(ctx, NULL);
+
+ return 0;
+}
+
+static int setup_aes128ecb(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes)
+{
+ return ecb_setup(ctx, is_enc, key_bytes, PSA_KEY_TYPE_AES);
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_aes128ecb = {
+ "AES128-ECB", PTLS_AES128_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 0 /* iv size */, sizeof(struct st_ptls_mbedtls_cipher_context_t),
+ setup_aes128ecb};
+
+static int setup_aes256ecb(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes)
+{
+ return ecb_setup(ctx, is_enc, key_bytes, PSA_KEY_TYPE_AES);
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_aes256ecb = {
+ "AES256-ECB", PTLS_AES256_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 0 /* iv size */, sizeof(struct st_ptls_mbedtls_cipher_context_t),
+ setup_aes256ecb};
+
+static int setup_aes128ctr(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes)
+{
+ return cipher_setup(ctx, is_enc, key_bytes, PSA_ALG_CTR, PSA_KEY_TYPE_AES);
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_aes128ctr = {
+ "AES128-CTR", PTLS_AES128_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 16 /* iv size */, sizeof(struct st_ptls_mbedtls_cipher_context_t),
+ setup_aes128ctr};
+
+static int setup_aes256ctr(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes)
+{
+ return cipher_setup(ctx, is_enc, key_bytes, PSA_ALG_CTR, PSA_KEY_TYPE_AES);
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_aes256ctr = {
+ "AES128-CTR", PTLS_AES256_KEY_SIZE, PTLS_AES_BLOCK_SIZE, 16 /* iv size */, sizeof(struct st_ptls_mbedtls_cipher_context_t),
+ setup_aes256ctr};
+
+#if 0
+/* CHACHA20 backend using PSA API is disabled for now, as there seems to be an issue when setting the 16 bytes long IV that we
+ * need. */
+static int setup_chacha20(ptls_cipher_context_t *ctx, int is_enc, const void *key_bytes)
+{
+ return cipher_setup(ctx, is_enc, key_bytes, PSA_ALG_CTR, PSA_KEY_TYPE_CHACHA20);
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_chacha20 = {
+ "CHACHA20", PTLS_CHACHA20_KEY_SIZE, 1 /* block size */, PTLS_CHACHA20_IV_SIZE, sizeof(struct st_ptls_mbedtls_cipher_context_t),
+ setup_chacha20};
+#else
+/* Implementation of ChaCha20 using the low level ChaCha20 API.
+ * TODO: remove this and the reference to chacha20.h as soon as the IV bug in the generic implementation is fixed. */
+struct st_ptls_mbedtls_chacha20_context_t {
+ ptls_cipher_context_t super;
+ mbedtls_chacha20_context mctx;
+};
+
+static void chacha20_init(ptls_cipher_context_t *_ctx, const void *v_iv)
+{
+ struct st_ptls_mbedtls_chacha20_context_t *ctx = (struct st_ptls_mbedtls_chacha20_context_t *)_ctx;
+ const uint8_t *iv = (const uint8_t *)v_iv;
+ uint32_t ctr = iv[0] | ((uint32_t)iv[1] << 8) | ((uint32_t)iv[2] << 16) | ((uint32_t)iv[3] << 24);
+
+ int ret = mbedtls_chacha20_starts(&ctx->mctx, (const uint8_t *)(iv + 4), ctr);
+ if (ret != 0)
+ PSA_FUNC_FAILED(mbedtls_chacha20_starts, ret);
+}
+
+static void chacha20_transform(ptls_cipher_context_t *_ctx, void *output, const void *input, size_t len)
+{
+ struct st_ptls_mbedtls_chacha20_context_t *ctx = (struct st_ptls_mbedtls_chacha20_context_t *)_ctx;
+
+ int ret = mbedtls_chacha20_update(&ctx->mctx, len, (const uint8_t *)input, (uint8_t *)output);
+ if (ret != 0)
+ PSA_FUNC_FAILED(mbedtls_chacha20_update, ret);
+}
+
+static void chacha20_dispose(ptls_cipher_context_t *_ctx)
+{
+ struct st_ptls_mbedtls_chacha20_context_t *ctx = (struct st_ptls_mbedtls_chacha20_context_t *)_ctx;
+
+ mbedtls_chacha20_free(&ctx->mctx);
+}
+
+static int setup_chacha20(ptls_cipher_context_t *_ctx, int is_enc, const void *key)
+{
+ struct st_ptls_mbedtls_chacha20_context_t *ctx = (struct st_ptls_mbedtls_chacha20_context_t *)_ctx;
+
+ mbedtls_chacha20_init(&ctx->mctx);
+ if (mbedtls_chacha20_setkey(&ctx->mctx, key) != 0)
+ return PTLS_ERROR_LIBRARY;
+
+ ctx->super.do_dispose = chacha20_dispose;
+ ctx->super.do_init = chacha20_init;
+ ctx->super.do_transform = chacha20_transform;
+
+ return 0;
+}
+
+ptls_cipher_algorithm_t ptls_mbedtls_chacha20 = {"CHACHA20",
+ PTLS_CHACHA20_KEY_SIZE,
+ 1 /* block size */,
+ PTLS_CHACHA20_IV_SIZE,
+ sizeof(struct st_ptls_mbedtls_chacha20_context_t),
+ setup_chacha20};
+#endif
+
+struct ptls_mbedtls_aead_context_t {
+ struct st_ptls_aead_context_t super;
+ uint8_t static_iv[PTLS_MAX_IV_SIZE];
+ psa_algorithm_t alg;
+ psa_key_id_t key;
+};
+
+static void aead_dispose_crypto(struct st_ptls_aead_context_t *_ctx)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+
+ psa_destroy_key(ctx->key);
+}
+
+static void aead_get_iv(ptls_aead_context_t *_ctx, void *iv)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+
+ memcpy(iv, ctx->static_iv, ctx->super.algo->iv_size);
+}
+
+static void aead_set_iv(ptls_aead_context_t *_ctx, const void *iv)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+
+ memcpy(ctx->static_iv, iv, ctx->super.algo->iv_size);
+}
+
+static void aead_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)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+ psa_aead_operation_t op = psa_aead_operation_init();
+ uint8_t *dst = output, iv[PTLS_MAX_IV_SIZE], tag[PSA_AEAD_TAG_MAX_SIZE];
+ size_t outlen, taglen;
+
+ /* setup op */
+ CALL_WITH_CHECK(psa_aead_encrypt_setup, &op, ctx->key, ctx->alg);
+ ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq);
+ CALL_WITH_CHECK(psa_aead_set_nonce, &op, iv, ctx->super.algo->iv_size);
+ CALL_WITH_CHECK(psa_aead_update_ad, &op, aad, aadlen);
+
+ /* encrypt */
+ for (size_t i = 0; i < incnt; i++) {
+ CALL_WITH_CHECK(psa_aead_update, &op, input[i].base, input[i].len, dst, SIZE_MAX, &outlen);
+ dst += outlen;
+ }
+ CALL_WITH_CHECK(psa_aead_finish, &op, dst, SIZE_MAX, &outlen, tag, sizeof(tag), &taglen);
+ dst += outlen;
+ memcpy(dst, tag, taglen);
+
+ /* destroy op */
+ psa_aead_abort(&op);
+}
+
+static size_t aead_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)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+ uint8_t iv[PTLS_MAX_IV_SIZE];
+ size_t outlen;
+
+ ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq);
+
+ psa_status_t ret =
+ psa_aead_decrypt(ctx->key, ctx->alg, iv, ctx->super.algo->iv_size, aad, aadlen, input, inlen, output, inlen, &outlen);
+ switch (ret) {
+ case PSA_SUCCESS:
+ break;
+ case PSA_ERROR_INVALID_SIGNATURE:
+ outlen = SIZE_MAX;
+ break;
+ default:
+ PSA_FUNC_FAILED(psa_aead_decrypt, ret);
+ break;
+ }
+
+ return outlen;
+}
+
+static int aead_setup(ptls_aead_context_t *_ctx, int is_enc, const void *key_bytes, const void *iv, psa_algorithm_t psa_alg,
+ size_t key_bits, psa_key_type_t key_type)
+{
+ struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx;
+
+ { /* setup key */
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ psa_set_key_usage_flags(&attributes, is_enc ? PSA_KEY_USAGE_ENCRYPT : PSA_KEY_USAGE_DECRYPT);
+ psa_set_key_algorithm(&attributes, psa_alg);
+ psa_set_key_type(&attributes, key_type);
+ psa_set_key_bits(&attributes, key_bits);
+ if (psa_import_key(&attributes, key_bytes, key_bits / 8, &ctx->key) != PSA_SUCCESS)
+ return PTLS_ERROR_LIBRARY;
+ }
+
+ /* setup the rest */
+ ctx->super.dispose_crypto = aead_dispose_crypto;
+ ctx->super.do_get_iv = aead_get_iv;
+ ctx->super.do_set_iv = aead_set_iv;
+ if (is_enc) {
+ ctx->super.do_encrypt = ptls_aead__do_encrypt;
+ ctx->super.do_encrypt_v = aead_encrypt_v;
+ } else {
+ ctx->super.do_decrypt = aead_decrypt;
+ }
+ memcpy(ctx->static_iv, iv, ctx->super.algo->iv_size);
+ ctx->alg = psa_alg;
+
+ return 0;
+}
+
+static int aead_setup_aes128gcm(ptls_aead_context_t *_ctx, int is_enc, const void *key_bytes, const void *iv)
+{
+ return aead_setup(_ctx, is_enc, key_bytes, iv, PSA_ALG_GCM, 128, PSA_KEY_TYPE_AES);
+}
+
+ptls_aead_algorithm_t ptls_mbedtls_aes128gcm = {"AES128-GCM",
+ PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+ PTLS_AESGCM_INTEGRITY_LIMIT,
+ &ptls_mbedtls_aes128ctr,
+ &ptls_mbedtls_aes128ecb,
+ PTLS_AES128_KEY_SIZE,
+ PTLS_AESGCM_IV_SIZE,
+ PTLS_AESGCM_TAG_SIZE,
+ {PTLS_TLS12_AESGCM_FIXED_IV_SIZE, PTLS_TLS12_AESGCM_RECORD_IV_SIZE},
+ 0,
+ 0,
+ sizeof(struct ptls_mbedtls_aead_context_t),
+ aead_setup_aes128gcm};
+
+ptls_cipher_suite_t ptls_mbedtls_aes128gcmsha256 = {.id = PTLS_CIPHER_SUITE_AES_128_GCM_SHA256,
+ .name = PTLS_CIPHER_SUITE_NAME_AES_128_GCM_SHA256,
+ .aead = &ptls_mbedtls_aes128gcm,
+ .hash = &ptls_mbedtls_sha256};
+
+static int aead_setup_aes256gcm(ptls_aead_context_t *_ctx, int is_enc, const void *key_bytes, const void *iv)
+{
+ return aead_setup(_ctx, is_enc, key_bytes, iv, PSA_ALG_GCM, 256, PSA_KEY_TYPE_AES);
+}
+
+ptls_aead_algorithm_t ptls_mbedtls_aes256gcm = {"AES256-GCM",
+ PTLS_AESGCM_CONFIDENTIALITY_LIMIT,
+ PTLS_AESGCM_INTEGRITY_LIMIT,
+ &ptls_mbedtls_aes256ctr,
+ &ptls_mbedtls_aes256ecb,
+ PTLS_AES256_KEY_SIZE,
+ PTLS_AESGCM_IV_SIZE,
+ PTLS_AESGCM_TAG_SIZE,
+ {PTLS_TLS12_AESGCM_FIXED_IV_SIZE, PTLS_TLS12_AESGCM_RECORD_IV_SIZE},
+ 0,
+ 0,
+ sizeof(struct ptls_mbedtls_aead_context_t),
+ aead_setup_aes256gcm};
+
+#if defined(MBEDTLS_SHA384_C)
+ptls_cipher_suite_t ptls_mbedtls_aes256gcmsha384 = {.id = PTLS_CIPHER_SUITE_AES_256_GCM_SHA384,
+ .name = PTLS_CIPHER_SUITE_NAME_AES_256_GCM_SHA384,
+ .aead = &ptls_mbedtls_aes256gcm,
+ .hash = &ptls_mbedtls_sha384};
+#endif
+
+static int aead_setup_chacha20poly1305(ptls_aead_context_t *_ctx, int is_enc, const void *key_bytes, const void *iv)
+{
+ return aead_setup(_ctx, is_enc, key_bytes, iv, PSA_ALG_CHACHA20_POLY1305, 256, PSA_KEY_TYPE_CHACHA20);
+}
+
+ptls_aead_algorithm_t ptls_mbedtls_chacha20poly1305 = {"CHACHA20-POLY1305",
+ PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT,
+ PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT,
+ &ptls_mbedtls_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 ptls_mbedtls_aead_context_t),
+ aead_setup_chacha20poly1305};
+
+ptls_cipher_suite_t ptls_mbedtls_chacha20poly1305sha256 = {.id = PTLS_CIPHER_SUITE_CHACHA20_POLY1305_SHA256,
+ .name = PTLS_CIPHER_SUITE_NAME_CHACHA20_POLY1305_SHA256,
+ .aead = &ptls_mbedtls_chacha20poly1305,
+ .hash = &ptls_mbedtls_sha256};
+
+ptls_cipher_suite_t *ptls_mbedtls_cipher_suites[] = {
+#if defined(MBEDTLS_SHA384_C)
+ &ptls_mbedtls_aes256gcmsha384,
+#endif
+ &ptls_mbedtls_aes128gcmsha256, &ptls_mbedtls_chacha20poly1305sha256, NULL};
+
+#define PTLS_MBEDTLS_ECDH_PUBKEY_MAX 129
+
+static const struct ptls_mbedtls_key_exchange_params_t {
+ psa_algorithm_t alg;
+ psa_ecc_family_t curve;
+ size_t curve_bits;
+ size_t secret_size;
+} secp256r1_params = {PSA_ALG_ECDH, PSA_ECC_FAMILY_SECP_R1, 256, 32},
+ x25519_params = {PSA_ALG_ECDH, PSA_ECC_FAMILY_MONTGOMERY, 255, 32};
+
+struct ptls_mbedtls_key_exchange_context_t {
+ ptls_key_exchange_context_t super;
+ const struct ptls_mbedtls_key_exchange_params_t *params;
+ psa_key_id_t private_key;
+ uint8_t pubkeybuf[PTLS_MBEDTLS_ECDH_PUBKEY_MAX];
+};
+
+/**
+ * Generates a private key. For now, we only support ECC.
+ */
+static int generate_private_key(psa_key_id_t *private_key, const struct ptls_mbedtls_key_exchange_params_t *params)
+{
+ psa_key_attributes_t attributes = PSA_KEY_ATTRIBUTES_INIT;
+ int ret = 0;
+
+ psa_set_key_usage_flags(&attributes, PSA_KEY_USAGE_DERIVE);
+ psa_set_key_algorithm(&attributes, params->alg);
+ psa_set_key_type(&attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(params->curve));
+ psa_set_key_bits(&attributes, params->curve_bits);
+ if (psa_generate_key(&attributes, private_key) != 0) {
+ ret = -1;
+ }
+ return ret;
+}
+
+static int key_exchange_on_exchange(struct st_ptls_key_exchange_context_t **_keyex, int release, ptls_iovec_t *secret,
+ ptls_iovec_t peerkey)
+{
+ struct ptls_mbedtls_key_exchange_context_t *keyex = (struct ptls_mbedtls_key_exchange_context_t *)*_keyex;
+ int ret = 0;
+
+ if (secret == NULL)
+ goto Exit;
+
+ /* derive shared secret */
+ if ((secret->base = malloc(keyex->params->secret_size)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
+ if (psa_raw_key_agreement(keyex->params->alg, keyex->private_key, peerkey.base, peerkey.len, secret->base,
+ keyex->params->secret_size, &secret->len) != 0) {
+ ret = PTLS_ERROR_LIBRARY;
+ goto Exit;
+ }
+ assert(keyex->params->secret_size == secret->len);
+ ret = 0;
+
+Exit:
+ if (ret != 0 && secret != NULL) {
+ free(secret->base);
+ *secret = ptls_iovec_init(NULL, 0);
+ }
+ if (release) {
+ psa_destroy_key(keyex->private_key);
+ free(keyex);
+ *_keyex = NULL;
+ }
+ return ret;
+}
+
+static int key_exchange_create(ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx,
+ const struct ptls_mbedtls_key_exchange_params_t *params)
+{
+ struct ptls_mbedtls_key_exchange_context_t *keyex;
+
+ *ctx = NULL;
+
+ /* setup context */
+ if ((keyex = malloc(sizeof(*keyex))) == NULL)
+ return PTLS_ERROR_NO_MEMORY;
+ *keyex = (struct ptls_mbedtls_key_exchange_context_t){
+ .super.algo = algo,
+ .super.pubkey.base = keyex->pubkeybuf,
+ .super.on_exchange = key_exchange_on_exchange,
+ .params = params,
+ };
+
+ /* generate private key */
+ if (generate_private_key(&keyex->private_key, keyex->params) != 0) {
+ free(keyex);
+ return PTLS_ERROR_LIBRARY;
+ }
+ { /* export public key */
+ psa_status_t ret =
+ psa_export_public_key(keyex->private_key, keyex->pubkeybuf, sizeof(keyex->pubkeybuf), &keyex->super.pubkey.len);
+ if (ret != 0)
+ PSA_FUNC_FAILED(psa_export_public_key, ret);
+ }
+
+ *ctx = &keyex->super;
+ return 0;
+}
+
+static int key_exchange_exchange(ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
+ ptls_iovec_t peerkey, const struct ptls_mbedtls_key_exchange_params_t *params)
+{
+ psa_key_id_t private_key;
+ int ret;
+
+ *pubkey = ptls_iovec_init(NULL, 0);
+ *secret = ptls_iovec_init(NULL, 0);
+
+ /* generate private key (and return immediately upon failure) */
+ if (generate_private_key(&private_key, params) != 0)
+ return PTLS_ERROR_LIBRARY;
+
+ /* allocate buffers */
+ if ((secret->base = malloc(params->secret_size)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
+ if ((pubkey->base = malloc(PTLS_MBEDTLS_ECDH_PUBKEY_MAX)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
+
+ /* export public key and call key agrement function */
+ if (psa_export_public_key(private_key, pubkey->base, PTLS_MBEDTLS_ECDH_PUBKEY_MAX, &pubkey->len) != 0 ||
+ psa_raw_key_agreement(params->alg, private_key, peerkey.base, peerkey.len, secret->base, params->secret_size,
+ &secret->len) != 0) {
+ ret = PTLS_ERROR_LIBRARY;
+ goto Exit;
+ }
+
+ ret = 0;
+
+Exit:
+ if (ret != 0) {
+ free(pubkey->base);
+ *pubkey = ptls_iovec_init(NULL, 0);
+ free(secret->base);
+ *secret = ptls_iovec_init(NULL, 0);
+ }
+ psa_destroy_key(private_key);
+
+ return ret;
+}
+
+static int secp256r1_create(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx)
+{
+ return key_exchange_create(algo, ctx, &secp256r1_params);
+}
+
+static int secp256r1_exchange(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
+ ptls_iovec_t peerkey)
+{
+ return key_exchange_exchange(algo, pubkey, secret, peerkey, &secp256r1_params);
+}
+
+ptls_key_exchange_algorithm_t ptls_mbedtls_secp256r1 = {
+ .id = PTLS_GROUP_SECP256R1, .name = PTLS_GROUP_NAME_SECP256R1, .create = secp256r1_create, .exchange = secp256r1_exchange};
+
+static int x25519_create(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **ctx)
+{
+ return key_exchange_create(algo, ctx, &x25519_params);
+}
+
+static int x25519_exchange(const struct st_ptls_key_exchange_algorithm_t *algo, ptls_iovec_t *pubkey, ptls_iovec_t *secret,
+ ptls_iovec_t peerkey)
+{
+ return key_exchange_exchange(algo, pubkey, secret, peerkey, &x25519_params);
+}
+
+ptls_key_exchange_algorithm_t ptls_mbedtls_x25519 = {
+ .id = PTLS_GROUP_X25519, .name = PTLS_GROUP_NAME_X25519, .create = x25519_create, .exchange = x25519_exchange};
+
+ptls_key_exchange_algorithm_t *ptls_mbedtls_key_exchanges[] = {&ptls_mbedtls_secp256r1, NULL};
diff --git a/lib/openssl.c b/lib/openssl.c
index b035339..70a3e7e 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -525,22 +525,35 @@
}
#ifdef OPENSSL_IS_BORINGSSL
+#define X25519_KEY_SIZE 32
if (ctx->super.algo->id == PTLS_GROUP_X25519) {
- secret->len = peerkey.len;
- if ((secret->base = malloc(secret->len)) == NULL) {
+ /* allocate memory to return secret */
+ if ((secret->base = malloc(X25519_KEY_SIZE)) == NULL) {
ret = PTLS_ERROR_NO_MEMORY;
goto Exit;
}
- uint8_t sk_raw[32];
+ secret->len = X25519_KEY_SIZE;
+ /* fetch raw key and derive the secret */
+ uint8_t sk_raw[X25519_KEY_SIZE];
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;
}
+ assert(sk_raw_len == sizeof(sk_raw));
X25519(secret->base, sk_raw, peerkey.base);
+ ptls_clear_memory(sk_raw, sizeof(sk_raw));
+ /* check bad key */
+ static const uint8_t zeros[X25519_KEY_SIZE] = {0};
+ if (ptls_mem_equal(secret->base, zeros, X25519_KEY_SIZE)) {
+ ret = PTLS_ERROR_INCOMPATIBLE_KEY;
+ goto Exit;
+ }
+ /* success */
ret = 0;
goto Exit;
}
+#undef X25519_KEY_SIZE
#endif
if ((evppeer = EVP_PKEY_new()) == NULL) {
@@ -595,6 +608,9 @@
return ret;
}
+/**
+ * Upon success, ownership of `pkey` is transferred to the object being created. Otherwise, the refcount remains unchanged.
+ */
static int evp_keyex_init(ptls_key_exchange_algorithm_t *algo, ptls_key_exchange_context_t **_ctx, EVP_PKEY *pkey)
{
struct st_evp_keyex_context_t *ctx = NULL;
@@ -617,8 +633,10 @@
*_ctx = &ctx->super;
ret = 0;
Exit:
- if (ret != 0 && ctx != NULL)
+ if (ret != 0 && ctx != NULL) {
+ ctx->privkey = NULL; /* do not decrement refcount of pkey in case of error */
evp_keyex_free(ctx);
+ }
return ret;
}
@@ -2202,10 +2220,10 @@
.context_size = sizeof(struct aegis256_context_t),
.setup_crypto = aegis256_setup_crypto,
};
-ptls_cipher_suite_t ptls_openssl_aegis256sha384 = {.id = PTLS_CIPHER_SUITE_AEGIS256_SHA384,
- .name = PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA384,
+ptls_cipher_suite_t ptls_openssl_aegis256sha512 = {.id = PTLS_CIPHER_SUITE_AEGIS256_SHA512,
+ .name = PTLS_CIPHER_SUITE_NAME_AEGIS256_SHA512,
.aead = &ptls_openssl_aegis256,
- .hash = &ptls_openssl_sha384};
+ .hash = &ptls_openssl_sha512};
#endif
@@ -2222,7 +2240,7 @@
ptls_cipher_suite_t *ptls_openssl_cipher_suites_all[] = {// ciphers used with sha384 (must be first)
#if PTLS_HAVE_AEGIS
- &ptls_openssl_aegis256sha384,
+ &ptls_openssl_aegis256sha512,
#endif
&ptls_openssl_aes256gcmsha384,
diff --git a/lib/picotls.c b/lib/picotls.c
index e2a3e04..9ba15c7 100644
--- a/lib/picotls.c
+++ b/lib/picotls.c
@@ -39,10 +39,6 @@
#include "picotls-probes.h"
#endif
-#ifdef PTLS_HAVE_AEGIS
-#include <aegis.h>
-#endif
-
#define PTLS_MAX_PLAINTEXT_RECORD_SIZE 16384
#define PTLS_MAX_ENCRYPTED_RECORD_SIZE (16384 + 256)
@@ -2376,7 +2372,10 @@
/* initialize key schedule */
if (!is_second_flight) {
- tls->key_schedule = key_schedule_new(tls->cipher_suite, tls->ctx->cipher_suites, tls->ech.aead != NULL);
+ if ((tls->key_schedule = key_schedule_new(tls->cipher_suite, tls->ctx->cipher_suites, tls->ech.aead != NULL)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
if ((ret = key_schedule_extract(tls->key_schedule, resumption_secret)) != 0)
goto Exit;
}
@@ -3573,10 +3572,10 @@
src = end;
});
- /* CH defined in TLS versions below 1.2 might not have extensions (or they might, see what OpenSSL 1.0.0 sends); so bail out
- * after parsing the main variables. Zero is returned as it is a valid ClientHello. However `ptls_t::selected_version` remains
- * zero indicating that no compatible version were found. */
- if (ch->legacy_version < 0x0303 && src == end) {
+ /* In TLS versions 1.2 and earlier CH might not have an extensions block (or they might, see what OpenSSL 1.0.0 sends); so bail
+ * out if that is the case after parsing the main variables. Zero is returned as it is a valid ClientHello. However
+ * `ptls_t::selected_version` remains zero indicating that no compatible version were found. */
+ if (src == end) {
ret = 0;
goto Exit;
}
@@ -4376,7 +4375,10 @@
goto Exit;
if (!is_second_flight) {
tls->cipher_suite = cs;
- tls->key_schedule = key_schedule_new(cs, NULL, 0);
+ if ((tls->key_schedule = key_schedule_new(cs, NULL, 0)) == NULL) {
+ ret = PTLS_ERROR_NO_MEMORY;
+ goto Exit;
+ }
} else {
if (tls->cipher_suite != cs) {
ret = PTLS_ALERT_HANDSHAKE_FAILURE;
diff --git a/picotls.xcodeproj/project.pbxproj b/picotls.xcodeproj/project.pbxproj
index 6882e19..338535e 100644
--- a/picotls.xcodeproj/project.pbxproj
+++ b/picotls.xcodeproj/project.pbxproj
@@ -205,6 +205,14 @@
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>"; };
+ 085BDAE52B1D618E002851EA /* libaegis.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = libaegis.c; sourceTree = "<group>"; };
+ 085BDAE62B1D6238002851EA /* libaegis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = libaegis.h; sourceTree = "<group>"; };
+ 087F1A732B034AEB00E81AC1 /* FindMbedTLS.cmake */ = {isa = PBXFileReference; lastKnownFileType = text; path = FindMbedTLS.cmake; sourceTree = "<group>"; };
+ 0883D3272AEF8F2500B711CC /* fusion.cmake */ = {isa = PBXFileReference; lastKnownFileType = text; path = fusion.cmake; sourceTree = "<group>"; };
+ 0883D32A2AF601A700B711CC /* mbedtls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mbedtls.c; sourceTree = "<group>"; };
+ 0883D32B2AF601B900B711CC /* mbedtls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mbedtls.c; sourceTree = "<group>"; };
+ 0883D32C2AF601CB00B711CC /* mbedtls.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = mbedtls.h; sourceTree = "<group>"; };
+ 0883D32D2AF6020300B711CC /* ptlsbench.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ptlsbench.c; 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; };
@@ -402,7 +410,6 @@
106530BD1D998624005B2C60 /* lib */,
E95EBCC2227E82BA0022C32D /* misc */,
E95EBCC0227B71170022C32D /* picotls-probes.d */,
- E992F79920E99A080008154D /* src */,
106530C41D9B1A0E005B2C60 /* t */,
106530B31D9985E0005B2C60 /* Products */,
E973651D246E37300039AA49 /* Frameworks */,
@@ -443,6 +450,8 @@
E97577022212405D00D1EF74 /* ffx.c */,
E9B43DBF24619D1700824E51 /* fusion.c */,
08F0FDF52910F67A00EE657D /* hpke.c */,
+ 085BDAE62B1D6238002851EA /* libaegis.h */,
+ 0883D32B2AF601B900B711CC /* mbedtls.c */,
E949EF272073629300511ECA /* minicrypto-pem.c */,
106530C21D9B004B005B2C60 /* openssl.c */,
E99B75DF1F5CDDB500CF503E /* pembase64.c */,
@@ -461,9 +470,11 @@
08B3298229419DFC009D6766 /* ech-live.t */,
E9B43DE224619D7E00824E51 /* fusion.c */,
081F00C92918823200534A86 /* hpke.c */,
+ 0883D32A2AF601A700B711CC /* mbedtls.c */,
1059003D1DC8D4E300FB4085 /* minicrypto.c */,
106530C51D9B1A98005B2C60 /* openssl.c */,
106530E91D9B7C13005B2C60 /* picotls.c */,
+ 0883D32D2AF6020300B711CC /* ptlsbench.c */,
106530E61D9B7AF6005B2C60 /* test.h */,
E9E3849C1F0748DD00D50990 /* util.h */,
);
@@ -496,6 +507,7 @@
E9E4B1292180514000514B47 /* certificate_compression.h */,
E97577002212405300D1EF74 /* ffx.h */,
E9B43DE62461A06800824E51 /* fusion.h */,
+ 0883D32C2AF601CB00B711CC /* mbedtls.h */,
1059004F1DC8D64E00FB4085 /* minicrypto.h */,
106530ED1D9CEFF7005B2C60 /* openssl.h */,
081F00CD291A358800534A86 /* pembase64.h */,
@@ -527,6 +539,8 @@
children = (
08A835EB2996971300D872CE /* boringssl-adjust.cmake */,
E95EBCCA227EA0180022C32D /* dtrace-utils.cmake */,
+ 087F1A732B034AEB00E81AC1 /* FindMbedTLS.cmake */,
+ 0883D3272AEF8F2500B711CC /* fusion.cmake */,
);
path = cmake;
sourceTree = "<group>";
@@ -538,13 +552,6 @@
name = Frameworks;
sourceTree = "<group>";
};
- E992F79920E99A080008154D /* src */ = {
- isa = PBXGroup;
- children = (
- );
- path = src;
- sourceTree = "<group>";
- };
E9F20BDF22E34B210018D260 /* cifra */ = {
isa = PBXGroup;
children = (
@@ -552,6 +559,7 @@
E9F20BE222E34B340018D260 /* aes128.c */,
E9F20BE022E34B340018D260 /* aes256.c */,
E9F20BE422E34B340018D260 /* chacha20.c */,
+ 085BDAE52B1D618E002851EA /* libaegis.c */,
E9F20BF922E34C110018D260 /* random.c */,
E9F20BE122E34B340018D260 /* x25519.c */,
);
diff --git a/t/mbedtls.c b/t/mbedtls.c
new file mode 100644
index 0000000..d3651de
--- /dev/null
+++ b/t/mbedtls.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2023, Christian Huitema
+ *
+ * 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.
+ */
+
+#ifdef _WINDOWS
+#include "wincompat.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <picotls.h>
+#include "picotls/mbedtls.h"
+#include "picotls/minicrypto.h"
+#include "../deps/picotest/picotest.h"
+#include "test.h"
+
+static int random_trial()
+{
+ /* The random test is just trying to check that we call the API properly.
+ * This is done by getting a vector of 1021 bytes, computing the sum of
+ * all values, and comparing to theoretical min and max,
+ * computed as average +- 8*standard deviation for sum of 1021 terms.
+ * 8 random deviations results in an extremely low probability of random
+ * failure.
+ * Note that this does not actually test the random generator.
+ */
+
+ uint8_t buf[1021];
+ uint64_t sum = 0;
+ const uint64_t max_sum_1021 = 149505;
+ const uint64_t min_sum_1021 = 110849;
+ int ret = 0;
+
+ ptls_mbedtls_random_bytes(buf, sizeof(buf));
+ for (size_t i = 0; i < sizeof(buf); i++) {
+ sum += buf[i];
+ }
+ if (sum > max_sum_1021 || sum < min_sum_1021) {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static void test_random(void)
+{
+ if (random_trial() != 0) {
+ ok(!"fail");
+ return;
+ }
+ ok(!!"success");
+}
+
+static void test_secp256r1(void)
+{
+ test_key_exchange(&ptls_mbedtls_secp256r1, &ptls_minicrypto_secp256r1);
+ test_key_exchange(&ptls_minicrypto_secp256r1, &ptls_mbedtls_secp256r1);
+}
+
+static void test_x25519(void)
+{
+ test_key_exchange(&ptls_mbedtls_x25519, &ptls_minicrypto_x25519);
+ test_key_exchange(&ptls_minicrypto_x25519, &ptls_mbedtls_x25519);
+}
+
+static void test_key_exchanges(void)
+{
+ subtest("secp256r1", test_secp256r1);
+ subtest("x25519", test_x25519);
+}
+
+DEFINE_FFX_AES128_ALGORITHMS(mbedtls);
+DEFINE_FFX_CHACHA20_ALGORITHMS(mbedtls);
+
+int main(int argc, char **argv)
+{
+ /* Initialize the PSA crypto library. */
+ if (psa_crypto_init() != PSA_SUCCESS) {
+ note("psa_crypto_init fails.");
+ return done_testing();
+ }
+
+ /* Test of the port of the mbedtls random generator */
+ subtest("random", test_random);
+ subtest("key_exchanges", test_key_exchanges);
+
+ ADD_FFX_AES128_ALGORITHMS(mbedtls);
+ ADD_FFX_CHACHA20_ALGORITHMS(mbedtls);
+
+ /* minicrypto contexts used as peer for valiation */
+ ptls_iovec_t secp256r1_certificate = ptls_iovec_init(SECP256R1_CERTIFICATE, sizeof(SECP256R1_CERTIFICATE) - 1);
+ ptls_minicrypto_secp256r1sha256_sign_certificate_t minicrypto_sign_certificate;
+ ptls_minicrypto_init_secp256r1sha256_sign_certificate(
+ &minicrypto_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
+ ptls_context_t minicrypto_ctx = {ptls_minicrypto_random_bytes,
+ &ptls_get_time,
+ ptls_minicrypto_key_exchanges,
+ ptls_minicrypto_cipher_suites,
+ {&secp256r1_certificate, 1},
+ {{NULL}},
+ NULL,
+ NULL,
+ &minicrypto_sign_certificate.super};
+
+ /* context using mbedtls as backend; minicrypto is used for signing certificate as the mbedtls backend does not (yet) have the
+ * capability */
+ ptls_minicrypto_secp256r1sha256_sign_certificate_t mbedtls_sign_certificate;
+ ptls_minicrypto_init_secp256r1sha256_sign_certificate(
+ &mbedtls_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
+ ptls_context_t mbedtls_ctx = {ptls_mbedtls_random_bytes,
+ &ptls_get_time,
+ ptls_mbedtls_key_exchanges,
+ ptls_mbedtls_cipher_suites,
+ {&secp256r1_certificate, 1},
+ {{NULL}},
+ NULL,
+ NULL,
+ &mbedtls_sign_certificate.super};
+
+ ctx = &mbedtls_ctx;
+ ctx_peer = &mbedtls_ctx;
+ subtest("selt-test", test_picotls);
+
+ ctx = &mbedtls_ctx;
+ ctx_peer = &minicrypto_ctx;
+ subtest("vs. minicrypto", test_picotls);
+
+ ctx = &minicrypto_ctx;
+ ctx_peer = &mbedtls_ctx;
+ subtest("minicrypto vs.", test_picotls);
+
+ /* Deinitialize the PSA crypto library. */
+ mbedtls_psa_crypto_free();
+
+ return done_testing();
+}
diff --git a/t/openssl.c b/t/openssl.c
index b3188ff..d487445 100644
--- a/t/openssl.c
+++ b/t/openssl.c
@@ -564,7 +564,8 @@
.sign_certificate = &openssl_sign_certificate.super};
ptls_context_t openssl_ctx_sha256only = openssl_ctx;
while (openssl_ctx_sha256only.cipher_suites[0]->hash->digest_size != 32) {
- assert(openssl_ctx.cipher_suites[0]->hash->digest_size == 48); /* sha384 */
+ assert(openssl_ctx.cipher_suites[0]->hash->digest_size == 64 || /* sha512 */
+ openssl_ctx.cipher_suites[0]->hash->digest_size == 48); /* sha384 */
++openssl_ctx_sha256only.cipher_suites;
}
assert(openssl_ctx_sha256only.cipher_suites[0]->hash->digest_size == 32); /* sha256 */
diff --git a/t/picotls.c b/t/picotls.c
index ecca51d..c82cc41 100644
--- a/t/picotls.c
+++ b/t/picotls.c
@@ -225,12 +225,8 @@
/* encrypt */
c = ptls_aead_new(cs1->aead, cs1->hash, 1, traffic_secret, NULL);
assert(c != NULL);
- ptls_aead_encrypt_init(c, 0, NULL, 0);
- enc1len = ptls_aead_encrypt_update(c, enc1, src1, strlen(src1));
- enc1len += ptls_aead_encrypt_final(c, enc1 + enc1len);
- ptls_aead_encrypt_init(c, 1, NULL, 0);
- enc2len = ptls_aead_encrypt_update(c, enc2, src2, strlen(src2));
- enc2len += ptls_aead_encrypt_final(c, enc2 + enc2len);
+ enc1len = ptls_aead_encrypt(c, enc1, src1, strlen(src1), 0, NULL, 0);
+ enc2len = ptls_aead_encrypt(c, enc2, src2, strlen(src2), 1, NULL, 0);
ptls_aead_free(c);
c = ptls_aead_new(cs2->aead, cs2->hash, 0, traffic_secret, NULL);
@@ -275,6 +271,10 @@
/* encrypt */
c = ptls_aead_new(cs1->aead, cs1->hash, 1, traffic_secret, NULL);
assert(c != NULL);
+ if (c->do_encrypt_init == NULL) {
+ note("new ciphers may omit support for init-update-final");
+ return;
+ }
ptls_aead_encrypt_init(c, 0, NULL, 0);
enclen = 0;
for (size_t i = 0; text[i] != NULL; ++i)
@@ -311,9 +311,7 @@
/* encrypt */
c = ptls_aead_new(cs1->aead, cs1->hash, 1, traffic_secret, NULL);
assert(c != NULL);
- ptls_aead_encrypt_init(c, 123, aad, strlen(aad));
- enclen = ptls_aead_encrypt_update(c, enc, src, strlen(src));
- enclen += ptls_aead_encrypt_final(c, enc + enclen);
+ enclen = ptls_aead_encrypt(c, enc, src, strlen(src), 123, aad, strlen(aad));
ptls_aead_free(c);
/* decrypt */
@@ -340,9 +338,7 @@
c = ptls_aead_new(cs1->aead, cs1->hash, 1, traffic_secret, NULL);
assert(c != NULL);
ptls_aead_xor_iv(c, seq32, sizeof(seq32));
- ptls_aead_encrypt_init(c, 123, aad, strlen(aad));
- enclen = ptls_aead_encrypt_update(c, enc, src, strlen(src));
- enclen += ptls_aead_encrypt_final(c, enc + enclen);
+ enclen = ptls_aead_encrypt(c, enc, src, strlen(src), 123, aad, strlen(aad));
ptls_aead_free(c);
/* decrypt */
@@ -510,8 +506,8 @@
static void test_aegis256(void)
{
- ptls_cipher_suite_t *cs = find_cipher(ctx, PTLS_CIPHER_SUITE_AEGIS256_SHA384),
- *cs_peer = find_cipher(ctx_peer, PTLS_CIPHER_SUITE_AEGIS256_SHA384);
+ ptls_cipher_suite_t *cs = find_cipher(ctx, PTLS_CIPHER_SUITE_AEGIS256_SHA512),
+ *cs_peer = find_cipher(ctx_peer, PTLS_CIPHER_SUITE_AEGIS256_SHA512);
if (cs != NULL && cs_peer != NULL) {
test_ciphersuite(cs, cs_peer);
@@ -2026,6 +2022,13 @@
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x33, 0x00, 0x32, 0x00, 0x0a, 0x00, 0x16,
0x00, 0x13, 0x00, 0x09, 0x00, 0x15, 0x00, 0x12, 0x00, 0x03, 0x00, 0x08, 0x00, 0x14, 0x00, 0x11, 0x00, 0xff, 0x01, 0x00};
+ static const uint8_t tls12_no_exts[] = {
+ 0x16, 0x03, 0x01, 0x00, 0x67, 0x01, 0x00, 0x00, 0x63, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0xee, 0x8a, 0x29, 0xdd, 0xcf, 0x6d, 0x64, 0xfd, 0xd0, 0xcd,
+ 0xa0, 0x9b, 0xc1, 0x32, 0x46, 0xbf, 0x53, 0xda, 0x29, 0x23, 0x81, 0x5f, 0x54, 0x1f, 0xbd, 0xe0, 0x8e, 0x97,
+ 0x17, 0x5b, 0x03, 0x5d, 0x00, 0x1c, 0x00, 0xff, 0x00, 0x9c, 0xc0, 0x2b, 0xc0, 0x2f, 0xc0, 0x0a, 0xc0, 0x09,
+ 0xc0, 0x13, 0xc0, 0x14, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x9e, 0x00, 0x33, 0x00, 0x39, 0x00, 0x0a, 0x01, 0x00};
/* client hello generated by openssl 1.0.0s; s_client -bugs -no_ticket -cipher DES-CBC-SHA -connect */
static const uint8_t tls10_with_exts[] = {0x16, 0x03, 0x01, 0x00, 0x2f, 0x01, 0x00, 0x00, 0x2b, 0x03, 0x01, 0x63, 0xfc,
0x5a, 0x16, 0xde, 0x7a, 0xfc, 0xc1, 0x0c, 0x54, 0x12, 0xa6, 0xd3, 0x8c, 0xcf,
@@ -2088,6 +2091,14 @@
legacy_params = NULL;
tls = ptls_new(ctx, 1);
+ len = sizeof(tls12_no_exts);
+ ret = ptls_handshake(tls, &sendbuf, tls12_no_exts, &len, NULL);
+ ptls_free(tls);
+ ok(ret == PTLS_ALERT_PROTOCOL_VERSION);
+ free(legacy_params);
+ legacy_params = NULL;
+
+ tls = ptls_new(ctx, 1);
len = sizeof(tls10_with_exts);
ret = ptls_handshake(tls, &sendbuf, tls10_with_exts, &len, NULL);
ptls_free(tls);
@@ -2188,4 +2199,10 @@
ret = ctx->on_exchange(&ctx, 1, NULL, ptls_iovec_init(NULL, 0));
ok(ret == 0);
ok(ctx == NULL);
+
+ /* test derivation failure. In case of X25519, the outcome is derived key becoming all-zero and rejected. In case of others, it
+ * is most likely that the provided key would be rejected. */
+ static uint8_t zeros[32] = {0};
+ ret = server->exchange(server, &server_pubkey, &server_secret, ptls_iovec_init(zeros, sizeof(zeros)));
+ ok(ret != 0);
}
diff --git a/t/ptlsbench.c b/t/ptlsbench.c
index 1b27607..b0f525b 100644
--- a/t/ptlsbench.c
+++ b/t/ptlsbench.c
@@ -36,8 +36,10 @@
#include "picotls/minicrypto.h"
#include "picotls/openssl.h"
#ifndef _WINDOWS
+#ifdef PTLS_HAVE_FUSION
#include "picotls/fusion.h"
#endif
+#endif
#include <openssl/opensslv.h>
#ifdef _WINDOWS
@@ -57,6 +59,10 @@
#endif
#endif
+#ifdef PTLS_HAVE_MBEDTLS
+#include "picotls/mbedtls.h"
+#endif
+
/* Time in microseconds */
static uint64_t bench_time()
{
@@ -262,14 +268,24 @@
{"ptlsbcrypt", "aes256gcm", &ptls_bcrypt_aes256gcm, &ptls_bcrypt_sha384, 1},
#endif
#if !defined(_WINDOWS)
+#ifdef PTLS_HAVE_FUSION
{"fusion", "aes128gcm", &ptls_fusion_aes128gcm, &ptls_minicrypto_sha256, 1},
{"fusion", "aes256gcm", &ptls_fusion_aes256gcm, &ptls_minicrypto_sha384, 1},
#endif
+#endif
#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305
{"openssl", "chacha20poly1305", &ptls_openssl_chacha20poly1305, &ptls_minicrypto_sha256, 1},
#endif
{"openssl", "aes128gcm", &ptls_openssl_aes128gcm, &ptls_minicrypto_sha256, 1},
- {"openssl", "aes256gcm", &ptls_openssl_aes256gcm, &ptls_minicrypto_sha384, 1}};
+ {"openssl", "aes256gcm", &ptls_openssl_aes256gcm, &ptls_minicrypto_sha384, 1},
+#ifdef PTLS_HAVE_MBEDTLS
+ {"mbedtls", "aes128gcm", &ptls_mbedtls_aes128gcm, &ptls_mbedtls_sha256, 1},
+#if defined(MBEDTLS_SHA384_C)
+ {"mbedtls", "aes256gcm", &ptls_mbedtls_aes256gcm, &ptls_mbedtls_sha384, 1},
+#endif
+ {"mbedtls", "chacha20poly1305", &ptls_mbedtls_chacha20poly1305, &ptls_mbedtls_sha256, 1},
+#endif
+};
static size_t nb_aead_list = sizeof(aead_list) / sizeof(ptls_bench_entry_t);
@@ -323,6 +339,13 @@
}
#endif
+#ifdef PTLS_HAVE_MBEDTLS
+ if (psa_crypto_init() != PSA_SUCCESS) {
+ fprintf(stderr, "psa_crypto_init fails.\n");
+ exit(-1);
+ }
+#endif
+
if (argc == 2 && strcmp(argv[1], "-f") == 0) {
force_all_tests = 1;
} else if (argc > 1) {
@@ -346,5 +369,10 @@
printf("Unexpected value of test sum s = %llx\n", (unsigned long long)s);
}
+#ifdef PTLS_HAVE_MBEDTLS
+ /* Deinitialize the PSA crypto library. */
+ mbedtls_psa_crypto_free();
+#endif
+
return ret;
}