Merge branch 'master' into mbed-tls-sign-certificate
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dc146a8..f42f21a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -204,7 +204,7 @@
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 b649246..581c416 100644
--- a/include/picotls/mbedtls.h
+++ b/include/picotls/mbedtls.h
@@ -60,6 +60,9 @@
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 2e167ae..c774cb2 100644
--- a/lib/mbedtls_sign.c
+++ b/lib/mbedtls_sign.c
@@ -1,24 +1,25 @@
/*
- * 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.
- */
+* Copyright (c) 2023, Christian Huitema
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
#ifdef _WINDOWS
#include "wincompat.h"
@@ -38,6 +39,7 @@
#include <psa/crypto_values.h>
#include "ptls_mbedtls.h"
+
typedef struct st_ptls_mbedtls_signature_scheme_t {
uint16_t scheme_id;
psa_algorithm_t hash_algo;
@@ -47,29 +49,33 @@
ptls_sign_certificate_t super;
mbedtls_svc_key_id_t key_id;
psa_key_attributes_t attributes;
- const ptls_mbedtls_signature_scheme_t *schemes;
+ const ptls_mbedtls_signature_scheme_t * schemes;
} ptls_mbedtls_sign_certificate_t;
-static const unsigned char ptls_mbedtls_oid_ec_key[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01};
-static const unsigned char ptls_mbedtls_oid_rsa_key[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01};
-static const unsigned char ptls_mbedtls_oid_ed25519[] = {0x2b, 0x65, 0x70};
+static const unsigned char ptls_mbedtls_oid_ec_key[] = { 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01 };
+static const unsigned char ptls_mbedtls_oid_rsa_key[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01 };
+static const unsigned char ptls_mbedtls_oid_ed25519[] = { 0x2b, 0x65, 0x70 };
-static const ptls_mbedtls_signature_scheme_t rsa_signature_schemes[] = {{PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, PSA_ALG_SHA_256},
- {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 rsa_signature_schemes[] = {
+ {PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256, PSA_ALG_SHA_256},
+ {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[] = {
{PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384, PSA_ALG_SHA_384}, {UINT16_MAX, PSA_ALG_NONE}};
static const ptls_mbedtls_signature_scheme_t secp521r1_signature_schemes[] = {
{PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512, PSA_ALG_SHA_512}, {UINT16_MAX, PSA_ALG_NONE}};
-static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {{PTLS_SIGNATURE_ED25519, PSA_ALG_NONE},
- {UINT16_MAX, PSA_ALG_NONE}};
+static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {
+ {PTLS_SIGNATURE_ED25519, PSA_ALG_NONE}, {UINT16_MAX, PSA_ALG_NONE}};
#if defined(MBEDTLS_PEM_PARSE_C)
-static int ptls_mbedtls_parse_der_length(const unsigned char *pem_buf, size_t pem_len, size_t *px, size_t *pl)
+/* 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;
size_t x = *px;
@@ -91,17 +97,18 @@
return ret;
}
-static int ptls_mbedtls_parse_ecdsa_field(const unsigned char *pem_buf, size_t pem_len, size_t *key_index, size_t *key_length)
+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 }
- if (pem_len < 16 || pem_buf[x++] != 0x30 /* type = sequence */) {
+ if (pem_len < 16 ||
+ pem_buf[x++] != 0x30 /* type = sequence */)
+ {
ret = -1;
- } else {
+ }
+ else {
size_t l = 0;
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l);
@@ -109,11 +116,15 @@
ret = -1;
}
}
- if (ret == 0) {
- if (pem_buf[x++] != 0x02 /* type = int */ || pem_buf[x++] != 0x01 /* length of int = 1 */ ||
- pem_buf[x++] != 0x01 /* version = 1 */ || pem_buf[x++] != 0x04 /*octet string */ || pem_buf[x] + x >= pem_len) {
+ if (ret == 0){
+ if (pem_buf[x++] != 0x02 /* type = int */ ||
+ pem_buf[x++] != 0x01 /* length of int = 1 */ ||
+ pem_buf[x++] != 0x01 /* version = 1 */ ||
+ pem_buf[x++] != 0x04 /*octet string */ ||
+ pem_buf[x] + x >= pem_len) {
ret = -1;
- } else {
+ }
+ else {
*key_index = x + 1;
*key_length = pem_buf[x];
x += 1 + pem_buf[x];
@@ -124,16 +135,19 @@
if (x + pem_buf[x] >= pem_len) {
/* EC parameters extend beyond buffer */
ret = -1;
- } else {
+ }
+ else {
x += pem_buf[x] + 1;
}
}
if (ret == 0 && x < pem_len) {
/* skip the public key parameter */
- if (pem_buf[x++] != 0xa1 || x >= pem_len) {
+ if (pem_buf[x++] != 0xa1 ||
+ x >= pem_len) {
ret = -1;
- } else {
+ }
+ else {
size_t l = 0;
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l);
x += l;
@@ -149,11 +163,12 @@
}
/* On input, key_index points at the "key information" in a
- * "private key" message. For EDDSA, this contains an
- * octet string carrying the key itself. On return, key index
- * and key length are updated to point at the key field.
- */
-static int ptls_mbedtls_parse_eddsa_key(const unsigned char *pem_buf, size_t pem_len, size_t *key_index, size_t *key_length)
+* "private key" message. For EDDSA, this contains an
+* octet string carrying the key itself. On return, key index
+* and key length are updated to point at the key field.
+*/
+static int ptls_mbedtls_parse_eddsa_key(const unsigned char* pem_buf, size_t pem_len,
+ size_t* key_index, size_t* key_length)
{
int ret = 0;
size_t x = *key_index;
@@ -165,7 +180,9 @@
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l_key);
if (x + l_key != *key_index + *key_length) {
ret = -1;
- } else {
+ }
+ else {
+
*key_index = x;
*key_length = l_key;
}
@@ -174,11 +191,12 @@
}
/* If using PKCS8 encoding, the "private key" field contains the
- * same "ecdsa field" found in PEM "EC PRIVATE KEY" files. We
- * use the same parser, but we need to reset indices so they
- * reflect the unwrapped key.
- */
-int ptls_mbedtls_parse_ec_private_key(const unsigned char *pem_buf, size_t pem_len, size_t *key_index, size_t *key_length)
+* same "ecdsa field" found in PEM "EC PRIVATE KEY" files. We
+* use the same parser, but we need to reset indices so they
+* reflect the unwrapped key.
+*/
+int ptls_mbedtls_parse_ec_private_key(const unsigned char* pem_buf, size_t pem_len,
+ size_t* key_index, size_t* key_length)
{
size_t x_offset = 0;
size_t x_len = 0;
@@ -191,8 +209,9 @@
return ret;
}
-int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, size_t *oid_index, size_t *oid_length,
- size_t *key_index, size_t *key_length)
+int test_parse_private_key_field(const unsigned char* pem_buf, size_t pem_len,
+ size_t* oid_index, size_t *oid_length,
+ size_t* key_index, size_t* key_length)
{
int ret = 0;
size_t l_oid = 0;
@@ -202,9 +221,12 @@
size_t x = 0;
/* const unsigned char head = {0x30, l - 2, 0x02, 0x01, 0x00} */
- if (pem_len < 16 || pem_buf[x++] != 0x30 /* type = sequence */) {
+ if (pem_len < 16 ||
+ pem_buf[x++] != 0x30 /* type = sequence */)
+ {
ret = -1;
- } else {
+ }
+ else {
size_t l = 0;
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l);
@@ -213,25 +235,31 @@
}
}
if (ret == 0) {
- if (pem_buf[x++] != 0x02 /* type = int */ || pem_buf[x++] != 0x01 /* length of int = 1 */ ||
- pem_buf[x++] != 0x00 /* version = 0 */ || pem_buf[x++] != 0x30 /* sequence */) {
+ if (pem_buf[x++] != 0x02 /* type = int */ ||
+ pem_buf[x++] != 0x01 /* length of int = 1 */ ||
+ pem_buf[x++] != 0x00 /* version = 0 */ ||
+ pem_buf[x++] != 0x30 /* sequence */){
ret = -1;
- } else {
+ }
+ else {
/* the sequence contains the OID and optional key attributes,
- * which we ignore for now.
- */
+ * which we ignore for now.
+ */
size_t l_seq = 0;
size_t x_seq;
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l_seq);
x_seq = x;
- if (x + l_seq >= pem_len || pem_buf[x++] != 0x06) {
+ if (x + l_seq >= pem_len ||
+ pem_buf[x++] != 0x06) {
ret = -1;
- } else {
+ }
+ else {
l_oid = pem_buf[x++];
x_oid = x;
if (x + l_oid > x_seq + l_seq) {
ret = -1;
- } else {
+ }
+ else {
x = x_seq + l_seq;
}
}
@@ -239,12 +267,13 @@
}
if (ret == 0) {
/* 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) {
+ * The next parameter is an octet string containing the key info.
+ */
+ if (x + 2 > pem_len ||
+ pem_buf[x++] != 0x04){
ret = -1;
- } else {
+ }
+ else {
ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l_key);
x_key = x;
x += l_key;
@@ -261,8 +290,11 @@
return ret;
}
-int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_type, const unsigned char *key, size_t keylen,
- const unsigned char *pwd, size_t pwdlen, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+int ptls_mbedtls_get_der_key(mbedtls_pem_context* pem,
+ mbedtls_pk_type_t * pk_type,
+ const unsigned char* key, size_t keylen,
+ const unsigned char* pwd, size_t pwdlen,
+ int (*f_rng)(void*, unsigned char*, size_t), void* p_rng)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
#if defined(MBEDTLS_PEM_PARSE_C)
@@ -279,19 +311,26 @@
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if (key[keylen - 1] != '\0') {
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
- } else {
- ret = mbedtls_pem_read_buffer(pem, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----", key, pwd, pwdlen,
- &len);
+ }
+ else {
+ ret = mbedtls_pem_read_buffer(pem,
+ "-----BEGIN RSA PRIVATE KEY-----",
+ "-----END RSA PRIVATE KEY-----",
+ key, pwd, pwdlen, &len);
}
if (ret == 0) {
- *pk_type = MBEDTLS_PK_RSA;
+ * pk_type = MBEDTLS_PK_RSA;
return ret;
- } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
+ }
+ else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
- } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
+ }
+ else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
- } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
+ }
+ else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
+
return ret;
}
#endif /* MBEDTLS_RSA_C */
@@ -300,18 +339,24 @@
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if (key[keylen - 1] != '\0') {
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
- } else {
- ret =
- mbedtls_pem_read_buffer(pem, "-----BEGIN EC PRIVATE KEY-----", "-----END EC PRIVATE KEY-----", key, pwd, pwdlen, &len);
+ }
+ else {
+ ret = mbedtls_pem_read_buffer(pem,
+ "-----BEGIN EC PRIVATE KEY-----",
+ "-----END EC PRIVATE KEY-----",
+ key, pwd, pwdlen, &len);
}
if (ret == 0) {
- *pk_type = MBEDTLS_PK_ECKEY;
+ * pk_type = MBEDTLS_PK_ECKEY;
return ret;
- } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
+ }
+ else if (ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) {
return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
- } else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
+ }
+ else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
- } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
+ }
+ else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
return ret;
}
#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
@@ -319,12 +364,17 @@
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if (key[keylen - 1] != '\0') {
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
- } else {
- ret = mbedtls_pem_read_buffer(pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----", key, NULL, 0, &len);
+ }
+ else {
+ ret = mbedtls_pem_read_buffer(pem,
+ "-----BEGIN PRIVATE KEY-----",
+ "-----END PRIVATE KEY-----",
+ key, NULL, 0, &len);
if (ret == 0) {
/* info is unknown */
return ret;
- } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
+ }
+ else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
return ret;
}
}
@@ -333,14 +383,18 @@
/* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
if (key[keylen - 1] != '\0') {
ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
- } else {
- ret = mbedtls_pem_read_buffer(pem, "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----", key,
- NULL, 0, &len);
+ }
+ else {
+ ret = mbedtls_pem_read_buffer(pem,
+ "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+ "-----END ENCRYPTED PRIVATE KEY-----",
+ key, NULL, 0, &len);
}
if (ret == 0) {
/* infor is unknown */
return ret;
- } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
+ }
+ else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
return ret;
}
#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
@@ -348,10 +402,12 @@
}
#endif
-const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(const ptls_mbedtls_signature_scheme_t *available,
- const uint16_t *algorithms, size_t num_algorithms)
+const ptls_mbedtls_signature_scheme_t* ptls_mbedtls_select_signature_scheme(
+ const ptls_mbedtls_signature_scheme_t *available,
+ const uint16_t *algorithms, size_t num_algorithms)
{
- const ptls_mbedtls_signature_scheme_t *scheme;
+ 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) {
@@ -363,7 +419,8 @@
return NULL;
}
-int ptls_mbedtls_set_available_schemes(ptls_mbedtls_sign_certificate_t *signer)
+int ptls_mbedtls_set_available_schemes(
+ ptls_mbedtls_sign_certificate_t* signer)
{
int ret = 0;
psa_algorithm_t algo = psa_get_key_algorithm(&signer->attributes);
@@ -411,51 +468,55 @@
}
/*
- * Sign a certificate
- * - step1, selected a signature algorithm compatible with the public key algorithm
- * and with the list specified by the application.
- * - step2, compute the hash with the specified algorithm.
- * - step3, compute the signature of the hash using psa_sign_hash.
- *
- * In the case of RSA, we use the algorithm PSA_ALG_RSA_PKCS1V15_SIGN_RAW, which
- * pads the hash according to PKCS1V15 before doing the private key operation.
- * The implementation of RSA/PKCS1V15 also includes a verification step to protect
- * against key attacks through partial faults.
- *
- * MBEDTLS has a "psa_sign_message" that combines step2 and step3. However, it
- * requires specifying an algorithm type that exactly specifies the signature
- * algorithm, such as "RSA with SHA384". This is not compatible with the
- * "RSA sign raw" algorithm. Instead, we decompose the operation in two steps.
- * There is no performance penalty doing so, as "psa_sign_message" is only
- * a convenience API.
- */
+* Sign a certificate
+* - step1, selected a signature algorithm compatible with the public key algorithm
+* and with the list specified by the application.
+* - step2, compute the hash with the specified algorithm.
+* - step3, compute the signature of the hash using psa_sign_hash.
+*
+* In the case of RSA, we use the algorithm PSA_ALG_RSA_PKCS1V15_SIGN_RAW, which
+* pads the hash according to PKCS1V15 before doing the private key operation.
+* The implementation of RSA/PKCS1V15 also includes a verification step to protect
+* against key attacks through partial faults.
+*
+* MBEDTLS has a "psa_sign_message" that combines step2 and step3. However, it
+* requires specifying an algorithm type that exactly specifies the signature
+* algorithm, such as "RSA with SHA384". This is not compatible with the
+* "RSA sign raw" algorithm. Instead, we decompose the operation in two steps.
+* There is no performance penalty doing so, as "psa_sign_message" is only
+* a convenience API.
+*/
-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)
+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)
{
int ret = 0;
- ptls_mbedtls_sign_certificate_t *self =
- (ptls_mbedtls_sign_certificate_t *)(((unsigned char *)_self) - offsetof(struct st_ptls_mbedtls_sign_certificate_t, super));
+ ptls_mbedtls_sign_certificate_t* self = (ptls_mbedtls_sign_certificate_t*)
+ (((unsigned char*)_self) - offsetof(struct st_ptls_mbedtls_sign_certificate_t, super));
/* First, find the set of compatible algorithms */
- const ptls_mbedtls_signature_scheme_t *scheme = ptls_mbedtls_select_signature_scheme(self->schemes, algorithms, num_algorithms);
+ const ptls_mbedtls_signature_scheme_t* scheme =
+ ptls_mbedtls_select_signature_scheme(self->schemes, algorithms, num_algorithms);
if (scheme == NULL) {
ret = PTLS_ERROR_INCOMPATIBLE_KEY;
- } else {
+ }
+ else {
/* First prepare the hash */
unsigned char hash_buffer[PTLS_MAX_DIGEST_SIZE];
- unsigned char *hash_value = NULL;
+ unsigned char* hash_value = NULL;
+
size_t hash_length = 0;
if (scheme->hash_algo == PSA_ALG_NONE) {
hash_value = input.base;
hash_length = input.len;
- } else {
- if (psa_hash_compute(scheme->hash_algo, input.base, input.len, hash_buffer, PTLS_MAX_DIGEST_SIZE, &hash_length) !=
- PSA_SUCCESS) {
+ }
+ else {
+ if (psa_hash_compute(scheme->hash_algo, input.base, input.len, hash_buffer, PTLS_MAX_DIGEST_SIZE, &hash_length) != PSA_SUCCESS) {
ret = PTLS_ERROR_NOT_AVAILABLE;
- } else {
+ }
+ else {
hash_value = hash_buffer;
}
}
@@ -467,7 +528,8 @@
if (sign_algo == PSA_ALG_RSA_PKCS1V15_SIGN_RAW) {
/* assume at most 4096 bit key */
nb_bytes = 512;
- } else {
+ }
+ else {
/* Max size assumed, secp521r1 */
nb_bytes = 124;
}
@@ -476,11 +538,11 @@
}
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) {
+ 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;
- } else {
+ }
+ else {
outbuf->off += signature_length;
}
}
@@ -492,9 +554,8 @@
void ptls_mbedtls_dispose_sign_certificate(ptls_sign_certificate_t *_self)
{
if (_self != NULL) {
- ptls_mbedtls_sign_certificate_t *self =
- (ptls_mbedtls_sign_certificate_t *)(((unsigned char *)_self) -
- offsetof(struct st_ptls_mbedtls_sign_certificate_t, super));
+ ptls_mbedtls_sign_certificate_t* self = (ptls_mbedtls_sign_certificate_t*)
+ (((unsigned char*)_self) - offsetof(struct st_ptls_mbedtls_sign_certificate_t, super));
/* Destroy the key */
psa_destroy_key(self->key_id);
psa_reset_key_attributes(&self->attributes);
@@ -503,24 +564,24 @@
}
}
/*
- * An RSa key is encoded in DER as:
- * RSAPrivateKey ::= SEQUENCE {
- * version INTEGER, -- must be 0
- * modulus INTEGER, -- n
- * publicExponent INTEGER, -- e
- * privateExponent INTEGER, -- d
- * prime1 INTEGER, -- p
- * prime2 INTEGER, -- q
- * exponent1 INTEGER, -- d mod (p-1)
- * exponent2 INTEGER, -- d mod (q-1)
- * coefficient INTEGER, -- (inverse of q) mod p
- * }
- *
- * The number of key bits is the size in bits of the integer N.
- * We must decode the length in octets of the integer representation,
- * then subtract the number of zeros at the beginning of the data.
- */
-int ptls_mbedtls_rsa_get_key_bits(const unsigned char *key_value, size_t key_length, size_t *p_nb_bits)
+* An RSa key is encoded in DER as:
+* RSAPrivateKey ::= SEQUENCE {
+* version INTEGER, -- must be 0
+* modulus INTEGER, -- n
+* publicExponent INTEGER, -- e
+* privateExponent INTEGER, -- d
+* prime1 INTEGER, -- p
+* prime2 INTEGER, -- q
+* exponent1 INTEGER, -- d mod (p-1)
+* exponent2 INTEGER, -- d mod (q-1)
+* coefficient INTEGER, -- (inverse of q) mod p
+* }
+*
+* The number of key bits is the size in bits of the integer N.
+* We must decode the length in octets of the integer representation,
+* then subtract the number of zeros at the beginning of the data.
+*/
+int ptls_mbedtls_rsa_get_key_bits(const unsigned char* key_value, size_t key_length, size_t * p_nb_bits)
{
int ret = 0;
size_t nb_bytes = 0;
@@ -537,10 +598,15 @@
}
}
- if (ret == 0 && key_value[x] == 0x02 && key_value[x + 1] == 0x01 && key_value[x + 2] == 0x00 && key_value[x + 3] == 0x02) {
+ if (ret == 0 &&
+ key_value[x] == 0x02 &&
+ key_value[x + 1] == 0x01 &&
+ key_value[x + 2] == 0x00 &&
+ key_value[x + 3] == 0x02) {
x += 4;
ret = ptls_mbedtls_parse_der_length(key_value, key_length, &x, &nb_bytes);
- } else {
+ }
+ else {
ret = -1;
}
@@ -550,7 +616,8 @@
if (v == 0) {
nb_bits -= 8;
- } else {
+ }
+ else {
while ((v & 0x80) == 0) {
nb_bits--;
v <<= 1;
@@ -561,7 +628,8 @@
return ret;
}
-void ptls_mbedtls_set_rsa_key_attributes(ptls_mbedtls_sign_certificate_t *signer, const unsigned char *key_value, size_t key_length)
+void ptls_mbedtls_set_rsa_key_attributes(ptls_mbedtls_sign_certificate_t* signer,
+ const unsigned char * key_value, size_t key_length)
{
size_t nb_bits = 0;
psa_set_key_usage_flags(&signer->attributes, PSA_KEY_USAGE_SIGN_HASH);
@@ -572,7 +640,7 @@
}
}
-int ptls_mbedtls_set_ec_key_attributes(ptls_mbedtls_sign_certificate_t *signer, size_t key_length)
+int ptls_mbedtls_set_ec_key_attributes(ptls_mbedtls_sign_certificate_t* signer, size_t key_length)
{
int ret = 0;
@@ -580,44 +648,51 @@
psa_set_key_algorithm(&signer->attributes, PSA_ALG_ECDSA_BASE);
psa_set_key_type(&signer->attributes, PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1));
if (key_length == 32) {
- psa_set_key_algorithm(&signer->attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
+ psa_set_key_algorithm(&signer->attributes,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256));
psa_set_key_bits(&signer->attributes, 256);
- } else if (key_length == 48) {
- psa_set_key_algorithm(&signer->attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384));
+ }
+ else if (key_length == 48) {
+ psa_set_key_algorithm(&signer->attributes,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384));
psa_set_key_bits(&signer->attributes, 384);
- } else if (key_length == 66) {
- psa_set_key_algorithm(&signer->attributes, PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_512));
+ }
+ else if (key_length == 66) {
+ psa_set_key_algorithm(&signer->attributes,
+ PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_512));
psa_set_key_bits(&signer->attributes, 521);
- } else {
+ }
+ else {
ret = -1;
}
return ret;
}
-int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname)
+int ptls_mbedtls_load_private_key(ptls_context_t* ctx, char const* pem_fname)
{
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
size_t n;
- unsigned char *buf;
- mbedtls_pem_context pem = {0};
+ 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));
+ ptls_mbedtls_sign_certificate_t* signer = (ptls_mbedtls_sign_certificate_t*)malloc(sizeof(ptls_mbedtls_sign_certificate_t));
if (signer == NULL) {
- return (PTLS_ERROR_NO_MEMORY);
+ return(PTLS_ERROR_NO_MEMORY);
}
memset(signer, 0, sizeof(ptls_mbedtls_sign_certificate_t));
signer->attributes = psa_key_attributes_init();
if ((ret = mbedtls_pk_load_file(pem_fname, &buf, &n)) != 0) {
if (ret == MBEDTLS_ERR_PK_ALLOC_FAILED) {
- return (PTLS_ERROR_NO_MEMORY);
- } else {
- return (PTLS_ERROR_NOT_AVAILABLE);
+ return(PTLS_ERROR_NO_MEMORY);
+ }
+ else {
+ return(PTLS_ERROR_NOT_AVAILABLE);
}
}
ret = ptls_mbedtls_get_der_key(&pem, &pk_type, buf, n, NULL, 0, NULL, NULL);
@@ -633,20 +708,21 @@
if (pk_type == MBEDTLS_PK_RSA) {
key_length = pem.private_buflen;
ptls_mbedtls_set_rsa_key_attributes(signer, pem.private_buf, key_length);
- } else if (pk_type == MBEDTLS_PK_ECKEY) {
+ }
+ else if (pk_type == MBEDTLS_PK_ECKEY) {
ret = ptls_mbedtls_parse_ecdsa_field(pem.private_buf, pem.private_buflen, &key_index, &key_length);
if (ret == 0) {
ret = ptls_mbedtls_set_ec_key_attributes(signer, key_length);
}
- } else if (pk_type == MBEDTLS_PK_NONE) {
+ }
+ else if (pk_type == MBEDTLS_PK_NONE) {
/* TODO: not clear whether MBDED TLS supports ED25519 yet. Probably not. */
/* Should have option to encode RSA or ECDSA using PKCS8 */
size_t oid_index = 0;
size_t oid_length = 0;
psa_set_key_usage_flags(&signer->attributes, PSA_KEY_USAGE_SIGN_HASH);
- ret =
- test_parse_private_key_field(pem.private_buf, pem.private_buflen, &oid_index, &oid_length, &key_index, &key_length);
+ ret = test_parse_private_key_field(pem.private_buf, pem.private_buflen, &oid_index, &oid_length, &key_index, &key_length);
if (ret == 0) {
/* need to parse the OID in order to set the parameters */
@@ -656,23 +732,27 @@
if (ret == 0) {
ret = ptls_mbedtls_set_ec_key_attributes(signer, key_length);
}
- } else if (oid_length == sizeof(ptls_mbedtls_oid_ed25519) &&
- memcmp(pem.private_buf + oid_index, ptls_mbedtls_oid_ed25519, sizeof(ptls_mbedtls_oid_ed25519)) == 0) {
+ }
+ else if (oid_length == sizeof(ptls_mbedtls_oid_ed25519) &&
+ memcmp(pem.private_buf + oid_index, ptls_mbedtls_oid_ed25519, sizeof(ptls_mbedtls_oid_ed25519)) == 0) {
/* We recognized ED25519 -- PSA_ECC_FAMILY_TWISTED_EDWARDS -- PSA_ALG_ED25519PH */
psa_set_key_algorithm(&signer->attributes, PSA_ALG_PURE_EDDSA);
psa_set_key_type(&signer->attributes, PSA_ECC_FAMILY_TWISTED_EDWARDS);
ret = ptls_mbedtls_parse_eddsa_key(pem.private_buf, pem.private_buflen, &key_index, &key_length);
psa_set_key_bits(&signer->attributes, 256);
- } else if (oid_length == sizeof(ptls_mbedtls_oid_rsa_key) &&
- memcmp(pem.private_buf + oid_index, ptls_mbedtls_oid_rsa_key, sizeof(ptls_mbedtls_oid_rsa_key)) == 0) {
+ }
+ else if (oid_length == sizeof(ptls_mbedtls_oid_rsa_key) &&
+ memcmp(pem.private_buf + oid_index, ptls_mbedtls_oid_rsa_key, sizeof(ptls_mbedtls_oid_rsa_key)) == 0) {
/* We recognized RSA */
key_length = pem.private_buflen;
ptls_mbedtls_set_rsa_key_attributes(signer, pem.private_buf, key_length);
- } else {
+ }
+ else {
ret = PTLS_ERROR_NOT_AVAILABLE;
}
}
- } else {
+ }
+ else {
ret = -1;
}
@@ -682,7 +762,8 @@
if (status != PSA_SUCCESS) {
ret = -1;
- } else {
+ }
+ else {
ret = ptls_mbedtls_set_available_schemes(signer);
}
}
diff --git a/t/mbedtls.c b/t/mbedtls.c
index d3651de..cec11df 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,164 @@
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);
@@ -113,29 +287,29 @@
ptls_minicrypto_init_secp256r1sha256_sign_certificate(
&minicrypto_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
ptls_context_t minicrypto_ctx = {ptls_minicrypto_random_bytes,
- &ptls_get_time,
- ptls_minicrypto_key_exchanges,
- ptls_minicrypto_cipher_suites,
- {&secp256r1_certificate, 1},
- {{NULL}},
- NULL,
- NULL,
- &minicrypto_sign_certificate.super};
+ &ptls_get_time,
+ ptls_minicrypto_key_exchanges,
+ ptls_minicrypto_cipher_suites,
+ {&secp256r1_certificate, 1},
+ {{NULL}},
+ NULL,
+ NULL,
+ &minicrypto_sign_certificate.super};
/* context using mbedtls as backend; minicrypto is used for signing certificate as the mbedtls backend does not (yet) have the
- * capability */
+ * capability */
ptls_minicrypto_secp256r1sha256_sign_certificate_t mbedtls_sign_certificate;
ptls_minicrypto_init_secp256r1sha256_sign_certificate(
&mbedtls_sign_certificate, ptls_iovec_init(SECP256R1_PRIVATE_KEY, sizeof(SECP256R1_PRIVATE_KEY) - 1));
ptls_context_t mbedtls_ctx = {ptls_mbedtls_random_bytes,
- &ptls_get_time,
- ptls_mbedtls_key_exchanges,
- ptls_mbedtls_cipher_suites,
- {&secp256r1_certificate, 1},
- {{NULL}},
- NULL,
- NULL,
- &mbedtls_sign_certificate.super};
+ &ptls_get_time,
+ ptls_mbedtls_key_exchanges,
+ ptls_mbedtls_cipher_suites,
+ {&secp256r1_certificate, 1},
+ {{NULL}},
+ NULL,
+ NULL,
+ &mbedtls_sign_certificate.super};
ctx = &mbedtls_ctx;
ctx_peer = &mbedtls_ctx;
@@ -149,6 +323,9 @@
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();