Merge branch 'master' into kazuho/pr501
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..8eed140 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"
@@ -36,7 +37,8 @@
 #include <psa/crypto.h>
 #include <psa/crypto_struct.h>
 #include <psa/crypto_values.h>
-#include "ptls_mbedtls.h"
+/* #include "ptls_mbedtls.h" */
+
 
 typedef struct st_ptls_mbedtls_signature_scheme_t {
     uint16_t scheme_id;
@@ -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 af3ec95..8cbe0a9 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);
 
@@ -120,7 +294,7 @@
                                      .sign_certificate = &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));
@@ -143,6 +317,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();