Merge branch 'bugfix/backport_certificate_bundle_fixes_v4.3' into 'release/v4.3'

Certificate bundle fixes (v4.3)

See merge request espressif/esp-idf!18353
This commit is contained in:
Jiang Jiang Jian
2022-06-09 11:13:41 +08:00
8 changed files with 1019 additions and 931 deletions

View File

@@ -15,9 +15,9 @@ if(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
set(GENERATE_CERT_BUNDLEPY ${python} ${COMPONENT_DIR}/esp_crt_bundle/gen_crt_bundle.py) set(GENERATE_CERT_BUNDLEPY ${python} ${COMPONENT_DIR}/esp_crt_bundle/gen_crt_bundle.py)
if(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL) if(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL)
list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem) list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem ${DEFAULT_CRT_DIR}/cacrt_local.pem)
elseif(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN) elseif(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN)
list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem) list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem ${DEFAULT_CRT_DIR}/cacrt_local.pem)
list(APPEND args --filter ${DEFAULT_CRT_DIR}/cmn_crt_authorities.csv) list(APPEND args --filter ${DEFAULT_CRT_DIR}/cmn_crt_authorities.csv)
endif() endif()

View File

@@ -323,6 +323,12 @@ menu "mbedTLS"
help help
Name of the custom certificate directory or file. This path is evaluated Name of the custom certificate directory or file. This path is evaluated
relative to the project root directory. relative to the project root directory.
config MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS
int "Maximum no of certificates allowed in certificate bundle"
default 200
depends on MBEDTLS_CERTIFICATE_BUNDLE
endmenu endmenu
config MBEDTLS_ECP_RESTARTABLE config MBEDTLS_ECP_RESTARTABLE

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
##
## Local CA Root Certificates
##
## Local CA Root Certificates that gets appended to "cacrt_all.pem"
## letsencrypt has generated a cross signed certificate with DST ROOT CA X3
## for compatibility after the expiry of the certificate.
## The new certificate has the ISSUER name as DST Root CA X3.
## Thus, the handshake fails if esp_crt_bundle does not find the
## respective name in the crt_bundle.
## Keeping this certificate for compatibility reasons.
## This will be removed once the cross-signed certificate expires in Sep 2024.
DST Root CA X3
==============
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/MSQwIgYDVQQK
ExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMTDkRTVCBSb290IENBIFgzMB4X
DTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVowPzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1
cmUgVHJ1c3QgQ28uMRcwFQYDVQQDEw5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQAD
ggEPADCCAQoCggEBAN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmT
rE4Orz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEqOLl5CjH9
UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9bxiqKqy69cK3FCxolkHRy
xXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40d
utolucbY38EVAjqr2m7xPi71XAicPNaDaeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0T
AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQ
MA0GCSqGSIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69ikug
dB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXrAvHRAosZy5Q6XkjE
GB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZzR8srzJmwN0jP41ZL9c8PDHIyh8bw
RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----

View File

