From 0058a94958377c55b6fe72abcb196f28aeb7e988 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 16:44:54 -0700 Subject: [PATCH 01/28] copy-updated-mbedtls_files --- include/picotls/mbedtls.h | 12 + lib/mbedtls_sign.c | 549 +++++++++++++++++++++++++++++++++++++- t/mbedtls.c | 465 +++++++++++++++++++++++++++++++- 3 files changed, 1022 insertions(+), 4 deletions(-) diff --git a/include/picotls/mbedtls.h b/include/picotls/mbedtls.h index 62fd382d..b18b9010 100644 --- a/include/picotls/mbedtls.h +++ b/include/picotls/mbedtls.h @@ -60,9 +60,21 @@ extern ptls_key_exchange_algorithm_t *ptls_mbedtls_key_exchanges[]; void ptls_mbedtls_random_bytes(void *buf, size_t len); +int ptls_mbedtls_load_file(char const* file_name, unsigned char** buf, size_t* n); + 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); +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 picoquic_mbedtls_get_certs_from_file(char const* pem_fname, ptls_iovec_t** vec, size_t* count); +int ptls_mbedtls_init_verify_certificate(ptls_context_t* ptls_ctx, char const* pem_fname); +void ptls_mbedtls_dispose_verify_certificate(ptls_context_t* ptls_ctx); + + + #ifdef __cplusplus } #endif diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index de06175f..d4955376 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -33,6 +33,7 @@ #include #include #include +#include "mbedtls/x509_crt.h" #include #include #include @@ -50,9 +51,21 @@ typedef struct st_ptls_mbedtls_sign_certificate_t { const ptls_mbedtls_signature_scheme_t *schemes; } ptls_mbedtls_sign_certificate_t; + +typedef struct st_ptls_mbedtls_verify_certificate_t { + ptls_verify_certificate_t super; + mbedtls_x509_crt *trust_ca; + mbedtls_x509_crl *trust_crl; + int (*f_vrfy)(void*, mbedtls_x509_crt*, int, uint32_t*); + void* p_vrfy; +} ptls_mbedtls_verify_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}; +#if 0 +/* Commented out for now, as EDDSA is not yet supported by MbedTLS */ static const unsigned char ptls_mbedtls_oid_ed25519[] = {0x2b, 0x65, 0x70}; +#endif 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}, @@ -65,8 +78,11 @@ 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}}; +#if 0 +/* Commented out for now, as EDDSA is not yet supported by MbedTLS */ static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {{PTLS_SIGNATURE_ED25519, PSA_ALG_NONE}, {UINT16_MAX, PSA_ALG_NONE}}; +#endif #if defined(MBEDTLS_PEM_PARSE_C) @@ -149,6 +165,9 @@ static int ptls_mbedtls_parse_ecdsa_field(const unsigned char *pem_buf, size_t p return ret; } +#if 0 +/* Commenting out, as EDDSA is no yet supported in MbedTLS */ + /* 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 @@ -174,6 +193,7 @@ static int ptls_mbedtls_parse_eddsa_key(const unsigned char *pem_buf, size_t pem } return ret; } +#endif /* If using PKCS8 encoding, the "private key" field contains the * same "ecdsa field" found in PEM "EC PRIVATE KEY" files. We @@ -452,6 +472,8 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p size_t hash_length = 0; + *selected_algorithm = scheme->scheme_id; + if (scheme->hash_algo == PSA_ALG_NONE) { hash_value = input.base; hash_length = input.len; @@ -598,6 +620,72 @@ int ptls_mbedtls_set_ec_key_attributes(ptls_mbedtls_sign_certificate_t *signer, return ret; } +int ptls_mbedtls_load_file(char const * file_name, unsigned char ** buf, size_t * n) +{ + int ret = 0; + FILE* F = NULL; + *buf = NULL; + *n = 0; +#ifdef _WINDOWS + errno_t err = fopen_s(&F, file_name, "rb"); + if (err != 0){ + if (F != NULL) { + fclose(F); + F = NULL; + } + } +#else + F = fopen(file_name, "rb"); +#endif + + if (F == NULL) { + ret = PTLS_ERROR_NOT_AVAILABLE; + } + else { + long sz; + fseek(F, 0, SEEK_END); + sz = ftell(F); + if (sz <= 0) { + ret = PTLS_ERROR_NOT_AVAILABLE; + } + else { + *buf = (unsigned char *)malloc(sz + 1); + if (*buf == NULL){ + ret = PTLS_ERROR_NO_MEMORY; + } + else { + size_t nb_read = 0; + *n = (size_t)sz + 1; + + fseek(F, 0, SEEK_SET); + while(nb_read < (size_t)sz){ + size_t bytes_read = fread((*buf) + nb_read, 1, sz - nb_read, F); + if (bytes_read > 0){ + nb_read += bytes_read; + } else { + /* No need to check for EOF, since we know the length of the file */ + ret = PTLS_ERROR_NOT_AVAILABLE; + break; + } + } + } + } + (void)fclose(F); + } + if (ret == 0){ + (*buf)[(*n) - 1] = 0; + } + else { + if (*buf != NULL){ + free(*buf); + *buf = NULL; + } + *n = 0; + } + + return ret; +} + int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; @@ -616,7 +704,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) 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 = ptls_mbedtls_load_file(pem_fname, &buf, &n)) != 0) { if (ret == MBEDTLS_ERR_PK_ALLOC_FAILED) { return (PTLS_ERROR_NO_MEMORY); } else { @@ -659,6 +747,8 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) if (ret == 0) { ret = ptls_mbedtls_set_ec_key_attributes(signer, key_length); } +#if 0 + /* Commenting out, as EDDSA is no yet supported in MbedTLS */ } 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 */ @@ -666,6 +756,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) 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); +#endif } 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 */ @@ -701,3 +792,459 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) } return ret; } + + +/* Handling of certificates. +* Certificates in picotls are used both at the client and the server side. +* +* The server is programmed with a copy of the certificate chain linking +* the local key and identity to a certificate authority. Picotls formats +* that key and sends it as part of the "server hello". It is signed with +* the server key. +* +* The client is programmed with a list of trusted certificates. It should +* process the list received from the server and verifies that it does +* correctly link the server certificate to one of the certificates in the +* root list. +* +* Mbedtls documents a series of certificate related API in `x509_crt.h`. +* +* On the server side, we read the certificates from a PEM encoded +* file, and provide it to the server. +* +* For verify certificate, picotls uses a two phase API: +* +* - During initialization, prepare a "verify certificate callback" +* - During the handshake, picotls executes the callback. +* +* Picotls verifies certificates using the "verify_certificate" callback. +* +* if ((ret = tls->ctx->verify_certificate->cb(tls->ctx->verify_certificate, +* tls, server_name, &tls->certificate_verify.cb, +* &tls->certificate_verify.verify_ctx, certs, num_certs)) != 0) +* goto Exit; +* +* This is implemented using the function mbedtls_verify_certificate, +* documented during the initialization of the "cb" structure, +* ptls_mbedtls_verify_certificate_t. The function pointer is +* the first member of that structure, followed by other arguments. +* The callback structure is passed as the first argument in the +* callback, with type "self". +* +* The callback should return 0 if the certificate is good. The call may +* also set the value of tls->certificate_verify.cb and +* tls->certificate_verify.verify_ctx. If these are set, picotls will +* then use tls->certificate_verify.cb to verify that the TLS messages +* are properly signed using that certificate. +* +* The function mbedtls_verify_certificate is implemented using the +* function "mbedtls_x509_crt_verify", which has the following arguments: +* +* - A chain of certificates, starting from the server certificate and hopefully +* going all the way to one of the root certificates. In our code, this +* is obtained by parsing the "certs" argument provided by picotls, which +* is an iovec vector of length numcerts, with one entry per certificate in +* the CERTS parameter received from the server. +* - The chain of trusted certificate authorities. In our case, that list is +* initialized during the call to `ptls_mbedssl_init_verify_certificate`, +* loading certificates from a `root` file. +* - A certificate revocation list. We leave that parameter NULL for now. +* - The expected server name, a NULL terminated string. +* - A "verify" function pointer, and its argument. +* +* The call returns 0 (and flags set to 0) if the chain was verified and valid, +* MBEDTLS_ERR_X509_CERT_VERIFY_FAILED if the chain was verified but found to +* be invalid, in which case *flags will have one or more MBEDTLS_X509_BADCERT_XXX +* or MBEDTLS_X509_BADCRL_XXX flags set, or another error +* (and flags set to 0xffffffff) in case of a fatal error encountered +* during the verification process. +* +* The verify callback is a user-supplied callback that can clear / modify / add +* flags for a certificate. If set, the verification callback is called for each +* certificate in the chain (from the trust-ca down to the presented crt). +* The parameters for the callback are: (void *parameter, mbedtls_x509_crt *crt, +* int certificate_depth, int *flags). With the flags representing current flags +* for that specific certificate and the certificate depth from the bottom +* (Peer cert depth = 0). Function pointer and parameters can be set in the call +* to `ptls_mbedssl_init_verify_certificate`. +* +* If the certificate verification is successfull, the code sets the pointer +* and the context for the certificate_verify callback: +* +* struct { +* int (*cb)(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature); +* void *verify_ctx; +* } certificate_verify; +* +* The structure "certificate_verify" is allocated as part of the PTLS context. We will +* allcoate a a "ptls_mbetls_certificate_verify_ctx_t" ctx as part of the +* +* The verify callback is implemented using `psa_verify_message`, which takes the following +* arguments: +* +* psa_status_t psa_verify_message(psa_key_id_t key, +* psa_algorithm_t alg, +* const uint8_t * input, +* size_t input_length, +* const uint8_t * signature, +* size_t signature_length); +* +* The public key ID will be set from the certificate proposed by the server. The +* input and length of the data to be signed are derived from the data parameter +* in the callback, and the signature and length from the signature parameter of +* the callback. The "alg" parameter of type "psa_algorithm_t" will have to +* be derived from the algo parameter of the callback, which is a 16 bit +* "signature scheme" (see +* https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-signaturescheme). +* +* Picotls will use that callback exactly once, then reset the callback +* pointer to NULL. It does not reset of free the "verify_ctx" -- if necessary, +* the value there should be reset after the first call. +*/ + +typedef struct st_mbedtls_message_verify_ctx_t { + psa_key_id_t key_id; +} mbedtls_message_verify_ctx_t; + +uint16_t mbedtls_verify_sign_algos[] = { + 0x0201, 0x0203, 0x0401, 0x0403, 0x501, 0x0503, 0x0601, 0x0603, + 0x0804, 0x0805, 0x0806, + 0xFFFF +}; + +static int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature) +{ + /* Obtain the key parameters, etc. */ + int ret = 0; + psa_algorithm_t alg = PSA_ALG_NONE; + mbedtls_message_verify_ctx_t * message_verify_ctx = (mbedtls_message_verify_ctx_t*)verify_ctx; + + if (message_verify_ctx == NULL) { + ret = PTLS_ERROR_LIBRARY; + } else if (data.base != NULL) { + /* Picotls will call verify_sign with data.base == NULL when it + * only wants to clear the memory. This is not an error condition. */ + /* Find the PSA_ALG for the signature scheme is supported */ + switch (algo) { + case 0x0201: /* PTLS_SIGNATURE_RSA_PKCS1_SHA1 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_1); + break; + case 0x0203: /* ecdsa_sha1 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_1); + break; + case 0x401: /* PTLS_SIGNATURE_RSA_PKCS1_SHA256 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256); + break; + case 0x0403: /* PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + break; +#if 0 + /* For further study. These two algorithms might be available in MbedTLS */ + case 0x0420: /* rsa_pkcs1_sha256_legacy */ + break; + case 0x0520: /* rsa_pkcs1_sha384_legacy */ + break; +#endif + case 0x501: /* rsa_pkcs1_sha384 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_384); + break; + case 0x0503: /* PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384); + break; + case 0x0601: /* rsa_pkcs1_sha512 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_512); + break; + case 0x0603: /* PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_512); + break; + case 0x0804: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256); + break; + case 0x0805: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_384); + break; + case 0x0806: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_512); + break; +#if 0 + /* Commented out, as EDDSA is not supported yet in MbedTLS*/ + case 0x0807: /* PTLS_SIGNATURE_ED25519 */ + alg = PSA_ALG_ED25519PH; + break; + case 0x0808: /* PTLS_SIGNATURE_ED448 */ + alg = PSA_ALG_ED448PH; + break; +#endif + default: + break; + } + + if (alg == PSA_ALG_NONE) { + ret = PTLS_ALERT_ILLEGAL_PARAMETER; + } + else { + psa_status_t status = psa_verify_message(message_verify_ctx->key_id, alg, data.base, data.len, signature.base, signature.len); + + if (status != PSA_SUCCESS) { + switch (status) { + case PSA_ERROR_NOT_PERMITTED: /* The key does not have the PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit the requested algorithm. */ + ret = PTLS_ERROR_INCOMPATIBLE_KEY; + break; + case PSA_ERROR_INVALID_SIGNATURE: /* The calculation was performed successfully, but the passed signature is not a valid signature. */ + ret = PTLS_ALERT_DECRYPT_ERROR; + break; + case PSA_ERROR_NOT_SUPPORTED: + ret = PTLS_ALERT_ILLEGAL_PARAMETER; + break; + case PSA_ERROR_INSUFFICIENT_MEMORY: + ret = PTLS_ERROR_NO_MEMORY; + break; + default: + ret = PTLS_ERROR_LIBRARY; + break; + } + } + } + } + /* destroy the key because it is used only once. */ + if (message_verify_ctx != NULL) { + psa_destroy_key(message_verify_ctx->key_id); + free(message_verify_ctx); + } + return ret; +} + +static int mbedtls_verify_certificate(ptls_verify_certificate_t *_self, ptls_t *tls, const char *server_name, + int (**verifier)(void *, uint16_t, ptls_iovec_t, ptls_iovec_t), void **verify_data, ptls_iovec_t *certs, + size_t num_certs) +{ + size_t i; + int ret = 0; + ptls_mbedtls_verify_certificate_t *self = (ptls_mbedtls_verify_certificate_t *)_self; + mbedtls_x509_crt chain_head = { 0 }; + + *verifier = NULL; + *verify_data = NULL; + + /* If any certs are given, convert them to MbedTLS representation, then verify the cert chain. If no certs are given, just give + * the override_callback to see if we want to stay fail open. */ + if (num_certs == 0) { + ret = PTLS_ALERT_CERTIFICATE_REQUIRED; + } else { + mbedtls_x509_crt* previous_chain = &chain_head; + mbedtls_x509_crt_init(&chain_head); + + for (i = 0; i != num_certs; ++i) { + ret = mbedtls_x509_crt_parse_der(previous_chain, certs[i].base, certs[i].len); + if (i != 0) { + if (previous_chain->next == NULL) { + ret = PTLS_ALERT_BAD_CERTIFICATE; + break; + } + previous_chain = previous_chain->next; + } + } + + if (ret == 0) { + uint32_t flags = 0; + + int verify_ret = mbedtls_x509_crt_verify(&chain_head, self->trust_ca, self->trust_crl, server_name, &flags, + self->f_vrfy, self->p_vrfy); + + if (verify_ret != 0) { + switch (verify_ret) { + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + /* if the chain was verified but found to be invalid, in which case + * flags will have one or more MBEDTLS_X509_BADCERT_XXX + * or MBEDTLS_X509_BADCRL_XXX flags set, or another + * error(and flags set to 0xffffffff) in case of a fatal error + * encountered during the verification process. */ + ret = PTLS_ALERT_BAD_CERTIFICATE; + break; + default: + ret = PTLS_ERROR_LIBRARY; + break; + } + } + } + + if (ret == 0) { + mbedtls_message_verify_ctx_t* message_verify_ctx = (mbedtls_message_verify_ctx_t*) + malloc(sizeof(mbedtls_message_verify_ctx_t)); + if (message_verify_ctx == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + psa_status_t status; + psa_key_attributes_t attributes; + memset(&attributes, 0, sizeof(attributes)); + memset(message_verify_ctx, 0, sizeof(mbedtls_message_verify_ctx_t)); + + status = mbedtls_pk_get_psa_attributes(&chain_head.next->pk, PSA_KEY_USAGE_VERIFY_MESSAGE, &attributes); + if (status == PSA_SUCCESS) { + status = mbedtls_pk_import_into_psa(&chain_head.next->pk, &attributes, &message_verify_ctx->key_id); + } + if (status != PSA_SUCCESS) { + ret = PTLS_ERROR_LIBRARY; + free(message_verify_ctx); + } + else { + *verifier = mbedtls_verify_sign; + *verify_data = message_verify_ctx; + } + } + } + } + + if (chain_head.next != NULL) { + mbedtls_x509_crt_free(chain_head.next); + } + return ret; +} + +/* Read certificates from a file using MbedTLS functions. +* We only use the PEM function to parse PEM files, find +* up to 16 certificates, and convert the base64 encoded +* data to DER encoded binary. No attempt is made to verify +* that these actually are certificates. +* +* Discuss: picotls has a built in function for this. +* Is it really necessary to program an alternative? +*/ +int picoquic_mbedtls_get_certs_from_file(char const * pem_fname, ptls_iovec_t** pvec, size_t * count) +{ + int ret = 0; + *pvec = (ptls_iovec_t*)malloc(sizeof(ptls_iovec_t) * 16); + + *count = 0; + if (*pvec == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } else { + size_t buf_length; + unsigned char* buf = NULL; + /* The load file function simply loads the file content in memory */ + if ((ret = ptls_mbedtls_load_file(pem_fname, &buf, &buf_length)) == 0) { + size_t length_already_read = 0; + + while (ret == 0 && *count < 16 && length_already_read < (size_t)buf_length) { + mbedtls_pem_context pem = { 0 }; + size_t length_read = 0; + + /* PEM context setup. */ + mbedtls_pem_init(&pem); + /* Read a buffer for PEM information and store the resulting data into the specified context buffers. */ + ret = mbedtls_pem_read_buffer(&pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf + length_already_read, NULL, 0, &length_read); + if (ret == 0) { + /* Certificate was read successfully. PEM buffer contains the base64 value */ + uint8_t* cert = (uint8_t*)malloc(pem.private_buflen); + if (cert == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + memcpy(cert, pem.private_buf, pem.private_buflen); + (*pvec)[*count].base = cert; + (*pvec)[*count].len = pem.private_buflen; + *count += 1; + } + } + mbedtls_pem_free(&pem); + length_already_read += length_read; + } + + free(buf); + } + } + return ret; +} + +int ptls_mbedtls_load_certificates(ptls_context_t *ctx, char const *cert_pem_file) +{ + return picoquic_mbedtls_get_certs_from_file(cert_pem_file, &ctx->certificates.list, + &ctx->certificates.count); +} + +/* Creating the call back. This API is not described by picotls. The "backend" +* merely has to provide a "certicate verifier" callback. We consider two ways of +* providing this callback: an API very close to the details of the MBedTLS code, +* with a list of explicit parameters, and a "portable" API whose only +* parameter is a file name for the list of trusted certificates. +*/ + +int ptls_mbedssl_init_verify_certificate_complete(ptls_context_t * ptls_ctx, + mbedtls_x509_crt* trust_ca, mbedtls_x509_crl* trust_crl, + int (*f_vrfy)(void*, mbedtls_x509_crt*, int, uint32_t*), void* p_vrfy) +{ + int ret = 0; + ptls_mbedtls_verify_certificate_t* verifier = + (ptls_mbedtls_verify_certificate_t*)malloc(sizeof(ptls_mbedtls_verify_certificate_t)); + if (verifier == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + memset(verifier, 0, sizeof(ptls_mbedtls_verify_certificate_t)); + verifier->super.cb = mbedtls_verify_certificate; + verifier->super.algos = mbedtls_verify_sign_algos; /* list of supported algorithms, end with 0xFFFF */ + verifier->trust_ca = trust_ca; + verifier->trust_crl = trust_crl; + verifier->f_vrfy = f_vrfy; + verifier->p_vrfy = p_vrfy; + ptls_ctx->verify_certificate = &verifier->super; + } + return ret; +} + +int ptls_mbedtls_init_verify_certificate(ptls_context_t* ptls_ctx, char const* pem_fname) +{ + int ret = 0; + mbedtls_x509_crt* chain_head = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); + + if (chain_head == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + int psa_ret; + mbedtls_x509_crt_init(chain_head); + + psa_ret = mbedtls_x509_crt_parse_file(chain_head, pem_fname); + if (psa_ret == 0) { + ret = ptls_mbedssl_init_verify_certificate_complete(ptls_ctx, + chain_head, NULL, NULL, NULL); + } + else if (psa_ret > 0) { + /* some of the certificates could not parsed */ + ret = PTLS_ALERT_BAD_CERTIFICATE; + } + else if (psa_ret == PSA_ERROR_INSUFFICIENT_MEMORY) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + ret = PTLS_ERROR_LIBRARY; + } + + if (ret != 0 && chain_head != NULL) { + mbedtls_x509_crt_free(chain_head); + } + } + return ret; +} + +void ptls_mbedtls_dispose_verify_certificate(ptls_context_t* ptls_ctx) +{ + ptls_mbedtls_verify_certificate_t* verifier = + (ptls_mbedtls_verify_certificate_t*)ptls_ctx->verify_certificate; + if (verifier != NULL) { + if (verifier->trust_ca != NULL) { + mbedtls_x509_crt_free(verifier->trust_ca); + verifier->trust_ca = NULL; + } + if (verifier->trust_crl != NULL) { + mbedtls_x509_crl_free(verifier->trust_crl); + } + memset(verifier, 0, sizeof(ptls_mbedtls_verify_certificate_t)); + free(verifier); + ptls_ctx->verify_certificate = NULL; + } +} \ No newline at end of file diff --git a/t/mbedtls.c b/t/mbedtls.c index 1ea3416b..d7885565 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -133,6 +133,66 @@ Output buffer is already partially filled. #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" +#define ASSET_ED25519_KEY "t/assets/ed25519/key.pem" +#define ASSET_NO_SUCH_FILE "t/assets/no_such_file.pem" +#define ASSET_NOT_A_PEM_FILE "t/assets/not_a_valid_pem_file.pem" +#define ASSET_RSA_CERT "t/assets/rsa/cert.pem" +#define ASSET_RSA_PKCS8_CERT "t/assets/rsa-pkcs8/cert.pem" +#define ASSET_SECP256R1_CERT "t/assets/secp256r1/cert.pem" +#define ASSET_SECP384R1_CERT "t/assets/secp384r1/cert.pem" +#define ASSET_SECP521R1_CERT "t/assets/secp521r1/cert.pem" +#define ASSET_SECP256R1_PKCS8_CERT "t/assets/secp256r1-pkcs8/cert.pem" +#define ASSET_ED25519_CERT "t/assets/ed25519/cert.pem" +#define ASSET_TEST_CA "data/test-ca.crt" +#endif + +int test_load_one_file(char const* path) +{ + size_t n; + unsigned char *buf; + int ret = ptls_mbedtls_load_file(path, &buf, &n); + if (ret != 0) { + printf("Cannot load file from: %s, ret = %d (0x%x, -0x%x)\n", path, ret, ret, (int16_t)-ret); + } + else if (n == 0) { + printf("File %s is empty\n", path); + ret = -1; + } + else if (buf[n] != 0) { + printf("Buffer from %s is not null terminated\n", path); + ret = -1; + } + if (buf != NULL) { + free(buf); + } + return ret; +} + +static void test_load_file_key() +{ + int ret = test_load_file_key(ASSET_RSA_KEY); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_file_cert() +{ + int ret = test_load_file_key(ASSET_SECP256R1_PKCS8_CERT); + if (ret != 0) { + ok(!"fail"); + return; + } + ok(!!"success"); +} + +void test_load_file() +{ + subtest("load file key", test_load_file_key()); + subtest("load file cert", test_load_file_cert); +} int test_load_one_der_key(char const *path) { @@ -244,7 +304,7 @@ static void test_load_rsa_pkcs8_key() ok(!!"success"); } -void test_sign_certificate(void) +void test_load_keys(void) { subtest("load rsa key", test_load_rsa_key); subtest("load secp256r1 key", test_load_secp256r1_key); @@ -256,6 +316,396 @@ void test_sign_certificate(void) /* we do not test EDDSA keys, because they are not yet supported */ } +static void test_load_key_no_such_file() +{ + int ret = test_load_one_der_key(ASSET_NO_SUCH_FILE); + if (ret == 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_key_not_a_pem_file() +{ + int ret = test_load_one_der_key(ASSET_NOT_A_PEM_FILE); + if (ret == 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_key_not_a_key_file() +{ + int ret = test_load_one_der_key(ASSET_RSA_CERT); + if (ret == 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_load_key_not_supported() +{ + int ret = test_load_one_der_key(ASSET_ED25519_KEY); + if (ret == 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +/* +* Testing of failure modes. +* +* Testing the various reasons why loading of key should fail: +* - key file does not exist +* - key file is empty, no PEM keyword +* - key file does not contain a key (we use a cert file for that) +* - key file is for ED25559, which is not supported +*/ + +static void test_load_key_fail() +{ + subtest("load key no such file", test_load_key_no_such_file); + subtest("load key not a PEM file", test_load_key_not_a_pem_file); + subtest("load key not a key file", test_load_key_not_a_key_file); + subtest("load key not supported", test_load_key_not_supported); +} + +/* +* End to end testing of signature and verifiers: +* The general scenario is: +* - prepare a signature of a test string using a simulated +* server programmed with a private key and a certificate +* list. +* - verify the signature in a simulated client programmed +* with a list of trusted certificates. +* +* The test is configured with the file names for the key, +* certificate list, and trusted certificates. +* +* Ideally, we should be able to run the test by mixing and +* matching mbedtls server or clients with other backends. +* However, using openssl will require some plumbing, +* which will be done when integrating this code in +* picotls. For now, we will only do self tests, and test with +* minicrypto if the key is supported. +* +* Consider breaking out parts of this test in separate subtests, +* e.g., load certificate chain, verify certificate chain, +* extract key from certificare chain, verify signature. +*/ + +static const unsigned char test_sign_verify_message[] = { + 0, 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, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64 +}; +const size_t test_sign_verify_message_size = sizeof(test_sign_verify_message); + +static uint16_t test_sign_signature_algorithms[] = { + 0x0401, 0x0403, 0x501, 0x0503, 0x0601, 0x0603, + 0x0804, 0x0805, 0x0806, 0x0807, 0x0808 +}; + +static size_t num_test_sign_signature_algorithms = sizeof(test_sign_signature_algorithms) / sizeof(uint16_t); + +char const* test_sign_server_name = "test.example.com"; + +static int test_sign_init_server_mbedtls(ptls_context_t* ctx, char const* key_path, char const* cert_path) +{ + int ret = ptls_mbedtls_load_private_key(ctx, key_path); + if (ret == 0) { + ret = picoquic_mbedtls_get_certs_from_file(cert_path, &ctx->certificates.list, &ctx->certificates.count); + } + return ret; +} + +static int test_sign_init_server_minicrypto(ptls_context_t* ctx, char const* key_path, char const* cert_path) +{ + int ret = ptls_minicrypto_load_private_key(ctx, key_path); + if (ret == 0) { + ret = ptls_load_certificates(ctx, cert_path); + } + return ret; +} + +static void test_sign_free_certificates(ptls_context_t* ctx) +{ + if (ctx->certificates.list != NULL) { + for (int i = 0; i < ctx->certificates.count; i++) { + free(ctx->certificates.list[i].base); + } + free(ctx->certificates.list); + } + ctx->certificates.list = NULL; + ctx->certificates.count = 0; +} + +static void test_sign_free_context(ptls_context_t* ctx, int config) +{ + /* Free the server context */ + if (ctx == NULL) { + return; + } + test_sign_free_certificates(ctx); + if (ctx->sign_certificate != NULL) { + switch (config) { + case 0: + ptls_mbedtls_dispose_sign_certificate(ctx->sign_certificate); + break; + case 1: + default: + free(ctx->sign_certificate); + ctx->sign_certificate = NULL; + } + } + + if (ctx->verify_certificate != NULL) { + switch (config) { + case 0: + ptls_mbedtls_dispose_verify_certificate(ctx); + break; + default: + break; + } + } + + free(ctx); +} + +static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char const* cert_path, char const* trusted_path, int is_server, int config) +{ + int ret = 0; + ptls_context_t* ctx = (ptls_context_t*)malloc(sizeof(ptls_context_t)); + if (ctx == NULL) { + return NULL; + } + + memset(ctx, 0, sizeof(ptls_context_t)); + ctx->get_time = &ptls_get_time; + + switch (config) { + case 0: + ctx->random_bytes = ptls_mbedtls_random_bytes; + case 1: + default: + break; + } + + if (is_server) { + /* First, create the "signer" plug-in */ + switch (config) { + case 0: /* MbedTLS */ + ret = test_sign_init_server_mbedtls(ctx, key_path, cert_path); + break; + case 1: /* Minicrypto */ + ret = test_sign_init_server_minicrypto(ctx, key_path, cert_path); + break; + default: + ret = -1; + break; + } + } + else { + /* Initialize the client verify context */ + switch (config) { + case 0: /* MbedTLS */ + ret = ptls_mbedtls_init_verify_certificate(ctx, trusted_path); + break; + default: + ret = -1; + break; + } + } + + if (ret != 0) { + /* Release and return NULL */ + test_sign_free_context(ctx, config); + ctx = NULL; + } + return ctx; +} + +static int test_sign_verify_one(char const* key_path, char const * cert_path, char const * trusted_path, int server_config, int client_config) +{ + int ret = 0; + ptls_context_t* server_ctx = test_sign_set_ptls_context(key_path, cert_path, trusted_path, 1, server_config); + ptls_context_t* client_ctx = test_sign_set_ptls_context(key_path, cert_path, trusted_path, 0, client_config); + ptls_t* client_tls = NULL; + ptls_t* server_tls = NULL; + uint16_t selected_algorithm = 0; + uint8_t signature_smallbuf[256]; + ptls_buffer_t signature; + struct { + int (*cb)(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature); + void *verify_ctx; + } certificate_verify; + ptls_iovec_t input; + input.base = (uint8_t *)test_sign_verify_message; + input.len = test_sign_verify_message_size; + + ptls_buffer_init(&signature, signature_smallbuf, sizeof(signature_smallbuf)); + + if (server_ctx == NULL || client_ctx == NULL) { + ret = -1; + } + + if (ret == 0) { + /* Then, create a tls context for the server. */ + server_tls = ptls_new(server_ctx, 1); + if (server_tls == NULL) { + ret = -1; + } + } + + if (ret == 0) { + /* Then, create the signature messages */ + ret = server_ctx->sign_certificate->cb(server_ctx->sign_certificate, server_tls, NULL, + &selected_algorithm, &signature, input, + test_sign_signature_algorithms, num_test_sign_signature_algorithms); + if (ret != 0) { + printf("sign_certificate (%s) returns 0x%x\n", key_path, ret); + } + } + + if (ret == 0) { + /* Then, create a tls context for the client. */ + client_tls = ptls_new(client_ctx, 0); + if (client_tls == NULL) { + ret = -1; + } + } + + if (ret == 0) { + /* verify the certificates */ + ret = client_ctx->verify_certificate->cb(client_ctx->verify_certificate, client_tls, test_sign_server_name, + &certificate_verify.cb, &certificate_verify.verify_ctx, + server_ctx->certificates.list, server_ctx->certificates.count); + if (ret != 0) { + printf("verify_certificate (%s) returns 0x%x\n", cert_path, ret); + } + /* verify the signature */ + if (ret == 0) { + ptls_iovec_t sig; + sig.base = signature.base; + sig.len = signature.off; + + ret = certificate_verify.cb(certificate_verify.verify_ctx, selected_algorithm, input, sig); + if (ret != 0) { + printf("verify_signature (%s) returns 0x%x\n", key_path, ret); + } + } + else if (certificate_verify.cb != NULL) { + ptls_iovec_t empty; + empty.base = NULL; + empty.len = 0; + (void)certificate_verify.cb(certificate_verify.verify_ctx, 0, empty, empty); + } + } + if (ret == 0) { + printf("verify_signature (%s) and cert (%s) succeeds\n", key_path, cert_path); + } + + ptls_buffer_dispose(&signature); + + if (client_tls != NULL) { + ptls_free(client_tls); + } + if (server_tls != NULL) { + ptls_free(server_tls); + } + + test_sign_free_context(server_ctx, server_config); + test_sign_free_context(client_ctx, client_config); + + return ret; +} + +static void test_sign_verify_rsa_mbedtls_mbedtls() +{ + int ret = test_sign_verify_one(ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_sign_verify_rsa_mbedtls_mbedtls() +{ + int ret = test_sign_verify_one(ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_sign_verify_secp256r1_mbedtls_mbedtls() +{ + ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_SECP256R1_CERT, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_sign_verify_secp384r1_mbedtls_mbedtls() +{ + int ret = test_sign_verify_one(ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT, ASSET_SECP384R1_CERT, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_sign_verify_secp521r1_mbedtls_mbedtls() +{ + ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_SECP521R1_CERT, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() +{ + ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_SECP256R1_PKCS8_CERT, 0, 0); + if (ret != 0){ + ok(!"fail"); + return; + } + ok(!!"success"); +} + +/* TODO: all these tests are failing, because we do not have the +* proper combination of hostname and certificate. Fix that, then +* enable the test. +* +* TODO: add tests of minicrypto server and mbedtls client. +* TODO: add tests of mbedtls versus openssl. +* TODO: add negative testing. + */ + +static void test_sign_verify() +{ + subtest("sign verify rsa mbedtls mbedtls", test_sign_verify_rsa_mbedtls_mbedtls); + subtest("sign verify secp256r1 mbedtls mbedtls", test_sign_verify_secp256r1_mbedtls_mbedtls); + subtest("sign verify secp384r1 mbedtls mbedtls", test_sign_verify_secp384r1_mbedtls_mbedtls); + subtest("sign verify secp521r1 mbedtls mbedtls", test_sign_verify_secp521r1_mbedtls_mbedtls); + subtest("sign verify secp256r1 pkcs8 mbedtls mbedtls", test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls); + + return ret; +} + + DEFINE_FFX_AES128_ALGORITHMS(mbedtls); DEFINE_FFX_CHACHA20_ALGORITHMS(mbedtls); @@ -310,8 +760,17 @@ 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); + /* Test loading file in memory */ + subtest("test load file", test_load_file); + + /* test loading of keys in memory and capability to sign */ + subtest("test load keys", test_load_keys); + + /* Test that loading bad files or bad keys fails */ + subtest("test load key failures", test_load_key_fail); + + /* End to end test of signing and verifying certicates */ + subtest("test sign verify certiciates", test_load_key_fail); /* Deinitialize the PSA crypto library. */ mbedtls_psa_crypto_free(); From 059249a762c3e6d34f85b0418cfc94d2288f9c8f Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 18:01:53 -0700 Subject: [PATCH 02/28] Small cmake fixes --- cmake/FindMbedTLS.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindMbedTLS.cmake b/cmake/FindMbedTLS.cmake index 048a1e9b..92a8a836 100644 --- a/cmake/FindMbedTLS.cmake +++ b/cmake/FindMbedTLS.cmake @@ -43,6 +43,6 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS(MbedTLS REQUIRED_VARS MBEDTLS_X509 MBEDTLS_INCLUDE_DIRS) IF (MbedTLS_FOUND) - SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDTLS_CRYPTO} ${MBEDTLS_X509}) + SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDTLS_X509} ${MBEDTLS_CRYPTO} ) MARK_AS_ADVANCED(MBEDTLS_LIBRARIES MBEDTLS_INCLUDE_DIRS) ENDIF () From ed0f87244ed31e2c1c46b4c15f64970d009a6b97 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 19:04:13 -0700 Subject: [PATCH 03/28] Another errant ref to ed25519 --- lib/mbedtls_sign.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index d4955376..04a1cb66 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -33,7 +33,7 @@ #include #include #include -#include "mbedtls/x509_crt.h" +#include #include #include #include @@ -422,9 +422,12 @@ int ptls_mbedtls_set_available_schemes(ptls_mbedtls_sign_certificate_t *signer) break; } break; +#if 0 + /* Commenting out as MbedTLS does not support ED25519 yet */ case PSA_ALG_ED25519PH: signer->schemes = ed25519_signature_schemes; break; +#endif default: printf("Unknown algo: %x\n", algo); ret = -1; From e53f8800c7798552f8715ff7798b2df7fb837676 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 19:14:41 -0700 Subject: [PATCH 04/28] Fix more compile warnings --- t/mbedtls.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index d7885565..765b6804 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -144,7 +144,6 @@ Output buffer is already partially filled. #define ASSET_SECP256R1_PKCS8_CERT "t/assets/secp256r1-pkcs8/cert.pem" #define ASSET_ED25519_CERT "t/assets/ed25519/cert.pem" #define ASSET_TEST_CA "data/test-ca.crt" -#endif int test_load_one_file(char const* path) { @@ -170,7 +169,7 @@ int test_load_one_file(char const* path) static void test_load_file_key() { - int ret = test_load_file_key(ASSET_RSA_KEY); + int ret = test_load_one_file(ASSET_RSA_KEY); if (ret != 0) { ok(!"fail"); return; @@ -180,7 +179,7 @@ static void test_load_file_key() static void test_load_file_cert() { - int ret = test_load_file_key(ASSET_SECP256R1_PKCS8_CERT); + int ret = test_load_one_file(ASSET_SECP256R1_PKCS8_CERT); if (ret != 0) { ok(!"fail"); return; @@ -635,16 +634,6 @@ static void test_sign_verify_rsa_mbedtls_mbedtls() ok(!!"success"); } -static void test_sign_verify_rsa_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - static void test_sign_verify_secp256r1_mbedtls_mbedtls() { ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_SECP256R1_CERT, 0, 0); @@ -694,7 +683,7 @@ static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() * TODO: add negative testing. */ -static void test_sign_verify() +static void test_sign_verify_end_to_end() { subtest("sign verify rsa mbedtls mbedtls", test_sign_verify_rsa_mbedtls_mbedtls); subtest("sign verify secp256r1 mbedtls mbedtls", test_sign_verify_secp256r1_mbedtls_mbedtls); @@ -770,7 +759,7 @@ int main(int argc, char **argv) subtest("test load key failures", test_load_key_fail); /* End to end test of signing and verifying certicates */ - subtest("test sign verify certiciates", test_load_key_fail); + subtest("test sign verify end to end", test_sign_verify_end_to_end); /* Deinitialize the PSA crypto library. */ mbedtls_psa_crypto_free(); From d32c1ad3de7a017cc6889d919f5bfb594c390317 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 19:17:51 -0700 Subject: [PATCH 05/28] More compile warnings --- t/mbedtls.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 765b6804..ec264834 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -636,7 +636,7 @@ static void test_sign_verify_rsa_mbedtls_mbedtls() static void test_sign_verify_secp256r1_mbedtls_mbedtls() { - ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_SECP256R1_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_SECP256R1_CERT, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -656,7 +656,7 @@ static void test_sign_verify_secp384r1_mbedtls_mbedtls() static void test_sign_verify_secp521r1_mbedtls_mbedtls() { - ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_SECP521R1_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_SECP521R1_CERT, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -666,7 +666,7 @@ static void test_sign_verify_secp521r1_mbedtls_mbedtls() static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() { - ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_SECP256R1_PKCS8_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_SECP256R1_PKCS8_CERT, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -690,8 +690,6 @@ static void test_sign_verify_end_to_end() subtest("sign verify secp384r1 mbedtls mbedtls", test_sign_verify_secp384r1_mbedtls_mbedtls); subtest("sign verify secp521r1 mbedtls mbedtls", test_sign_verify_secp521r1_mbedtls_mbedtls); subtest("sign verify secp256r1 pkcs8 mbedtls mbedtls", test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls); - - return ret; } From 973349629877310890955d53d999cd1d57222bbb Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Thu, 16 May 2024 19:18:45 -0700 Subject: [PATCH 06/28] More typos fixed. --- t/mbedtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index ec264834..b61a93e8 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -189,7 +189,7 @@ static void test_load_file_cert() void test_load_file() { - subtest("load file key", test_load_file_key()); + subtest("load file key", test_load_file_key); subtest("load file cert", test_load_file_cert); } From b08896e5b2a1f9708fd5f10bbf9c4b2186fe395b Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Fri, 17 May 2024 22:16:20 -0700 Subject: [PATCH 07/28] Do not set the output length to excessive value --- lib/mbedtls.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/mbedtls.c b/lib/mbedtls.c index 86fa7b01..6824e22f 100644 --- a/lib/mbedtls.c +++ b/lib/mbedtls.c @@ -305,20 +305,27 @@ static void aead_encrypt_v(struct st_ptls_aead_context_t *_ctx, void *output, pt struct ptls_mbedtls_aead_context_t *ctx = (struct ptls_mbedtls_aead_context_t *)_ctx; psa_aead_operation_t op = psa_aead_operation_init(); uint8_t *dst = output, iv[PTLS_MAX_IV_SIZE], tag[PSA_AEAD_TAG_MAX_SIZE]; - size_t outlen, taglen; + size_t outlen, taglen, inlen = 0, outlen_max; + /* Compute the complete input length, so we can call */ + for (size_t i = 0; i < incnt; i++) { + inlen += input[i].len; + } + outlen_max = PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(input_length); /* setup op */ CALL_WITH_CHECK(psa_aead_encrypt_setup, &op, ctx->key, ctx->alg); ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); CALL_WITH_CHECK(psa_aead_set_nonce, &op, iv, ctx->super.algo->iv_size); + CALL_WITH_CHECK(psa_aead_set_lengths, &op, aadlen, inlen); CALL_WITH_CHECK(psa_aead_update_ad, &op, aad, aadlen); /* encrypt */ for (size_t i = 0; i < incnt; i++) { - CALL_WITH_CHECK(psa_aead_update, &op, input[i].base, input[i].len, dst, SIZE_MAX, &outlen); + CALL_WITH_CHECK(psa_aead_update, &op, input[i].base, input[i].len, dst, outlen_max, &outlen); dst += outlen; + outlen_max -= outlen; } - CALL_WITH_CHECK(psa_aead_finish, &op, dst, SIZE_MAX, &outlen, tag, sizeof(tag), &taglen); + CALL_WITH_CHECK(psa_aead_finish, &op, dst, outlen_max, &outlen, tag, sizeof(tag), &taglen); dst += outlen; memcpy(dst, tag, taglen); From 03befd1b3732a077f98b6f0873e430063aeb57fd Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Fri, 17 May 2024 22:18:31 -0700 Subject: [PATCH 08/28] Fix typo --- lib/mbedtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mbedtls.c b/lib/mbedtls.c index 6824e22f..8c0569f7 100644 --- a/lib/mbedtls.c +++ b/lib/mbedtls.c @@ -311,7 +311,7 @@ static void aead_encrypt_v(struct st_ptls_aead_context_t *_ctx, void *output, pt for (size_t i = 0; i < incnt; i++) { inlen += input[i].len; } - outlen_max = PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(input_length); + outlen_max = PSA_AEAD_UPDATE_OUTPUT_MAX_SIZE(inlen); /* setup op */ CALL_WITH_CHECK(psa_aead_encrypt_setup, &op, ctx->key, ctx->alg); ptls_aead__build_iv(ctx->super.algo, iv, ctx->static_iv, seq); From 5c3943c30fa1b1c10fd58db3e4d29f9560e072cc Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 11:39:15 -0700 Subject: [PATCH 09/28] Add verification of signature. --- t/mbedtls.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 65 insertions(+), 4 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index b61a93e8..e45275c3 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -196,8 +196,7 @@ void test_load_file() 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, + const unsigned char test_message[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}; @@ -217,11 +216,10 @@ int test_load_one_der_key(char const *path) /* get the key algorithm */ ptls_buffer_t outbuf; uint8_t outbuf_smallbuf[256]; - ptls_iovec_t input = {hash, sizeof(hash)}; + ptls_iovec_t input = {test_message, sizeof(test_message)}; 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++; @@ -236,6 +234,69 @@ int test_load_one_der_key(char const *path) } else { printf("Sign failed, key: %s, scheme: %x, signature size: %zu\n", path, selected_algorithm, outbuf.off); } + + if (ret == 0) { + /* Create a verifier context and attempt to check the key */ + ptls_iovec_t sig; + uint8_t pubkey_data[1024]; + size_t pubkey_len = 0; + psa_status_t psa_status; + psa_key_attributes_t attr; + psa_key_attributes_t public_attributes = psa_key_attributes_init(); + + if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { + printf("Cannot export public key, status = %d\n", psa_status); + ret = -1; + } + + if (ret == 0) { + switch (psa_get_key_type(&signer->attributes)) { + case PSA_KEY_TYPE_RSA_KEY_PAIR: + psa_set_key_type(&public_attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY); + break; + case PSA_KEY_TYPE_ECC_KEY_PAIR(PSA_ECC_FAMILY_SECP_R1): + psa_set_key_type(&public_attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + break; + default: + /* TODO: add ED25519 when supported by MbedTLS */ + printf("Cannot derive public key from key type.\n"); + ret = -1; + break; + } + } + + if (ret == 0) { + mbedtls_message_verify_ctx_t* verify_ctx = (mbedtls_message_verify_ctx_t*)malloc(sizeof(mbedtls_message_verify_ctx_t)); + if (verify_ctx == NULL) { + ret = -1; + } + else { + psa_algorithm_t sign_alg = mbedtls_get_psa_alg_from_tls_number(selected_algorithm); + + psa_set_key_usage_flags(&public_attributes, PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH); + psa_set_key_algorithm(&public_attributes, sign_alg /* psa_get_key_algorithm(&signer->attributes) */); + + if ((psa_status = psa_import_key(&public_attributes, pubkey_data, pubkey_len, &verify_ctx->key_id)) != 0) { + printf("Cannot import public key, status = %d\n", psa_status); + free(verify_ctx); + ret = -1; + } + else { + sig.base = outbuf.base; + sig.len = outbuf.off; + + ret = mbedtls_verify_sign(verify_ctx, selected_algorithm, input, sig); + if (ret == 0) { + printf("Verified message signature.\n"); + } + else { + printf("Failed to verify signature, ret = %d\n", ret); + } + } + } + } + } + ptls_buffer_dispose(&outbuf); ptls_mbedtls_dispose_sign_certificate(&signer->super); } From 0bbab1c0384ada90416bbe019b0f5f0a0d47e9bb Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 11:45:04 -0700 Subject: [PATCH 10/28] Fixing test compile issues. --- t/mbedtls.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index e45275c3..831ce075 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -33,6 +33,12 @@ #include "picotls/minicrypto.h" #include "../deps/picotest/picotest.h" #include "test.h" +#include "mbedtls/build_info.h" +#include "ptls_mbedtls.h" +#include "picotls/minicrypto.h" +#include "mbedtls/pk.h" +#include "mbedtls/pem.h" +#include "mbedtls/error.h" typedef struct st_ptls_mbedtls_signature_scheme_t { uint16_t scheme_id; @@ -193,10 +199,17 @@ void test_load_file() subtest("load file cert", test_load_file_cert); } +typedef struct st_mbedtls_message_verify_ctx_t { + psa_key_id_t key_id; +} mbedtls_message_verify_ctx_t; + +int mbedtls_verify_sign(void* verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature); +psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo); + int test_load_one_der_key(char const *path) { int ret = -1; - const unsigned char test_message[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + unsigned char test_message[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}; From 73d49257b29df05f788c7bd357ca633ed16e01f2 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 11:49:15 -0700 Subject: [PATCH 11/28] remove spurious include ref. --- t/mbedtls.c | 1 - 1 file changed, 1 deletion(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 831ce075..b1611fe7 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -34,7 +34,6 @@ #include "../deps/picotest/picotest.h" #include "test.h" #include "mbedtls/build_info.h" -#include "ptls_mbedtls.h" #include "picotls/minicrypto.h" #include "mbedtls/pk.h" #include "mbedtls/pem.h" From e0ed5f961688220c3168b1ca33fa97ab005147a0 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 13:22:30 -0700 Subject: [PATCH 12/28] Fix code porting issues. --- lib/mbedtls_sign.c | 127 ++++++++++++++++++++++++--------------------- t/mbedtls.c | 1 - 2 files changed, 69 insertions(+), 59 deletions(-) diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index 04a1cb66..d59e24d9 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -375,7 +375,7 @@ const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(cons { const ptls_mbedtls_signature_scheme_t *scheme; - /* select the algorithm, driven by server-isde preference of `available` */ + /* select the algorithm, driven by server preference of `available` */ for (scheme = available; scheme->scheme_id != UINT16_MAX; ++scheme) { for (size_t i = 0; i != num_algorithms; ++i) { if (algorithms[i] == scheme->scheme_id) { @@ -915,7 +915,68 @@ uint16_t mbedtls_verify_sign_algos[] = { 0xFFFF }; -static int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature) + +/* Find the psa_algorithm_t values corresponding to the 16 bit TLS signature scheme */ +psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo) +{ + psa_algorithm_t alg = PSA_ALG_NONE; + switch (tls_algo) { + case 0x0201: /* PTLS_SIGNATURE_RSA_PKCS1_SHA1 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_1); + break; + case 0x0203: /* ecdsa_sha1 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_1); + break; + case 0x401: /* PTLS_SIGNATURE_RSA_PKCS1_SHA256 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256); + break; + case 0x0403: /* PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); + break; +#if 0 + /* For further study. These two algorithms might be available in MbedTLS */ + case 0x0420: /* rsa_pkcs1_sha256_legacy */ + break; + case 0x0520: /* rsa_pkcs1_sha384_legacy */ + break; +#endif + case 0x501: /* rsa_pkcs1_sha384 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_384); + break; + case 0x0503: /* PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384); + break; + case 0x0601: /* rsa_pkcs1_sha512 */ + alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_512); + break; + case 0x0603: /* PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512 */ + alg = PSA_ALG_ECDSA(PSA_ALG_SHA_512); + break; + case 0x0804: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256); + break; + case 0x0805: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_384); + break; + case 0x0806: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512 */ + alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_512); + break; +#if 0 + /* Commented out, as EDDSA is not supported yet in MbedTLS*/ + case 0x0807: /* PTLS_SIGNATURE_ED25519 */ + alg = PSA_ALG_ED25519PH; + break; + case 0x0808: /* PTLS_SIGNATURE_ED448 */ + alg = PSA_ALG_ED448PH; + break; +#endif + default: + break; + } + return alg; +} + +int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature) { /* Obtain the key parameters, etc. */ int ret = 0; @@ -924,63 +985,13 @@ static int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t dat if (message_verify_ctx == NULL) { ret = PTLS_ERROR_LIBRARY; - } else if (data.base != NULL) { + } + else if (data.base != NULL) { /* Picotls will call verify_sign with data.base == NULL when it * only wants to clear the memory. This is not an error condition. */ - /* Find the PSA_ALG for the signature scheme is supported */ - switch (algo) { - case 0x0201: /* PTLS_SIGNATURE_RSA_PKCS1_SHA1 */ - alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_1); - break; - case 0x0203: /* ecdsa_sha1 */ - alg = PSA_ALG_ECDSA(PSA_ALG_SHA_1); - break; - case 0x401: /* PTLS_SIGNATURE_RSA_PKCS1_SHA256 */ - alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_256); - break; - case 0x0403: /* PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256 */ - alg = PSA_ALG_ECDSA(PSA_ALG_SHA_256); - break; -#if 0 - /* For further study. These two algorithms might be available in MbedTLS */ - case 0x0420: /* rsa_pkcs1_sha256_legacy */ - break; - case 0x0520: /* rsa_pkcs1_sha384_legacy */ - break; -#endif - case 0x501: /* rsa_pkcs1_sha384 */ - alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_384); - break; - case 0x0503: /* PTLS_SIGNATURE_ECDSA_SECP384R1_SHA384 */ - alg = PSA_ALG_ECDSA(PSA_ALG_SHA_384); - break; - case 0x0601: /* rsa_pkcs1_sha512 */ - alg = PSA_ALG_RSA_PKCS1V15_SIGN(PSA_ALG_SHA_512); - break; - case 0x0603: /* PTLS_SIGNATURE_ECDSA_SECP521R1_SHA512 */ - alg = PSA_ALG_ECDSA(PSA_ALG_SHA_512); - break; - case 0x0804: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA256 */ - alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_256); - break; - case 0x0805: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384 */ - alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_384); - break; - case 0x0806: /* PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512 */ - alg = PSA_ALG_RSA_PSS(PSA_ALG_SHA_512); - break; -#if 0 - /* Commented out, as EDDSA is not supported yet in MbedTLS*/ - case 0x0807: /* PTLS_SIGNATURE_ED25519 */ - alg = PSA_ALG_ED25519PH; - break; - case 0x0808: /* PTLS_SIGNATURE_ED448 */ - alg = PSA_ALG_ED448PH; - break; -#endif - default: - break; - } + + /* Find the PSA_ALG for the signature scheme */ + alg = mbedtls_get_psa_alg_from_tls_number(algo); if (alg == PSA_ALG_NONE) { ret = PTLS_ALERT_ILLEGAL_PARAMETER; @@ -1009,7 +1020,7 @@ static int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t dat } } } - /* destroy the key because it is used only once. */ + /* destroy the key because it is used only once.*/ if (message_verify_ctx != NULL) { psa_destroy_key(message_verify_ctx->key_id); free(message_verify_ctx); diff --git a/t/mbedtls.c b/t/mbedtls.c index b1611fe7..0e690717 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -253,7 +253,6 @@ int test_load_one_der_key(char const *path) uint8_t pubkey_data[1024]; size_t pubkey_len = 0; psa_status_t psa_status; - psa_key_attributes_t attr; psa_key_attributes_t public_attributes = psa_key_attributes_init(); if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { From 4a4940e5cc6659fee48cb9801eea79742f81c5e7 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 13:29:28 -0700 Subject: [PATCH 13/28] Not be so verbose. --- t/mbedtls.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 0e690717..f89ed8cf 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -214,10 +214,10 @@ int test_load_one_der_key(char const *path) ret = ptls_mbedtls_load_private_key(&ctx, path); if (ret != 0) { - printf("Cannot create sign_certificate from: %s\n", path); + /* Cannot create sign_certificate */ ret = -1; } else if (ctx.sign_certificate == NULL) { - printf("Sign_certificate not set in ptls context for: %s\n", path); + /* Sign_certificate not set in ptls context */ ret = -1; } else { /* Try to sign something */ @@ -241,11 +241,6 @@ int test_load_one_der_key(char const *path) 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); - } if (ret == 0) { /* Create a verifier context and attempt to check the key */ @@ -256,7 +251,7 @@ int test_load_one_der_key(char const *path) psa_key_attributes_t public_attributes = psa_key_attributes_init(); if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { - printf("Cannot export public key, status = %d\n", psa_status); + /* Cannot export public key */ ret = -1; } @@ -270,7 +265,7 @@ int test_load_one_der_key(char const *path) break; default: /* TODO: add ED25519 when supported by MbedTLS */ - printf("Cannot derive public key from key type.\n"); + /* Cannot derive public key from key type */ ret = -1; break; } @@ -288,7 +283,7 @@ int test_load_one_der_key(char const *path) psa_set_key_algorithm(&public_attributes, sign_alg /* psa_get_key_algorithm(&signer->attributes) */); if ((psa_status = psa_import_key(&public_attributes, pubkey_data, pubkey_len, &verify_ctx->key_id)) != 0) { - printf("Cannot import public key, status = %d\n", psa_status); + /* Cannot import public key */ free(verify_ctx); ret = -1; } @@ -297,12 +292,7 @@ int test_load_one_der_key(char const *path) sig.len = outbuf.off; ret = mbedtls_verify_sign(verify_ctx, selected_algorithm, input, sig); - if (ret == 0) { - printf("Verified message signature.\n"); - } - else { - printf("Failed to verify signature, ret = %d\n", ret); - } + /* ret != 0 => Failed to verify signature */ } } } From 460c4871face38994660ba22b3fa2dfe746bf4d0 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 15:45:34 -0700 Subject: [PATCH 14/28] Fix reference totrust CA --- t/mbedtls.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index f89ed8cf..a38dc9a3 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -278,9 +278,8 @@ int test_load_one_der_key(char const *path) } else { psa_algorithm_t sign_alg = mbedtls_get_psa_alg_from_tls_number(selected_algorithm); - psa_set_key_usage_flags(&public_attributes, PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_VERIFY_HASH); - psa_set_key_algorithm(&public_attributes, sign_alg /* psa_get_key_algorithm(&signer->attributes) */); + psa_set_key_algorithm(&public_attributes, sign_alg); if ((psa_status = psa_import_key(&public_attributes, pubkey_data, pubkey_len, &verify_ctx->key_id)) != 0) { /* Cannot import public key */ @@ -698,7 +697,7 @@ static void test_sign_verify_rsa_mbedtls_mbedtls() static void test_sign_verify_secp256r1_mbedtls_mbedtls() { - int ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_SECP256R1_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_TEST_CA, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -708,7 +707,7 @@ static void test_sign_verify_secp256r1_mbedtls_mbedtls() static void test_sign_verify_secp384r1_mbedtls_mbedtls() { - int ret = test_sign_verify_one(ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT, ASSET_SECP384R1_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT, ASSET_TEST_CA, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -718,7 +717,7 @@ static void test_sign_verify_secp384r1_mbedtls_mbedtls() static void test_sign_verify_secp521r1_mbedtls_mbedtls() { - int ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_SECP521R1_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_TEST_CA, 0, 0); if (ret != 0){ ok(!"fail"); return; @@ -728,7 +727,7 @@ static void test_sign_verify_secp521r1_mbedtls_mbedtls() static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() { - int ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_SECP256R1_PKCS8_CERT, 0, 0); + int ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_TEST_CA, 0, 0); if (ret != 0){ ok(!"fail"); return; From 1f38b04a5b525ddad307a2d68bec173cc515323f Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 16:10:19 -0700 Subject: [PATCH 15/28] Add intermediate checks for sign-verify --- t/mbedtls.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index a38dc9a3..51b921f3 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -213,6 +213,7 @@ int test_load_one_der_key(char const *path) ptls_context_t ctx = {0}; ret = ptls_mbedtls_load_private_key(&ctx, path); + ok(ret == 0); if (ret != 0) { /* Cannot create sign_certificate */ ret = -1; @@ -241,6 +242,7 @@ int test_load_one_der_key(char const *path) ret = ptls_mbedtls_sign_certificate(ctx.sign_certificate, NULL, NULL, &selected_algorithm, &outbuf, input, algorithms, num_algorithms); + ok(ret == 0); if (ret == 0) { /* Create a verifier context and attempt to check the key */ @@ -254,7 +256,7 @@ int test_load_one_der_key(char const *path) /* Cannot export public key */ ret = -1; } - + ok(ret == 0); if (ret == 0) { switch (psa_get_key_type(&signer->attributes)) { case PSA_KEY_TYPE_RSA_KEY_PAIR: @@ -270,9 +272,10 @@ int test_load_one_der_key(char const *path) break; } } - + ok(ret == 0); if (ret == 0) { mbedtls_message_verify_ctx_t* verify_ctx = (mbedtls_message_verify_ctx_t*)malloc(sizeof(mbedtls_message_verify_ctx_t)); + ok(verify_ctx != NULL); if (verify_ctx == NULL) { ret = -1; } @@ -283,15 +286,17 @@ int test_load_one_der_key(char const *path) if ((psa_status = psa_import_key(&public_attributes, pubkey_data, pubkey_len, &verify_ctx->key_id)) != 0) { /* Cannot import public key */ + ok(psa_status == 0); free(verify_ctx); ret = -1; } else { + ok(psa_status == 0); sig.base = outbuf.base; sig.len = outbuf.off; ret = mbedtls_verify_sign(verify_ctx, selected_algorithm, input, sig); - /* ret != 0 => Failed to verify signature */ + ok(ret == 0); } } } From 387a35435c1dcd5beb2b007e23497f7206480393 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 16:20:23 -0700 Subject: [PATCH 16/28] Disable rsa-p --- t/mbedtls.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 51b921f3..00b18e33 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -142,7 +142,6 @@ Output buffer is already partially filled. #define ASSET_NO_SUCH_FILE "t/assets/no_such_file.pem" #define ASSET_NOT_A_PEM_FILE "t/assets/not_a_valid_pem_file.pem" #define ASSET_RSA_CERT "t/assets/rsa/cert.pem" -#define ASSET_RSA_PKCS8_CERT "t/assets/rsa-pkcs8/cert.pem" #define ASSET_SECP256R1_CERT "t/assets/secp256r1/cert.pem" #define ASSET_SECP384R1_CERT "t/assets/secp384r1/cert.pem" #define ASSET_SECP521R1_CERT "t/assets/secp521r1/cert.pem" @@ -216,9 +215,11 @@ int test_load_one_der_key(char const *path) ok(ret == 0); if (ret != 0) { /* Cannot create sign_certificate */ + ok(ret == 0); ret = -1; } else if (ctx.sign_certificate == NULL) { /* Sign_certificate not set in ptls context */ + ok(ctx.sign_certificate != NULL); ret = -1; } else { /* Try to sign something */ @@ -376,7 +377,10 @@ void test_load_keys(void) 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); +#if 0 + /* disabling for now, need to debug. */ subtest("load rsa-pkcs8 key", test_load_rsa_pkcs8_key); +#endif /* we do not test EDDSA keys, because they are not yet supported */ } From f3bb5e5ac4f1e35dda48ccaef616e72954b240b9 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 16:21:44 -0700 Subject: [PATCH 17/28] Also disabling unused code. --- t/mbedtls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/t/mbedtls.c b/t/mbedtls.c index 00b18e33..6d592f61 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -360,6 +360,7 @@ static void test_load_secp256r1_pkcs8_key() ok(!!"success"); } +#if 0 static void test_load_rsa_pkcs8_key() { int ret = test_load_one_der_key(ASSET_RSA_PKCS8_KEY); @@ -369,6 +370,7 @@ static void test_load_rsa_pkcs8_key() } ok(!!"success"); } +#endif void test_load_keys(void) { From 0a5a506e6eae4bf7292787ac4536fbe20221d03b Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 18:10:14 -0700 Subject: [PATCH 18/28] Update mbedtls sign to latest tested. --- lib/mbedtls_sign.c | 466 +++++++++++++++++++++++---------------------- t/mbedtls.c | 7 +- 2 files changed, 236 insertions(+), 237 deletions(-) diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index d59e24d9..99afda7d 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -1,24 +1,24 @@ /* - * 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" @@ -51,7 +51,6 @@ typedef struct st_ptls_mbedtls_sign_certificate_t { const ptls_mbedtls_signature_scheme_t *schemes; } ptls_mbedtls_sign_certificate_t; - typedef struct st_ptls_mbedtls_verify_certificate_t { ptls_verify_certificate_t super; mbedtls_x509_crt *trust_ca; @@ -67,10 +66,14 @@ static const unsigned char ptls_mbedtls_oid_rsa_key[] = {0x2a, 0x86, 0x48, 0x86, static const unsigned char ptls_mbedtls_oid_ed25519[] = {0x2b, 0x65, 0x70}; #endif -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_PKCS1_SHA256, PSA_ALG_SHA_256}, + {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}, + {PTLS_SIGNATURE_RSA_PKCS1_SHA1, PSA_ALG_SHA_1}, + {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}}; @@ -81,7 +84,7 @@ static const ptls_mbedtls_signature_scheme_t secp521r1_signature_schemes[] = { #if 0 /* Commented out for now, as EDDSA is not yet supported by MbedTLS */ static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {{PTLS_SIGNATURE_ED25519, PSA_ALG_NONE}, - {UINT16_MAX, PSA_ALG_NONE}}; + {UINT16_MAX, PSA_ALG_NONE}}; #endif #if defined(MBEDTLS_PEM_PARSE_C) @@ -166,13 +169,13 @@ static int ptls_mbedtls_parse_ecdsa_field(const unsigned char *pem_buf, size_t p } #if 0 -/* Commenting out, as EDDSA is no yet supported in MbedTLS */ +/* Code commented out for now, as EDDSA is not supported yet in MbedTLS */ /* 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. - */ +* "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; @@ -196,10 +199,10 @@ static int ptls_mbedtls_parse_eddsa_key(const unsigned char *pem_buf, size_t pem #endif /* 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. - */ +* 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; @@ -214,7 +217,7 @@ int ptls_mbedtls_parse_ec_private_key(const unsigned char *pem_buf, size_t pem_l } 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) + size_t *key_index, size_t *key_length) { int ret = 0; size_t l_oid = 0; @@ -240,8 +243,8 @@ int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, s ret = -1; } 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); @@ -261,8 +264,8 @@ int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, s } if (ret == 0) { /* At that point the oid has been identified. - * The next parameter is an octet string containing the key info. - */ + * The next parameter is an octet string containing the key info. + */ if (x + 2 > pem_len || pem_buf[x++] != 0x04) { ret = -1; } else { @@ -283,7 +286,7 @@ int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, s } 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) + 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) @@ -298,11 +301,11 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ #if defined(MBEDTLS_RSA_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if (key[keylen - 1] != '\0') { + if (key[keylen] != '\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); + &len); } if (ret == 0) { @@ -313,14 +316,13 @@ 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 */ #if defined(MBEDTLS_PK_HAVE_ECC_KEYS) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if (key[keylen - 1] != '\0') { + if (key[keylen] != '\0') { ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; } else { ret = @@ -339,7 +341,7 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ #endif /* MBEDTLS_PK_HAVE_ECC_KEYS */ /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if (key[keylen - 1] != '\0') { + if (key[keylen] != '\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); @@ -353,11 +355,11 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ - if (key[keylen - 1] != '\0') { + if (key[keylen] != '\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); + NULL, 0, &len); } if (ret == 0) { /* infor is unknown */ @@ -371,7 +373,7 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ #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 uint16_t *algorithms, size_t num_algorithms, uint16_t * selected_algorithm) { const ptls_mbedtls_signature_scheme_t *scheme; @@ -379,6 +381,7 @@ const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(cons for (scheme = available; scheme->scheme_id != UINT16_MAX; ++scheme) { for (size_t i = 0; i != num_algorithms; ++i) { if (algorithms[i] == scheme->scheme_id) { + *selected_algorithm = scheme->scheme_id; return scheme; } } @@ -386,85 +389,95 @@ const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(cons return NULL; } -int ptls_mbedtls_set_available_schemes(ptls_mbedtls_sign_certificate_t *signer) +/* Find whether the signature scheme is supported */ +int ptls_mbedtls_set_schemes_from_key_params(psa_algorithm_t key_algo, size_t key_nb_bits, const ptls_mbedtls_signature_scheme_t** schemes) { int ret = 0; - psa_algorithm_t algo = psa_get_key_algorithm(&signer->attributes); - size_t nb_bits = psa_get_key_bits(&signer->attributes); - switch (algo) { + switch (key_algo) { case PSA_ALG_RSA_PKCS1V15_SIGN_RAW: - signer->schemes = rsa_signature_schemes; + *schemes = rsa_signature_schemes; break; case PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_256): - signer->schemes = secp256r1_signature_schemes; + *schemes = secp256r1_signature_schemes; break; case PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_384): - signer->schemes = secp384r1_signature_schemes; + *schemes = secp384r1_signature_schemes; break; case PSA_ALG_DETERMINISTIC_ECDSA(PSA_ALG_SHA_512): - signer->schemes = secp521r1_signature_schemes; + *schemes = secp521r1_signature_schemes; break; case PSA_ALG_ECDSA_BASE: - switch (nb_bits) { + switch (key_nb_bits) { case 521: - signer->schemes = secp521r1_signature_schemes; + *schemes = secp521r1_signature_schemes; break; case 384: - signer->schemes = secp384r1_signature_schemes; + *schemes = secp384r1_signature_schemes; break; case 256: - signer->schemes = secp256r1_signature_schemes; + *schemes = secp256r1_signature_schemes; break; default: - signer->schemes = secp256r1_signature_schemes; + *schemes = secp256r1_signature_schemes; ret = -1; break; } break; #if 0 - /* Commenting out as MbedTLS does not support ED25519 yet */ case PSA_ALG_ED25519PH: - signer->schemes = ed25519_signature_schemes; + *schemes = ed25519_signature_schemes; break; #endif default: - printf("Unknown algo: %x\n", algo); + /* printf("Unknown algo: %x\n", key_algo); */ ret = -1; } return ret; } +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); + size_t nb_bits = psa_get_key_bits(&signer->attributes); + + ret = ptls_mbedtls_set_schemes_from_key_params(algo, nb_bits, &signer->schemes); + + return ret; +} + + /* - * 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) + 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)); /* 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, selected_algorithm); if (scheme == NULL) { ret = PTLS_ERROR_INCOMPATIBLE_KEY; @@ -475,8 +488,6 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p size_t hash_length = 0; - *selected_algorithm = scheme->scheme_id; - if (scheme->hash_algo == PSA_ALG_NONE) { hash_value = input.base; hash_length = input.len; @@ -506,7 +517,7 @@ 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) { + &signature_length) != 0) { ret = PTLS_ERROR_INCOMPATIBLE_KEY; } else { outbuf->off += signature_length; @@ -522,7 +533,7 @@ 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)); + offsetof(struct st_ptls_mbedtls_sign_certificate_t, super)); /* Destroy the key */ psa_destroy_key(self->key_id); psa_reset_key_attributes(&self->attributes); @@ -531,23 +542,23 @@ void ptls_mbedtls_dispose_sign_certificate(ptls_sign_certificate_t *_self) } } /* - * 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. - */ +* 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; @@ -641,51 +652,41 @@ int ptls_mbedtls_load_file(char const * file_name, unsigned char ** buf, size_t F = fopen(file_name, "rb"); #endif + if (F == NULL) { ret = PTLS_ERROR_NOT_AVAILABLE; - } - else { + } else { long sz; fseek(F, 0, SEEK_END); sz = ftell(F); - if (sz <= 0) { - ret = PTLS_ERROR_NOT_AVAILABLE; - } - else { - *buf = (unsigned char *)malloc(sz + 1); + + if (sz > 0) { + *buf = (unsigned char *)malloc(sz+1); if (*buf == NULL){ ret = PTLS_ERROR_NO_MEMORY; } else { size_t nb_read = 0; - *n = (size_t)sz + 1; - fseek(F, 0, SEEK_SET); while(nb_read < (size_t)sz){ - size_t bytes_read = fread((*buf) + nb_read, 1, sz - nb_read, F); - if (bytes_read > 0){ - nb_read += bytes_read; + *n = sz; + size_t ret = fread((*buf) + nb_read, 1, sz - nb_read, F); + if (ret > 0){ + nb_read += ret; + (*buf)[nb_read] = 0; } else { /* No need to check for EOF, since we know the length of the file */ ret = PTLS_ERROR_NOT_AVAILABLE; + free(*buf); + *buf = NULL; + *n = 0; break; } } } + (void)fclose(F); } - (void)fclose(F); - } - if (ret == 0){ - (*buf)[(*n) - 1] = 0; } - else { - if (*buf != NULL){ - free(*buf); - *buf = NULL; - } - *n = 0; - } - return ret; } @@ -708,11 +709,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) signer->attributes = psa_key_attributes_init(); if ((ret = ptls_mbedtls_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 ret; } ret = ptls_mbedtls_get_der_key(&pem, &pk_type, buf, n, NULL, 0, NULL, NULL); @@ -733,8 +730,6 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) ret = ptls_mbedtls_set_ec_key_attributes(signer, key_length); } } 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; @@ -751,20 +746,21 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) ret = ptls_mbedtls_set_ec_key_attributes(signer, key_length); } #if 0 - /* Commenting out, as EDDSA is no yet supported in MbedTLS */ + /* Commenting out as MbedTLS does not support 25519 yet */ } 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) { + memcmp(pem.private_buf + oid_index, ptls_mbedtls_oid_ed25519, sizeof(ptls_mbedtls_oid_ed25519)) == 0) { + /* This code looks correct, but EDDSA is not supported yet by MbedTLS, + * and attempts to import the key will result in an error, so commenting out for now. */ /* We recognized ED25519 -- PSA_ECC_FAMILY_TWISTED_EDWARDS -- PSA_ALG_ED25519PH */ - psa_set_key_algorithm(&signer->attributes, PSA_ALG_PURE_EDDSA); + psa_set_key_algorithm(&signer->attributes, PSA_ALG_ED25519PH); 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); #endif } 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) { + 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); + ptls_mbedtls_set_rsa_key_attributes(signer, pem.private_buf + key_index, key_length); } else { ret = PTLS_ERROR_NOT_AVAILABLE; } @@ -796,7 +792,6 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) return ret; } - /* Handling of certificates. * Certificates in picotls are used both at the client and the server side. * @@ -915,7 +910,6 @@ uint16_t mbedtls_verify_sign_algos[] = { 0xFFFF }; - /* Find the psa_algorithm_t values corresponding to the 16 bit TLS signature scheme */ psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo) { @@ -973,6 +967,7 @@ psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo) default: break; } + return alg; } @@ -996,31 +991,31 @@ int mbedtls_verify_sign(void *verify_ctx, uint16_t algo, ptls_iovec_t data, ptls if (alg == PSA_ALG_NONE) { ret = PTLS_ALERT_ILLEGAL_PARAMETER; } - else { - psa_status_t status = psa_verify_message(message_verify_ctx->key_id, alg, data.base, data.len, signature.base, signature.len); - - if (status != PSA_SUCCESS) { - switch (status) { - case PSA_ERROR_NOT_PERMITTED: /* The key does not have the PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit the requested algorithm. */ - ret = PTLS_ERROR_INCOMPATIBLE_KEY; - break; - case PSA_ERROR_INVALID_SIGNATURE: /* The calculation was performed successfully, but the passed signature is not a valid signature. */ - ret = PTLS_ALERT_DECRYPT_ERROR; - break; - case PSA_ERROR_NOT_SUPPORTED: - ret = PTLS_ALERT_ILLEGAL_PARAMETER; - break; - case PSA_ERROR_INSUFFICIENT_MEMORY: - ret = PTLS_ERROR_NO_MEMORY; - break; - default: - ret = PTLS_ERROR_LIBRARY; - break; - } + } + else { + psa_status_t status = psa_verify_message(message_verify_ctx->key_id, alg, data.base, data.len, signature.base, signature.len); + + if (status != PSA_SUCCESS) { + switch (status) { + case PSA_ERROR_NOT_PERMITTED: /* The key does not have the PSA_KEY_USAGE_SIGN_MESSAGE flag, or it does not permit the requested algorithm. */ + ret = PTLS_ERROR_INCOMPATIBLE_KEY; + break; + case PSA_ERROR_INVALID_SIGNATURE: /* The calculation was performed successfully, but the passed signature is not a valid signature. */ + ret = PTLS_ALERT_DECRYPT_ERROR; + break; + case PSA_ERROR_NOT_SUPPORTED: + ret = PTLS_ALERT_ILLEGAL_PARAMETER; + break; + case PSA_ERROR_INSUFFICIENT_MEMORY: + ret = PTLS_ERROR_NO_MEMORY; + break; + default: + ret = PTLS_ERROR_LIBRARY; + break; } } } - /* destroy the key because it is used only once.*/ + /* destroy the key because it is used only once. */ if (message_verify_ctx != NULL) { psa_destroy_key(message_verify_ctx->key_id); free(message_verify_ctx); @@ -1034,84 +1029,91 @@ static int mbedtls_verify_certificate(ptls_verify_certificate_t *_self, ptls_t * { size_t i; int ret = 0; - ptls_mbedtls_verify_certificate_t *self = (ptls_mbedtls_verify_certificate_t *)_self; - mbedtls_x509_crt chain_head = { 0 }; + mbedtls_x509_crt* chain_head = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); - *verifier = NULL; - *verify_data = NULL; + if (chain_head == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + } + else { + ptls_mbedtls_verify_certificate_t* self = (ptls_mbedtls_verify_certificate_t*)_self; + *verifier = NULL; + *verify_data = NULL; + mbedtls_x509_crt_init(chain_head); - /* If any certs are given, convert them to MbedTLS representation, then verify the cert chain. If no certs are given, just give - * the override_callback to see if we want to stay fail open. */ - if (num_certs == 0) { - ret = PTLS_ALERT_CERTIFICATE_REQUIRED; - } else { - mbedtls_x509_crt* previous_chain = &chain_head; - mbedtls_x509_crt_init(&chain_head); - - for (i = 0; i != num_certs; ++i) { - ret = mbedtls_x509_crt_parse_der(previous_chain, certs[i].base, certs[i].len); - if (i != 0) { - if (previous_chain->next == NULL) { - ret = PTLS_ALERT_BAD_CERTIFICATE; - break; + /* If any certs are given, convert them to MbedTLS representation, then verify the cert chain. If no certs are given, just give + * the override_callback to see if we want to stay fail open. */ + if (num_certs == 0) { + ret = PTLS_ALERT_CERTIFICATE_REQUIRED; + } + else { + mbedtls_x509_crt* previous_chain = chain_head; + mbedtls_x509_crt_init(chain_head); + + for (i = 0; i != num_certs; ++i) { + ret = mbedtls_x509_crt_parse_der(previous_chain, certs[i].base, certs[i].len); + if (i != 0) { + if (previous_chain->next == NULL) { + ret = PTLS_ALERT_BAD_CERTIFICATE; + break; + } + previous_chain = previous_chain->next; } - previous_chain = previous_chain->next; } - } - if (ret == 0) { - uint32_t flags = 0; - - int verify_ret = mbedtls_x509_crt_verify(&chain_head, self->trust_ca, self->trust_crl, server_name, &flags, - self->f_vrfy, self->p_vrfy); - - if (verify_ret != 0) { - switch (verify_ret) { - case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: - /* if the chain was verified but found to be invalid, in which case - * flags will have one or more MBEDTLS_X509_BADCERT_XXX - * or MBEDTLS_X509_BADCRL_XXX flags set, or another - * error(and flags set to 0xffffffff) in case of a fatal error - * encountered during the verification process. */ - ret = PTLS_ALERT_BAD_CERTIFICATE; - break; - default: - ret = PTLS_ERROR_LIBRARY; - break; + if (ret == 0) { + uint32_t flags = 0; + + int verify_ret = mbedtls_x509_crt_verify(chain_head, self->trust_ca, self->trust_crl, server_name, &flags, + self->f_vrfy, self->p_vrfy); + + if (verify_ret != 0) { + switch (verify_ret) { + case MBEDTLS_ERR_X509_CERT_VERIFY_FAILED: + /* if the chain was verified but found to be invalid, in which case + * flags will have one or more MBEDTLS_X509_BADCERT_XXX + * or MBEDTLS_X509_BADCRL_XXX flags set, or another + * error(and flags set to 0xffffffff) in case of a fatal error + * encountered during the verification process. */ + ret = PTLS_ALERT_BAD_CERTIFICATE; + break; + default: + ret = PTLS_ERROR_LIBRARY; + break; + } } } - } - if (ret == 0) { - mbedtls_message_verify_ctx_t* message_verify_ctx = (mbedtls_message_verify_ctx_t*) - malloc(sizeof(mbedtls_message_verify_ctx_t)); - if (message_verify_ctx == NULL) { - ret = PTLS_ERROR_NO_MEMORY; - } - else { - psa_status_t status; - psa_key_attributes_t attributes; - memset(&attributes, 0, sizeof(attributes)); - memset(message_verify_ctx, 0, sizeof(mbedtls_message_verify_ctx_t)); - - status = mbedtls_pk_get_psa_attributes(&chain_head.next->pk, PSA_KEY_USAGE_VERIFY_MESSAGE, &attributes); - if (status == PSA_SUCCESS) { - status = mbedtls_pk_import_into_psa(&chain_head.next->pk, &attributes, &message_verify_ctx->key_id); - } - if (status != PSA_SUCCESS) { - ret = PTLS_ERROR_LIBRARY; - free(message_verify_ctx); + if (ret == 0) { + mbedtls_message_verify_ctx_t* message_verify_ctx = (mbedtls_message_verify_ctx_t*) + malloc(sizeof(mbedtls_message_verify_ctx_t)); + if (message_verify_ctx == NULL) { + ret = PTLS_ERROR_NO_MEMORY; } else { - *verifier = mbedtls_verify_sign; - *verify_data = message_verify_ctx; + psa_status_t status; + psa_key_attributes_t attributes; + memset(&attributes, 0, sizeof(attributes)); + memset(message_verify_ctx, 0, sizeof(mbedtls_message_verify_ctx_t)); + + status = mbedtls_pk_get_psa_attributes(&chain_head->pk, PSA_KEY_USAGE_VERIFY_MESSAGE, &attributes); + if (status == PSA_SUCCESS) { + status = mbedtls_pk_import_into_psa(&chain_head->pk, &attributes, &message_verify_ctx->key_id); + } + if (status != PSA_SUCCESS) { + ret = PTLS_ERROR_LIBRARY; + free(message_verify_ctx); + } + else { + *verifier = mbedtls_verify_sign; + *verify_data = message_verify_ctx; + } } } } } - if (chain_head.next != NULL) { - mbedtls_x509_crt_free(chain_head.next); + if (chain_head != NULL) { + mbedtls_x509_crt_free(chain_head); } return ret; } @@ -1261,4 +1263,4 @@ void ptls_mbedtls_dispose_verify_certificate(ptls_context_t* ptls_ctx) free(verifier); ptls_ctx->verify_certificate = NULL; } -} \ No newline at end of file +} diff --git a/t/mbedtls.c b/t/mbedtls.c index 6d592f61..15b6dcdc 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -212,7 +212,6 @@ int test_load_one_der_key(char const *path) ptls_context_t ctx = {0}; ret = ptls_mbedtls_load_private_key(&ctx, path); - ok(ret == 0); if (ret != 0) { /* Cannot create sign_certificate */ ok(ret == 0); @@ -223,7 +222,6 @@ int test_load_one_der_key(char const *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)); @@ -256,8 +254,8 @@ int test_load_one_der_key(char const *path) if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { /* Cannot export public key */ ret = -1; + ok(ret == 0); } - ok(ret == 0); if (ret == 0) { switch (psa_get_key_type(&signer->attributes)) { case PSA_KEY_TYPE_RSA_KEY_PAIR: @@ -276,8 +274,8 @@ int test_load_one_der_key(char const *path) ok(ret == 0); if (ret == 0) { mbedtls_message_verify_ctx_t* verify_ctx = (mbedtls_message_verify_ctx_t*)malloc(sizeof(mbedtls_message_verify_ctx_t)); - ok(verify_ctx != NULL); if (verify_ctx == NULL) { + ok(verify_ctx != NULL); ret = -1; } else { @@ -292,7 +290,6 @@ int test_load_one_der_key(char const *path) ret = -1; } else { - ok(psa_status == 0); sig.base = outbuf.base; sig.len = outbuf.off; From 44741e984152d146226db7b23bf70b9c4ceb6f52 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 18:33:02 -0700 Subject: [PATCH 19/28] Simplify flow of tests --- t/mbedtls.c | 56 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 15b6dcdc..0d2faa17 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -204,7 +204,7 @@ typedef struct st_mbedtls_message_verify_ctx_t { int mbedtls_verify_sign(void* verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature); psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo); -int test_load_one_der_key(char const *path) +int test_load_one_der_key(char const *path, int expect_failure) { int ret = -1; unsigned char test_message[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, @@ -212,13 +212,13 @@ int test_load_one_der_key(char const *path) ptls_context_t ctx = {0}; ret = ptls_mbedtls_load_private_key(&ctx, path); - if (ret != 0) { + if (ret != 0 || expect_failure) { /* Cannot create sign_certificate */ ok(ret == 0); ret = -1; } else if (ctx.sign_certificate == NULL) { /* Sign_certificate not set in ptls context */ - ok(ctx.sign_certificate != NULL); + ok(ctx.sign_certificate != NULL || expect_failure); ret = -1; } else { /* Try to sign something */ @@ -241,7 +241,7 @@ int test_load_one_der_key(char const *path) ret = ptls_mbedtls_sign_certificate(ctx.sign_certificate, NULL, NULL, &selected_algorithm, &outbuf, input, algorithms, num_algorithms); - ok(ret == 0); + ok(ret == 0 || expect_failure); if (ret == 0) { /* Create a verifier context and attempt to check the key */ @@ -254,7 +254,7 @@ int test_load_one_der_key(char const *path) if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { /* Cannot export public key */ ret = -1; - ok(ret == 0); + ok(ret == 0 || expect_failure); } if (ret == 0) { switch (psa_get_key_type(&signer->attributes)) { @@ -271,11 +271,11 @@ int test_load_one_der_key(char const *path) break; } } - ok(ret == 0); + ok(ret == 0 || expect_failure); if (ret == 0) { mbedtls_message_verify_ctx_t* verify_ctx = (mbedtls_message_verify_ctx_t*)malloc(sizeof(mbedtls_message_verify_ctx_t)); if (verify_ctx == NULL) { - ok(verify_ctx != NULL); + ok(verify_ctx != NULL || expect_failure); ret = -1; } else { @@ -285,7 +285,7 @@ int test_load_one_der_key(char const *path) if ((psa_status = psa_import_key(&public_attributes, pubkey_data, pubkey_len, &verify_ctx->key_id)) != 0) { /* Cannot import public key */ - ok(psa_status == 0); + ok(psa_status == 0 || expect_failure); free(verify_ctx); ret = -1; } @@ -294,7 +294,7 @@ int test_load_one_der_key(char const *path) sig.len = outbuf.off; ret = mbedtls_verify_sign(verify_ctx, selected_algorithm, input, sig); - ok(ret == 0); + ok(ret == 0 || expect_failure); } } } @@ -303,9 +303,18 @@ int test_load_one_der_key(char const *path) ptls_buffer_dispose(&outbuf); ptls_mbedtls_dispose_sign_certificate(&signer->super); } + if (expect_failure){ + ok(ret != 0); + if (ret == 0) { + ret = -1; + } + else { + ret = 0; + } + } return ret; } - +#if 0 static void test_load_rsa_key() { int ret = test_load_one_der_key(ASSET_RSA_KEY); @@ -368,22 +377,29 @@ static void test_load_rsa_pkcs8_key() ok(!!"success"); } #endif +#endif void test_load_keys(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); -#if 0 + subtest("load rsa key", test_load_one_der_key, ASSET_RSA_KEY, 0); + subtest("load secp256r1 key", test_load_one_der_key, ASSET_SECP256R1_KEY, 0); + subtest("load secp384r1 key", test_load_one_der_key, ASSET_SECP384R1_KEY, 0); + subtest("load secp521r1 key", test_load_one_der_key, ASSET_SECP521R1_KEY, 0); + subtest("load secp521r1-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); +#if 1 /* disabling for now, need to debug. */ - subtest("load rsa-pkcs8 key", test_load_rsa_pkcs8_key); + subtest("load rsa-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); #endif /* we do not test EDDSA keys, because they are not yet supported */ -} + /* add tests for failure modes */ + subtest("load key no such file", test_load_one_der_key, ASSET_NO_SUCH_FILE, 1); + subtest("load key not a PEM file", test_load_one_der_key, ASSET_NOT_A_PEM_FILE, 1); + subtest("load key not a key file", test_load_one_der_key, ASSET_RSA_CERT, 1); + subtest("load key not supported", test_load_one_der_key, ASSET_ED25519_KEY, 1); +} +#if 0 static void test_load_key_no_such_file() { int ret = test_load_one_der_key(ASSET_NO_SUCH_FILE); @@ -441,6 +457,7 @@ static void test_load_key_fail() subtest("load key not a key file", test_load_key_not_a_key_file); subtest("load key not supported", test_load_key_not_supported); } +#endif /* * End to end testing of signature and verifiers: @@ -821,9 +838,10 @@ int main(int argc, char **argv) /* test loading of keys in memory and capability to sign */ subtest("test load keys", test_load_keys); - +#if 0 /* Test that loading bad files or bad keys fails */ subtest("test load key failures", test_load_key_fail); +#endif /* End to end test of signing and verifying certicates */ subtest("test sign verify end to end", test_sign_verify_end_to_end); From 117011f4e603f08232cbd4d1c5dc8b31af463f72 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 18:35:15 -0700 Subject: [PATCH 20/28] Fix test on line 217 --- t/mbedtls.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 0d2faa17..b033d45f 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -212,9 +212,9 @@ int test_load_one_der_key(char const *path, int expect_failure) ptls_context_t ctx = {0}; ret = ptls_mbedtls_load_private_key(&ctx, path); - if (ret != 0 || expect_failure) { + if (ret != 0) { /* Cannot create sign_certificate */ - ok(ret == 0); + ok(ret == 0 || expect_failure); ret = -1; } else if (ctx.sign_certificate == NULL) { /* Sign_certificate not set in ptls context */ From 7d3f7adcbc59f1c8afa270978b88f71604b4073d Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 19:08:43 -0700 Subject: [PATCH 21/28] Use server name in verify cert --- t/mbedtls.c | 173 +++++++++------------------------------------------- 1 file changed, 28 insertions(+), 145 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index b033d45f..a6d80903 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -149,6 +149,13 @@ Output buffer is already partially filled. #define ASSET_ED25519_CERT "t/assets/ed25519/cert.pem" #define ASSET_TEST_CA "data/test-ca.crt" +#define ASSET_RSA_NAME "rsa.test.example.com" +#define ASSET_RSA_PKCS8_NAME "rsa.test.example.com" +#define ASSET_SECP256R1_NAME "test.example.com" +#define ASSET_SECP384R1_NAME "secp384r1.test.example.com" +#define ASSET_SECP521R1_NAME "secp521r1.test.example.com" +#define ASSET_SECP256R1_PKCS8_NAME "test.example.com" + int test_load_one_file(char const* path) { size_t n; @@ -312,72 +319,9 @@ int test_load_one_der_key(char const *path, int expect_failure) ret = 0; } } + ok(ret == 0); return ret; } -#if 0 -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"); -} - -#if 0 -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"); -} -#endif -#endif void test_load_keys(void) { @@ -386,78 +330,15 @@ void test_load_keys(void) subtest("load secp384r1 key", test_load_one_der_key, ASSET_SECP384R1_KEY, 0); subtest("load secp521r1 key", test_load_one_der_key, ASSET_SECP521R1_KEY, 0); subtest("load secp521r1-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); -#if 1 - /* disabling for now, need to debug. */ subtest("load rsa-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); -#endif - /* we do not test EDDSA keys, because they are not yet supported */ - /* add tests for failure modes */ + /* add tests for failure modes, including EDDSA which is not supported */ subtest("load key no such file", test_load_one_der_key, ASSET_NO_SUCH_FILE, 1); subtest("load key not a PEM file", test_load_one_der_key, ASSET_NOT_A_PEM_FILE, 1); subtest("load key not a key file", test_load_one_der_key, ASSET_RSA_CERT, 1); subtest("load key not supported", test_load_one_der_key, ASSET_ED25519_KEY, 1); } -#if 0 -static void test_load_key_no_such_file() -{ - int ret = test_load_one_der_key(ASSET_NO_SUCH_FILE); - if (ret == 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_load_key_not_a_pem_file() -{ - int ret = test_load_one_der_key(ASSET_NOT_A_PEM_FILE); - if (ret == 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_load_key_not_a_key_file() -{ - int ret = test_load_one_der_key(ASSET_RSA_CERT); - if (ret == 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_load_key_not_supported() -{ - int ret = test_load_one_der_key(ASSET_ED25519_KEY); - if (ret == 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -/* -* Testing of failure modes. -* -* Testing the various reasons why loading of key should fail: -* - key file does not exist -* - key file is empty, no PEM keyword -* - key file does not contain a key (we use a cert file for that) -* - key file is for ED25559, which is not supported -*/ - -static void test_load_key_fail() -{ - subtest("load key no such file", test_load_key_no_such_file); - subtest("load key not a PEM file", test_load_key_not_a_pem_file); - subtest("load key not a key file", test_load_key_not_a_key_file); - subtest("load key not supported", test_load_key_not_supported); -} -#endif /* * End to end testing of signature and verifiers: @@ -498,8 +379,6 @@ static uint16_t test_sign_signature_algorithms[] = { static size_t num_test_sign_signature_algorithms = sizeof(test_sign_signature_algorithms) / sizeof(uint16_t); -char const* test_sign_server_name = "test.example.com"; - static int test_sign_init_server_mbedtls(ptls_context_t* ctx, char const* key_path, char const* cert_path) { int ret = ptls_mbedtls_load_private_key(ctx, key_path); @@ -615,7 +494,7 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con return ctx; } -static int test_sign_verify_one(char const* key_path, char const * cert_path, char const * trusted_path, int server_config, int client_config) +static int test_sign_verify_one(char const* key_path, char const * cert_path, char const * trusted_path, char const * server_name, int server_config, int client_config) { int ret = 0; ptls_context_t* server_ctx = test_sign_set_ptls_context(key_path, cert_path, trusted_path, 1, server_config); @@ -653,7 +532,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch &selected_algorithm, &signature, input, test_sign_signature_algorithms, num_test_sign_signature_algorithms); if (ret != 0) { - printf("sign_certificate (%s) returns 0x%x\n", key_path, ret); + ok(ret == 0); } } @@ -661,17 +540,18 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch /* Then, create a tls context for the client. */ client_tls = ptls_new(client_ctx, 0); if (client_tls == NULL) { + ok(client_tls != NULL); ret = -1; } } if (ret == 0) { /* verify the certificates */ - ret = client_ctx->verify_certificate->cb(client_ctx->verify_certificate, client_tls, test_sign_server_name, + ret = client_ctx->verify_certificate->cb(client_ctx->verify_certificate, client_tls, server_name, &certificate_verify.cb, &certificate_verify.verify_ctx, server_ctx->certificates.list, server_ctx->certificates.count); if (ret != 0) { - printf("verify_certificate (%s) returns 0x%x\n", cert_path, ret); + ok(ret == 0); } /* verify the signature */ if (ret == 0) { @@ -681,7 +561,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch ret = certificate_verify.cb(certificate_verify.verify_ctx, selected_algorithm, input, sig); if (ret != 0) { - printf("verify_signature (%s) returns 0x%x\n", key_path, ret); + ok(ret == 0); } } else if (certificate_verify.cb != NULL) { @@ -691,9 +571,6 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch (void)certificate_verify.cb(certificate_verify.verify_ctx, 0, empty, empty); } } - if (ret == 0) { - printf("verify_signature (%s) and cert (%s) succeeds\n", key_path, cert_path); - } ptls_buffer_dispose(&signature); @@ -707,9 +584,10 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch test_sign_free_context(server_ctx, server_config); test_sign_free_context(client_ctx, client_config); + ok(ret == 0); return ret; } - +#if 0 static void test_sign_verify_rsa_mbedtls_mbedtls() { int ret = test_sign_verify_one(ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, 0, 0); @@ -759,7 +637,7 @@ static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() } ok(!!"success"); } - +#endif /* TODO: all these tests are failing, because we do not have the * proper combination of hostname and certificate. Fix that, then * enable the test. @@ -771,11 +649,16 @@ static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() static void test_sign_verify_end_to_end() { - subtest("sign verify rsa mbedtls mbedtls", test_sign_verify_rsa_mbedtls_mbedtls); - subtest("sign verify secp256r1 mbedtls mbedtls", test_sign_verify_secp256r1_mbedtls_mbedtls); - subtest("sign verify secp384r1 mbedtls mbedtls", test_sign_verify_secp384r1_mbedtls_mbedtls); - subtest("sign verify secp521r1 mbedtls mbedtls", test_sign_verify_secp521r1_mbedtls_mbedtls); - subtest("sign verify secp256r1 pkcs8 mbedtls mbedtls", test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls); + subtest("verify rsa mbedtls mbedtls", test_sign_verify_one, + ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, ASSET_RSA_NAME, 0, 0); + subtest("verify secp256r1 mbedtls mbedtls", test_sign_verify_one, + ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_TEST_CA, ASSET_SECP256R1_NAME, 0, 0); + subtest("verify secp384r1 mbedtls mbedtls", test_sign_verify_one, + ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT, ASSET_TEST_CA, ASSET_SECP384R1_NAME, 0, 0); + subtest("verify secp521r1 mbedtls mbedtls", test_sign_verify_one, + ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_TEST_CA, ASSET_SECP521R1_NAME, 0, 0); + subtest("verify secp256r1 pkcs8 mbedtls mbedtls", test_sign_verify_one, + ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_TEST_CA, ASSET_SECP256R1_PKCS8_NAME, 0, 0); } From 428e6d83be5bb4c2e4a5f552d7f5295b298e1752 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 19:14:37 -0700 Subject: [PATCH 22/28] Debugging the end to end test. --- t/mbedtls.c | 63 +++++------------------------------------------------ 1 file changed, 5 insertions(+), 58 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index a6d80903..fd463d76 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -515,6 +515,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch ptls_buffer_init(&signature, signature_smallbuf, sizeof(signature_smallbuf)); if (server_ctx == NULL || client_ctx == NULL) { + ok(server_ctx != NULL && client_ctx != NULL); ret = -1; } @@ -522,6 +523,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch /* Then, create a tls context for the server. */ server_tls = ptls_new(server_ctx, 1); if (server_tls == NULL) { + ok(server_tls != NULL) ret = -1; } } @@ -560,9 +562,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch sig.len = signature.off; ret = certificate_verify.cb(certificate_verify.verify_ctx, selected_algorithm, input, sig); - if (ret != 0) { - ok(ret == 0); - } + ok(ret == 0); } else if (certificate_verify.cb != NULL) { ptls_iovec_t empty; @@ -587,57 +587,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch ok(ret == 0); return ret; } -#if 0 -static void test_sign_verify_rsa_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_RSA_KEY, ASSET_RSA_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} -static void test_sign_verify_secp256r1_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_sign_verify_secp384r1_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_sign_verify_secp521r1_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} - -static void test_sign_verify_secp256r1_pkcs8_mbedtls_mbedtls() -{ - int ret = test_sign_verify_one(ASSET_SECP256R1_PKCS8_KEY, ASSET_SECP256R1_PKCS8_CERT, ASSET_TEST_CA, 0, 0); - if (ret != 0){ - ok(!"fail"); - return; - } - ok(!!"success"); -} -#endif /* TODO: all these tests are failing, because we do not have the * proper combination of hostname and certificate. Fix that, then * enable the test. @@ -719,12 +669,9 @@ int main(int argc, char **argv) /* Test loading file in memory */ subtest("test load file", test_load_file); - /* test loading of keys in memory and capability to sign */ + /* test loading of keys in memory and capability to sign, + * and also verify failure modes. */ subtest("test load keys", test_load_keys); -#if 0 - /* Test that loading bad files or bad keys fails */ - subtest("test load key failures", test_load_key_fail); -#endif /* End to end test of signing and verifying certicates */ subtest("test sign verify end to end", test_sign_verify_end_to_end); From 0408666e24b9c8c3a0d137adaa3ed91756bc05fa Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 19:17:11 -0700 Subject: [PATCH 23/28] Fix typo --- t/mbedtls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index fd463d76..05f6e5b9 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -523,7 +523,7 @@ static int test_sign_verify_one(char const* key_path, char const * cert_path, ch /* Then, create a tls context for the server. */ server_tls = ptls_new(server_ctx, 1); if (server_tls == NULL) { - ok(server_tls != NULL) + ok(server_tls != NULL); ret = -1; } } From cbd630cace179230488ef283d5ddbdc249f53dee Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 19:24:15 -0700 Subject: [PATCH 24/28] Add debugging traces --- t/mbedtls.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/t/mbedtls.c b/t/mbedtls.c index 05f6e5b9..2976cf2f 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -446,6 +446,7 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con int ret = 0; ptls_context_t* ctx = (ptls_context_t*)malloc(sizeof(ptls_context_t)); if (ctx == NULL) { + ok(ctx != 0); return NULL; } @@ -465,11 +466,14 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con switch (config) { case 0: /* MbedTLS */ ret = test_sign_init_server_mbedtls(ctx, key_path, cert_path); + ok(ret == 0); break; case 1: /* Minicrypto */ ret = test_sign_init_server_minicrypto(ctx, key_path, cert_path); + ok(ret == 0); break; default: + ok(ret == 0); ret = -1; break; } @@ -479,8 +483,10 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con switch (config) { case 0: /* MbedTLS */ ret = ptls_mbedtls_init_verify_certificate(ctx, trusted_path); + ok(ret == 0); break; default: + ok(ret == 0); ret = -1; break; } From 675dced12f081710dc54df27e8ae9ba2200ca624 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Sun, 19 May 2024 19:33:26 -0700 Subject: [PATCH 25/28] Fix location of trusted CA --- t/mbedtls.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 2976cf2f..14a00fc4 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -147,7 +147,7 @@ Output buffer is already partially filled. #define ASSET_SECP521R1_CERT "t/assets/secp521r1/cert.pem" #define ASSET_SECP256R1_PKCS8_CERT "t/assets/secp256r1-pkcs8/cert.pem" #define ASSET_ED25519_CERT "t/assets/ed25519/cert.pem" -#define ASSET_TEST_CA "data/test-ca.crt" +#define ASSET_TEST_CA "t/assets/test-ca.crt" #define ASSET_RSA_NAME "rsa.test.example.com" #define ASSET_RSA_PKCS8_NAME "rsa.test.example.com" @@ -255,7 +255,7 @@ int test_load_one_der_key(char const *path, int expect_failure) ptls_iovec_t sig; uint8_t pubkey_data[1024]; size_t pubkey_len = 0; - psa_status_t psa_status; + psa_status_t psa_status; psa_key_attributes_t public_attributes = psa_key_attributes_init(); if ((psa_status = psa_export_public_key(signer->key_id, pubkey_data, sizeof(pubkey_data), &pubkey_len)) != 0) { @@ -446,7 +446,7 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con int ret = 0; ptls_context_t* ctx = (ptls_context_t*)malloc(sizeof(ptls_context_t)); if (ctx == NULL) { - ok(ctx != 0); + ok(ctx != NULL); return NULL; } @@ -466,15 +466,19 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con switch (config) { case 0: /* MbedTLS */ ret = test_sign_init_server_mbedtls(ctx, key_path, cert_path); - ok(ret == 0); + if (ret != 0) { + ok(ret == 0); + } break; case 1: /* Minicrypto */ ret = test_sign_init_server_minicrypto(ctx, key_path, cert_path); - ok(ret == 0); + if (ret != 0) { + ok(ret == 0); + } break; default: - ok(ret == 0); ret = -1; + ok(ret == 0); break; } } @@ -483,11 +487,13 @@ static ptls_context_t* test_sign_set_ptls_context(char const* key_path, char con switch (config) { case 0: /* MbedTLS */ ret = ptls_mbedtls_init_verify_certificate(ctx, trusted_path); - ok(ret == 0); + if (ret != 0) { + ok(ret == 0); + } break; default: - ok(ret == 0); ret = -1; + ok(ret == 0); break; } } From 95ab894e92148fec2565d46a368ef69b9d6c24d0 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Mon, 20 May 2024 19:08:25 -0700 Subject: [PATCH 26/28] Don't use problematic API --- lib/mbedtls_sign.c | 152 +++++++++++++++++++++++++++++++++++++++++++-- t/mbedtls.c | 137 +++++++++++++++++++++++++++++++++++----- 2 files changed, 269 insertions(+), 20 deletions(-) diff --git a/lib/mbedtls_sign.c b/lib/mbedtls_sign.c index 99afda7d..3ebedcb8 100644 --- a/lib/mbedtls_sign.c +++ b/lib/mbedtls_sign.c @@ -216,7 +216,14 @@ int ptls_mbedtls_parse_ec_private_key(const unsigned char *pem_buf, size_t pem_l 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, +/* Parsing the private key field in a PEM key object. +* The syntax is similar to the "public key info", but there +* are differences, such as encoding the key as an octet +* string instead of a bit field. +* TODO: look at unifying the common parts for making the +* code a bit smaller. +*/ +int ptls_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; @@ -372,12 +379,128 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ } #endif +/* When finding public keys in a certificate, we expect the syntax to be: +* SubjectPublicKeyInfo ::= SEQUENCE { +* algorithm AlgorithmIdentifier, +* subjectPublicKey BIT STRING +* } +* AlgorithmIdentifier ::= SEQUENCE { +* algorithm OBJECT IDENTIFIER, +* parameters ANY DEFINED BY algorithm OPTIONAL +* } +*/ +static int ptls_mbedtls_parse_public_key_info(const unsigned char *pem_buf, size_t pem_len, + size_t *oid_index, size_t *oid_length, + size_t *param_index, size_t *param_length, + size_t *key_index, size_t *key_length) +{ + int ret = 0; + size_t x = 0; + + if (ret == 0) { + if (pem_buf[x++] != 0x30 /* sequence */) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + else { + size_t l_seq1 = 0; + size_t x_seq1; + ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, &l_seq1); + x_seq1 = x; + if (x + l_seq1 > pem_len || pem_buf[x++] != 0x30) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + else { + 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) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + else { + /* Sequence contains the OID and optional key attributes */ + *oid_length = pem_buf[x++]; + *oid_index = x; + *param_index = x + *oid_length; + x = x_seq + l_seq; + if (*param_index > x) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + else { + *param_length = x - *param_index; + } + } + } + + if (ret == 0) { + /* At that point the oid has been identified. + * The next parameter is an octet string containing the key info. + */ + if (x + 2 > pem_len || pem_buf[x++] != 0x03) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + else { + ret = ptls_mbedtls_parse_der_length(pem_buf, pem_len, &x, key_length); + *key_index = x; + x += *key_length; + if (x > pem_len) { + ret = PTLS_ERROR_INCORRECT_ASN1_SYNTAX; + } + } + } + } + } + + return ret; +} + +/* Obtain the public key bits and the public key attributes from the +* subject public key info in a certificate. +*/ +int ptls_mbedtls_get_public_key_info(const unsigned char* pk_raw, size_t pk_raw_len, + psa_key_attributes_t* attributes, + size_t* key_index, size_t* key_length) +{ + size_t oid_index, oid_length, param_index, param_length; + int ret = ptls_mbedtls_parse_public_key_info(pk_raw, pk_raw_len, + &oid_index, &oid_length, ¶m_index, ¶m_length, key_index, key_length); + + if (ret == 0) { + /* find the key type from the OID. Use key type to derive + * further attributes from parameter, or update the value + * of the key index to skip unused version field, etc. + */ + if (oid_length == sizeof(ptls_mbedtls_oid_rsa_key) && + memcmp(pk_raw + oid_index, ptls_mbedtls_oid_rsa_key, sizeof(ptls_mbedtls_oid_rsa_key)) == 0) { + /* We recognized RSA */ + psa_set_key_type(attributes, PSA_KEY_TYPE_RSA_PUBLIC_KEY); + if (*key_length > 0 && pk_raw[*key_index] == 0) { + (*key_index)++; + (*key_length)--; + } + } + else if (oid_length == sizeof(ptls_mbedtls_oid_ec_key) && + memcmp(pk_raw + oid_index, ptls_mbedtls_oid_ec_key, sizeof(ptls_mbedtls_oid_ec_key)) == 0) { + /* We recognized ECDSA */ + psa_set_key_type(attributes, PSA_KEY_TYPE_ECC_PUBLIC_KEY(PSA_ECC_FAMILY_SECP_R1)); + if (*key_length > 0 && pk_raw[*key_index] == 0) { + (*key_index)++; + (*key_length)--; + } + } else { + ret = PTLS_ERROR_NOT_AVAILABLE; + } + } + return ret; +} + + 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, uint16_t * selected_algorithm) { const ptls_mbedtls_signature_scheme_t *scheme; - /* select the algorithm, driven by server preference of `available` */ + /* 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) { if (algorithms[i] == scheme->scheme_id) { @@ -652,7 +775,6 @@ int ptls_mbedtls_load_file(char const * file_name, unsigned char ** buf, size_t F = fopen(file_name, "rb"); #endif - if (F == NULL) { ret = PTLS_ERROR_NOT_AVAILABLE; } else { @@ -735,7 +857,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname) 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); + ptls_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 */ @@ -1090,7 +1212,22 @@ static int mbedtls_verify_certificate(ptls_verify_certificate_t *_self, ptls_t * ret = PTLS_ERROR_NO_MEMORY; } else { - psa_status_t status; +#if 1 + /* Obtain the key bits from the certificate */ + size_t key_index; + size_t key_length; + psa_key_attributes_t attributes = psa_key_attributes_init(); + + ret = ptls_mbedtls_get_public_key_info(chain_head->pk_raw.p, chain_head->pk_raw.len, + &attributes, &key_index, &key_length); + + if (ret == 0) { + if (psa_import_key(&attributes, chain_head->pk_raw.p + key_index, key_length, &message_verify_ctx->key_id) != 0) { + ret = PTLS_ERROR_LIBRARY; + } + } +#else + psa_status_t status = 0; psa_key_attributes_t attributes; memset(&attributes, 0, sizeof(attributes)); memset(message_verify_ctx, 0, sizeof(mbedtls_message_verify_ctx_t)); @@ -1101,6 +1238,9 @@ static int mbedtls_verify_certificate(ptls_verify_certificate_t *_self, ptls_t * } if (status != PSA_SUCCESS) { ret = PTLS_ERROR_LIBRARY; + } +#endif + if (ret != 0) { free(message_verify_ctx); } else { @@ -1263,4 +1403,4 @@ void ptls_mbedtls_dispose_verify_certificate(ptls_context_t* ptls_ctx) free(verifier); ptls_ctx->verify_certificate = NULL; } -} +} \ No newline at end of file diff --git a/t/mbedtls.c b/t/mbedtls.c index 14a00fc4..78f0c187 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -211,7 +211,7 @@ typedef struct st_mbedtls_message_verify_ctx_t { int mbedtls_verify_sign(void* verify_ctx, uint16_t algo, ptls_iovec_t data, ptls_iovec_t signature); psa_algorithm_t mbedtls_get_psa_alg_from_tls_number(uint16_t tls_algo); -int test_load_one_der_key(char const *path, int expect_failure) +int test_load_one_key(char const *path, int expect_failure) { int ret = -1; unsigned char test_message[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, @@ -325,19 +325,125 @@ int test_load_one_der_key(char const *path, int expect_failure) void test_load_keys(void) { - subtest("load rsa key", test_load_one_der_key, ASSET_RSA_KEY, 0); - subtest("load secp256r1 key", test_load_one_der_key, ASSET_SECP256R1_KEY, 0); - subtest("load secp384r1 key", test_load_one_der_key, ASSET_SECP384R1_KEY, 0); - subtest("load secp521r1 key", test_load_one_der_key, ASSET_SECP521R1_KEY, 0); - subtest("load secp521r1-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); - subtest("load rsa-pkcs8 key", test_load_one_der_key, ASSET_RSA_PKCS8_KEY, 0); + subtest("load rsa key", test_load_one_key, ASSET_RSA_KEY, 0); + subtest("load secp256r1 key", test_load_one_key, ASSET_SECP256R1_KEY, 0); + subtest("load secp384r1 key", test_load_one_key, ASSET_SECP384R1_KEY, 0); + subtest("load secp521r1 key", test_load_one_key, ASSET_SECP521R1_KEY, 0); + subtest("load secp521r1-pkcs8 key", test_load_one_key, ASSET_RSA_PKCS8_KEY, 0); + subtest("load rsa-pkcs8 key", test_load_one_key, ASSET_RSA_PKCS8_KEY, 0); /* add tests for failure modes, including EDDSA which is not supported */ - subtest("load key no such file", test_load_one_der_key, ASSET_NO_SUCH_FILE, 1); - subtest("load key not a PEM file", test_load_one_der_key, ASSET_NOT_A_PEM_FILE, 1); - subtest("load key not a key file", test_load_one_der_key, ASSET_RSA_CERT, 1); - subtest("load key not supported", test_load_one_der_key, ASSET_ED25519_KEY, 1); + subtest("load key no such file", test_load_one_key, ASSET_NO_SUCH_FILE, 1); + subtest("load key not a PEM file", test_load_one_key, ASSET_NOT_A_PEM_FILE, 1); + subtest("load key not a key file", test_load_one_key, ASSET_RSA_CERT, 1); + subtest("load key not supported", test_load_one_key, ASSET_ED25519_KEY, 1); +} + +/* testing of public key export. +* The API to export a public key directly from the certificate is not present +* in older versions of MbedTLS, which might be installed by default in +* old versions of operating systems. Instead, we develop a robust way to +* export the key bits from the "raw public key" bytes in the certificate. +* But we need to test that this work properly, and we do that by +* comparing to the export of key bits from the private key, because for +* these tests we know the private key. +*/ +int ptls_mbedtls_get_public_key_info(const unsigned char* pk_raw, size_t pk_raw_len, + psa_key_attributes_t* attributes, + size_t* key_index, size_t* key_length); + +static int test_retrieve_pubkey_one(char const* key_path, char const* cert_path) +{ + int ret = 0; + ptls_context_t ctx = { 0 }; + mbedtls_x509_crt* chain_head = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); + uint8_t pubkey_ref[1024]; + uint8_t pubkey_val[1024]; + size_t pubkey_ref_len = 0; + size_t pubkey_val_len = 0; + + /* Preparation: load the certificate and the private key */ + if (chain_head == NULL) { + ret = PTLS_ERROR_NO_MEMORY; + ok(ret == 0); + } + if (ret == 0) { + mbedtls_x509_crt_init(chain_head); + + if (mbedtls_x509_crt_parse_file(chain_head, cert_path) != 0) { + ret = -1; + ok(ret == 0); + } + } + if (ret == 0) { + ret = ptls_mbedtls_load_private_key(&ctx, key_path); + if (ret != 0) { + ok(ret == 0); + } + } + /* Export the pubkey bits from the private key, for reference */ + if (ret == 0) { + 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)); + if (psa_export_public_key(signer->key_id, pubkey_ref, sizeof(pubkey_ref), &pubkey_ref_len) != 0) { + ret = -1; + ok(ret == 0); + } + } + /* Obtain the key bits from the certificate */ + if (ret == 0) { + uint8_t * pk_raw = chain_head->pk_raw.p; + size_t pk_raw_len = chain_head->pk_raw.len; + size_t key_index; + size_t key_length; + psa_key_attributes_t attributes = psa_key_attributes_init(); + + ret = ptls_mbedtls_get_public_key_info(pk_raw, pk_raw_len, + &attributes, &key_index, &key_length); + + if (ret == 0) { + if (key_length > sizeof(pubkey_val)) { + ret = -1; + ok(ret == 0); + } + else { + mbedtls_svc_key_id_t pub_key_id; + memcpy(pubkey_val, pk_raw + key_index, key_length); + pubkey_val_len = key_length; + } + } + else { + ok(ret == 0); + } + } + + /* Compare key bits */ + if (ret == 0) { + if (pubkey_ref_len != pubkey_val_len || + memcmp(pubkey_ref, pubkey_val, pubkey_ref_len) != 0) { + ret = -1; + ok(ret == 0); + } + } + /* Clean up */ + if (ctx.sign_certificate != NULL) { + ptls_mbedtls_dispose_sign_certificate(ctx.sign_certificate); + } + if (chain_head != NULL) { + mbedtls_x509_crt_free(chain_head); + } + ok(ret == 0); + + return ret; +} + +static int test_retrieve_pubkey() +{ + subtest("retrieve pubkey RSA", test_retrieve_pubkey_one, ASSET_RSA_KEY, ASSET_RSA_CERT); + subtest("retrieve pubkey secp256r1", test_retrieve_pubkey_one, ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT); + subtest("retrieve pubkey secp384r1", test_retrieve_pubkey_one, ASSET_SECP384R1_KEY, ASSET_SECP384R1_CERT); + subtest("retrieve pubkey secp521r1", test_retrieve_pubkey_one, ASSET_SECP521R1_KEY, ASSET_SECP521R1_CERT); } /* @@ -679,14 +785,17 @@ int main(int argc, char **argv) subtest("minicrypto vs.", test_picotls); /* Test loading file in memory */ - subtest("test load file", test_load_file); + subtest("load file", test_load_file); /* test loading of keys in memory and capability to sign, * and also verify failure modes. */ - subtest("test load keys", test_load_keys); + subtest("load keys", test_load_keys); + + /* Check that the bits of the public key are correctly retrieved from a certificate */ + subtest("retrieve public key from cert", test_retrieve_pubkey); /* End to end test of signing and verifying certicates */ - subtest("test sign verify end to end", test_sign_verify_end_to_end); + subtest("sign verify end to end", test_sign_verify_end_to_end); /* Deinitialize the PSA crypto library. */ mbedtls_psa_crypto_free(); From f37b7bcf62605516637deb7f6efd02f8f40223f6 Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Mon, 20 May 2024 19:20:29 -0700 Subject: [PATCH 27/28] Add include, simplify test --- t/mbedtls.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 78f0c187..34ad729c 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -37,6 +37,7 @@ #include "picotls/minicrypto.h" #include "mbedtls/pk.h" #include "mbedtls/pem.h" +#include "mbedtls/x509_crt.h" #include "mbedtls/error.h" typedef struct st_ptls_mbedtls_signature_scheme_t { @@ -353,7 +354,7 @@ int ptls_mbedtls_get_public_key_info(const unsigned char* pk_raw, size_t pk_raw_ psa_key_attributes_t* attributes, size_t* key_index, size_t* key_length); -static int test_retrieve_pubkey_one(char const* key_path, char const* cert_path) +static void test_retrieve_pubkey_one(char const* key_path, char const* cert_path) { int ret = 0; ptls_context_t ctx = { 0 }; @@ -403,29 +404,17 @@ static int test_retrieve_pubkey_one(char const* key_path, char const* cert_path) &attributes, &key_index, &key_length); if (ret == 0) { - if (key_length > sizeof(pubkey_val)) { - ret = -1; + /* Compare key bits */ + if (pubkey_ref_len != key_length || + memcmp(pubkey_ref, chain_head->pk_raw.p + key_index, key_length) != 0) { ok(ret == 0); } - else { - mbedtls_svc_key_id_t pub_key_id; - memcpy(pubkey_val, pk_raw + key_index, key_length); - pubkey_val_len = key_length; - } } else { ok(ret == 0); } } - /* Compare key bits */ - if (ret == 0) { - if (pubkey_ref_len != pubkey_val_len || - memcmp(pubkey_ref, pubkey_val, pubkey_ref_len) != 0) { - ret = -1; - ok(ret == 0); - } - } /* Clean up */ if (ctx.sign_certificate != NULL) { ptls_mbedtls_dispose_sign_certificate(ctx.sign_certificate); @@ -434,11 +423,9 @@ static int test_retrieve_pubkey_one(char const* key_path, char const* cert_path) mbedtls_x509_crt_free(chain_head); } ok(ret == 0); - - return ret; } -static int test_retrieve_pubkey() +static void test_retrieve_pubkey() { subtest("retrieve pubkey RSA", test_retrieve_pubkey_one, ASSET_RSA_KEY, ASSET_RSA_CERT); subtest("retrieve pubkey secp256r1", test_retrieve_pubkey_one, ASSET_SECP256R1_KEY, ASSET_SECP256R1_CERT); From bad0e5077fc4d6673092a4fffec0a5620f6140ad Mon Sep 17 00:00:00 2001 From: Christian Huitema Date: Mon, 20 May 2024 19:39:33 -0700 Subject: [PATCH 28/28] Remove unused variable. --- t/mbedtls.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/t/mbedtls.c b/t/mbedtls.c index 34ad729c..feea42e5 100644 --- a/t/mbedtls.c +++ b/t/mbedtls.c @@ -360,9 +360,7 @@ static void test_retrieve_pubkey_one(char const* key_path, char const* cert_path ptls_context_t ctx = { 0 }; mbedtls_x509_crt* chain_head = (mbedtls_x509_crt*)malloc(sizeof(mbedtls_x509_crt)); uint8_t pubkey_ref[1024]; - uint8_t pubkey_val[1024]; size_t pubkey_ref_len = 0; - size_t pubkey_val_len = 0; /* Preparation: load the certificate and the private key */ if (chain_head == NULL) {