diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02cd62674..80b5401a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: - name: "Linux / OpenSSL 1.1.0" 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 + 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 1.1.1 + ASan & UBSan" diff --git a/CMakeLists.txt b/CMakeLists.txt index 6faf288c9..42692a520 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ ENDIF () IF (WITH_FUSION) MESSAGE(STATUS "Enabling 'fusion' AES-GCM engine") ENDIF () +OPTION(WITH_AEGIS "enable AEGIS (requires libaegis)" ${WITH_AEGIS}) SET(CMAKE_C_FLAGS "-std=c99 -Wall -O2 -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}") INCLUDE_DIRECTORIES( @@ -88,8 +89,13 @@ ADD_LIBRARY(picotls-core ${CORE_FILES}) TARGET_LINK_LIBRARIES(picotls-core ${CORE_EXTRA_LIBS}) TARGET_LINK_DIRECTORIES(picotls-core PUBLIC ${CORE_EXTRA_LIBS_DIRS}) +IF (WITH_AEGIS) + SET(MINICRYPTO_AEGIS_FILES lib/cifra/libaegis.c) +ENDIF () + ADD_LIBRARY(picotls-minicrypto ${MINICRYPTO_LIBRARY_FILES} + ${MINICRYPTO_AEGIS_FILES} lib/cifra.c lib/cifra/x25519.c lib/cifra/chacha20.c @@ -103,6 +109,7 @@ ADD_LIBRARY(picotls-minicrypto TARGET_LINK_LIBRARIES(picotls-minicrypto picotls-core) ADD_EXECUTABLE(test-minicrypto.t ${MINICRYPTO_LIBRARY_FILES} + ${MINICRYPTO_AEGIS_FILES} deps/picotest/picotest.c ${CORE_TEST_FILES} t/minicrypto.c @@ -120,6 +127,23 @@ SET(TEST_EXES test-minicrypto.t) SET(PTLSBENCH_LIBS picotls-minicrypto picotls-core) +IF (WITH_AEGIS) + FIND_PACKAGE(aegis) + IF (aegis_FOUND) + INCLUDE_DIRECTORIES(${AEGIS_INCLUDE_DIR}) + IF (EXISTS "${AEGIS_INCLUDE_DIR}/aegis.h") + MESSAGE(STATUS "Enabling AEGIS support (library found in ${aegis_DIR})") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DPTLS_HAVE_AEGIS=1") + SET(AEGIS_LIBRARIES ${aegis_LIBRARIES}) + TARGET_LINK_LIBRARIES(test-minicrypto.t ${AEGIS_LIBRARIES}) + ELSE() + MESSAGE(FATAL_ERROR "libaegis found, but aegis.h not found - Define AEGIS_INCLUDE_DIR accordingly") + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "libaegis not found") + ENDIF() +ENDIF() + FIND_PACKAGE(OpenSSL) BORINGSSL_ADJUST() @@ -127,12 +151,13 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1")) MESSAGE(STATUS " Enabling OpenSSL support") INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) ADD_LIBRARY(picotls-openssl lib/openssl.c) - TARGET_LINK_LIBRARIES(picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} picotls-core ${CMAKE_DL_LIBS}) + TARGET_LINK_LIBRARIES(picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} picotls-core ${CMAKE_DL_LIBS}) ADD_EXECUTABLE(cli t/cli.c lib/pembase64.c) TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core) ADD_EXECUTABLE(test-openssl.t ${MINICRYPTO_LIBRARY_FILES} + ${MINICRYPTO_AEGIS_FILES} lib/cifra.c lib/cifra/x25519.c lib/cifra/chacha20.c @@ -147,9 +172,9 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1")) ${CORE_TEST_FILES} t/openssl.c) SET_TARGET_PROPERTIES(test-openssl.t PROPERTIES COMPILE_FLAGS "-DPTLS_MEMORY_DEBUG=1") - TARGET_LINK_LIBRARIES(test-openssl.t ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) + TARGET_LINK_LIBRARIES(test-openssl.t ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} ${CMAKE_DL_LIBS}) - LIST(APPEND PTLSBENCH_LIBS picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${CMAKE_DL_LIBS}) + LIST(APPEND PTLSBENCH_LIBS picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} ${CMAKE_DL_LIBS}) SET(TEST_EXES ${TEST_EXES} test-openssl.t) ELSE () @@ -225,8 +250,8 @@ IF (BUILD_FUZZER) LINK_FLAGS "-fsanitize=fuzzer") ENDIF (OSS_FUZZ) - TARGET_LINK_LIBRARIES(fuzz-asn1 picotls-minicrypto picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${LIB_FUZZER}) - TARGET_LINK_LIBRARIES(fuzz-server-hello picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${LIB_FUZZER}) - TARGET_LINK_LIBRARIES(fuzz-client-hello picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${LIB_FUZZER}) + TARGET_LINK_LIBRARIES(fuzz-asn1 picotls-minicrypto picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} ${LIB_FUZZER}) + TARGET_LINK_LIBRARIES(fuzz-server-hello picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} ${LIB_FUZZER}) + TARGET_LINK_LIBRARIES(fuzz-client-hello picotls-core picotls-openssl ${OPENSSL_CRYPTO_LIBRARIES} ${AEGIS_LIBRARIES} ${LIB_FUZZER}) ENDIF() diff --git a/README.md b/README.md index 5bb0e3a64..3f4570e9b 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Picotls is a [TLS 1.3 (RFC 8446)](https://tools.ietf.org/html/rfc8446) protocol * "OpenSSL" backend using libcrypto for crypto and X.509 operations * "minicrypto" backend using [cifra](https://github.com/ctz/cifra) for most crypto and [micro-ecc](https://github.com/kmackay/micro-ecc) for secp256r1 * ["fusion" AES-GCM engine, optimized for QUIC and other protocols that use short AEAD blocks](https://github.com/h2o/picotls/pull/310) + * [libaegis](https://github.com/jedisct1/libaegis) for the AEGIS AEADs * support for PSK, PSK-DHE resumption using 0-RTT * API for dealing directly with TLS handshake messages (essential for QUIC) * supported extensions: @@ -23,8 +24,8 @@ License and the cryptographic algorithms supported by the crypto bindings are as | Binding | License | Key Exchange | Certificate | AEAD cipher | |:-----:|:-----:|:-----:|:-----:|:-----:| -| minicrypto | [CC0](https://github.com/ctz/cifra/) / [2-clause BSD](https://github.com/kmackay/micro-ecc) | secp256r1, x25519 | ECDSA (secp256r1)1 | AES-128-GCM, chacha20-poly1305 | -| OpenSSL | OpenSSL | secp256r1, secp384r1, secp521r1, x25519 | RSA, ECDSA (secp256r1, secp384r1, secp521r1), ed25519 | AES-128-GCM, AES-256-GCM, chacha20-poly1305 | +| minicrypto | [CC0](https://github.com/ctz/cifra/) / [2-clause BSD](https://github.com/kmackay/micro-ecc) | secp256r1, x25519 | ECDSA (secp256r1)1 | AES-128-GCM, chacha20-poly1305, AEGIS-128L (using libaegis), AEGIS-256 (using libaegis) | +| OpenSSL | OpenSSL | secp256r1, secp384r1, secp521r1, x25519 | RSA, ECDSA (secp256r1, secp384r1, secp521r1), ed25519 | AES-128-GCM, AES-256-GCM, chacha20-poly1305, AEGIS-128L (using libaegis), AEGIS-256 (using libaegis) | Note 1: Minicrypto binding is capable of signing a handshake using the certificate's key, but cannot verify a signature sent by the peer. diff --git a/include/picotls.h b/include/picotls.h index 2d829cc89..b701e780b 100644 --- a/include/picotls.h +++ b/include/picotls.h @@ -91,6 +91,18 @@ extern "C" { #define PTLS_CHACHA20POLY1305_CONFIDENTIALITY_LIMIT UINT64_MAX /* at least 2^64 */ #define PTLS_CHACHA20POLY1305_INTEGRITY_LIMIT UINT64_C(0x1000000000) /* 2^36 */ +#define PTLS_AEGIS128L_KEY_SIZE 16 +#define PTLS_AEGIS128L_IV_SIZE 16 +#define PTLS_AEGIS128L_TAG_SIZE 16 +#define PTLS_AEGIS128L_CONFIDENTIALITY_LIMIT UINT64_MAX /* at least 2^64 */ +#define PTLS_AEGIS128L_INTEGRITY_LIMIT UINT64_C(0x1000000000000) /* 2^48 */ + +#define PTLS_AEGIS256_KEY_SIZE 32 +#define PTLS_AEGIS256_IV_SIZE 32 +#define PTLS_AEGIS256_TAG_SIZE 16 +#define PTLS_AEGIS256_CONFIDENTIALITY_LIMIT UINT64_MAX /* at least 2^64 */ +#define PTLS_AEGIS256_INTEGRITY_LIMIT UINT64_C(0x1000000000000) /* 2^48 */ + #define PTLS_BLOWFISH_KEY_SIZE 16 #define PTLS_BLOWFISH_BLOCK_SIZE 8 @@ -104,7 +116,7 @@ extern "C" { #define PTLS_SHA512_DIGEST_SIZE 64 #define PTLS_MAX_SECRET_SIZE 32 -#define PTLS_MAX_IV_SIZE 16 +#define PTLS_MAX_IV_SIZE 32 #define PTLS_MAX_DIGEST_SIZE 64 /* versions */ @@ -118,6 +130,10 @@ extern "C" { #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_AEGIS128L_SHA256 0x1307 +#define PTLS_CIPHER_SUITE_NAME_AEGIS128L_SHA256 "TLS_AEGIS_128L_SHA256" /* TLS/1.2 cipher-suites that we support (for compatibility, OpenSSL names are used) */ #define PTLS_CIPHER_SUITE_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xc02b diff --git a/include/picotls/minicrypto.h b/include/picotls/minicrypto.h index af0c71466..ca3a31d9d 100644 --- a/include/picotls/minicrypto.h +++ b/include/picotls/minicrypto.h @@ -47,9 +47,18 @@ extern ptls_key_exchange_algorithm_t *ptls_minicrypto_key_exchanges[]; extern ptls_cipher_algorithm_t ptls_minicrypto_aes128ecb, ptls_minicrypto_aes256ecb, ptls_minicrypto_aes128ctr, ptls_minicrypto_aes256ctr, ptls_minicrypto_chacha20; extern ptls_aead_algorithm_t ptls_minicrypto_aes128gcm, ptls_minicrypto_aes256gcm, ptls_minicrypto_chacha20poly1305; +#ifdef PTLS_HAVE_AEGIS +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_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; +#endif extern ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[]; +extern ptls_cipher_suite_t *ptls_minicrypto_cipher_suites_all[]; typedef struct st_ptls_asn1_pkcs8_private_key_t { ptls_iovec_t vec; diff --git a/include/picotls/openssl.h b/include/picotls/openssl.h index e0761ed08..987b9b1f2 100644 --- a/include/picotls/openssl.h +++ b/include/picotls/openssl.h @@ -85,6 +85,7 @@ extern ptls_hash_algorithm_t ptls_openssl_sha512; extern ptls_cipher_suite_t ptls_openssl_aes128gcmsha256; extern ptls_cipher_suite_t ptls_openssl_aes256gcmsha384; extern ptls_cipher_suite_t *ptls_openssl_cipher_suites[]; +extern ptls_cipher_suite_t *ptls_openssl_cipher_suites_all[]; extern ptls_cipher_suite_t *ptls_openssl_tls12_cipher_suites[]; #if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 @@ -93,6 +94,13 @@ extern ptls_aead_algorithm_t ptls_openssl_chacha20poly1305; extern ptls_cipher_suite_t ptls_openssl_chacha20poly1305sha256; #endif +#ifdef PTLS_HAVE_AEGIS +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; +#endif + extern ptls_cipher_suite_t ptls_openssl_tls12_ecdhe_rsa_aes128gcmsha256; extern ptls_cipher_suite_t ptls_openssl_tls12_ecdhe_ecdsa_aes128gcmsha256; extern ptls_cipher_suite_t ptls_openssl_tls12_ecdhe_rsa_aes256gcmsha384; diff --git a/lib/cifra.c b/lib/cifra.c index b41d3bc0d..d51f2b703 100644 --- a/lib/cifra.c +++ b/lib/cifra.c @@ -23,5 +23,24 @@ #include "picotls.h" #include "picotls/minicrypto.h" -ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = {&ptls_minicrypto_aes256gcmsha384, &ptls_minicrypto_aes128gcmsha256, - &ptls_minicrypto_chacha20poly1305sha256, NULL}; +ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = {// ciphers used with sha384 (must be first) + &ptls_minicrypto_aes256gcmsha384, + + // ciphers used with sha256 + &ptls_minicrypto_aes128gcmsha256, + &ptls_minicrypto_chacha20poly1305sha256, + NULL}; + +ptls_cipher_suite_t *ptls_minicrypto_cipher_suites_all[] = {// ciphers used with sha384 (must be first) +#ifdef PTLS_HAVE_AEGIS + &ptls_minicrypto_aegis256sha384, +#endif + &ptls_minicrypto_aes256gcmsha384, + + // ciphers used with sha256 +#ifdef PTLS_HAVE_AEGIS + &ptls_minicrypto_aegis128lsha256, +#endif + &ptls_minicrypto_aes128gcmsha256, + &ptls_minicrypto_chacha20poly1305sha256, + NULL}; diff --git a/lib/cifra/libaegis.c b/lib/cifra/libaegis.c new file mode 100644 index 000000000..0b4af9349 --- /dev/null +++ b/lib/cifra/libaegis.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 Frank Denis + * + * 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 "../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, + NULL, + NULL, + PTLS_AEGIS128L_KEY_SIZE, + PTLS_AEGIS128L_IV_SIZE, + PTLS_AEGIS128L_TAG_SIZE, + { 0, 0 }, + 0, + 0, + sizeof(struct aegis128l_context_t), + aegis128l_setup_crypto}; +ptls_cipher_suite_t ptls_minicrypto_aegis128lsha256 = {.id = PTLS_CIPHER_SUITE_AEGIS128L_SHA256, + .name = PTLS_CIPHER_SUITE_NAME_AEGIS128L_SHA256, + .aead = &ptls_minicrypto_aegis128l, + .hash = &ptls_minicrypto_sha256}; + +ptls_aead_algorithm_t ptls_minicrypto_aegis256 = {"AEGIS-256", + PTLS_AEGIS256_CONFIDENTIALITY_LIMIT, + PTLS_AEGIS256_INTEGRITY_LIMIT, + NULL, + NULL, + PTLS_AEGIS256_KEY_SIZE, + PTLS_AEGIS256_IV_SIZE, + PTLS_AEGIS256_TAG_SIZE, + { 0, 0 }, + 0, + 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, + .aead = &ptls_minicrypto_aegis256, + .hash = &ptls_minicrypto_sha384}; diff --git a/lib/libaegis.h b/lib/libaegis.h new file mode 100644 index 000000000..ec78a4bb1 --- /dev/null +++ b/lib/libaegis.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2023 Frank Denis + * + * 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 + +#include "picotls.h" + +// AEGIS-128L + +struct aegis128l_context_t { + ptls_aead_context_t super; + aegis128l_state st; + uint8_t key[PTLS_AEGIS128L_KEY_SIZE]; + uint8_t static_iv[PTLS_AEGIS128L_IV_SIZE]; +}; + +static void aegis128l_get_iv(ptls_aead_context_t *_ctx, void *iv) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + + memcpy(iv, ctx->static_iv, sizeof(ctx->static_iv)); +} + +static void aegis128l_set_iv(ptls_aead_context_t *_ctx, const void *iv) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + + memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv)); +} + +static void aegis128l_init(ptls_aead_context_t *_ctx, uint64_t seq, const void *aad, size_t aadlen) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + uint8_t iv[PTLS_AEGIS128L_IV_SIZE]; + + ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); + + aegis128l_state_init(&ctx->st, (const uint8_t *)aad, aadlen, iv, ctx->key); + + return; +} + +static size_t aegis128l_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + size_t written; + + aegis128l_state_encrypt_update(&ctx->st, (uint8_t *)output, inlen + aegis128l_TAILBYTES_MAX, &written, (const uint8_t *)input, inlen); + + return written; +} + +static size_t aegis128l_encrypt_final(ptls_aead_context_t *_ctx, void *output) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + size_t written; + + aegis128l_state_encrypt_final(&ctx->st, (uint8_t *)output, aegis128l_TAILBYTES_MAX + PTLS_AEGIS128L_TAG_SIZE, &written, PTLS_AEGIS128L_TAG_SIZE); + + return written; +} + +static size_t aegis128l_decrypt_oneshot(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, uint64_t seq, + const void *aad, size_t aadlen) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + uint8_t iv[PTLS_AEGIS128L_IV_SIZE] = {0}; + + if (inlen < PTLS_AEGIS128L_TAG_SIZE) { + return SIZE_MAX; + } + + ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); + + if (aegis128l_decrypt((uint8_t *)output, (const uint8_t *)input, inlen, PTLS_AEGIS128L_TAG_SIZE, (const uint8_t *)aad, aadlen, + iv, ctx->key) != 0) { + return SIZE_MAX; + } + + return inlen - PTLS_AEGIS128L_TAG_SIZE; +} + +static void aegis128l_dispose_crypto(ptls_aead_context_t *_ctx) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + + ptls_clear_memory(ctx->key, sizeof(ctx->key)); + + return; +} + +static int aegis128l_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv) +{ + struct aegis128l_context_t *ctx = (struct aegis128l_context_t *)_ctx; + + ctx->super.dispose_crypto = aegis128l_dispose_crypto; + ctx->super.do_get_iv = aegis128l_get_iv; + ctx->super.do_set_iv = aegis128l_set_iv; + + if (is_enc) { + ctx->super.do_encrypt_init = aegis128l_init; + ctx->super.do_encrypt_update = aegis128l_encrypt_update; + ctx->super.do_encrypt_final = aegis128l_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 = aegis128l_decrypt_oneshot; + } + + memcpy(ctx->key, key, sizeof(ctx->key)); + memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv)); + + return 0; +} + +// AEGIS-256 + +struct aegis256_context_t { + ptls_aead_context_t super; + aegis256_state st; + uint8_t key[PTLS_AEGIS256_KEY_SIZE]; + uint8_t static_iv[PTLS_AEGIS256_IV_SIZE]; +}; + +static void aegis256_get_iv(ptls_aead_context_t *_ctx, void *iv) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + + memcpy(iv, ctx->static_iv, sizeof(ctx->static_iv)); +} + +static void aegis256_set_iv(ptls_aead_context_t *_ctx, const void *iv) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + + memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv)); +} + +static void aegis256_init(ptls_aead_context_t *_ctx, uint64_t seq, const void *aad, size_t aadlen) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + uint8_t iv[PTLS_AEGIS256_IV_SIZE] = {0}; + + ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); + + aegis256_state_init(&ctx->st, (const uint8_t *)aad, aadlen, iv, ctx->key); + + return; +} + +static size_t aegis256_encrypt_update(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + size_t written; + + aegis256_state_encrypt_update(&ctx->st, (uint8_t *)output, inlen + aegis256_TAILBYTES_MAX, &written, (const uint8_t *)input, inlen); + + return written; +} + +static size_t aegis256_encrypt_final(ptls_aead_context_t *_ctx, void *output) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + size_t written; + + aegis256_state_encrypt_final(&ctx->st, (uint8_t *)output, aegis256_TAILBYTES_MAX + PTLS_AEGIS256_TAG_SIZE, &written, PTLS_AEGIS256_TAG_SIZE); + + return written; +} + +static size_t aegis256_decrypt_oneshot(ptls_aead_context_t *_ctx, void *output, const void *input, size_t inlen, uint64_t seq, + const void *aad, size_t aadlen) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + uint8_t iv[PTLS_AEGIS256_IV_SIZE]; + + if (inlen < PTLS_AEGIS256_TAG_SIZE) { + return SIZE_MAX; + } + + ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); + + if (aegis256_decrypt((uint8_t *)output, (const uint8_t *)input, inlen, PTLS_AEGIS256_TAG_SIZE, (const uint8_t *)aad, aadlen, iv, + ctx->key) != 0) { + return SIZE_MAX; + } + + return inlen - PTLS_AEGIS256_TAG_SIZE; +} + +static void aegis256_dispose_crypto(ptls_aead_context_t *_ctx) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + + ptls_clear_memory(ctx->key, sizeof(ctx->key)); + + return; +} + +static int aegis256_setup_crypto(ptls_aead_context_t *_ctx, int is_enc, const void *key, const void *iv) +{ + struct aegis256_context_t *ctx = (struct aegis256_context_t *)_ctx; + + ctx->super.dispose_crypto = aegis256_dispose_crypto; + ctx->super.do_get_iv = aegis256_get_iv; + ctx->super.do_set_iv = aegis256_set_iv; + + if (is_enc) { + ctx->super.do_encrypt_init = aegis256_init; + ctx->super.do_encrypt_update = aegis256_encrypt_update; + ctx->super.do_encrypt_final = aegis256_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 = aegis256_decrypt_oneshot; + } + + memcpy(ctx->key, key, sizeof(ctx->key)); + memcpy(ctx->static_iv, iv, sizeof(ctx->static_iv)); + + return 0; +} diff --git a/lib/openssl.c b/lib/openssl.c index 0cd39767f..b03533909 100644 --- a/lib/openssl.c +++ b/lib/openssl.c @@ -52,6 +52,9 @@ #ifdef OPENSSL_IS_BORINGSSL #include "./chacha20poly1305.h" #endif +#ifdef PTLS_HAVE_AEGIS +#include "./libaegis.h" +#endif #ifdef _WINDOWS #ifndef _CRT_SECURE_NO_WARNINGS @@ -2161,12 +2164,78 @@ ptls_cipher_suite_t ptls_openssl_tls12_ecdhe_ecdsa_chacha20poly1305sha256 = { .aead = &ptls_openssl_chacha20poly1305, .hash = &ptls_openssl_sha256}; #endif -ptls_cipher_suite_t *ptls_openssl_cipher_suites[] = {&ptls_openssl_aes256gcmsha384, &ptls_openssl_aes128gcmsha256, + + +#if PTLS_HAVE_AEGIS +ptls_aead_algorithm_t ptls_openssl_aegis128l = { + .name = "AEGIS-128L", + .confidentiality_limit = PTLS_AEGIS128L_CONFIDENTIALITY_LIMIT, + .integrity_limit = PTLS_AEGIS128L_INTEGRITY_LIMIT, + .ctr_cipher = NULL, + .ecb_cipher = NULL, + .key_size = PTLS_AEGIS128L_KEY_SIZE, + .iv_size = PTLS_AEGIS128L_IV_SIZE, + .tag_size = PTLS_AEGIS128L_TAG_SIZE, + .tls12 = { .fixed_iv_size = 0, .record_iv_size = 0 }, + .non_temporal = 0, + .align_bits = 0, + .context_size = sizeof(struct aegis128l_context_t), + .setup_crypto = aegis128l_setup_crypto, +}; +ptls_cipher_suite_t ptls_openssl_aegis128lsha256 = {.id = PTLS_CIPHER_SUITE_AEGIS128L_SHA256, + .name = PTLS_CIPHER_SUITE_NAME_AEGIS128L_SHA256, + .aead = &ptls_openssl_aegis128l, + .hash = &ptls_openssl_sha256}; + +ptls_aead_algorithm_t ptls_openssl_aegis256 = { + .name = "AEGIS-256", + .confidentiality_limit = PTLS_AEGIS256_CONFIDENTIALITY_LIMIT, + .integrity_limit = PTLS_AEGIS256_INTEGRITY_LIMIT, + .ctr_cipher = NULL, + .ecb_cipher = NULL, + .key_size = PTLS_AEGIS256_KEY_SIZE, + .iv_size = PTLS_AEGIS256_IV_SIZE, + .tag_size = PTLS_AEGIS256_TAG_SIZE, + .tls12 = { .fixed_iv_size = 0, .record_iv_size = 0 }, + .non_temporal = 0, + .align_bits = 0, + .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, + .aead = &ptls_openssl_aegis256, + .hash = &ptls_openssl_sha384}; +#endif + + + +ptls_cipher_suite_t *ptls_openssl_cipher_suites[] = {// ciphers used with sha384 (must be first) + &ptls_openssl_aes256gcmsha384, + + // ciphers used with sha256 + &ptls_openssl_aes128gcmsha256, #if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 &ptls_openssl_chacha20poly1305sha256, #endif NULL}; +ptls_cipher_suite_t *ptls_openssl_cipher_suites_all[] = {// ciphers used with sha384 (must be first) +#if PTLS_HAVE_AEGIS + &ptls_openssl_aegis256sha384, +#endif + &ptls_openssl_aes256gcmsha384, + + // ciphers used with sha256 +#if PTLS_HAVE_AEGIS + &ptls_openssl_aegis128lsha256, +#endif + &ptls_openssl_aes128gcmsha256, +#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 + &ptls_openssl_chacha20poly1305sha256, +#endif + NULL}; + ptls_cipher_suite_t *ptls_openssl_tls12_cipher_suites[] = {&ptls_openssl_tls12_ecdhe_rsa_aes128gcmsha256, &ptls_openssl_tls12_ecdhe_ecdsa_aes128gcmsha256, &ptls_openssl_tls12_ecdhe_rsa_aes256gcmsha384, diff --git a/lib/picotls.c b/lib/picotls.c index 14ea227da..906bc97f6 100644 --- a/lib/picotls.c +++ b/lib/picotls.c @@ -39,6 +39,10 @@ #include "picotls-probes.h" #endif +#ifdef PTLS_HAVE_AEGIS +#include +#endif + #define PTLS_MAX_PLAINTEXT_RECORD_SIZE 16384 #define PTLS_MAX_ENCRYPTED_RECORD_SIZE (16384 + 256) diff --git a/t/cli.c b/t/cli.c index ef3c1ed81..e5d1473d9 100644 --- a/t/cli.c +++ b/t/cli.c @@ -558,6 +558,10 @@ int main(int argc, char **argv) #if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 MATCH(chacha20poly1305sha256); #endif +#if PTLS_HAVE_AEGIS + MATCH(aegis128lsha256); + MATCH(aegis256sha384); +#endif #undef MATCH if (cipher_suites[i] == NULL) { fprintf(stderr, "unknown cipher-suite: %s\n", optarg); @@ -635,7 +639,7 @@ int main(int argc, char **argv) if (cipher_suites[0] == NULL) { size_t i; for (i = 0; ptls_openssl_cipher_suites[i] != NULL; ++i) - cipher_suites[i] = ptls_openssl_cipher_suites[i]; + cipher_suites[i] = ptls_openssl_cipher_suites_all[i]; } if (argc != 2) { fprintf(stderr, "missing host and port\n"); diff --git a/t/minicrypto.c b/t/minicrypto.c index 17a05d26f..cf49ce811 100644 --- a/t/minicrypto.c +++ b/t/minicrypto.c @@ -64,7 +64,7 @@ static void test_secp256r1_sign(void) static void test_hrr(void) { ptls_key_exchange_algorithm_t *client_keyex[] = {&ptls_minicrypto_x25519, &ptls_minicrypto_secp256r1, NULL}; - ptls_context_t client_ctx = {ptls_minicrypto_random_bytes, &ptls_get_time, client_keyex, ptls_minicrypto_cipher_suites}; + ptls_context_t client_ctx = {ptls_minicrypto_random_bytes, &ptls_get_time, client_keyex, ptls_minicrypto_cipher_suites_all}; ptls_t *client, *server; ptls_buffer_t cbuf, sbuf, decbuf; uint8_t cbuf_small[16384], sbuf_small[16384], decbuf_small[16384]; @@ -153,7 +153,7 @@ int main(int argc, char **argv) ptls_context_t ctxbuf = {ptls_minicrypto_random_bytes, &ptls_get_time, ptls_minicrypto_key_exchanges, - ptls_minicrypto_cipher_suites, + ptls_minicrypto_cipher_suites_all, {&cert, 1}, {{NULL}}, NULL, diff --git a/t/openssl.c b/t/openssl.c index 4ca49aa38..b3188ff0a 100644 --- a/t/openssl.c +++ b/t/openssl.c @@ -555,16 +555,18 @@ int main(int argc, char **argv) ptls_context_t openssl_ctx = {.random_bytes = ptls_openssl_random_bytes, .get_time = &ptls_get_time, .key_exchanges = ptls_openssl_key_exchanges, - .cipher_suites = ptls_openssl_cipher_suites, + .cipher_suites = ptls_openssl_cipher_suites_all, .tls12_cipher_suites = ptls_openssl_tls12_cipher_suites, .certificates = {&cert, 1}, .ech = {.client = {.ciphers = ptls_openssl_hpke_cipher_suites, .kems = ptls_openssl_hpke_kems}, .server = {.create_opener = &ech_create_opener, .retry_configs = {(uint8_t *)ECH_CONFIG_LIST, sizeof(ECH_CONFIG_LIST) - 1}}}, .sign_certificate = &openssl_sign_certificate.super}; - assert(openssl_ctx.cipher_suites[0]->hash->digest_size == 48); /* sha384 */ ptls_context_t openssl_ctx_sha256only = openssl_ctx; - ++openssl_ctx_sha256only.cipher_suites; + while (openssl_ctx_sha256only.cipher_suites[0]->hash->digest_size != 32) { + assert(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 */ ctx = ctx_peer = &openssl_ctx; diff --git a/t/picotls.c b/t/picotls.c index 6116de02b..ecca51d3c 100644 --- a/t/picotls.c +++ b/t/picotls.c @@ -494,6 +494,34 @@ static void test_chacha20poly1305(void) } } +#ifdef PTLS_HAVE_AEGIS +static void test_aegis128l(void) +{ + ptls_cipher_suite_t *cs = find_cipher(ctx, PTLS_CIPHER_SUITE_AEGIS128L_SHA256), + *cs_peer = find_cipher(ctx_peer, PTLS_CIPHER_SUITE_AEGIS128L_SHA256); + + 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); + } +} + +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); + + 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); + } +} +#endif + static void test_ffx(void) { static uint8_t ffx_test_source[32] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', @@ -2112,6 +2140,10 @@ void test_picotls(void) subtest("aes128gcm", test_aes128gcm); subtest("aes256gcm", test_aes256gcm); subtest("chacha20poly1305", test_chacha20poly1305); +#ifdef PTLS_HAVE_AEGIS + subtest("aegis-128l", test_aegis128l); + subtest("aegis-256", test_aegis256); +#endif subtest("aes128ecb", test_aes128ecb); subtest("aes256ecb", test_aes256ecb); subtest("aes128ctr", test_aes128ctr); diff --git a/t/ptlsbench.c b/t/ptlsbench.c index 62ac3595e..1b27607eb 100644 --- a/t/ptlsbench.c +++ b/t/ptlsbench.c @@ -253,6 +253,10 @@ static ptls_bench_entry_t aead_list[] = { {"minicrypto", "aes128gcm", &ptls_minicrypto_aes128gcm, &ptls_minicrypto_sha256, 0}, {"minicrypto", "aes256gcm", &ptls_minicrypto_aes256gcm, &ptls_minicrypto_sha384, 0}, {"minicrypto", "chacha20poly1305", &ptls_minicrypto_chacha20poly1305, &ptls_minicrypto_sha256, 1}, +#ifdef PTLS_HAVE_AEGIS + {"minicrypto", "aegis128l", &ptls_minicrypto_aegis128l, &ptls_minicrypto_sha256, 1}, + {"minicrypto", "aegis256", &ptls_minicrypto_aegis256, &ptls_minicrypto_sha384, 1}, +#endif #ifdef _WINDOWS {"ptlsbcrypt", "aes128gcm", &ptls_bcrypt_aes128gcm, &ptls_bcrypt_sha256, 1}, {"ptlsbcrypt", "aes256gcm", &ptls_bcrypt_aes256gcm, &ptls_bcrypt_sha384, 1},