@@ -17,7 +17,6 @@
#include <esp_system.h> #include <esp_system.h>
#include "esp_crt_bundle.h" #include "esp_crt_bundle.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_err.h"
#define BUNDLE_HEADER_OFFSET 2 #define BUNDLE_HEADER_OFFSET 2
#define CRT_HEADER_OFFSET 4 #define CRT_HEADER_OFFSET 4
@@ -157,27 +156,56 @@ int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int depth, uint32_
/* Initialize the bundle into an array so we can do binary search for certs, /* Initialize the bundle into an array so we can do binary search for certs,
the bundle generated by the python utility is already presorted by subject name the bundle generated by the python utility is already presorted by subject name
*/ */
static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle) static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle, size_t bundle_size)
{ {
s_crt_bundle.num_certs = (x509_bundle[0] << 8) | x509_bundle[1]; if (bundle_size < BUNDLE_HEADER_OFFSET + CRT_HEADER_OFFSET) {
s_crt_bundle.crts = calloc(s_crt_bundle.num_certs, sizeof(x509_bundle)); ESP_LOGE(TAG, "Invalid certificate bundle");
return ESP_ERR_INVALID_ARG;
}
if (s_crt_bundle.crts == NULL) { uint16_t num_certs = (x509_bundle[0] << 8) | x509_bundle[1];
if (num_certs > CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS) {
ESP_LOGE(TAG, "No. of certs in the certificate bundle = %d exceeds\n"
"Max allowed certificates in the certificate bundle = %d\n"
"Please update the menuconfig option with appropriate value", num_certs, CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS);
return ESP_ERR_INVALID_ARG;
}
const uint8_t **crts = calloc(num_certs, sizeof(x509_bundle));
if (crts == NULL) {
ESP_LOGE(TAG, "Unable to allocate memory for bundle"); ESP_LOGE(TAG, "Unable to allocate memory for bundle");
return ESP_ERR_NO_MEM; return ESP_ERR_NO_MEM;
} }
const uint8_t *cur_crt; const uint8_t *cur_crt;
/* This is the maximum region that is allowed to access */
const uint8_t *bundle_end = x509_bundle + bundle_size;
cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET; cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET;
for (int i = 0; i < s_crt_bundle.num_certs; i++) { for (int i = 0; i < num_certs; i++) {
s_crt_bundle.crts[i] = cur_crt; crts[i] = cur_crt;
if (cur_crt + CRT_HEADER_OFFSET > bundle_end) {
ESP_LOGE(TAG, "Invalid certificate bundle");
free(crts);
return ESP_ERR_INVALID_ARG;
}
size_t name_len = cur_crt[0] << 8 | cur_crt[1]; size_t name_len = cur_crt[0] << 8 | cur_crt[1];
size_t key_len = cur_crt[2] << 8 | cur_crt[3]; size_t key_len = cur_crt[2] << 8 | cur_crt[3];
cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len; cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len;
} }
if (cur_crt > bundle_end) {
ESP_LOGE(TAG, "Invalid certificate bundle");
free(crts);
return ESP_ERR_INVALID_ARG;
}
/* The previous crt bundle is only updated when initialization of the
* current crt_bundle is successful */
/* Free previous crt_bundle */
free(s_crt_bundle.crts);
s_crt_bundle.num_certs = num_certs;
s_crt_bundle.crts = crts;
return ESP_OK; return ESP_OK;
} }
@@ -186,7 +214,7 @@ esp_err_t esp_crt_bundle_attach(void *conf)
esp_err_t ret = ESP_OK; esp_err_t ret = ESP_OK;
// If no bundle has been set by the user then use the bundle embedded in the binary // If no bundle has been set by the user then use the bundle embedded in the binary
if (s_crt_bundle.crts == NULL) { if (s_crt_bundle.crts == NULL) {
ret = esp_crt_bundle_init(x509_crt_imported_bundle_bin_start); ret = esp_crt_bundle_init(x509_crt_imported_bundle_bin_start, x509_crt_imported_bundle_bin_end - x509_crt_imported_bundle_bin_start);
} }
if (ret != ESP_OK) { if (ret != ESP_OK) {
@@ -217,9 +245,7 @@ void esp_crt_bundle_detach(mbedtls_ssl_config *conf)
} }
} }
void esp_crt_bundle_set(const uint8_t *x509_bundle) esp_err_t esp_crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size)
{ {
// Free any previously used bundle return esp_crt_bundle_init(x509_bundle, bundle_size);
free(s_crt_bundle.crts);
esp_crt_bundle_init(x509_bundle);
} }

View File

