diff --git a/CMakeLists.txt b/CMakeLists.txt index dc146a8f7..f42f21a9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -204,7 +204,7 @@ IF (WITH_MBEDTLS) 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_LIBRARY(picotls-mbedtls lib/mbedtls.c lib/mbedtls_sign.c) ADD_EXECUTABLE(test-mbedtls.t deps/picotest/picotest.c ${CORE_TEST_FILES} diff --git a/include/picotls/mbedtls.h b/include/picotls/mbedtls.h index b64924694..62fd382d3 100644 --- a/include/picotls/mbedtls.h +++ b/include/picotls/mbedtls.h @@ -60,6 +60,9 @@ extern ptls_key_exchange_algorithm_t *ptls_mbedtls_key_exchanges[]; void ptls_mbedtls_random_bytes(void *buf, size_t len); +int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname); +void ptls_mbedtls_dispose_sign_certificate(ptls_sign_certificate_t *_self); + #ifdef __cplusplus } #endif diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index 2e167ae8f..de06175f3 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -36,7 +36,7 @@ #include #include #include -#include "ptls_mbedtls.h" +/* #include "ptls_mbedtls.h" */ typedef struct st_ptls_mbedtls_signature_scheme_t { uint16_t scheme_id; @@ -58,6 +58,7 @@ static const ptls_mbedtls_signature_scheme_t rsa_signature_schemes[] = {{PTLS_SI {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384, PSA_ALG_SHA_384}, {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512, PSA_ALG_SHA_512}, {UINT16_MAX, PSA_ALG_NONE}}; + static const ptls_mbedtls_signature_scheme_t secp256r1_signature_schemes[] = { {PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256, PSA_ALG_SHA_256}, {UINT16_MAX, PSA_ALG_NONE}}; static const ptls_mbedtls_signature_scheme_t secp384r1_signature_schemes[] = { @@ -69,6 +70,8 @@ static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {{PTL #if defined(MBEDTLS_PEM_PARSE_C) +/* Mapping of MBEDTLS APIs to Picotls */ + static int ptls_mbedtls_parse_der_length(const unsigned char *pem_buf, size_t pem_len, size_t *px, size_t *pl) { int ret = 0; @@ -94,8 +97,6 @@ static int ptls_mbedtls_parse_der_length(const unsigned char *pem_buf, size_t pe static int ptls_mbedtls_parse_ecdsa_field(const unsigned char *pem_buf, size_t pem_len, size_t *key_index, size_t *key_length) { int ret = 0; - int param_index_index = -1; - int param_length = 0; size_t x = 0; // const unsigned char head = { 0x30, l-2, 0x02, 0x01, 0x01, 0x04 } @@ -166,6 +167,7 @@ static int ptls_mbedtls_parse_eddsa_key(const unsigned char *pem_buf, size_t pem if (x + l_key != *key_index + *key_length) { ret = -1; } else { + *key_index = x; *key_length = l_key; } @@ -241,7 +243,6 @@ int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, s /* At that point the oid has been identified. * The next parameter is an octet string containing the key info. */ - size_t l = 0; if (x + 2 > pem_len || pem_buf[x++] != 0x04) { ret = -1; } else { @@ -292,6 +293,7 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) { return MBEDTLS_ERR_PK_PASSWORD_REQUIRED; } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) { + return ret; } #endif /* MBEDTLS_RSA_C */ @@ -352,6 +354,7 @@ const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(cons const uint16_t *algorithms, size_t num_algorithms) { const ptls_mbedtls_signature_scheme_t *scheme; + /* select the algorithm, driven by server-isde preference of `available` */ for (scheme = available; scheme->scheme_id != UINT16_MAX; ++scheme) { for (size_t i = 0; i != num_algorithms; ++i) { @@ -446,6 +449,7 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p /* First prepare the hash */ unsigned char hash_buffer[PTLS_MAX_DIGEST_SIZE]; unsigned char *hash_value = NULL; + size_t hash_length = 0; if (scheme->hash_algo == PSA_ALG_NONE) { @@ -476,7 +480,6 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p } if ((ret = ptls_buffer_reserve(outbuf, nb_bytes)) == 0) { size_t signature_length = 0; - if (psa_sign_hash(self->key_id, sign_algo, hash_value, hash_length, outbuf->base + outbuf->off, nb_bytes, &signature_length) != 0) { ret = PTLS_ERROR_INCOMPATIBLE_KEY; @@ -602,7 +605,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) unsigned char *buf; mbedtls_pem_context pem = {0}; mbedtls_pk_type_t pk_type = 0; - mbedtls_svc_key_id_t key_id = 0; + /* mbedtls_svc_key_id_t key_id = 0; */ size_t key_length = 0; size_t key_index = 0; ptls_mbedtls_sign_certificate_t *signer = (ptls_mbedtls_sign_certificate_t *)malloc(sizeof(ptls_mbedtls_sign_certificate_t)); diff --git a/t/mbedtls.c b/t/mbedtls.c index af3ec95fc..1ea3416bf 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -34,6 +34,22 @@ #include "../deps/picotest/picotest.h" #include "test.h" +typedef struct st_ptls_mbedtls_signature_scheme_t { + uint16_t scheme_id; + psa_algorithm_t hash_algo; +} ptls_mbedtls_signature_scheme_t; + +typedef struct st_ptls_mbedtls_sign_certificate_t { + ptls_sign_certificate_t super; + mbedtls_svc_key_id_t key_id; + psa_key_attributes_t attributes; + const ptls_mbedtls_signature_scheme_t *schemes; +} ptls_mbedtls_sign_certificate_t; + +int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, ptls_async_job_t **async, + uint16_t *selected_algorithm, ptls_buffer_t *outbuf, ptls_iovec_t input, + const uint16_t *algorithms, size_t num_algorithms); + static int random_trial() { /* The random test is just trying to check that we call the API properly. @@ -89,6 +105,157 @@ static void test_key_exchanges(void) subtest("x25519", test_x25519); } +/* +Sign certificate implements a callback: + +if ((ret = tls->ctx->sign_certificate->cb( +tls->ctx->sign_certificate, tls, tls->is_server ? &tls->server.async_job : NULL, &algo, sendbuf, +ptls_iovec_init(data, datalen), signature_algorithms != NULL ? signature_algorithms->list : NULL, +signature_algorithms != NULL ? signature_algorithms->count : 0)) != 0) { + +or: + +static int sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, ptls_async_job_t **async, uint16_t *selected_algorithm, +ptls_buffer_t *outbuf, ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms) + +The callback "super" type is ptls_sign_certificate_t, defined by the macro: +PTLS_CALLBACK_TYPE(int, sign_certificate, ptls_t *tls, ptls_async_job_t **async, uint16_t *selected_algorithm, +ptls_buffer_t *output, ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms); + +The notation is simple: input buffer and supported algorithms as input, selected algo and output buffer as output. +Output buffer is already partially filled. + +*/ + +#define ASSET_RSA_KEY "t/assets/rsa/key.pem" +#define ASSET_RSA_PKCS8_KEY "t/assets/rsa-pkcs8/key.pem" +#define ASSET_SECP256R1_KEY "t/assets/secp256r1/key.pem" +#define ASSET_SECP384R1_KEY "t/assets/secp384r1/key.pem" +#define ASSET_SECP521R1_KEY "t/assets/secp521r1/key.pem" +#define ASSET_SECP256R1_PKCS8_KEY "t/assets/secp256r1-pkcs8/key.pem" + +int test_load_one_der_key(char const *path) +{ + int ret = -1; + unsigned char hash[32]; + const unsigned char h0[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}; + ptls_context_t ctx = {0}; + + ret = ptls_mbedtls_load_private_key(&ctx, path); + if (ret != 0) { + printf("Cannot create sign_certificate from: %s\n", path); + ret = -1; + } else if (ctx.sign_certificate == NULL) { + printf("Sign_certificate not set in ptls context for: %s\n", path); + ret = -1; + } else { + /* Try to sign something */ + int ret; + ptls_mbedtls_sign_certificate_t *signer = + (ptls_mbedtls_sign_certificate_t *)(((unsigned char *)ctx.sign_certificate) - + offsetof(struct st_ptls_mbedtls_sign_certificate_t, super)); + /* get the key algorithm */ + ptls_buffer_t outbuf; + uint8_t outbuf_smallbuf[256]; + ptls_iovec_t input = {hash, sizeof(hash)}; + uint16_t selected_algorithm = 0; + int num_algorithms = 0; + uint16_t algorithms[16]; + memcpy(hash, h0, 32); + while (signer->schemes[num_algorithms].scheme_id != UINT16_MAX && num_algorithms < 16) { + algorithms[num_algorithms] = signer->schemes[num_algorithms].scheme_id; + num_algorithms++; + } + + ptls_buffer_init(&outbuf, outbuf_smallbuf, sizeof(outbuf_smallbuf)); + + ret = ptls_mbedtls_sign_certificate(ctx.sign_certificate, NULL, NULL, &selected_algorithm, &outbuf, input, algorithms, + num_algorithms); + if (ret == 0) { + printf("Signed a message, key: %s, scheme: %x, signature size: %zu\n", path, selected_algorithm, outbuf.off); + } else { + printf("Sign failed, key: %s, scheme: %x, signature size: %zu\n", path, selected_algorithm, outbuf.off); + } + ptls_buffer_dispose(&outbuf); + ptls_mbedtls_dispose_sign_certificate(&signer->super); + } + return ret; +} + +static void test_load_rsa_key() +{ + int ret = test_load_one_der_key(ASSET_RSA_KEY); + + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_secp256r1_key() +{ + int ret = test_load_one_der_key(ASSET_SECP256R1_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_secp384r1_key() +{ + int ret = test_load_one_der_key(ASSET_SECP384R1_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_secp521r1_key() +{ + int ret = test_load_one_der_key(ASSET_SECP521R1_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_secp256r1_pkcs8_key() +{ + int ret = test_load_one_der_key(ASSET_SECP256R1_PKCS8_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_rsa_pkcs8_key() +{ + int ret = test_load_one_der_key(ASSET_RSA_PKCS8_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +void test_sign_certificate(void) +{ + subtest("load rsa key", test_load_rsa_key); + subtest("load secp256r1 key", test_load_secp256r1_key); + subtest("load secp384r1 key", test_load_secp384r1_key); + subtest("load secp521r1 key", test_load_secp521r1_key); + subtest("load secp521r1-pkcs8 key", test_load_secp256r1_pkcs8_key); + subtest("load rsa-pkcs8 key", test_load_rsa_pkcs8_key); + + /* we do not test EDDSA keys, because they are not yet supported */ +} + DEFINE_FFX_AES128_ALGORITHMS(mbedtls); DEFINE_FFX_CHACHA20_ALGORITHMS(mbedtls); @@ -143,6 +310,9 @@ int main(int argc, char **argv) ctx_peer = &mbedtls_ctx; subtest("minicrypto vs.", test_picotls); + /* test the sign certificate */ + subtest("sign certificate", test_sign_certificate); + /* Deinitialize the PSA crypto library. */ mbedtls_psa_crypto_free();