Skip to content

Commit

Permalink
Merge pull request #495 from h2o/kazuho/mbedtls
Browse files Browse the repository at this point in the history
support mbedtls as backend
  • Loading branch information
kazuho authored Nov 16, 2023
2 parents 8fb46c6 + 3c2af6d commit dfe6072
Show file tree
Hide file tree
Showing 10 changed files with 1,067 additions and 36 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ jobs:
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"
Expand Down
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ FIND_PACKAGE(PkgConfig REQUIRED)
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)
CHECK_FUSION_PREREQUISITES()
Expand All @@ -26,6 +27,7 @@ IF (WITH_FUSION)
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(
Expand Down Expand Up @@ -190,9 +192,30 @@ IF (WITH_FUSION)
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})
Expand Down
48 changes: 48 additions & 0 deletions cmake/FindMbedTLS.cmake
Original file line number Diff line number Diff line change
@@ -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 ()
97 changes: 84 additions & 13 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,14 @@ typedef struct st_ptls_key_exchange_context_t {
*/
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;
Expand All @@ -356,12 +359,14 @@ typedef const struct st_ptls_key_exchange_algorithm_t {
*/
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);
Expand Down Expand Up @@ -398,31 +403,81 @@ typedef const struct st_ptls_cipher_algorithm_t {
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;
Expand Down Expand Up @@ -479,12 +534,16 @@ typedef const struct st_ptls_aead_algorithm_t {
*/
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;
Expand Down Expand Up @@ -1763,6 +1822,10 @@ char *ptls_jsonescape(char *buf, const char *s, size_t len);
* 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
/**
*
Expand Down Expand Up @@ -1919,7 +1982,14 @@ inline size_t ptls_aead_decrypt(ptls_aead_context_t *ctx, void *output, const vo
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; \
Expand Down Expand Up @@ -1962,7 +2032,8 @@ inline size_t ptls_aead_decrypt(ptls_aead_context_t *ctx, void *output, const vo
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; \
} \
\
Expand Down
66 changes: 66 additions & 0 deletions include/picotls/mbedtls.h
Original file line number Diff line number Diff line change
@@ -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 */
Loading

0 comments on commit dfe6072

Please sign in to comment.