@@ -1,21 +1,14 @@
// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD /*
// * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
// Licensed under the Apache License, Version 2.0 (the "License"); *
// you may not use this file except in compliance with the License. * SPDX-License-Identifier: Apache-2.0
// You may obtain a copy of the License at */
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_CRT_BUNDLE_H_ #ifndef _ESP_CRT_BUNDLE_H_
#define _ESP_CRT_BUNDLE_H_ #define _ESP_CRT_BUNDLE_H_
#include "esp_err.h"
#include "mbedtls/ssl.h" #include "mbedtls/ssl.h"
#ifdef __cplusplus #ifdef __cplusplus
@@ -52,13 +45,19 @@ void esp_crt_bundle_detach(mbedtls_ssl_config *conf);
/** /**
* @brief Set the default certificate bundle used for verification * @brief Set the default certificate bundle used for verification
* *
* Overrides the default certificate bundle. In most use cases the bundle should be * Overrides the default certificate bundle only in case of successful initialization. In most use cases the bundle should be
* set through menuconfig. The bundle needs to be sorted by subject name since binary search is * set through menuconfig. The bundle needs to be sorted by subject name since binary search is
* used to find certificates. * used to find certificates.
* *
* @param[in] x509_bundle A pointer to the certificate bundle. * @param[in] x509_bundle A pointer to the certificate bundle.
*
* @param[in] bundle_size Size of the certificate bundle in bytes.
*
* @return
* - ESP_OK if adding certificates was successful.
* - Other if an error occured or an action must be taken by the calling process.
*/ */
void esp_crt_bundle_set(const uint8_t *x509_bundle); esp_err_t esp_crt_bundle_set(const uint8_t *x509_bundle, size_t bundle_size);
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -35,6 +35,7 @@
#include "mbedtls/debug.h" #include "mbedtls/debug.h"
#include "esp_crt_bundle.h" #include "esp_crt_bundle.h"
// #include "esp_random.h"
#include "unity.h" #include "unity.h"
#include "test_utils.h" #include "test_utils.h"
@@ -253,7 +254,7 @@ esp_err_t client_setup(mbedtls_endpoint_t *client)
return ESP_OK; return ESP_OK;
} }
int client_task(const uint8_t *bundle, esp_crt_validate_res_t *res) int client_task(const uint8_t *bundle, size_t bundle_size, esp_crt_validate_res_t *res)
{ {
int ret = ESP_FAIL; int ret = ESP_FAIL;
@@ -269,7 +270,7 @@ int client_task(const uint8_t *bundle, esp_crt_validate_res_t *res)
esp_crt_bundle_attach(&client.conf); esp_crt_bundle_attach(&client.conf);
if (bundle) { if (bundle) {
/* Set a bundle different from the menuconfig bundle */ /* Set a bundle different from the menuconfig bundle */
esp_crt_bundle_set(bundle); esp_crt_bundle_set(bundle, bundle_size);
} }
ESP_LOGI(TAG, "Connecting to %s:%s...", SERVER_ADDRESS, SERVER_PORT); ESP_LOGI(TAG, "Connecting to %s:%s...", SERVER_ADDRESS, SERVER_PORT);
@@ -329,11 +330,11 @@ TEST_CASE("custom certificate bundle", "[mbedtls]")
} }
/* Test with default crt bundle that doesnt contain the ca crt */ /* Test with default crt bundle that doesnt contain the ca crt */
client_task(NULL, &validate_res); client_task(NULL, 0, &validate_res);
TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_FAIL); TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_FAIL);
/* Test with bundle that does contain the CA crt */ /* Test with bundle that does contain the CA crt */
client_task(server_cert_bundle_start, &validate_res); client_task(server_cert_bundle_start, server_cert_bundle_end - server_cert_bundle_start, &validate_res);
TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_OK); TEST_ASSERT(validate_res == ESP_CRT_VALIDATE_OK);
exit_flag = true; exit_flag = true;
@@ -390,3 +391,50 @@ TEST_CASE("custom certificate bundle - wrong signature", "[mbedtls]")
esp_crt_bundle_detach(NULL); esp_crt_bundle_detach(NULL);
} }
TEST_CASE("custom certificate bundle init API - bound checking", "[mbedtls]")
{
uint8_t test_bundle[256] = {0};
esp_err_t esp_ret;
/* The API should fail with bundle size given as 1 */
esp_ret = esp_crt_bundle_set(test_bundle, 1);
TEST_ASSERT( esp_ret == ESP_ERR_INVALID_ARG);
/* Check that the esp_crt_bundle_set API will not accept a bundle
* which has more no. of certs than configured in
* CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS */
uint8_t rand;
esp_fill_random(&rand, 1);
test_bundle[0] = rand;
/* Make sure that the number of certs will always be greater than
* CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS */
test_bundle[1] = rand + CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_MAX_CERTS;
esp_ret = esp_crt_bundle_set(test_bundle, sizeof(test_bundle));
TEST_ASSERT( esp_ret == ESP_ERR_INVALID_ARG);
/* The API should fail with bundle_size < BUNDLE_HEADER_OFFSET (2) + CRT_HEADER_OFFSET (4) */
test_bundle[0] = 0;
test_bundle[1] = 1; /* set num_certs = 1 */
esp_ret = esp_crt_bundle_set(test_bundle, 5);
TEST_ASSERT(esp_ret == ESP_ERR_INVALID_ARG);
/* Cert number is greater than actual certs present, The API should fail */
/* Actual No. of certs present in bundle = 1, setting num_certs to 5 */
test_bundle[1] = 5; /* num_certs */
test_bundle[3] = 5; /* cert_1_name_len */
test_bundle[5] = 10; /* cert_1_pub_key_len */
/* Actual bundle size becomes BUNDLE_HEADER_OFFSET (2) + CRT_HEADER_OFFSET (4) + cert_1_name_len(5) + cert_1_pub_key_len(10)
* i.e. 21 bytes */
esp_ret = esp_crt_bundle_set(test_bundle, 21);
TEST_ASSERT(esp_ret == ESP_ERR_INVALID_ARG);
/* The API should fail if bundle_size < BUNDLE_HEADER_OFFSET (2) + CRT_HEADER_OFFSET (4) + cert_1_name_len(5) + cert_1_pub_key_len(10) */
esp_ret = esp_crt_bundle_set(test_bundle, 20);
TEST_ASSERT(esp_ret == ESP_ERR_INVALID_ARG);
esp_crt_bundle_detach(NULL);
}

View File

@@ -12,7 +12,7 @@ The bundle comes with the complete list of root certificates from Mozillas NS
When generating the bundle you may choose between: When generating the bundle you may choose between:
* The full root certificate bundle from Mozilla, containing more than 130 certificates. The current bundle was updated Wed Jan 23 04:12:09 2019 GMT. * The full root certificate bundle from Mozilla, containing more than 130 certificates. The current bundle was updated Tue Apr 26 03:12:05 2022 GMT.
* A pre-selected filter list of the name of the most commonly used root certificates, reducing the amount of certificates to around 35 while still having around 90 % coverage according to market share statistics. * A pre-selected filter list of the name of the most commonly used root certificates, reducing the amount of certificates to around 35 while still having around 90 % coverage according to market share statistics.
In addition it is possible to specify a path to a certificate file or a directory containing certificates which then will be added to the generated bundle. In addition it is possible to specify a path to a certificate file or a directory containing certificates which then will be added to the generated bundle.