From b39818a4c396c7a44ed660eefb433832db09494e Mon Sep 17 00:00:00 2001 From: doublex <274624+doublex@users.noreply.github.com> Date: Tue, 21 Jan 2025 20:44:46 +0100 Subject: [PATCH] minicrypto API --- include/picotls/minicrypto.h | 202 ++++++++++--- lib/cifra.c | 42 --- lib/minicrypto-pem.c | 350 ---------------------- lib/minicrypto.c | 549 +++++++++++++++++++++++++++++++++++ 4 files changed, 714 insertions(+), 429 deletions(-) delete mode 100644 lib/cifra.c delete mode 100644 lib/minicrypto-pem.c create mode 100644 lib/minicrypto.c diff --git a/include/picotls/minicrypto.h b/include/picotls/minicrypto.h index a6202d026..1a3fad698 100644 --- a/include/picotls/minicrypto.h +++ b/include/picotls/minicrypto.h @@ -26,51 +26,179 @@ extern "C" { #endif +#include #include "picotls.h" -#define SECP256R1_PRIVATE_KEY_SIZE 32 -#define SECP256R1_PUBLIC_KEY_SIZE 65 /* including the header */ -#define SECP256R1_SHARED_SECRET_SIZE 32 +/* defaults */ +#ifndef PTLS_USE_OPENSSL +#define PTLS_USE_OPENSSL 0 +#endif +#ifndef PTLS_HAVE_AEGIS +#define PTLS_HAVE_AEGIS 0 +#endif -typedef struct st_ptls_minicrypto_secp256r1sha256_sign_certificate_t { - ptls_sign_certificate_t super; - uint8_t key[SECP256R1_PRIVATE_KEY_SIZE]; -} ptls_minicrypto_secp256r1sha256_sign_certificate_t; +/* minicrypto */ +extern ptls_hash_algorithm_t ptls_minicrypto_sha256, ptls_minicrypto_sha384, ptls_minicrypto_sha5; +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; +extern ptls_cipher_suite_t ptls_minicrypto_aes128gcmsha256, ptls_minicrypto_aes256gcmsha384, + ptls_minicrypto_chacha20poly1305sha256; +extern ptls_key_exchange_algorithm_t ptls_minicrypto_secp256r1, + ptls_minicrypto_x25519; void ptls_minicrypto_random_bytes(void *buf, size_t len); -int ptls_minicrypto_init_secp256r1sha256_sign_certificate(ptls_minicrypto_secp256r1sha256_sign_certificate_t *self, - ptls_iovec_t key); - -extern ptls_key_exchange_algorithm_t ptls_minicrypto_secp256r1, ptls_minicrypto_x25519; -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; +/* convenience interface */ +#if PTLS_USE_OPENSSL +#include "openssl.h" + +#define ptls_crypto_sha256 ptls_openssl_sha256 +#define ptls_crypto_sha384 ptls_openssl_sha384 +#define ptls_crypto_sha512 ptls_openssl_sha512 + +#define ptls_crypto_aes128ecb ptls_openssl_aes128ecb +#define ptls_crypto_aes128ctr ptls_openssl_aes128ctr +#define ptls_crypto_aes128gcm ptls_openssl_aes128gcm +#define ptls_crypto_aes128gcmsha256 ptls_openssl_aes128gcmsha256 + +#define ptls_crypto_aes256ecb ptls_openssl_aes256ecb +#define ptls_crypto_aes256ctr ptls_openssl_aes256ctr +#define ptls_crypto_aes256gcm ptls_openssl_aes256gcm +#define ptls_crypto_aes256gcmsha384 ptls_openssl_aes256gcmsha384 + +#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 +#define PTLS_CRYPTO_HAVE_CHACHA20_POLY1305 1 +#define ptls_crypto_chacha20 ptls_openssl_chacha20 +#define ptls_crypto_chacha20poly1305 ptls_openssl_chacha20poly1305 +#define ptls_crypto_chacha20poly1305sha256 ptls_openssl_chacha20poly1305sha256 +#endif + +#if PTLS_HAVE_AEGIS +#define PTLS_CRYPTO_HAVE_AEGIS 1 +#define ptls_crypto_aegis128l ptls_openssl_aegis128l +#define ptls_crypto_aegis256 ptls_openssl_aegis256 +#define ptls_crypto_aegis128lsha256 ptls_openssl_aegis128lsha256 +#define ptls_crypto_aegis256sha512 ptls_openssl_aegis256sha512 +#endif + +#define ptls_crypto_secp256r1 ptls_openssl_secp256r1 +#if PTLS_OPENSSL_HAVE_SECP384R1 +#define PTLS_CRYPTO_HAVE_SECP384R1 1 +#define ptls_crypto_secp384r1 ptls_openssl_secp384r1 +#endif + +#if PTLS_OPENSSL_HAVE_SECP521R1 +#define PTLS_CRYPTO_HAVE_SECP521R1 1 +#define ptls_crypto_secp521r1 ptls_openssl_secp521r1 +#endif + +#if PTLS_OPENSSL_HAVE_X25519 +#define PTLS_CRYPTO_HAVE_X25519 1 +#define ptls_crypto_x25519 ptls_openssl_x25519 #endif -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_aegis256sha512; + +#if PTLS_OPENSSL_HAVE_X25519MLKEM768 +#define PTLS_CRYPTO_HAVE_X25519MLKEM768 1 +extern ptls_key_exchange_algorithm_t ptls_openssl_x25519mlkem768; +#define ptls_openssl_x25519mlkem768 ptls_crypto_x25519mlkem768 +#endif + +#define ptls_crypto_random_bytes ptls_openssl_random_bytes + +/* crypto available */ +void ptls_openssl_init_cipher_suites(ptls_context_t *ptls_ctx); +void ptls_openssl_init_key_exchanges(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_cipher_suites ptls_openssl_init_cipher_suites +#define ptls_crypto_init_key_exchanges ptls_openssl_init_key_exchanges + +/* init sign */ +int ptls_openssl_init_sign_file(ptls_context_t *ptls_ctx, const char *privatekey_file, const char *certificate_file); +int ptls_openssl_init_sign_der(ptls_context_t *ptls_ctx, const ptls_iovec_t *privatekey, const ptls_iovec_t certificate[], size_t certificate_length); +void ptls_openssl_dispose_sign(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_sign_file ptls_openssl_init_sign_file +#define ptls_crypto_init_sign_der ptls_openssl_init_sign_der +#define ptls_crypto_dispose_sign ptls_openssl_dispose_sign + +/* init verify */ +int ptls_openssl_init_verify_file(ptls_context_t *ptls_ctx, const char *truststore_file); +int ptls_openssl_init_verify_der(ptls_context_t *ptls_ctx, const ptls_iovec_t truststore[], size_t truststore_length); +void ptls_openssl_dispose_verify(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_verify_file ptls_openssl_init_verify_file +#define ptls_crypto_init_verify_der ptls_openssl_init_verify_der +#define ptls_crypto_dispose_verify ptls_openssl_dispose_verify + +#else + +#define ptls_crypto_sha256 ptls_minicrypto_sha256 +#define ptls_crypto_sha384 ptls_minicrypto_sha384 +#define ptls_crypto_sha512 ptls_minicrypto_sha512 + +#define ptls_crypto_aes128ecb ptls_minicrypto_aes128ecb +#define ptls_crypto_aes128ctr ptls_minicrypto_aes128ctr +#define ptls_crypto_aes128gcm ptls_minicrypto_aes128gcm +#define ptls_crypto_aes128gcmsha256 ptls_minicrypto_aes128gcmsha256 + +#define ptls_crypto_aes256ecb ptls_minicrypto_aes256ecb +#define ptls_crypto_aes256ctr ptls_minicrypto_aes256ctr +#define ptls_crypto_aes256gcm ptls_minicrypto_aes256gcm +#define ptls_crypto_aes256gcmsha384 ptls_minicrypto_aes256gcmsha384 + +#define PTLS_CRYPTO_HAVE_CHACHA20_POLY1305 1 +#define ptls_crypto_chacha20 ptls_minicrypto_chacha20 +#define ptls_crypto_chacha20poly1305 ptls_minicrypto_chacha20poly1305 +#define ptls_crypto_chacha20poly1305sha256 ptls_minicrypto_chacha20poly1305sha256 + +#if PTLS_HAVE_AEGIS +extern ptls_aead_algorithm_t ptls_minicrypto_aegis128l, + ptls_minicrypto_aegis256; +extern ptls_cipher_suite_t ptls_minicrypto_aegis128lsha256, + ptls_minicrypto_aegis256sha512; +#define PTLS_CRYPTO_HAVE_AEGIS 1 +#define ptls_crypto_aegis128l ptls_minicrypto_aegis128l +#define ptls_crypto_aegis256 ptls_minicrypto_aegis256 +#define ptls_crypto_aegis128lsha256 ptls_minicrypto_aegis128lsha256 +#define ptls_crypto_aegis256sha512 ptls_minicrypto_aegis256sha512 +#endif + +#define ptls_crypto_secp256r1 ptls_minicrypto_secp256r1 +/* +#define PTLS_CRYPTO_HAVE_SECP384R1 1 +#define ptls_crypto_secp384r1 ptls_minicrypto_secp384r1 +#define PTLS_CRYPTO_HAVE_SECP521R1 1 +#define ptls_crypto_secp521r1 ptls_minicrypto_secp521r1 +*/ + +#define PTLS_CRYPTO_HAVE_X25519 1 +#define ptls_crypto_x25519 ptls_minicrypto_x25519 + +#define ptls_crypto_random_bytes ptls_minicrypto_random_bytes + +/* crypto available */ +void ptls_minicrypto_init_cipher_suites(ptls_context_t *ptls_ctx); +void ptls_minicrypto_init_key_exchanges(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_cipher_suites ptls_minicrypto_init_cipher_suites +#define ptls_crypto_init_key_exchanges ptls_minicrypto_init_key_exchanges + +/* init sign */ +int ptls_minicrypto_init_sign_file(ptls_context_t *ptls_ctx, const char *privatekey_file, const char *certificate_file); +int ptls_minicrypto_init_sign_der(ptls_context_t *ptls_ctx, const ptls_iovec_t *privatekey, const ptls_iovec_t certificate[], size_t certificate_length); +void ptls_minicrypto_dispose_sign(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_sign_file ptls_minicrypto_init_sign_file +#define ptls_crypto_init_sign_der ptls_minicrypto_init_sign_der +#define ptls_crypto_dispose_sign ptls_minicrypto_dispose_sign + +/* init verify */ +int ptls_minicrypto_init_verify_file(ptls_context_t *ptls_ctx, const char *truststore_file); +int ptls_minicrypto_init_verify_der(ptls_context_t *ptls_ctx, const ptls_iovec_t truststore[], size_t truststore_length); +void ptls_minicrypto_dispose_verify(ptls_context_t *ptls_ctx); +#define ptls_crypto_init_verify_file ptls_minicrypto_init_verify_file +#define ptls_crypto_init_verify_der ptls_minicrypto_init_verify_der +#define ptls_crypto_dispose_verify ptls_minicrypto_dispose_verify + #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; - size_t algorithm_index; - uint32_t algorithm_length; - size_t parameters_index; - uint32_t parameters_length; - size_t key_data_index; - uint32_t key_data_length; -} ptls_asn1_pkcs8_private_key_t; - -int ptls_minicrypto_load_private_key(ptls_context_t *ctx, char const *pem_fname); #ifdef __cplusplus } diff --git a/lib/cifra.c b/lib/cifra.c deleted file mode 100644 index 6be752fa0..000000000 --- a/lib/cifra.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2016 DeNA Co., Ltd., Kazuho Oku - * - * 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" -#include "picotls/minicrypto.h" - -ptls_cipher_suite_t *ptls_minicrypto_cipher_suites[] = { // ciphers used with sha512 and 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 sha512 and sha384 (must be first) -#ifdef PTLS_HAVE_AEGIS - &ptls_minicrypto_aegis256sha512, -#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/minicrypto-pem.c b/lib/minicrypto-pem.c deleted file mode 100644 index d9e8dc584..000000000 --- a/lib/minicrypto-pem.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (c) 2017,2018 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. - */ -#include -#include -#include -#include -#ifdef _WINDOWS -#include "wincompat.h" -#else -#include -#endif -#include "picotls.h" -#include "picotls/minicrypto.h" -#include "picotls/asn1.h" -#include "picotls/pembase64.h" - -/* - * This function could be declared as static, but we want to access it - * in the unit tests. - */ -size_t ptls_minicrypto_asn1_decode_private_key(ptls_asn1_pkcs8_private_key_t *pkey, int *decode_error, - ptls_minicrypto_log_ctx_t *log_ctx) -{ - uint8_t *bytes = pkey->vec.base; - size_t bytes_max = pkey->vec.len; - - /* read the ASN1 messages */ - size_t byte_index = 0; - uint32_t seq0_length = 0; - size_t last_byte0; - uint32_t seq1_length = 0; - size_t last_byte1 = 0; - uint32_t oid_length; - size_t last_oid_byte; - uint32_t key_data_length; - size_t key_data_last; - - /* start with sequence */ - byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq0_length, NULL, &last_byte0, - decode_error, log_ctx); - - if (*decode_error == 0 && bytes_max != last_byte0) { - byte_index = ptls_asn1_error_message("Length larger than message", bytes_max, byte_index, 0, log_ctx); - *decode_error = PTLS_ERROR_BER_EXCESSIVE_LENGTH; - } - - if (*decode_error == 0) { - /* get first component: version, INTEGER, expect value 0 */ - if (byte_index + 3 > bytes_max) { - byte_index = ptls_asn1_error_message("Cannot find key version", bytes_max, byte_index, 0, log_ctx); - *decode_error = PTLS_ERROR_INCORRECT_PEM_KEY_VERSION; - } else if (bytes[byte_index] != 0x02 || bytes[byte_index + 1] != 0x01 || bytes[byte_index + 2] != 0x00) { - *decode_error = PTLS_ERROR_INCORRECT_PEM_KEY_VERSION; - byte_index = ptls_asn1_error_message("Incorrect PEM Version", bytes_max, byte_index, 0, log_ctx); - } else { - byte_index += 3; - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, " Version = 1,\n"); - } - } - } - - if (*decode_error == 0) { - /* open embedded sequence */ - byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq1_length, NULL, &last_byte1, - decode_error, log_ctx); - } - - if (*decode_error == 0) { - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, " Algorithm Identifier:\n"); - } - /* get length of OID */ - byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte1, byte_index, 0x06, &oid_length, NULL, &last_oid_byte, - decode_error, log_ctx); - - if (*decode_error == 0) { - if (log_ctx != NULL) { - /* print the OID value */ - log_ctx->fn(log_ctx->ctx, " Algorithm:"); - ptls_asn1_dump_content(bytes + byte_index, oid_length, 0, log_ctx); - log_ctx->fn(log_ctx->ctx, ",\n"); - } - pkey->algorithm_index = byte_index; - pkey->algorithm_length = oid_length; - byte_index += oid_length; - } - } - - if (*decode_error == 0) { - /* get parameters, ANY */ - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, " Parameters:\n"); - } - - if (last_byte1 <= byte_index) { - pkey->parameters_index = 0; - pkey->parameters_length = 0; - } else { - pkey->parameters_index = byte_index; - - pkey->parameters_length = - (uint32_t)ptls_asn1_validation_recursive(bytes + byte_index, last_byte1 - byte_index, decode_error, 2, log_ctx); - if (*decode_error == 0) { - byte_index += pkey->parameters_length; - } - } - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, "\n"); - } - /* close sequence */ - if (*decode_error == 0 && byte_index != last_byte1) { - byte_index = ptls_asn1_error_message("Length larger than element", bytes_max, byte_index, 2, log_ctx); - *decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT; - } - } - - /* get octet string, key */ - if (*decode_error == 0) { - byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte0, byte_index, 0x04, &key_data_length, NULL, - &key_data_last, decode_error, log_ctx); - - if (*decode_error == 0) { - pkey->key_data_index = byte_index; - pkey->key_data_length = key_data_length; - byte_index += key_data_length; - - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, " Key data (%d bytes):\n", key_data_length); - - (void)ptls_asn1_validation_recursive(bytes + pkey->key_data_index, key_data_length, decode_error, 1, log_ctx); - log_ctx->fn(log_ctx->ctx, "\n"); - } - } - } - - if (*decode_error == 0 && byte_index != last_byte0) { - byte_index = ptls_asn1_error_message("Length larger than element", bytes_max, byte_index, 0, log_ctx); - *decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT; - } - - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, "\n"); - } - - return byte_index; -} - -static int ptls_pem_parse_private_key(char const *pem_fname, ptls_asn1_pkcs8_private_key_t *pkey, - ptls_minicrypto_log_ctx_t *log_ctx) -{ - size_t nb_keys = 0; - int ret = ptls_load_pem_objects(pem_fname, "PRIVATE KEY", &pkey->vec, 1, &nb_keys); - - if (ret == 0) { - if (nb_keys != 1) { - ret = PTLS_ERROR_PEM_LABEL_NOT_FOUND; - } - } - - if (ret == 0 && nb_keys == 1) { - int decode_error = 0; - - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, "\nFound PRIVATE KEY, length = %d bytes\n", (int)pkey->vec.len); - } - - (void)ptls_minicrypto_asn1_decode_private_key(pkey, &decode_error, log_ctx); - - if (decode_error != 0) { - ret = decode_error; - } - } - - return ret; -} - -static const uint8_t ptls_asn1_algorithm_ecdsa[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01}; - -static const uint8_t ptls_asn1_curve_secp256r1[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07}; - -static int ptls_set_ecdsa_private_key(ptls_context_t *ctx, ptls_asn1_pkcs8_private_key_t *pkey, ptls_minicrypto_log_ctx_t *log_ctx) -{ - uint8_t *bytes = pkey->vec.base + pkey->parameters_index; - size_t bytes_max = pkey->parameters_length; - size_t byte_index = 0; - uint8_t *curve_id = NULL; - uint32_t curve_id_length = 0; - int decode_error = 0; - uint32_t seq_length; - size_t last_byte = 0; - uint8_t *ecdsa_key_data = NULL; - uint32_t ecdsa_key_data_length = 0; - size_t ecdsa_key_data_last = 0; - - /* We expect the parameters to include just the curve ID */ - - byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x06, &curve_id_length, NULL, &last_byte, - &decode_error, log_ctx); - - if (decode_error == 0 && bytes_max != last_byte) { - byte_index = ptls_asn1_error_message("Length larger than parameters", bytes_max, byte_index, 0, log_ctx); - decode_error = PTLS_ERROR_BER_EXCESSIVE_LENGTH; - } - - if (decode_error == 0) { - curve_id = bytes + byte_index; - - if (log_ctx != NULL) { - /* print the OID value */ - log_ctx->fn(log_ctx->ctx, "Curve: "); - ptls_asn1_dump_content(curve_id, curve_id_length, 0, log_ctx); - log_ctx->fn(log_ctx->ctx, "\n"); - } - } - - /* We expect the key data to follow the ECDSA structure per RFC 5915 */ - bytes = pkey->vec.base + pkey->key_data_index; - bytes_max = pkey->key_data_length; - byte_index = 0; - - /* decode the wrapping sequence */ - if (decode_error == 0) { - byte_index = ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, 0x30, &seq_length, NULL, &last_byte, - &decode_error, log_ctx); - } - - if (decode_error == 0 && bytes_max != last_byte) { - byte_index = ptls_asn1_error_message("Length larger than key data", bytes_max, byte_index, 0, log_ctx); - decode_error = PTLS_ERROR_BER_ELEMENT_TOO_SHORT; - } - - /* verify and skip the version number 1 */ - if (decode_error == 0) { - /* get first component: version, INTEGER, expect value 0 */ - if (byte_index + 3 > bytes_max) { - byte_index = ptls_asn1_error_message("Cannot find ECDSA Key Data Version", bytes_max, byte_index, 0, log_ctx); - decode_error = PTLS_ERROR_INCORRECT_ASN1_ECDSA_KEY_SYNTAX; - } else if (bytes[byte_index] != 0x02 || bytes[byte_index + 1] != 0x01 || bytes[byte_index + 2] != 0x01) { - decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_KEY_VERSION; - byte_index = ptls_asn1_error_message("Incorrect ECDSA Key Data Version", bytes_max, byte_index, 0, log_ctx); - } else { - byte_index += 3; - if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, "ECDSA Version = 1,\n"); - } - } - } - - /* obtain the octet string that contains the ECDSA private key */ - if (decode_error == 0) { - byte_index = ptls_asn1_get_expected_type_and_length(bytes, last_byte, byte_index, 0x04, &ecdsa_key_data_length, NULL, - &ecdsa_key_data_last, &decode_error, log_ctx); - - if (decode_error == 0) { - ecdsa_key_data = bytes + byte_index; - } - } - - /* If everything is fine, associate the ECDSA key with the context */ - if (curve_id_length == sizeof(ptls_asn1_curve_secp256r1) && curve_id != NULL && - memcmp(curve_id, ptls_asn1_curve_secp256r1, sizeof(ptls_asn1_curve_secp256r1)) == 0) { - if (SECP256R1_PRIVATE_KEY_SIZE != ecdsa_key_data_length) { - decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_KEYSIZE; - if (log_ctx != NULL) { - /* print the OID value */ - log_ctx->fn(log_ctx->ctx, "Wrong SECP256R1 key length, %d instead of %d.\n", ecdsa_key_data_length, - SECP256R1_PRIVATE_KEY_SIZE); - } - } else { - ptls_minicrypto_secp256r1sha256_sign_certificate_t *minicrypto_sign_certificate; - - minicrypto_sign_certificate = (ptls_minicrypto_secp256r1sha256_sign_certificate_t *)malloc( - sizeof(ptls_minicrypto_secp256r1sha256_sign_certificate_t)); - - if (minicrypto_sign_certificate == NULL) { - decode_error = PTLS_ERROR_NO_MEMORY; - } else { - memset(minicrypto_sign_certificate, 0, sizeof(ptls_minicrypto_secp256r1sha256_sign_certificate_t)); - decode_error = ptls_minicrypto_init_secp256r1sha256_sign_certificate( - minicrypto_sign_certificate, ptls_iovec_init(ecdsa_key_data, ecdsa_key_data_length)); - } - if (decode_error == 0) { - ctx->sign_certificate = &minicrypto_sign_certificate->super; - - if (log_ctx != NULL) { - /* print the OID value */ - log_ctx->fn(log_ctx->ctx, "Initialized SECP512R1 signing key with %d bytes.\n", ecdsa_key_data_length); - } - } else if (log_ctx != NULL) { - log_ctx->fn(log_ctx->ctx, "SECP512R1 init with %d bytes returns %d.\n", ecdsa_key_data_length, decode_error); - } - } - } else { - decode_error = PTLS_ERROR_INCORRECT_PEM_ECDSA_CURVE; - if (log_ctx != NULL) { - /* print the OID value */ - log_ctx->fn(log_ctx->ctx, "Curve is not supported for signatures.\n"); - } - } - - return decode_error; -} - -int ptls_minicrypto_load_private_key(ptls_context_t *ctx, char const *pem_fname) -{ - ptls_asn1_pkcs8_private_key_t pkey = {{0}}; - int ret = ptls_pem_parse_private_key(pem_fname, &pkey, NULL); - - if (ret != 0) - goto err; - - /* Check that this is the expected key type. - * At this point, the minicrypto library only supports ECDSA keys. - * In theory, we could add support for RSA keys at some point. - */ - if (pkey.algorithm_length != sizeof(ptls_asn1_algorithm_ecdsa) || - memcmp(pkey.vec.base + pkey.algorithm_index, ptls_asn1_algorithm_ecdsa, sizeof(ptls_asn1_algorithm_ecdsa)) != 0) { - ret = -1; - goto err; - } - - ret = ptls_set_ecdsa_private_key(ctx, &pkey, NULL); - -err: - if (pkey.vec.base) { - ptls_clear_memory(pkey.vec.base, pkey.vec.len); - free(pkey.vec.base); - } - return ret; -} diff --git a/lib/minicrypto.c b/lib/minicrypto.c new file mode 100644 index 000000000..831cdd8be --- /dev/null +++ b/lib/minicrypto.c @@ -0,0 +1,549 @@ +/* + * Copyright (c) 2025 DeNA Co., Ltd., Kazuho Oku et al. + * + * 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 "minicrypto.h" +#include + +#ifndef PTLS_HAVE_FUSION +#if defined(__AES__) && defined(__VAES__) && defined(__VPCLMULQDQ__) && defined(__PCLMUL__) && defined(__AVX2__) +#define PTLS_HAVE_FUSION 1 +#else +#define PTLS_HAVE_FUSION 0 +#endif +#endif +#if PTLS_HAVE_FUSION +#include "fusion.h" +#endif + +#if PTLS_USE_OPENSSL + +#include +#include "openssl.h" +#include +#include + +#if PTLS_HAVE_AEGIS +#include "libaegis.h" +#endif + +void ptls_openssl_init_cipher_suites(ptls_context_t *ptls_ctx) +{ + static const ptls_cipher_suite_t *cipher_suites[] = { + /* ciphers used with sha512 and sha384 */ +#if PTLS_HAVE_AEGIS + &ptls_openssl_aegis256sha512, +#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, + }; +#if PTLS_HAVE_FUSION + static const ptls_cipher_suite_t ptls_fusion_aes128gcmsha256 = { + .id = PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, + .name = PTLS_CIPHER_SUITE_NAME_AES_128_GCM_SHA256, + .aead = &ptls_fusion_aes128gcm, + .hash = &ptls_openssl_sha256, + }; + static const ptls_cipher_suite_t ptls_fusion_aes256gcmsha384 = { + .id = PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, + .name = PTLS_CIPHER_SUITE_NAME_AES_256_GCM_SHA384, + .aead = &ptls_fusion_aes256gcm, + .hash = &ptls_openssl_sha384, + }; + static const ptls_cipher_suite_t *cipher_suites_fusion[] = { +#if PTLS_HAVE_AEGIS + &ptls_openssl_aegis256sha512, +#endif + &ptls_fusion_aes256gcmsha384, +#if PTLS_HAVE_AEGIS + &ptls_openssl_aegis128lsha256, +#endif + &ptls_fusion_aes128gcmsha256, +#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 + &ptls_openssl_chacha20poly1305sha256, +#endif + NULL, + }; + if (ptls_fusion_is_supported_by_cpu()) { + ptls_ctx->cipher_suites = cipher_suites_fusion; + return; + } +#endif + ptls_ctx->cipher_suites = cipher_suites; +} + +void ptls_openssl_init_key_exchanges(ptls_context_t *ptls_ctx) +{ + static const ptls_key_exchange_algorithm_t *key_exchanges[] = { +#if PTLS_OPENSSL_HAVE_X25519 + &ptls_openssl_x25519, +#endif + &ptls_openssl_secp256r1, + &ptls_openssl_secp384r1, + &ptls_openssl_secp521r1, + NULL, + }; + ptls_ctx->key_exchanges = key_exchanges; +} + +int ptls_openssl_init_sign_file(ptls_context_t *ptls_ctx, const char *privatekey_file, const char *certificate_file) +{ + int status; + FILE *fp; + EVP_PKEY *pkey; + STACK_OF(X509_INFO) *pemcerts; + size_t i, numcerts; + + /* context */ + ptls_openssl_sign_certificate_t *sign_ctx = (ptls_openssl_sign_certificate_t*)malloc(sizeof(ptls_openssl_sign_certificate_t)); + if (sign_ctx == NULL) { + return PTLS_ERROR_NO_MEMORY; + } + memset(sign_ctx, 0, sizeof(ptls_openssl_sign_certificate_t)); + + /* privatekey */ + fp = fopen(privatekey_file, "rb"); + if (fp == NULL) { + free(sign_ctx); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL); + if (pkey == NULL) + if (fp == NULL) { + free(sign_ctx); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + status = ptls_openssl_init_sign_certificate(sign_ctx, pkey); + if (status != 0) { + free(sign_ctx); + EVP_PKEY_free(pkey); + return status; + } + ptls_ctx->sign_certificate = &sign_ctx->super; + + /* certificates */ + fp = fopen(certificate_file, "rb"); + if (fp == NULL) { + free(sign_ctx); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + pemcerts = PEM_X509_INFO_read(fp, NULL, NULL, NULL); + if (pemcerts == NULL) { + free(sign_ctx); + fclose(fp); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + numcerts = sk_X509_INFO_num(pemcerts); + ptls_ctx->certificates.list = (ptls_iovec_t*)malloc(sizeof(ptls_iovec_t)*numcerts); + ptls_ctx->certificates.count = 0; + for( i=0; i < sk_X509_INFO_num(pemcerts); ++i ) + { + int length; + ptls_iovec_t *dst; + unsigned char *p; + X509_INFO *itmp = sk_X509_INFO_value( pemcerts, i ); + if (itmp->x509 == NULL) { + continue; + } + length = i2d_X509(itmp->x509, NULL); + if (length == 0) { + continue; + } + dst = &ptls_ctx->certificates.list[ptls_ctx->certificates.count]; + ptls_ctx->certificates.count += 1; + dst->base = (uint8_t*)malloc(length); + p = dst->base; + dst->len = i2d_X509(itmp->x509, &p); + } + sk_X509_INFO_pop_free(pemcerts, X509_INFO_free); + + /* callback internally increased reference counter */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_PKEY_free(pkey); +#endif + + return 0; +} + +int ptls_openssl_init_sign_der(ptls_context_t *ptls_ctx, const ptls_iovec_t *privatekey, const ptls_iovec_t certificate[], size_t certificate_length) +{ + size_t i; + int status; + EVP_PKEY *pkey; + BIO *cbio; + + /* context */ + ptls_openssl_sign_certificate_t *sign_ctx = (ptls_openssl_sign_certificate_t*)malloc(sizeof(ptls_openssl_sign_certificate_t)); + if (sign_ctx == NULL) { + return PTLS_ERROR_NO_MEMORY; + } + memset(sign_ctx, 0, sizeof(ptls_openssl_sign_certificate_t)); + + /* privatekey from DER */ + cbio = BIO_new_mem_buf(privatekey->base, privatekey->len); + if (cbio == NULL) { + free(sign_ctx); + return PTLS_ERROR_NO_MEMORY; + } + pkey = d2i_PrivateKey_bio(cbio, NULL); + if (pkey == NULL) { + free(sign_ctx); + BIO_free(cbio); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + status = ptls_openssl_init_sign_certificate(sign_ctx, pkey); + if (status != 0) { + free(sign_ctx); + BIO_free(cbio); + EVP_PKEY_free(pkey); + return status; + } + ptls_ctx->sign_certificate = &sign_ctx->super; + BIO_free(cbio); + + /* certificates already DER */ + ptls_ctx->certificates.list = (ptls_iovec_t*)calloc(certificate_length, sizeof(ptls_iovec_t)); + ptls_ctx->certificates.count = 0; + for (i=0; i < certificate_length; ++i) { + ptls_iovec_t *dst; + dst = &ptls_ctx->certificates.list[ptls_ctx->certificates.count]; + ptls_ctx->certificates.count += 1; + dst->base = (uint8_t*)malloc(certificate[i].len); + dst->len = certificate[i].len; + memcpy(dst->base, certificate[i].base, dst->len); + } + + /* callback internally increased reference counter */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + EVP_PKEY_free(pkey); +#endif + + return 0; +} + +void ptls_openssl_dispose_sign(ptls_context_t *ptls_ctx) +{ + size_t i; + + ptls_openssl_sign_certificate_t *sign_ctx = (ptls_openssl_sign_certificate_t*)ptls_ctx->sign_certificate; + if (sign_ctx == NULL) { + return; + } + ptls_openssl_dispose_sign_certificate(sign_ctx); + + for (i=0; i < ptls_ctx->certificates.count; ++i) { + free(ptls_ctx->certificates.list[i].base); + } + free(ptls_ctx->certificates.list); + free(sign_ctx); +} + +int ptls_openssl_init_verify_file(ptls_context_t *ptls_ctx, const char *truststore_file) +{ + int status; + X509_STORE *x509_store = NULL; + + /* context */ + ptls_openssl_verify_certificate_t *verify_ctx = (ptls_openssl_verify_certificate_t*)malloc(sizeof(ptls_openssl_verify_certificate_t)); + if (verify_ctx == NULL) { + return PTLS_ERROR_NO_MEMORY; + } + memset(verify_ctx, 0, sizeof(ptls_openssl_verify_certificate_t)); + + /* certificate */ + if (truststore_file != NULL) { + X509_LOOKUP *x509_lookup; + x509_store = X509_STORE_new(); + if (x509_store == NULL) { + free(verify_ctx); + return PTLS_ERROR_NO_MEMORY; + } + x509_lookup = X509_STORE_add_lookup(x509_store, X509_LOOKUP_file()); + status = X509_LOOKUP_load_file(x509_lookup, truststore_file, X509_FILETYPE_PEM); + if (status != 1) { + free(verify_ctx); + X509_STORE_free(x509_store); + return PTLS_ERROR_NO_MEMORY; + } + } + status = ptls_openssl_init_verify_certificate(verify_ctx, x509_store); + if (status != 0) { + free(verify_ctx); + X509_STORE_free(x509_store); + return status; + } + ptls_ctx->verify_certificate = &verify_ctx->super; + + /* callback internally increased reference counter */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + if (x509_store != NULL) { + X509_STORE_free(x509_store); + } +#endif + + return 0; +} + +int ptls_openssl_init_verify_der(ptls_context_t *ptls_ctx, const ptls_iovec_t truststore[], size_t truststore_length) +{ + size_t i; + int status; + X509_STORE *x509_store; + + /* context */ + ptls_openssl_verify_certificate_t *verify_ctx = (ptls_openssl_verify_certificate_t*)malloc(sizeof(ptls_openssl_verify_certificate_t)); + if (verify_ctx == NULL) { + return PTLS_ERROR_NO_MEMORY; + } + memset(verify_ctx, 0, sizeof(ptls_openssl_verify_certificate_t)); + + /* certificates from DER */ + x509_store = X509_STORE_new(); + if (x509_store == NULL) { + free(verify_ctx); + return PTLS_ERROR_NO_MEMORY; + } + for (i=0; i < truststore_length; ++i) { + const unsigned char *cert_der = truststore[i].base; + X509 *x509 = d2i_X509(NULL, &cert_der, truststore[i].len); + if (x509 == NULL) { + continue; + } + X509_STORE_add_cert(x509_store, x509); + X509_free(x509); + } + status = ptls_openssl_init_verify_certificate(verify_ctx, x509_store); + if (status != 0) { + free(verify_ctx); + X509_STORE_free(x509_store); + return status; + } + ptls_ctx->verify_certificate = &verify_ctx->super; + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L + /* callback internally increased reference counter */ + if (x509_store != NULL) { + X509_STORE_free(x509_store); + } +#endif + + return 0; +} + +void ptls_openssl_dispose_verify(ptls_context_t *ptls_ctx) +{ + ptls_openssl_verify_certificate_t *verify_ctx = (ptls_openssl_verify_certificate_t*)ptls_ctx->verify_certificate; + ptls_openssl_dispose_verify_certificate( verify_ctx ); + free(verify_ctx); +} + + +#else + +#include "pembase64.h" + +#if PTLS_HAVE_AEGIS +#include "cifra/libaegis.h" +#endif + +/* import */ +extern ptls_cipher_suite_t ptls_minicrypto_aes128gcmsha256, + ptls_minicrypto_aes256gcmsha384, + ptls_minicrypto_chacha20poly1305sha256; +extern ptls_key_exchange_algorithm_t ptls_minicrypto_secp256r1, + ptls_minicrypto_x25519; +/* sign */ +int ptls_minicrypto_init_sign_certificate(ptls_context_t *ptls_ctx, ptls_iovec_t key); +void ptls_minicrypto_dispose_sign_certificate(ptls_context_t *ptls_ctx); +/* verify */ +int ptls_minicrypto_init_verify_certificate(ptls_context_t *ptls_ctx, const ptls_iovec_t truststore[], size_t truststore_length); +void ptls_minicrypto_dispose_verify_certificate(ptls_context_t *ptls_ctx); + + +/* export */ +void ptls_minicrypto_init_cipher_suites(ptls_context_t *ptls_ctx) +{ + static const ptls_cipher_suite_t *cipher_suites[] = { + /* ciphers used with sha512 and sha384 */ +#if PTLS_HAVE_AEGIS + &ptls_minicrypto_aegis256sha512, +#endif + &ptls_minicrypto_aes256gcmsha384, + /* ciphers used with sha256 */ +#if PTLS_HAVE_AEGIS + &ptls_minicrypto_aegis128lsha256, +#endif + &ptls_minicrypto_aes128gcmsha256, +#if PTLS_OPENSSL_HAVE_CHACHA20_POLY1305 + &ptls_minicrypto_chacha20poly1305sha256, +#endif + NULL, + }; +#if PTLS_HAVE_FUSION + static const ptls_cipher_suite_t ptls_fusion_aes128gcmsha256 = { + .id = PTLS_CIPHER_SUITE_AES_128_GCM_SHA256, + .name = PTLS_CIPHER_SUITE_NAME_AES_128_GCM_SHA256, + .aead = &ptls_fusion_aes128gcm, + .hash = &ptls_minicrypto_sha256, + }; + static const ptls_cipher_suite_t ptls_fusion_aes256gcmsha384 = { + .id = PTLS_CIPHER_SUITE_AES_256_GCM_SHA384, + .name = PTLS_CIPHER_SUITE_NAME_AES_256_GCM_SHA384, + .aead = &ptls_fusion_aes256gcm, + .hash = &ptls_minicrypto_sha384, + }; + static const ptls_cipher_suite_t *cipher_suites_fusion[] = { +#if PTLS_HAVE_AEGIS + &ptls_minicrypto_aegis256sha512, +#endif + &ptls_fusion_aes256gcmsha384, +#if PTLS_HAVE_AEGIS + &ptlsminicrypto_aegis128lsha256, +#endif + &ptls_fusion_aes128gcmsha256, + &ptls_minicrypto_chacha20poly1305sha256, + NULL, + }; + if (ptls_fusion_is_supported_by_cpu()) { + ptls_ctx->cipher_suites = cipher_suites_fusion; + return; + } +#endif + ptls_ctx->cipher_suites = cipher_suites; +} + +void ptls_minicrypto_init_key_exchanges(ptls_context_t *ptls_ctx) +{ + static const ptls_key_exchange_algorithm_t *key_exchanges[] = { + &ptls_minicrypto_secp256r1, + &ptls_minicrypto_x25519, + NULL, + }; + ptls_ctx->key_exchanges = key_exchanges; +} + +#define PTLS_MAX_CERTS_IN_CONTEXT 16 +int ptls_minicrypto_init_sign_file(ptls_context_t *ptls_ctx, const char *privatekey_file, const char *certificate_file) +{ + ptls_iovec_t privatekey_vec = {0}; + ptls_iovec_t certificates_vecs[PTLS_MAX_CERTS_IN_CONTEXT]; + size_t nb_keys = 0, nb_certs = 0; + + /* load */ + int ret = ptls_load_pem_objects(privatekey_file, "PRIVATE KEY", &privatekey_vec, 1, &nb_keys); + if (ret != 0) + return ret; + if (nb_keys != 1) { + ptls_clear_memory(privatekey_vec.base, privatekey_vec.len); + free(privatekey_vec.base); + return PTLS_ERROR_INCOMPATIBLE_KEY; + } + ret = ptls_load_pem_objects(certificate_file, "CERTIFICATE", certificates_vecs, PTLS_MAX_CERTS_IN_CONTEXT, &nb_certs); + if (ret != 0) { + free(privatekey_vec.base); + return PTLS_ERROR_PEM_LABEL_NOT_FOUND; + } + + /* setup */ + ret = ptls_minicrypto_init_sign_der(ptls_ctx, &privatekey_vec, certificates_vecs, nb_certs); + + /* cleanup */ + if (privatekey_vec.base) { + ptls_clear_memory(privatekey_vec.base, privatekey_vec.len); + free(privatekey_vec.base); + } + return ret; +} + +int ptls_minicrypto_init_sign_der(ptls_context_t *ptls_ctx, const ptls_iovec_t *privatekey, const ptls_iovec_t certificate[], size_t certificate_length) +{ + size_t i; + int ret = ptls_minicrypto_init_sign_certificate(ptls_ctx, *privatekey); + if (ret != 0) { + return ret; + } + + ptls_ctx->certificates.list = (ptls_iovec_t*)calloc(certificate_length, sizeof(ptls_iovec_t)); + if (ptls_ctx->certificates.list == NULL) { + return PTLS_ERROR_NO_MEMORY; + } + ptls_ctx->certificates.count = 0; + for (i=0; i < certificate_length; ++i) { + ptls_iovec_t *dst; + dst = &ptls_ctx->certificates.list[ptls_ctx->certificates.count]; + ptls_ctx->certificates.count += 1; + dst->base = (uint8_t*)malloc(certificate[i].len); + dst->len = certificate[i].len; + memcpy(dst->base, certificate[i].base, dst->len); + } + return 0; +} + +void ptls_minicrypto_dispose_sign(ptls_context_t *ptls_ctx) +{ + size_t i; + ptls_minicrypto_dispose_sign_certificate(ptls_ctx); + + for (i=0; i < ptls_ctx->certificates.count; ++i) { + free(ptls_ctx->certificates.list[i].base); + } + free(ptls_ctx->certificates.list); +} + +#define PTLS_MAX_TRUSTCA_IN_CONTEXT 256 +int ptls_minicrypto_init_verify_file(ptls_context_t *ptls_ctx, const char *truststore_file) +{ + /* load */ + ptls_iovec_t truststore_vecs[PTLS_MAX_TRUSTCA_IN_CONTEXT]; + size_t i, nb_certs = 0; + int ret = ptls_load_pem_objects(truststore_file, "CERTIFICATE", truststore_vecs, PTLS_MAX_TRUSTCA_IN_CONTEXT, &nb_certs); + if (ret != 0) { + return PTLS_ERROR_PEM_LABEL_NOT_FOUND; + } + + /* setup */ + ret = ptls_minicrypto_init_verify_der(ptls_ctx, truststore_vecs, nb_certs); + + /* cleanup */ + for (i=0; i < ptls_ctx->certificates.count; ++i) { + free(truststore_vecs[i].base); + } + return ret; +} + +int ptls_minicrypto_init_verify_der(ptls_context_t *ptls_ctx, const ptls_iovec_t truststore[], size_t truststore_length) +{ + return ptls_minicrypto_init_verify_certificate(ptls_ctx, truststore, truststore_length); +} + +void ptls_minicrypto_dispose_verify(ptls_context_t *ptls_ctx) +{ + ptls_minicrypto_dispose_verify_certificate(ptls_ctx); +} + +#endif