Add ESP certificate bundle feature

Adds the ESP certificate bundle feature that enables users to bundle a
root certificate bundle together with their application.

Default bundle includes all Mozilla root certificates

Closes IDF-296
This commit is contained in:
Marius Vikhammer 2019-09-29 18:04:34 +08:00
parent 8e1442f0e7
commit 947e3e94ed
48 changed files with 5030 additions and 147 deletions

View file

@ -110,8 +110,8 @@ typedef struct psk_key_hint {
} psk_hint_key_t;
/**
* @brief ESP-TLS configuration parameters
*
* @brief ESP-TLS configuration parameters
*
* @note Note about format of certificates:
* - This structure includes certificates of a Certificate Authority, of client or server as well
* as private keys, which may be of PEM or DER format. In case of PEM format, the buffer must be
@ -121,17 +121,17 @@ typedef struct psk_key_hint {
* - Variables names of certificates and private key buffers and sizes are defined as unions providing
* backward compatibility for legacy *_pem_buf and *_pem_bytes names which suggested only PEM format
* was supported. It is encouraged to use generic names such as cacert_buf and cacert_bytes.
*/
*/
typedef struct esp_tls_cfg {
const char **alpn_protos; /*!< Application protocols required for HTTP2.
If HTTP2/ALPN support is required, a list
of protocols that should be negotiated.
of protocols that should be negotiated.
The format is length followed by protocol
name.
name.
For the most common cases the following is ok:
const char **alpn_protos = { "h2", NULL };
- where 'h2' is the protocol name */
union {
const unsigned char *cacert_buf; /*!< Certificate Authority's certificate in a buffer.
Format may be PEM or DER, depending on mbedtls-support
@ -179,8 +179,8 @@ typedef struct esp_tls_cfg {
unsigned int clientkey_password_len; /*!< String length of the password pointed to by
clientkey_password */
bool non_block; /*!< Configure non-blocking mode. If set to true the
underneath socket will be configured in non
bool non_block; /*!< Configure non-blocking mode. If set to true the
underneath socket will be configured in non
blocking mode after tls session is established */
int timeout_ms; /*!< Network timeout in milliseconds */
@ -197,6 +197,10 @@ typedef struct esp_tls_cfg {
then PSK authentication is enabled with configured setup.
Important note: the pointer must be valid for connection */
esp_err_t (*crt_bundle_attach)(mbedtls_ssl_config *conf);
/*!< Function pointer to esp_crt_bundle_attach. Enables the use of certification
bundle for server verification, must be enabled in menuconfig */
} esp_tls_cfg_t;
#ifdef CONFIG_ESP_TLS_SERVER
@ -255,24 +259,24 @@ typedef struct esp_tls_cfg_server {
#endif /* ! CONFIG_ESP_TLS_SERVER */
/**
* @brief ESP-TLS Connection Handle
* @brief ESP-TLS Connection Handle
*/
typedef struct esp_tls {
#ifdef CONFIG_ESP_TLS_USING_MBEDTLS
mbedtls_ssl_context ssl; /*!< TLS/SSL context */
mbedtls_entropy_context entropy; /*!< mbedTLS entropy context structure */
mbedtls_ctr_drbg_context ctr_drbg; /*!< mbedTLS ctr drbg context structure.
CTR_DRBG is deterministic random
CTR_DRBG is deterministic random
bit generation based on AES-256 */
mbedtls_ssl_config conf; /*!< TLS/SSL configuration to be shared
between mbedtls_ssl_context
mbedtls_ssl_config conf; /*!< TLS/SSL configuration to be shared
between mbedtls_ssl_context
structures */
mbedtls_net_context server_fd; /*!< mbedTLS wrapper type for sockets */
mbedtls_x509_crt cacert; /*!< Container for the X.509 CA certificate */
mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */
@ -292,10 +296,10 @@ typedef struct esp_tls {
void *priv_ssl;
#endif
int sockfd; /*!< Underlying socket file descriptor. */
ssize_t (*read)(struct esp_tls *tls, char *data, size_t datalen); /*!< Callback function for reading data from TLS/SSL
connection. */
ssize_t (*write)(struct esp_tls *tls, const char *data, size_t datalen); /*!< Callback function for writing data to TLS/SSL
connection. */
@ -375,7 +379,7 @@ int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp
* @brief Create a new blocking TLS/SSL connection with a given "HTTP" url
*
* The behaviour is same as esp_tls_conn_new() API. However this API accepts host's url.
*
*
* @param[in] url url of host.
* @param[in] cfg TLS configuration as esp_tls_cfg_t. If you wish to open
* non-TLS connection, keep this NULL. For TLS connection,
@ -384,7 +388,7 @@ int esp_tls_conn_new_sync(const char *hostname, int hostlen, int port, const esp
* @return pointer to esp_tls_t, or NULL if connection couldn't be opened.
*/
esp_tls_t *esp_tls_conn_http_new(const char *url, const esp_tls_cfg_t *cfg);
/**
* @brief Create a new non-blocking TLS/SSL connection
*
@ -423,18 +427,18 @@ int esp_tls_conn_http_new_async(const char *url, const esp_tls_cfg_t *cfg, esp_t
/**
* @brief Write from buffer 'data' into specified tls connection.
*
*
* @param[in] tls pointer to esp-tls as esp-tls handle.
* @param[in] data Buffer from which data will be written.
* @param[in] datalen Length of data buffer.
*
* @return
* - >0 if write operation was successful, the return value is the number
* of bytes actually written to the TLS/SSL connection.
*
* @return
* - >0 if write operation was successful, the return value is the number
* of bytes actually written to the TLS/SSL connection.
* - 0 if write operation was not successful. The underlying
* connection was closed.
* - <0 if write operation was not successful, because either an
* error occured or an action must be taken by the calling process.
* - <0 if write operation was not successful, because either an
* error occured or an action must be taken by the calling process.
*/
static inline ssize_t esp_tls_conn_write(esp_tls_t *tls, const void *data, size_t datalen)
{
@ -443,10 +447,10 @@ static inline ssize_t esp_tls_conn_write(esp_tls_t *tls, const void *data, size_
/**
* @brief Read from specified tls connection into the buffer 'data'.
*
*
* @param[in] tls pointer to esp-tls as esp-tls handle.
* @param[in] data Buffer to hold read data.
* @param[in] datalen Length of data buffer.
* @param[in] datalen Length of data buffer.
*
* @return
* - >0 if read operation was successful, the return value is the number
@ -463,11 +467,11 @@ static inline ssize_t esp_tls_conn_read(esp_tls_t *tls, void *data, size_t data
/**
* @brief Close the TLS/SSL connection and free any allocated resources.
*
* This function should be called to close each tls connection opened with esp_tls_conn_new() or
* esp_tls_conn_http_new() APIs.
*
* @param[in] tls pointer to esp-tls as esp-tls handle.
* This function should be called to close each tls connection opened with esp_tls_conn_new() or
* esp_tls_conn_http_new() APIs.
*
* @param[in] tls pointer to esp-tls as esp-tls handle.
*/
void esp_tls_conn_delete(esp_tls_t *tls);

View file

@ -26,6 +26,11 @@
#include <errno.h>
#include "esp_log.h"
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
#include "esp_crt_bundle.h"
#endif
static const char *TAG = "esp-tls-mbedtls";
static mbedtls_x509_crt *global_cacert = NULL;
@ -402,7 +407,17 @@ esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls_cfg_t
return ESP_ERR_INVALID_STATE;
#endif
}
if (cfg->use_global_ca_store == true) {
if (cfg->crt_bundle_attach != NULL) {
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
ESP_LOGD(TAG, "Use certificate bundle");
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
cfg->crt_bundle_attach(&tls->conf);
#else //CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
ESP_LOGE(TAG, "use_crt_bundle configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option");
return ESP_ERR_INVALID_STATE;
#endif
} else if (cfg->use_global_ca_store == true) {
esp_err_t esp_ret = set_global_ca_store(tls);
if (esp_ret != ESP_OK) {
return esp_ret;

View file

@ -188,6 +188,11 @@ static esp_err_t set_client_config(const char *hostname, size_t hostlen, esp_tls
return ESP_FAIL;
}
if (cfg->crt_bundle_attach != NULL) {
ESP_LOGE(TAG,"use_crt_bundle not supported in wolfssl");
return ESP_FAIL;
}
tls->priv_ssl =(void *)wolfSSL_new( (WOLFSSL_CTX *)tls->priv_ctx);
if (!tls->priv_ssl) {
ESP_LOGE(TAG, "Create wolfSSL failed");

View file

@ -1,10 +1,54 @@
idf_build_get_property(idf_target IDF_TARGET)
idf_component_register(INCLUDE_DIRS "port/include" "mbedtls/include"
idf_component_register(SRCS "esp_crt_bundle/esp_crt_bundle.c"
INCLUDE_DIRS "port/include" "mbedtls/include" "esp_crt_bundle/include"
REQUIRES lwip
PRIV_REQUIRES soc
)
if(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE)
set(bundle_name "x509_crt_bundle")
set(DEFAULT_CRT_DIR ${COMPONENT_DIR}/esp_crt_bundle)
# Generate custom certificate bundle using the generate_cert_bundle utility
set(GENERATE_CERT_BUNDLEPY ${python} ${COMPONENT_DIR}/esp_crt_bundle/gen_crt_bundle.py)
if(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL)
list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem)
elseif(CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN)
list(APPEND crt_paths ${DEFAULT_CRT_DIR}/cacrt_all.pem)
list(APPEND args --filter ${DEFAULT_CRT_DIR}/cmn_crt_authorities.csv)
endif()
if(CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE)
get_filename_component(custom_bundle_path
${CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH} ABSOLUTE BASE_DIR "${project_dir}")
list(APPEND crt_paths ${custom_bundle_path})
endif()
list(APPEND args --input ${crt_paths} -q)
get_filename_component(crt_bundle
${bundle_name}
ABSOLUTE BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
# Generate bundle according to config
add_custom_command(OUTPUT ${crt_bundle}
COMMAND ${GENERATE_CERT_BUNDLEPY} ${args}
DEPENDS ${custom_bundle_path}
VERBATIM)
add_custom_target(custom_bundle DEPENDS ${cert_bundle})
add_dependencies(${COMPONENT_LIB} custom_bundle)
target_add_binary_data(${COMPONENT_LIB} ${crt_bundle} BINARY)
set_property(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES
"${crt_bundle}")
endif()
# Only build mbedtls libraries
set(ENABLE_TESTING CACHE BOOL OFF)
set(ENABLE_PROGRAMS CACHE BOOL OFF)
@ -26,6 +70,8 @@ set(mbedtls_targets mbedtls mbedcrypto mbedx509)
target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/net_sockets.c")
target_sources(mbedcrypto PRIVATE "${COMPONENT_DIR}/port/esp_hardware.c"
"${COMPONENT_DIR}/port/esp_mem.c"
"${COMPONENT_DIR}/port/esp_sha.c"
@ -46,3 +92,4 @@ set_property(TARGET mbedcrypto APPEND PROPERTY LINK_INTERFACE_LIBRARIES mbedtls)
# Link mbedtls libraries to component library
target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets})

View file

@ -127,6 +127,52 @@ menu "mbedTLS"
default 3 if MBEDTLS_DEBUG_LEVEL_DEBUG
default 4 if MBEDTLS_DEBUG_LEVEL_VERBOSE
menu "Certificate Bundle"
config MBEDTLS_CERTIFICATE_BUNDLE
bool "Enable trusted root certificate bundle"
default y
help
Enable support for large number of default root certificates
When enabled this option allows user to store default as well
as customer specific root certificates in compressed format rather
than storing full certificate. For the root certificates the public key and the subject name
will be stored.
choice MBEDTLS_DEFAULT_CERTIFICATE_BUNDLE
bool "Default certificate bundle options"
depends on MBEDTLS_CERTIFICATE_BUNDLE
default MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL
config MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL
bool "Use the full default certificate bundle"
config MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN
bool "Use only the most common certificates from the default bundles"
help
Use only the most common certificates from the default bundles, reducing the size with 50%,
while still having around 99% coverage.
config MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE
bool "Do not use the default certificate bundle"
endchoice
config MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE
depends on MBEDTLS_CERTIFICATE_BUNDLE
default n
bool "Add custom certificates to the default bundle"
config MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH
depends on MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE
string "Custom certificate bundle path"
help
Name of the custom certificate directory or file. This path is evaluated
relative to the project root directory.
endmenu
config MBEDTLS_ECP_RESTARTABLE
bool "Enable mbedTLS ecp restartable"
default n

View file

@ -2,11 +2,44 @@
# Component Makefile
#
COMPONENT_ADD_INCLUDEDIRS := port/include mbedtls/include
COMPONENT_ADD_INCLUDEDIRS := port/include mbedtls/include esp_crt_bundle/include
COMPONENT_SRCDIRS := mbedtls/library port port/$(IDF_TARGET)
COMPONENT_SRCDIRS := mbedtls/library port port/$(IDF_TARGET) esp_crt_bundle
COMPONENT_OBJEXCLUDE := mbedtls/library/net_sockets.o
COMPONENT_SUBMODULES += mbedtls
ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
GEN_CRT_BUNDLEPY := $(PYTHON) $(COMPONENT_PATH)/esp_crt_bundle/gen_crt_bundle.py
DEFAULT_CRT_DIR := ${COMPONENT_PATH}/esp_crt_bundle
X509_CERTIFICATE_BUNDLE := $(abspath x509_crt_bundle)
CUSTOM_BUNDLE_PATH := $(PROJECT_PATH)/$(CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH)
ifdef CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE
CRT_PATHS += $(CUSTOM_BUNDLE_PATH)
endif
ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL
CRT_PATHS += ${DEFAULT_CRT_DIR}/cacrt_all.pem
endif
ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN
CRT_PATHS += ${DEFAULT_CRT_DIR}/cacrt_all.pem
ARGS += --filter ${DEFAULT_CRT_DIR}/cmn_crt_authorities.csv
endif
ARGS += --input $(CRT_PATHS) -q
# Generate certificate bundle using generate_cert_bundle.py
$(X509_CERTIFICATE_BUNDLE) : $(SDKCONFIG_MAKEFILE)
$(GEN_CRT_BUNDLEPY) $(ARGS)
COMPONENT_EXTRA_CLEAN += $(X509_CERTIFICATE_BUNDLE)
COMPONENT_EMBED_FILES := $(X509_CERTIFICATE_BUNDLE)
endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
Owner,Common Name or Certificate Name
Amazon Trust Services,Amazon Root CA 1
Amazon Trust Services,Amazon Root CA 2
Amazon Trust Services,Amazon Root CA 3
Amazon Trust Services,Amazon Root CA 4
Amazon Trust Services,Starfield Services Root Certificate Authority - G2
DigiCert,Baltimore CyberTrust Root
DigiCert,Cybertrust Global Root
DigiCert,DigiCert Assured ID Root CA
DigiCert,DigiCert Assured ID Root G2
DigiCert,DigiCert Assured ID Root G3
DigiCert,DigiCert Global Root CA
DigiCert,DigiCert Global Root G2
DigiCert,DigiCert Global Root G3
DigiCert,DigiCert High Assurance EV Root CA
DigiCert,DigiCert Trusted Root G4
GlobalSign,GlobalSign ECC Root CA - R5
GlobalSign,GlobalSign Root CA - R3
GlobalSign,GlobalSign Root CA - R6
GlobalSign,GlobalSign Root CA
GoDaddy,Go Daddy Class 2 CA
GoDaddy,Go Daddy Root Certificate Authority - G2
GoDaddy,Starfield Class 2 CA
GoDaddy,Starfield Root Certificate Authority - G2
Google Trust Services LLC (GTS),GlobalSign ECC Root CA - R4
Google Trust Services LLC (GTS),GlobalSign Root CA - R2
Google Trust Services LLC (GTS),GTS Root R1
Google Trust Services LLC (GTS),GTS Root R2
Google Trust Services LLC (GTS),GTS Root R3
Google Trust Services LLC (GTS),GTS Root R4
"IdenTrust Services, LLC",DST Root CA X3
"IdenTrust Services, LLC",IdenTrust Commercial Root CA 1
"IdenTrust Services, LLC",IdenTrust Public Sector Root CA 1
Sectigo,Comodo AAA Services root
Sectigo,COMODO Certification Authority
Sectigo,COMODO ECC Certification Authority
Sectigo,COMODO RSA Certification Authority
Sectigo,USERTrust ECC Certification Authority
Sectigo,USERTrust RSA Certification Authority
1 Owner Common Name or Certificate Name
2 Amazon Trust Services Amazon Root CA 1
3 Amazon Trust Services Amazon Root CA 2
4 Amazon Trust Services Amazon Root CA 3
5 Amazon Trust Services Amazon Root CA 4
6 Amazon Trust Services Starfield Services Root Certificate Authority - G2
7 DigiCert Baltimore CyberTrust Root
8 DigiCert Cybertrust Global Root
9 DigiCert DigiCert Assured ID Root CA
10 DigiCert DigiCert Assured ID Root G2
11 DigiCert DigiCert Assured ID Root G3
12 DigiCert DigiCert Global Root CA
13 DigiCert DigiCert Global Root G2
14 DigiCert DigiCert Global Root G3
15 DigiCert DigiCert High Assurance EV Root CA
16 DigiCert DigiCert Trusted Root G4
17 GlobalSign GlobalSign ECC Root CA - R5
18 GlobalSign GlobalSign Root CA - R3
19 GlobalSign GlobalSign Root CA - R6
20 GlobalSign GlobalSign Root CA
21 GoDaddy Go Daddy Class 2 CA
22 GoDaddy Go Daddy Root Certificate Authority - G2
23 GoDaddy Starfield Class 2 CA
24 GoDaddy Starfield Root Certificate Authority - G2
25 Google Trust Services LLC (GTS) GlobalSign ECC Root CA - R4
26 Google Trust Services LLC (GTS) GlobalSign Root CA - R2
27 Google Trust Services LLC (GTS) GTS Root R1
28 Google Trust Services LLC (GTS) GTS Root R2
29 Google Trust Services LLC (GTS) GTS Root R3
30 Google Trust Services LLC (GTS) GTS Root R4
31 IdenTrust Services, LLC DST Root CA X3
32 IdenTrust Services, LLC IdenTrust Commercial Root CA 1
33 IdenTrust Services, LLC IdenTrust Public Sector Root CA 1
34 Sectigo Comodo AAA Services root
35 Sectigo COMODO Certification Authority
36 Sectigo COMODO ECC Certification Authority
37 Sectigo COMODO RSA Certification Authority
38 Sectigo USERTrust ECC Certification Authority
39 Sectigo USERTrust RSA Certification Authority

View file

@ -0,0 +1,219 @@
// Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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.
#include <string.h>
#include <esp_system.h>
#include "esp_crt_bundle.h"
#include "esp_log.h"
#include "esp_err.h"
#define BUNDLE_HEADER_OFFSET 2
#define CRT_HEADER_OFFSET 4
static const char *TAG = "esp-x509-crt-bundle";
/* a dummy certificate so that
* cacert_ptr passes non-NULL check during handshake */
static mbedtls_x509_crt s_dummy_crt;
extern const uint8_t x509_crt_imported_bundle_bin_start[] asm("_binary_x509_crt_bundle_start");
extern const uint8_t x509_crt_imported_bundle_bin_end[] asm("_binary_x509_crt_bundle_end");
typedef struct crt_bundle_t {
const uint8_t **crts;
uint16_t num_certs;
size_t x509_crt_bundle_len;
} crt_bundle_t;
static crt_bundle_t s_crt_bundle;
static int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int data, uint32_t *flags);
static esp_err_t esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len);
static esp_err_t esp_crt_check_signature(mbedtls_x509_crt *child, const uint8_t *pub_key_buf, size_t pub_key_len)
{
int ret = ESP_FAIL;
mbedtls_x509_crt parent;
const mbedtls_md_info_t *md_info;
unsigned char hash[MBEDTLS_MD_MAX_SIZE];
mbedtls_x509_crt_init(&parent);
if ( (ret = mbedtls_pk_parse_public_key(&parent.pk , pub_key_buf, pub_key_len) ) != 0) {
ESP_LOGE(TAG, "PK parse failed with error %X", ret);
return ESP_FAIL;
}
// Fast check to avoid expensive computations when not necessary
if (!mbedtls_pk_can_do(&parent.pk, child->sig_pk)) {
ESP_LOGE(TAG, "Simple compare failed");
return ESP_FAIL;
}
md_info = mbedtls_md_info_from_type(child->sig_md);
if ( (ret = mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash )) != 0 ) {
ESP_LOGE(TAG, "Internal mbedTLS error %X", ret);
return ESP_FAIL;
}
ret = mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent.pk,
child->sig_md, hash, mbedtls_md_get_size( md_info ),
child->sig.p, child->sig.len ) ;
if (ret != 0) {
ESP_LOGE(TAG, "PK verify failed with error %X", ret);
return ESP_FAIL;
}
return ESP_OK;
}
/* This callback is called for every certificate in the chain. If the chain
* is proper each intermediate certificate is validated through its parent
* in the x509_crt_verify_chain() function. So this callback should
* only verify the first untrusted link in the chain is signed by the
* root certificate in the trusted bundle
*/
int esp_crt_verify_callback(void *buf, mbedtls_x509_crt *crt, int data, uint32_t *flags)
{
mbedtls_x509_crt *child = crt;
if (*flags != MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
return 0;
}
if (s_crt_bundle.crts == NULL) {
ESP_LOGE(TAG, "No certificates in bundle");
return MBEDTLS_ERR_X509_FATAL_ERROR;
}
ESP_LOGD(TAG, "%d certificates in bundle", s_crt_bundle.num_certs);
size_t name_len = 0;
const uint8_t *crt_name;
bool crt_found = false;
int start = 0;
int end = s_crt_bundle.num_certs - 1;
int middle = (end - start) / 2;
/* Look for the certificate using binary search on subject name */
while (start <= end) {
name_len = s_crt_bundle.crts[middle][0] << 8 | s_crt_bundle.crts[middle][1];
crt_name = s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET;
int cmp_res = memcmp(child->issuer_raw.p, crt_name, name_len );
if (cmp_res == 0) {
crt_found = true;
break;
} else if (cmp_res < 0) {
end = middle - 1;
} else {
start = middle + 1;
}
middle = (start + end) / 2;
}
int ret = MBEDTLS_ERR_X509_FATAL_ERROR;
if (crt_found) {
size_t key_len = s_crt_bundle.crts[middle][2] << 8 | s_crt_bundle.crts[middle][3];
ret = esp_crt_check_signature(child, s_crt_bundle.crts[middle] + CRT_HEADER_OFFSET + name_len, key_len);
}
if (ret == 0) {
ESP_LOGI(TAG, "Certificate validated");
*flags = 0;
return 0;
}
ESP_LOGE(TAG, "Failed to verify certificate");
return MBEDTLS_ERR_X509_FATAL_ERROR;
}
/* 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
*/
static esp_err_t esp_crt_bundle_init(const uint8_t *x509_bundle)
{
s_crt_bundle.num_certs = (x509_bundle[0] << 8) | x509_bundle[1];
s_crt_bundle.crts = calloc(s_crt_bundle.num_certs, sizeof(x509_bundle));
if (s_crt_bundle.crts == NULL) {
ESP_LOGE(TAG, "Unable to allocate memory for bundle");
return ESP_ERR_NO_MEM;
}
const uint8_t *cur_crt;
cur_crt = x509_bundle + BUNDLE_HEADER_OFFSET;
for (int i = 0; i < s_crt_bundle.num_certs; i++) {
s_crt_bundle.crts[i] = cur_crt;
size_t name_len = cur_crt[0] << 8 | cur_crt[1];
size_t key_len = cur_crt[2] << 8 | cur_crt[3];
cur_crt = cur_crt + CRT_HEADER_OFFSET + name_len + key_len;
}
return ESP_OK;
}
esp_err_t esp_crt_bundle_attach(mbedtls_ssl_config *conf)
{
esp_err_t ret = ESP_OK;
// If no bundle has been set by the user then use the bundle embedded in the binary
if (s_crt_bundle.crts == NULL) {
ret = esp_crt_bundle_init(x509_crt_imported_bundle_bin_start);
}
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to attach bundle");
return ret;
}
if (conf) {
/* point to a dummy certificate
* This is only required so that the
* cacert_ptr passes non-NULL check during handshake
*/
mbedtls_x509_crt_init(&s_dummy_crt);
conf->ca_chain = &s_dummy_crt;
mbedtls_ssl_conf_verify(conf, esp_crt_verify_callback, NULL);
}
return ret;
}
void esp_crt_bundle_detach(mbedtls_ssl_config *conf)
{
free(s_crt_bundle.crts);
if (conf) {
mbedtls_ssl_conf_verify(conf, NULL, NULL);
}
}
void esp_crt_bundle_set(const uint8_t *x509_bundle)
{
// Free any previously used bundle
free(s_crt_bundle.crts);
esp_crt_bundle_init(x509_bundle);
}

View file

@ -0,0 +1,226 @@
#!/usr/bin/env python
#
# ESP32 x509 certificate bundle generation utility
#
# Converts PEM and DER certificates to a custom bundle format which stores just the
# subject name and public key to reduce space
#
# The bundle will have the format: number of certificates; crt 1 subject name length; crt 1 public key length;
# crt 1 subject name; crt 1 public key; crt 2...
#
# Copyright 2018-2019 Espressif Systems (Shanghai) PTE LTD
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# 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.
from __future__ import with_statement
import os
import sys
import struct
import argparse
import csv
import re
try:
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
except ImportError:
print('The cryptography package is not installed.'
'Please refer to the Get Started section of the ESP-IDF Programming Guide for '
'setting up the required packages.')
raise
ca_bundle_bin_file = 'x509_crt_bundle'
quiet = False
def status(msg):
""" Print status message to stderr """
if not quiet:
critical(msg)
def critical(msg):
""" Print critical message to stderr """
sys.stderr.write('gen_crt_bundle.py: ')
sys.stderr.write(msg)
sys.stderr.write('\n')
class CertificateBundle:
def __init__(self):
self.certificates = []
self.compressed_crts = []
if os.path.isfile(ca_bundle_bin_file):
os.remove(ca_bundle_bin_file)
def add_from_path(self, crts_path):
found = False
for file_path in os.listdir(crts_path):
found |= self.add_from_file(os.path.join(crts_path, file_path))
if found is False:
raise InputError('No valid x509 certificates found in %s' % crts_path)
def add_from_file(self, file_path):
try:
if file_path.endswith('.pem'):
status("Parsing certificates from %s" % file_path)
with open(file_path, 'r') as f:
crt_str = f.read()
self.add_from_pem(crt_str)
return True
elif file_path.endswith('.der'):
status("Parsing certificates from %s" % file_path)
with open(file_path, 'rb') as f:
crt_str = f.read()
self.add_from_der(crt_str)
return True
except ValueError:
critical("Invalid certificate in %s" % file_path)
raise InputError("Invalid certificate")
return False
def add_from_pem(self, crt_str):
""" A single PEM file may have multiple certificates """
crt = ''
count = 0
start = False
for strg in crt_str.splitlines(True):
if strg == '-----BEGIN CERTIFICATE-----\n' and start is False:
crt = ''
start = True
elif strg == '-----END CERTIFICATE-----\n' and start is True:
crt += strg + '\n'
start = False
self.certificates.append(x509.load_pem_x509_certificate(crt.encode(), default_backend()))
count += 1
if start is True:
crt += strg
if(count == 0):
raise InputError("No certificate found")
status("Successfully added %d certificates" % count)
def add_from_der(self, crt_str):
self.certificates.append(x509.load_der_x509_certificate(crt_str, default_backend()))
status("Successfully added 1 certificate")
def create_bundle(self):
# Sort certificates in order to do binary search when looking up certificates
self.certificates = sorted(self.certificates, key=lambda cert: cert.subject.public_bytes(default_backend()))
bundle = struct.pack('>H', len(self.certificates))
for crt in self.certificates:
""" Read the public key as DER format """
pub_key = crt.public_key()
pub_key_der = pub_key.public_bytes(serialization.Encoding.DER, serialization.PublicFormat.SubjectPublicKeyInfo)
""" Read the subject name as DER format """
sub_name_der = crt.subject.public_bytes(default_backend())
name_len = len(sub_name_der)
key_len = len(pub_key_der)
len_data = struct.pack('>HH', name_len, key_len)
bundle += len_data
bundle += sub_name_der
bundle += pub_key_der
return bundle
def add_with_filter(self, crts_path, filter_path):
filter_set = set()
with open(filter_path, 'r') as f:
csv_reader = csv.reader(f, delimiter=',')
# Skip header
next(csv_reader)
for row in csv_reader:
filter_set.add(row[1])
status("Parsing certificates from %s" % crts_path)
crt_str = []
with open(crts_path, 'r') as f:
crt_str = f.read()
# Split all certs into a list of (name, certificate string) tuples
pem_crts = re.findall(r'(^.+?)\n(=+\n[\s\S]+?END CERTIFICATE-----\n)', crt_str, re.MULTILINE)
filtered_crts = ''
for name, crt in pem_crts:
if name in filter_set:
filtered_crts += crt
self.add_from_pem(filtered_crts)
class InputError(RuntimeError):
def __init__(self, e):
super(InputError, self).__init__(e)
def main():
global quiet
parser = argparse.ArgumentParser(description='ESP-IDF x509 certificate bundle utility')
parser.add_argument('--quiet', '-q', help="Don't print non-critical status messages to stderr", action='store_true')
parser.add_argument('--input', '-i', nargs='+', required=True,
help='Paths to the custom certificate folders or files to parse, parses all .pem or .der files')
parser.add_argument('--filter', '-f', help='Path to CSV-file where the second columns contains the name of the certificates \
that should be included from cacrt_all.pem')
args = parser.parse_args()
quiet = args.quiet
bundle = CertificateBundle()
for path in args.input:
if os.path.isfile(path):
if os.path.basename(path) == "cacrt_all.pem" and args.filter:
bundle.add_with_filter(path, args.filter)
else:
bundle.add_from_file(path)
elif os.path.isdir(path):
bundle.add_from_path(path)
else:
raise InputError("Invalid --input=%s, is neither file nor folder" % args.input)
status('Successfully added %d certificates in total' % len(bundle.certificates))
crt_bundle = bundle.create_bundle()
with open(ca_bundle_bin_file, 'wb') as f:
f.write(crt_bundle)
if __name__ == '__main__':
try:
main()
except InputError as e:
print(e)
sys.exit(2)

View file

@ -0,0 +1,67 @@
// Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// 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_
#define _ESP_CRT_BUNDLE_H_
#include "mbedtls/ssl.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Attach and enable use of a bundle for certificate verification
*
* Attach and enable use of a bundle for certificate verification through a verification callback.
* If no specific bundle has been set through esp_crt_bundle_set() it will default to the
* bundle defined in menuconfig and embedded in the binary.
*
* @param[in] conf The config struct for the SSL connection.
*
* @return
* - ESP_OK if adding certificates was successful.
* - Other if an error occured or an action must be taken by the calling process.
*/
esp_err_t esp_crt_bundle_attach(mbedtls_ssl_config *conf);
/**
* @brief Disable and dealloc the certification bundle
*
* Removes the certificate verification callback and deallocates used resources
*
* @param[in] conf The config struct for the SSL connection.
*/
void esp_crt_bundle_detach(mbedtls_ssl_config *conf);
/**
* @brief Set the default certificate bundle used for verification
*
* Overrides the default certificate bundle. In most use cases the bundle should be
* set through menuconfig. The bundle needs to be sorted by subject name since binary search is
* used to find certificates.
*
* @param[in] x509_bundle A pointer to the certificate bundle.
*/
void esp_crt_bundle_set(const uint8_t *x509_bundle);
#ifdef __cplusplus
}
#endif
#endif //_ESP_CRT_BUNDLE_H_

View file

@ -0,0 +1,26 @@
Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
MloXDTI2MTEyNzIwNTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----

View file

@ -0,0 +1,26 @@
Entrust Root Certification Authority
====================================
-----BEGIN CERTIFICATE-----
MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMCVVMxFjAUBgNV
BAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0Lm5ldC9DUFMgaXMgaW5jb3Jw
b3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMWKGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsG
A1UEAxMkRW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0
MloXDTI2MTEyNzIwNTM0MFFwgFFxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMu
MTkwNwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSByZWZlcmVu
Y2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNVBAMTJEVudHJ1c3QgUm9v
dCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
ALaVtkNC+sZtKm9I35RMOVcF7sN5EUFoNu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYsz
A9u3g3s+IIRe7bJWKKf44LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOww
Cj0Yzfv9KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGIrb68
j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi94DkZfs0Nw4pgHBN
rziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOBsDCBrTAOBgNVHQ8BAf8EBAMCAQYw
DwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAigA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1
MzQyWjAfBgNVHSMEGDAWgBRokORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DH
hmak8fdLQ/uEvW0wHQYJKoZIhvZ9B0EABBFFDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9tO1KzKtvn1ISM
Y/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxR22IkSNcUesyBrJ6ZuaAGAT/3B+XxFNSRuzFVJ7yVTa
v52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi447pynP9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTS
W3iDVuycNsMm4hH2Z0kdkquM++v/eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0
tHuu2guQOHXvgR1m0vdXcDazv/wor3ElhVsT/h5/WrQ8
-----END CERTIFICATE-----

View file

@ -0,0 +1,77 @@
#!/usr/bin/env python
import unittest
import sys
import os
try:
import gen_crt_bundle
except ImportError:
sys.path.append("..")
import gen_crt_bundle
idf_path = os.environ['IDF_PATH']
ca_crts_path = idf_path + '/components/mbedtls/esp_crt_bundle/'
test_crts_path = idf_path + '/components/mbedtls/esp_crt_bundle/test_gen_crt_bundle/'
ca_bundle_bin_file = 'x509_crt_bundle'
der_test_file = 'baltimore.der'
pem_test_file = 'entrust.pem'
verified_der_bundle = 'baltimore_crt_bundle'
verified_pem_bundle = 'entrust_crt_bundle'
invalid_test_file = 'invalid_crt.pem'
ca_crts_all_file = 'cacrt_all.pem'
class Py23TestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(Py23TestCase, self).__init__(*args, **kwargs)
try:
self.assertRaisesRegex
except AttributeError:
# assertRaisesRegexp is deprecated in Python3 but assertRaisesRegex doesn't exist in Python2
# This fix is used in order to avoid using the alias from the six library
self.assertRaisesRegex = self.assertRaisesRegexp
class GenCrtBundleTests(Py23TestCase):
# Verify generation from der vs known certificate
def test_gen_from_der(self):
bundle = gen_crt_bundle.CertificateBundle()
bundle.add_from_file(test_crts_path + der_test_file)
crt_bundle = bundle.create_bundle()
with open(test_crts_path + verified_der_bundle, 'rb') as f:
verified_bundle = f.read()
self.assertEqual(crt_bundle, verified_bundle)
# Verify generation from pem vs known certificate
def test_gen_from_pem(self):
bundle = gen_crt_bundle.CertificateBundle()
bundle.add_from_file(test_crts_path + pem_test_file)
crt_bundle = bundle.create_bundle()
with open(test_crts_path + verified_pem_bundle, 'rb') as f:
verified_bundle = f.read()
self.assertEqual(crt_bundle, verified_bundle)
def test_invalid_crt_input(self):
bundle = gen_crt_bundle.CertificateBundle()
with self.assertRaisesRegex(gen_crt_bundle.InputError, "Invalid certificate"):
bundle.add_from_file(test_crts_path + invalid_test_file)
with self.assertRaisesRegex(gen_crt_bundle.InputError, "No certificate found"):
bundle.add_from_pem("")
if __name__ == "__main__":
unittest.main()

View file

@ -1,6 +1,8 @@
idf_component_register(SRC_DIRS "."
INCLUDE_DIRS "."
REQUIRES unity test_utils mbedtls libsodium)
REQUIRES unity test_utils mbedtls libsodium
EMBED_TXTFILES server_cert_chain.pem prvtkey.pem server_cert_bundle)
idf_component_get_property(mbedtls mbedtls COMPONENT_LIB)
target_compile_definitions(${mbedtls} INTERFACE "-DMBEDTLS_DEPRECATED_WARNING")

View file

@ -3,3 +3,4 @@
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
COMPONENT_EMBED_FILES := server_cert_chain.pem prvtkey.pem server_cert_bundle

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAra9Pvr1J4ltGfVdnOv4DVdYTL68UaIKu37r0TMRdBKn5gSKm
nBnvDx4TyMfiaOyo6tADGZPbzYJ2r45Zmo8zoIiUwh9SWHkFghTl+jNp0+1QxRCH
HyRak3ShIZvje+c0xDDgMIv41l62FCE86dNW0gUCC/KgRCInqzsKurbxZU2qjebI
5TKDkOFJsmoaWPb3q2+wEztPpvjGlV33UVX3OK8bJtRKALFn3733E7g5F2qANjOu
S+7jXDzqxw5HD+QZTTH2Kehh/hrV96WeXUVGnMWru2BtYWKD0Pdh7zGcXjP8oSf2
FkVssh+0f9khI9Xz6KzdSIMVEeSrDXRKnyJnDQIDAQABAoIBAEtOCpZZvfIdvxdT
URfb0Jhj5Be1onSZzLaGeavbK7V8+QgLfQ+LkwIL+WoBeGIj0i1VGTL6z79wBIOj
hagk1K6S6WStbeecOU4oP3pW1lijuXRn8R4IhhkO5VoMG/q5yUATLPD/j1lq4Skj
LCT5k9glgbiqbuB7qpVsWP+RmGJiLh3jBDrb1NrZLuDlXhXJO+AF69syxxiyvnFA
s7aVHst2TPXgccA9Fh37GzxN4hratz6n0JAaMxpRdJaJF1sSQQznfrYfxnkwtE1y
ZXS5XgeDjqv00mucZVVzNkhT9WeS0bXd0lblboK2z39cN2YDYrmfEr2HonbTozNj
HPlBG2UCgYEA3zWj3kAFhpl6zrHvcIzaemDxi9pFam2wJLgzeSXuHBSZSazi//qm
Dv7rgP38XsY6MeaqpLW687FZ6yiDg2OLLMc4ho7Rq6mOKjp3nTVHjO+LONfxgWul
evhFIabW056jafecouUSvy/9nvrrA5QEJjaHxg0tREuaGiBBgMXTnd8CgYEAxzMr
NkVHqIis5AzGUJOaF2uTqnXbnM+/+kEkJD6yNzFovsxkaebGQF9LA1s/qiDtZtlH
QiXlDsWl/PrKmvxToBY3v3fJKeAMXValtAtX0h67RX6rJUqXBATT/AOcfdlWoaEt
xTCRwi70xjVoSwnvE8CZAGDyHk3/cjRcOBe5QJMCgYAyy4ApGaSoRtEdrHxyvnsR
knIlg1x8pc2J7ak5DpqrJTzk+UUHP8D+dKCfUC1YW//uTzHSHdEXl+qAi02yXrrT
S9rfNC0exY0mqvuBeRh5SCIEo4/ABgE4hLsmt1L4AYfqm4C3yS2E+KTcwvksbUis
cYhgV6tPeWzuORzu8xX/PQKBgG5puFv+jrel+l71jb7/8Xtlz5W+ehozNTAbh1Ln
xZS+OFb5p/bjSaRIraWQoHtGgRBvAwZxRsOnXlgZEtBRaHDln8TrOn+Rhoj+DB79
4pG/IwJkMa0b6RT7MB0SS12eaFxyoJIaV9CQgnCTDdn6CaCjMqt5EPsnNJ4y06Lr
020tAoGASPmKKVhXJxfhzyzsY9Kk9o31MKISUqVDNimqVDOt8vPZw8m/2WXUVH9T
DnuEGaBmpG22Gs1NxbktsYAUzBeRBpoQ/fNK55eaZorJLs3DfFK604lLClJlQsDd
yfp4LcRNQGodV4Utl6mPOtOFa8nrVGMQn3+M3TK6QTNpjLe87OE=
-----END RSA PRIVATE KEY-----

Binary file not shown.

View file

@ -0,0 +1,63 @@
-----BEGIN CERTIFICATE-----
MIIFODCCAyCgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwWjELMAkGA1UEBhMCQ04x
ETAPBgNVBAgMCFNoYW5naGFpMRIwEAYDVQQKDAlFc3ByZXNzaWYxJDAiBgNVBAMM
G0VzcHJlc3NpZiBJbnRlcm1lZGlhdGUgdGVzdDAeFw0xOTEwMTEwMjU0MDdaFw0z
MDA5MjMwMjU0MDdaMEgxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTaGFuZ2hhaTES
MBAGA1UECgwJRXNwcmVzc2lmMRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtr0++vUniW0Z9V2c6/gNV1hMvrxRogq7f
uvRMxF0EqfmBIqacGe8PHhPIx+Jo7Kjq0AMZk9vNgnavjlmajzOgiJTCH1JYeQWC
FOX6M2nT7VDFEIcfJFqTdKEhm+N75zTEMOAwi/jWXrYUITzp01bSBQIL8qBEIier
Owq6tvFlTaqN5sjlMoOQ4UmyahpY9verb7ATO0+m+MaVXfdRVfc4rxsm1EoAsWff
vfcTuDkXaoA2M65L7uNcPOrHDkcP5BlNMfYp6GH+GtX3pZ5dRUacxau7YG1hYoPQ
92HvMZxeM/yhJ/YWRWyyH7R/2SEj1fPorN1IgxUR5KsNdEqfImcNAgMBAAGjggEY
MIIBFDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAzBglghkgBhvhCAQ0E
JhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmljYXRlMB0GA1UdDgQW
BBR8LwbfGcYMVc++Ugdoc2XXYXUOBzB7BgNVHSMEdDBygBSZ45naA62T1+k4QIyt
n2h1bWyGOKFWpFQwUjELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFNoYW5naGFpMRIw
EAYDVQQKDAlFc3ByZXNzaWYxHDAaBgNVBAMME0VzcHJlc3NpZiBSb290IFRlc3SC
AhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG
9w0BAQsFAAOCAgEAQ/9JU171woAvQlZ8gmYIOkyIfYQfKmhvw+2DoP+5r1+LOHtO
frg9BshucqXlQ65yRWL8KaAIFKE4e/qBXnD/ZX8R8lR0aMKCgYVW6A1n0wWko/fU
RNXt+sXr+fMX7h0HOC3mzWf2fZkR5B0jUSBQSVkXNt+jkjWOFIGzfHDKldgX5rVX
vNmHwS5zRjbOvPaXrmNpV7wkQ/bRJbnFmbT5V6fwDFzdLzJami86eiT+C68d07/W
We5htv20nYFYdwQJMWYlnGLPPaSE+n5m4QqsrlfR7uOgnuX3RfKHMsiWa7TxLA4g
D9VZq88SQLshec/CIcYlSgnEfa9LxL2mKv386e9YWD2Oho/B33L5tdflihR5m1sd
9xIgka9aXmHu8GEVaBRqzqtIReoa7KfmEQWYjqXH8YdDLMlMKl968Y7c779/SDxC
1ibkanS1+2dPBYpoZldcnbH8w2dguk7luTuPlJxJph6NHGI7bbxL9z6yc5kJi2dS
R4TNXI3UKZ5s7ZUPTv2nYMJIbyEzSjkxinLsr7rFLGlAIpAlRq1C6jmh1ArGA3H2
jK0xYZcMN8Sz9gYV/zk/VTDMmiyZrYmZSxuhQFZCWaLN79z0pi5SefLW+1K6CzNj
hah0wJEtzq492IQS0q3gH82iGM35Ffy+rtAWIsxrL/2wn+cOrPGvRdmR6J0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFjjCCA3agAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwUjELMAkGA1UEBhMCQ04x
ETAPBgNVBAgMCFNoYW5naGFpMRIwEAYDVQQKDAlFc3ByZXNzaWYxHDAaBgNVBAMM
E0VzcHJlc3NpZiBSb290IFRlc3QwHhcNMTkxMDEwMTE1MDMyWhcNMjkxMDA3MTE1
MDMyWjBaMQswCQYDVQQGEwJDTjERMA8GA1UECAwIU2hhbmdoYWkxEjAQBgNVBAoM
CUVzcHJlc3NpZjEkMCIGA1UEAwwbRXNwcmVzc2lmIEludGVybWVkaWF0ZSB0ZXN0
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp7FJAjmfYsTlrcZPRJ3g
+IiKW/Gm3q23X4xzdKUQopth3DPO9FDvnce9e7JwXa1WDF8CZqWkvKrJS0njEAUR
JERLYSr28aVFUyodnfxp/+1B5aJFj7LHampLWXsnVCchHHZB0pYZ6KLrTUU73KKd
WaJODtBrq5g9mNNZqVOOHljgr5r8AJefemsCs+LhGcqq8ZFWeZBwzF2YC0h+55hc
7K5g0MnGnQHD3s5nuuSJ9Grz+NDvzESYjmZfTq56wXN6nQIi+4JYBpAx4y63n6NR
0JPsSePDlnGC4KNmHOeF9nXMgvqEP1doLssKKWdPZub6VQHLTk5ILFr1JKaSPjgj
4twKjCTzxN3dPmxY2KPq+tUtoXFxLxqrJk/HyBwiClxSlwhyAe9iZd3Lh0RFENEf
jS6gdD7coLlkJzALLcUTp0VWFWpPT1MbgYMHnnOuKXjw6KWXz/iuxvOJO4ip3tRf
ssuog/cMwmkxKC9oHfoIPBuafW42/os4aZwy/7fJgAFO/e1/n6T7T2qygNOKBvYq
mS6SWm9OFhUJuUtPlUdvHiVDQx40S0a8Z2Rp4XcuBU0M8Toi3lkEwJX/l89Wsos+
UOITA1B71HxkzHMZQNdXLfnV0tCtC6C3S8IktFm0Kfqa8ruXbjzkKg0I8Wfwyefv
HTc7FRQpyYgXkVLt1ziA+4MCAwEAAaNmMGQwHQYDVR0OBBYEFJnjmdoDrZPX6ThA
jK2faHVtbIY4MB8GA1UdIwQYMBaAFAqo9zQmHYRS1EF/1Fkb31gvGK9HMBIGA1Ud
EwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IC
AQBl+7vf7T6K7JhHQTFfOlUNoy4rdau6eAfoQE1wybUNIeuKLqhXfn7uLhYLE9Tq
LAYcMN8M8F2MFt7nNifbAFRiXCRRes6tFyQkjqG4SijvGoMiCL3pVYEgrET2qIm8
Rvupsh/u2UuGivy7XzJmMzU6HhTjF/Yfc6AiPkISzMqxLtbzCD+3TOxNe9nalsFv
gmQsCYUqVZCwdThvHMWY7lC+KZ/f0X8gyVHZpx6K/K+MbMSTzZZa7VEjcJcEQZ8r
+Br0e9X3EkGsKbnq/kVouMZGrZtbOXYNjoVStNdobNaJ1d379xbt8UgkvvSUhJoK
Y4pZoO3nZZUHslLDuLNG6m2tk1SHL7NPNhJoAGwqFtLyrUaUaGa+uIXev4xA0Cby
vUn+PXLKo9NcnDI38l/NxVhqWvKAwkWww/GDdic7GGfzJVSr+K4q3dxy3JW1nh4n
gaGSeKrP0lgO5NqJswGFSrY05lx06HKxHRJRtLf8g+llrGrhApRVqjM9t0By7CgK
E/EgGWG6MyGi2YLenFdFzFRgqEsKVn11XV+rkaC1NSu7l7QfTSiHrynBsYcCTnzD
z4QxJvlLon22Jp1qCwFVKXAE9wc/ncENqiA6vbjP9pq5yps+XbO2frdSQcNwHFIR
aaL+u5SAcyr3qV0I7Wghq0Xoo00DV/pm9K78tIamtsmNhw==
-----END CERTIFICATE-----

View file

@ -0,0 +1,312 @@
/* SSL server using plain mbedTLS sockets
*
* Adapted from the ssl_server example in mbedtls.
*
* Original Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* Additions Copyright (C) Copyright 2019 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
*/
#include "esp_err.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "esp_crt_bundle.h"
#include "unity.h"
#include "test_utils.h"
#define SERVER_ADDRESS "localhost"
#define SERVER_PORT "4433"
extern const uint8_t server_cert_chain_pem_start[] asm("_binary_server_cert_chain_pem_start");
extern const uint8_t server_cert_chain_pem_end[] asm("_binary_server_cert_chain_pem_end");
extern const uint8_t server_pk_start[] asm("_binary_prvtkey_pem_start");
extern const uint8_t server_pk_end[] asm("_binary_prvtkey_pem_end");
extern const uint8_t server_cert_bundle_start[] asm("_binary_server_cert_bundle_start");
extern const uint8_t server_cert_bundle_end[] asm("_binary_server_cert_bundle_end");
typedef struct {
mbedtls_ssl_context ssl;
mbedtls_net_context listen_fd;
mbedtls_net_context client_fd;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_config conf;
mbedtls_x509_crt cert;
mbedtls_pk_context pkey;
}mbedtls_endpoint_t;
static const char *TAG = "cert_bundle_test";
static volatile bool exit_flag;
esp_err_t endpoint_teardown(mbedtls_endpoint_t* endpoint);
esp_err_t server_setup(mbedtls_endpoint_t * server)
{
int ret;
mbedtls_ssl_config_init( &server->conf );
mbedtls_net_init( &server->listen_fd );
mbedtls_net_init( &server->client_fd );
mbedtls_ssl_init( &server->ssl );
mbedtls_x509_crt_init( &server->cert );
mbedtls_pk_init( &server->pkey );
mbedtls_entropy_init( &server->entropy );
mbedtls_ctr_drbg_init( &server->ctr_drbg );
ESP_LOGI(TAG, "Loading the server cert and key");
ret = mbedtls_x509_crt_parse( &server->cert, server_cert_chain_pem_start,
server_cert_chain_pem_end - server_cert_chain_pem_start);
if( ret != 0 ) {
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned %d", ret );
return ESP_FAIL;
}
ret = mbedtls_pk_parse_key( &server->pkey, (const unsigned char *)server_pk_start ,
server_pk_end - server_pk_start, NULL, 0 );
if( ret != 0 ) {
ESP_LOGE(TAG, "mbedtls_pk_parse_key returned %d", ret );
return ESP_FAIL;
}
ESP_LOGI(TAG, "Bind on https://%s:%s/", SERVER_ADDRESS, SERVER_PORT );
if( ( ret = mbedtls_net_bind( &server->listen_fd, NULL, SERVER_PORT, MBEDTLS_NET_PROTO_TCP ) ) != 0 ) {
ESP_LOGE(TAG, "mbedtls_net_bind returned %d", ret );
return ESP_FAIL;
}
ESP_LOGI(TAG, "Seeding the random number generator");
if( ( ret = mbedtls_ctr_drbg_seed( &server->ctr_drbg, mbedtls_entropy_func, &server->entropy,
NULL, 0) ) != 0 ) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret );
return ESP_FAIL;
}
ESP_LOGI(TAG, "Setting up the SSL data");
if( ( ret = mbedtls_ssl_config_defaults( &server->conf,
MBEDTLS_SSL_IS_SERVER,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
{
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret );
return ESP_FAIL;
}
mbedtls_ssl_conf_rng( &server->conf, mbedtls_ctr_drbg_random, &server->ctr_drbg );
mbedtls_ssl_conf_ca_chain( &server->conf, server->cert.next, NULL );
if (( ret = mbedtls_ssl_conf_own_cert( &server->conf, &server->cert, &server->pkey ) ) != 0 )
{
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned %d", ret );
return ESP_FAIL;
}
if (( ret = mbedtls_ssl_setup( &server->ssl, &server->conf ) ) != 0 )
{
ESP_LOGE(TAG, "mbedtls_ssl_setup returned %d", ret );
return ESP_FAIL;
}
return ESP_OK;
}
void server_task(void *pvParameters)
{
int ret;
mbedtls_endpoint_t server;
xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
if (server_setup(&server) != ESP_OK) {
ESP_LOGE(TAG, "SSL server setup failed");
goto exit;
}
ESP_LOGI(TAG, "Waiting for a remote connection" );
if( ( ret = mbedtls_net_accept( &server.listen_fd, &server.client_fd,
NULL, 0, NULL ) ) != 0 ) {
ESP_LOGE(TAG, "mbedtls_net_accept returned %d", ret );
goto exit;
}
mbedtls_ssl_set_bio( &server.ssl, &server.client_fd, mbedtls_net_send, mbedtls_net_recv, NULL );
while(exit_flag == false) {
mbedtls_ssl_handshake( &server.ssl );
}
ESP_LOGE(TAG, "Server shutdown");
exit:
endpoint_teardown(&server);
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
esp_err_t endpoint_teardown(mbedtls_endpoint_t* endpoint)
{
mbedtls_net_free( &endpoint->client_fd );
mbedtls_net_free( &endpoint->listen_fd );
mbedtls_x509_crt_free( &endpoint->cert );
mbedtls_pk_free( &endpoint->pkey );
mbedtls_ssl_free( &endpoint->ssl );
mbedtls_ssl_config_free( &endpoint->conf );
mbedtls_ctr_drbg_free( &endpoint->ctr_drbg );
mbedtls_entropy_free( &endpoint->entropy );
return ESP_OK;
}
esp_err_t client_setup(mbedtls_endpoint_t* client)
{
int ret;
mbedtls_ssl_config_init( &client->conf );
mbedtls_net_init( &client->client_fd );
mbedtls_ssl_init( &client->ssl );
mbedtls_x509_crt_init( &client->cert );
mbedtls_pk_init( &client->pkey );
mbedtls_entropy_init( &client->entropy );
mbedtls_ctr_drbg_init( &client->ctr_drbg );
ESP_LOGI(TAG, "Seeding the random number generator");
if((ret = mbedtls_ctr_drbg_seed(&client->ctr_drbg, mbedtls_entropy_func, &client->entropy,
NULL, 0)) != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
return ESP_FAIL;
}
ESP_LOGI(TAG, "Setting hostname for TLS session...");
/* Hostname set here should match CN in server certificate */
if((ret = mbedtls_ssl_set_hostname(&client->ssl, SERVER_ADDRESS)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
return ESP_FAIL;
}
ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
if((ret = mbedtls_ssl_config_defaults(&client->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
return ESP_FAIL;
}
mbedtls_ssl_conf_rng(&client->conf, mbedtls_ctr_drbg_random, &client->ctr_drbg);
if ((ret = mbedtls_ssl_setup(&client->ssl, &client->conf)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
return ESP_FAIL;
}
return ESP_OK;
}
void client_task(void *pvParameters)
{
int ret;
xSemaphoreHandle *sema = (xSemaphoreHandle *) pvParameters;
mbedtls_endpoint_t client;
if(client_setup(&client) != ESP_OK) {
ESP_LOGE(TAG, "SSL client setup failed");
goto exit;
}
// Set the custom bundle which DOESN'T includes the server's root certificate (default bundle)
esp_crt_bundle_attach(&client.conf);
ESP_LOGI(TAG, "Connecting to %s:%s...", SERVER_ADDRESS, SERVER_PORT);
if ((ret = mbedtls_net_connect(&client.client_fd, SERVER_ADDRESS, SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
goto exit;
}
ESP_LOGI(TAG, "Connected.");
mbedtls_ssl_set_bio(&client.ssl, &client.client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
ESP_LOGI(TAG, "Performing the SSL/TLS handshake with bundle that is missing the server root certificate");
ret = mbedtls_ssl_handshake(&client.ssl);
ESP_LOGI(TAG, "Verifying peer X.509 certificate for bundle ...");
TEST_ASSERT(mbedtls_ssl_get_verify_result(&client.ssl) != 0);
// Reset session before new connection
mbedtls_ssl_close_notify(&client.ssl);
mbedtls_ssl_session_reset(&client.ssl);
// Set the custom bundle which includes the server's root certificate
esp_crt_bundle_set(server_cert_bundle_start);
ESP_LOGI(TAG, "Performing the SSL/TLS handshake with bundle containing the server root certificate");
ret = mbedtls_ssl_handshake(&client.ssl);
ESP_LOGI(TAG, "Verifying peer X.509 certificate ...");
ret = mbedtls_ssl_get_verify_result(&client.ssl);
TEST_ASSERT(ret == 0);
if(ret == 0) {
ESP_LOGI(TAG, "Certificate validated");
}
exit_flag = true;
exit:
mbedtls_ssl_close_notify(&client.ssl);
mbedtls_ssl_session_reset(&client.ssl);
esp_crt_bundle_detach(&client.conf);
endpoint_teardown(&client);
xSemaphoreGive(*sema);
vTaskDelete(NULL);
}
TEST_CASE("custom certificate bundle", "[mbedtls]")
{
test_case_uses_tcpip();
xSemaphoreHandle exit_sema = xSemaphoreCreateCounting(2, 0);
xTaskCreate(server_task, "server task", 8192, &exit_sema, 5, NULL);
// Wait for the server to start up
vTaskDelay(100 / portTICK_PERIOD_MS);
xTaskCreate(client_task, "https_get_task", 8192, &exit_sema, 5, NULL);
for(int i = 0; i < 2; i++) {
if(!xSemaphoreTake(exit_sema, 10000/portTICK_PERIOD_MS)) {
TEST_FAIL_MESSAGE("exit_sem not released by test task");
}
}
vSemaphoreDelete(exit_sema);
}

View file

@ -154,6 +154,8 @@ INPUT = \
## ESP Serial Slave Link
$(IDF_PATH)/components/esp_serial_slave_link/include/esp_serial_slave_link/essl.h \
$(IDF_PATH)/components/esp_serial_slave_link/include/esp_serial_slave_link/essl_sdio.h \
## ESP Certificate Bundle
$(IDF_PATH)/components/mbedtls/esp_crt_bundle/include/esp_crt_bundle.h \
##
## Provisioning - API Reference
##

View file

@ -0,0 +1,82 @@
ESP x509 Certificate Bundle
===========================
Overview
--------
The ESP x509 Certificate Bundle API provides an easy way to include a bundle of custom x509 root certificates for TLS server verification.
.. note:: The bundle is currently not available when using WolfSSL.
The bundle comes with the complete list of root certificates from Mozillas NSS root certificate store. Using the gen_crt_bundle.py python utility the certificates subject name and public key are stored in a file and embedded in the {IDF_TARGET_NAME} binary.
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.
* 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.
.. note:: Trusting all root certificates means the list will have to be updated if any of the certificates are retracted. This includes removing them from `cacrt_all.pem`.
Configuration
-------------
Most configuration is done through menuconfig. Make and CMake will generate the bundle according to the configuration and embed it.
* :ref:`CONFIG_MBEDTLS_CERTIFICATE_BUNDLE`: automatically build and attach the bundle.
* :ref:`CONFIG_MBEDTLS_DEFAULT_CERTIFICATE_BUNDLE`: decide which certificates to include from the complete root list.
* :ref:`CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH`: specify the path of any additional certificates to embed in the bundle.
To enable the bundle when using ESP-TLS simply pass the function pointer to the bundle attach function:
.. code:: c
esp_tls_cfg_t cfg = {
.crt_bundle_attach = esp_crt_bundle_attach,
};
This is done to avoid embedding the certificate bundle unless activated by the user.
If using mbedTLS directly then the bundle may be activated by directly calling the attach function during the setup process:
.. code:: c
mbedtls_ssl_config conf;
mbedtls_ssl_config_init(&conf);
esp_crt_bundle_attach(&conf);
Generating the List of Root Certificates
----------------------------------------
The list of root certificates comes from Mozilla's NSS root certificate store, which can be found `here <https://wiki.mozilla.org/CA/Included_Certificates>`_
The list can be downloaded and created by running the script ``mk-ca-bundle.pl`` that is distributed as a part of `curl <https://github.com/curl/curl>`_.
Another alternative would be to download the finished list directly from the curl website: `CA certificates extracted from Mozilla <https://curl.haxx.se/docs/caextract.html>`_
The common certificates bundle were made by selecting the authorities with a market share of more than 1 % from w3tech's `SSL Survey <https://w3techs.com/technologies/overview/ssl_certificate/all>`_.
These authorities were then used to pick the names of the certificates for the filter list, `cmn_crt_authorities.csv`, from `this list <https://ccadb-public.secure.force.com/mozilla/IncludedCACertificateReportPEMCSV>`_ provided by Mozilla.
.. _updating_bundle:
Updating the Certificate Bundle
-------------------------------
The bundle is embedded into the app and can be updated along with the app by an OTA update. If you want to include a more up-to-date bundle than the bundle currently included in IDF, then the certificate list can be downloaded from Mozilla as described in :ref:`updating_bundle`.
Application Example
-------------------
Simple HTTPS example that uses ESP-TLS to establish a secure socket connection using the certificate bundle with two custom certificates added for verification: :example:`protocols/https_x509_bundle`.
HTTPS example that uses ESP-TLS and the default bundle: :example:`protocols/https_request`.
HTTPS example that uses mbedTLS and the default bundle: :example:`protocols/https_mbedtls`.
API Reference
-------------
.. include-build-file:: inc/esp_crt_bundle.inc

View file

@ -17,6 +17,7 @@ Application Protocols
Modbus <modbus>
Websocket Client <esp_websocket_client>
:esp32: ESP Serial Slave Link <esp_serial_slave_link>
Certificate Bundle <esp_crt_bundle>
Code examples for this API section are provided in the :example:`protocols` directory of ESP-IDF examples.

View file

@ -0,0 +1 @@
.. include:: ../../../en/api-reference/protocols/esp_crt_bundle.rst

View file

@ -17,6 +17,7 @@
Modbus slave <modbus>
Local Control <esp_local_ctrl>
:esp32: ESP Serial Slave Link <esp_serial_slave_link>
Certificate Bundle <esp_crt_bundle>
此 API 部分的示例代码在 ESP-IDF 示例工程的 :example:`protocols` 目录下提供。

View file

@ -2,5 +2,4 @@
#
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
idf_component_register(SRCS "https_mbedtls_example_main.c"
INCLUDE_DIRS "."
EMBED_TXTFILES server_root_cert.pem)
INCLUDE_DIRS ".")

View file

@ -3,8 +3,3 @@
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# embed files from the "certs" directory as binary data symbols
# in the app
COMPONENT_EMBED_TXTFILES := server_root_cert.pem

View file

@ -47,6 +47,7 @@
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"
#include "esp_crt_bundle.h"
/* Constants that aren't configurable in menuconfig */
@ -61,19 +62,6 @@ static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
static void https_get_task(void *pvParameters)
{
@ -102,14 +90,13 @@ static void https_get_task(void *pvParameters)
abort();
}
ESP_LOGI(TAG, "Loading the CA root certificate...");
ESP_LOGI(TAG, "Attaching the certificate bundle...");
ret = mbedtls_x509_crt_parse(&cacert, server_root_cert_pem_start,
server_root_cert_pem_end-server_root_cert_pem_start);
ret = esp_crt_bundle_attach(&conf);
if(ret < 0)
{
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
ESP_LOGE(TAG, "esp_crt_bundle_attach returned -0x%x\n\n", -ret);
abort();
}

View file

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -2,5 +2,4 @@
#
# (If this was a component, we would set COMPONENT_EMBED_TXTFILES here.)
idf_component_register(SRCS "https_request_example_main.c"
INCLUDE_DIRS "."
EMBED_TXTFILES server_root_cert.pem)
INCLUDE_DIRS ".")

View file

@ -3,8 +3,4 @@
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# embed files from the "certs" directory as binary data symbols
# in the app
COMPONENT_EMBED_TXTFILES := server_root_cert.pem

View file

@ -41,6 +41,7 @@
#include "lwip/dns.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"
/* Constants that aren't configurable in menuconfig */
#define WEB_SERVER "www.howsmyssl.com"
@ -54,20 +55,6 @@ static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
/* Root cert for howsmyssl.com, taken from server_root_cert.pem
The PEM file was extracted from the output of this command:
openssl s_client -showcerts -connect www.howsmyssl.com:443 </dev/null
The CA root cert is the last cert given in the chain of certs.
To embed it in the app binary, the PEM file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern const uint8_t server_root_cert_pem_start[] asm("_binary_server_root_cert_pem_start");
extern const uint8_t server_root_cert_pem_end[] asm("_binary_server_root_cert_pem_end");
static void https_get_task(void *pvParameters)
{
char buf[512];
@ -75,23 +62,22 @@ static void https_get_task(void *pvParameters)
while(1) {
esp_tls_cfg_t cfg = {
.cacert_buf = server_root_cert_pem_start,
.cacert_bytes = server_root_cert_pem_end - server_root_cert_pem_start,
.crt_bundle_attach = esp_crt_bundle_attach,
};
struct esp_tls *tls = esp_tls_conn_http_new(WEB_URL, &cfg);
if(tls != NULL) {
ESP_LOGI(TAG, "Connection established...");
} else {
ESP_LOGE(TAG, "Connection failed...");
goto exit;
}
size_t written_bytes = 0;
do {
ret = esp_tls_conn_write(tls,
REQUEST + written_bytes,
ret = esp_tls_conn_write(tls,
REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
if (ret >= 0) {
ESP_LOGI(TAG, "%d bytes written", ret);
@ -109,10 +95,10 @@ static void https_get_task(void *pvParameters)
len = sizeof(buf) - 1;
bzero(buf, sizeof(buf));
ret = esp_tls_conn_read(tls, (char *)buf, len);
if(ret == ESP_TLS_ERR_SSL_WANT_WRITE || ret == ESP_TLS_ERR_SSL_WANT_READ)
continue;
if(ret < 0)
{
ESP_LOGE(TAG, "esp_tls_conn_read returned -0x%x", -ret);
@ -134,7 +120,7 @@ static void https_get_task(void *pvParameters)
} while(1);
exit:
esp_tls_conn_delete(tls);
esp_tls_conn_delete(tls);
putchar('\n'); // JSON output doesn't have a newline at end
static int request_count;

View file

@ -1,27 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

View file

@ -0,0 +1,10 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(https_x509_bundle)

View file

@ -0,0 +1,11 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := https_x509_bundle
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,45 @@
# HTTPS x509 Bundle Example
This example shows how to use the ESP certificate bundle utility to embed a bundle of x509 certificates and use them to
establish a simple HTTPS connection over a secure connection. The path of the certificates are specified using menuconfig.
See the README.md file in the upper level 'examples' directory for more information about examples.
## Example workflow
- ESP TLS is initialized with the certificate bundle option enabled.
- The application loops through the given URLs, establishing a secure TLS connection to all of them, verifying the server certificate included.
### Configure the project
* Open the project configuration menu (`idf.py menuconfig`)
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../README.md) for more details.
* When using Make build system, set `Default serial port` under `Serial flasher config`.
* If using a different folder than `certs` for storing certificates then update `Custom Certificate Bundle Path` under `Component config` - `mbedTLS` - `Certificate Bundle`
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (0) cpu_start: Starting scheduler on APP CPU.
I (491) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (4051) example_connect: Ethernet Link Up
I (5971) tcpip_adapter: eth ip: 192.168.2.137, mask: 255.255.255.0, gw: 192.168.2.2
I (5971) example_connect: Connected to Ethernet
I (5971) example_connect: IPv4 address: 192.168.2.137
I (5971) example_connect: IPv6 address: fe80:0000:0000:0000:bedd:c2ff:fed4:a92b
I (5981) example: Connecting to 2 URLs
I (8371) example: Connection established to https://www.howsmyssl.com/a/check
I (11821) example: Connection established to https://espressif.com
I (12821) example: Completed 2 connections
I (12821) example: Starting over again...

View file

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----

View file

@ -0,0 +1,40 @@
import re
import os
import sys
try:
import IDF
except ImportError:
# this is a test case write with tiny-test-fw.
# to run test cases outside tiny-test-fw,
# we need to set environment variable `TEST_FW_PATH`,
# then get and insert `TEST_FW_PATH` to sys path before import FW module
test_fw_path = os.getenv("TEST_FW_PATH")
if test_fw_path and test_fw_path not in sys.path:
sys.path.insert(0, test_fw_path)
import IDF
@IDF.idf_example_test(env_tag="Example_WIFI", ignore=True)
def test_examples_protocol_https_x509_bundle(env, extra_data):
"""
steps: |
1. join AP
2. connect to multiple URLs
3. send http request
"""
dut1 = env.get_dut("https_x509_bundle", "examples/protocols/https_x509_bundle")
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, "https_x509_bundle.bin")
bin_size = os.path.getsize(binary_file)
IDF.log_performance("https_x509_bundle_bin_size", "{}KB".format(bin_size // 1024))
IDF.check_performance("https_x509_bundle_bin_size", bin_size // 1024)
# start test
dut1.start_app()
num_URLS = dut1.expect(re.compile(r"Connecting to (\d+) URLs"), timeout=30)
dut1.expect(re.compile(r"Connection established to ([\s\S]*)"), timeout=30)
dut1.expect("Completed {} connections".format(num_URLS[0]), timeout=60)
if __name__ == '__main__':
test_examples_protocol_https_x509_bundle()

View file

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "https_x509_bundle_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,97 @@
/* HTTPS GET Example using plain mbedTLS sockets
*
* Contacts the howsmyssl.com API via TLS v1.2 and reads a JSON
* response.
*
* Adapted from the ssl_client1 example in mbedtls.
*
* Original Copyright (C) 2006-2016, ARM Limited, All Rights Reserved, Apache 2.0 License.
* Additions Copyright (C) Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD, Apache 2.0 License.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.
*/
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "esp_tls.h"
#include "esp_crt_bundle.h"
#define MAX_URLS 2
static const char *web_urls[MAX_URLS] = {
"https://www.howsmyssl.com/a/check",
"https://espressif.com",
};
static const char *TAG = "example";
static void https_get_task(void *pvParameters)
{
while (1) {
int conn_count = 0;
ESP_LOGI(TAG, "Connecting to %d URLs", MAX_URLS);
for (int i = 0; i < MAX_URLS; i++) {
esp_tls_cfg_t cfg = {
.crt_bundle_attach = esp_crt_bundle_attach,
};
struct esp_tls *tls = esp_tls_conn_http_new(web_urls[i], &cfg);
if (tls != NULL) {
ESP_LOGI(TAG, "Connection established to %s", web_urls[i]);
conn_count++;
} else {
ESP_LOGE(TAG, "Could not connect to %s", web_urls[i]);
}
esp_tls_conn_delete(tls);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Completed %d connections", conn_count);
ESP_LOGI(TAG, "Starting over again...");
}
}
void app_main(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
}

View file

@ -0,0 +1,5 @@
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL is not set
# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE=y
CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE_PATH="certs"

View file

@ -157,6 +157,14 @@ test_multi_heap_on_host:
- cd components/heap/test_multi_heap_host
- ./test_all_configs.sh
test_certificate_bundle_on_host:
extends: .host_test_template
tags:
- build
script:
- cd components/mbedtls/esp_crt_bundle/test_gen_crt_bundle/
- ${IDF_PATH}/tools/ci/multirun_with_pyenv.sh ./test_gen_crt_bundle.py
test_confserver:
extends: .host_test_template
script:

View file

@ -6,6 +6,8 @@ components/espcoredump/espcoredump.py
components/espcoredump/test/test_espcoredump.py
components/espcoredump/test/test_espcoredump.sh
components/heap/test_multi_heap_host/test_all_configs.sh
components/mbedtls/esp_crt_bundle/gen_crt_bundle.py
components/mbedtls/esp_crt_bundle/test_gen_crt_bundle/test_gen_crt_bundle.py
components/nvs_flash/nvs_partition_generator/nvs_partition_gen.py
components/partition_table/gen_empty_partition.py
components/partition_table/gen_esp32part.py