Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e4369aa

Browse files
committed
Merge branch 'feature/mqtt_mutual_auth' into 'master'
MQTT: Added client cert ssl example per PR from GitHub See merge request idf/esp-idf!3473
2 parents 97e3542 + 0cdb33c commit e4369aa

14 files changed

Lines changed: 368 additions & 14 deletions

File tree

components/esp-tls/esp_tls.c

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,9 @@ static void mbedtls_cleanup(esp_tls_t *tls)
204204
mbedtls_x509_crt_free(tls->cacert_ptr);
205205
}
206206
tls->cacert_ptr = NULL;
207+
mbedtls_x509_crt_free(&tls->cacert);
208+
mbedtls_x509_crt_free(&tls->clientcert);
209+
mbedtls_pk_free(&tls->clientkey);
207210
mbedtls_entropy_free(&tls->entropy);
208211
mbedtls_ssl_config_free(&tls->conf);
209212
mbedtls_ctr_drbg_free(&tls->ctr_drbg);
@@ -274,7 +277,34 @@ static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostle
274277
} else {
275278
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
276279
}
277-
280+
281+
if (cfg->clientcert_pem_buf != NULL && cfg->clientkey_pem_buf != NULL) {
282+
mbedtls_x509_crt_init(&tls->clientcert);
283+
mbedtls_pk_init(&tls->clientkey);
284+
285+
ret = mbedtls_x509_crt_parse(&tls->clientcert, cfg->clientcert_pem_buf, cfg->clientcert_pem_bytes);
286+
if (ret < 0) {
287+
ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
288+
goto exit;
289+
}
290+
291+
ret = mbedtls_pk_parse_key(&tls->clientkey, cfg->clientkey_pem_buf, cfg->clientkey_pem_bytes,
292+
cfg->clientkey_password, cfg->clientkey_password_len);
293+
if (ret < 0) {
294+
ESP_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%x\n\n", -ret);
295+
goto exit;
296+
}
297+
298+
ret = mbedtls_ssl_conf_own_cert(&tls->conf, &tls->clientcert, &tls->clientkey);
299+
if (ret < 0) {
300+
ESP_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%x\n\n", -ret);
301+
goto exit;
302+
}
303+
} else if (cfg->clientcert_pem_buf != NULL || cfg->clientkey_pem_buf != NULL) {
304+
ESP_LOGE(TAG, "You have to provide both clientcert_pem_buf and clientkey_pem_buf for mutual authentication\n\n");
305+
goto exit;
306+
}
307+
278308
mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
279309

280310
#ifdef CONFIG_MBEDTLS_DEBUG
@@ -502,4 +532,4 @@ int esp_tls_conn_http_new_async(const char *url, const esp_tls_cfg_t *cfg, esp_t
502532
/* Connect to host */
503533
return esp_tls_conn_new_async(&url[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len,
504534
get_port(url, &u), cfg, tls);
505-
}
535+
}

components/esp-tls/esp_tls.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,22 @@ typedef struct esp_tls_cfg {
6060

6161
unsigned int cacert_pem_bytes; /*!< Size of Certificate Authority certificate
6262
pointed to by cacert_pem_buf */
63+
64+
const unsigned char *clientcert_pem_buf;/*!< Client certificate in a buffer */
6365

66+
unsigned int clientcert_pem_bytes; /*!< Size of client certificate pointed to by
67+
clientcert_pem_buf */
68+
69+
const unsigned char *clientkey_pem_buf; /*!< Client key in a buffer */
70+
71+
unsigned int clientkey_pem_bytes; /*!< Size of client key pointed to by
72+
clientkey_pem_buf */
73+
74+
const unsigned char *clientkey_password;/*!< Client key decryption password string */
75+
76+
unsigned int clientkey_password_len; /*!< String length of the password pointed to by
77+
clientkey_password */
78+
6479
bool non_block; /*!< Configure non-blocking mode. If set to true the
6580
underneath socket will be configured in non
6681
blocking mode after tls session is established */
@@ -89,10 +104,15 @@ typedef struct esp_tls {
89104

90105
mbedtls_net_context server_fd; /*!< mbedTLS wrapper type for sockets */
91106

92-
mbedtls_x509_crt cacert; /*!< Container for an X.509 certificate */
93-
107+
mbedtls_x509_crt cacert; /*!< Container for the X.509 CA certificate */
108+
94109
mbedtls_x509_crt *cacert_ptr; /*!< Pointer to the cacert being used. */
95110

111+
mbedtls_x509_crt clientcert; /*!< Container for the X.509 client certificate */
112+
113+
mbedtls_pk_context clientkey; /*!< Container for the private key of the client
114+
certificate */
115+
96116
int sockfd; /*!< Underlying socket file descriptor. */
97117

98118
ssize_t (*read)(struct esp_tls *tls, char *data, size_t datalen); /*!< Callback function for reading data from TLS/SSL

components/tcp_transport/include/esp_transport_ssl.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,35 @@ esp_transport_handle_t esp_transport_ssl_init();
3232
/**
3333
* @brief Set SSL certificate data (as PEM format).
3434
* Note that, this function stores the pointer to data, rather than making a copy.
35-
* So we need to make sure to keep the data lifetime before cleanup the connection
35+
* So this data must remain valid until after the connection is cleaned up
3636
*
3737
* @param t ssl transport
3838
* @param[in] data The pem data
3939
* @param[in] len The length
4040
*/
4141
void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data, int len);
4242

43+
/**
44+
* @brief Set SSL client certificate data for mutual authentication (as PEM format).
45+
* Note that, this function stores the pointer to data, rather than making a copy.
46+
* So this data must remain valid until after the connection is cleaned up
47+
*
48+
* @param t ssl transport
49+
* @param[in] data The pem data
50+
* @param[in] len The length
51+
*/
52+
void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len);
53+
54+
/**
55+
* @brief Set SSL client key data for mutual authentication (as PEM format).
56+
* Note that, this function stores the pointer to data, rather than making a copy.
57+
* So this data must remain valid until after the connection is cleaned up
58+
*
59+
* @param t ssl transport
60+
* @param[in] data The pem data
61+
* @param[in] len The length
62+
*/
63+
void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len);
4364

4465
#ifdef __cplusplus
4566
}

components/tcp_transport/transport_ssl.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ typedef struct {
3939
esp_tls_t *tls;
4040
esp_tls_cfg_t cfg;
4141
bool ssl_initialized;
42-
bool verify_server;
4342
transport_ssl_conn_state_t conn_state;
4443
} transport_ssl_t;
4544

@@ -49,9 +48,6 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por
4948
{
5049
transport_ssl_t *ssl = esp_transport_get_context_data(t);
5150
if (ssl->conn_state == TRANS_SSL_INIT) {
52-
if (ssl->cfg.cacert_pem_buf) {
53-
ssl->verify_server = true;
54-
}
5551
ssl->cfg.timeout_ms = timeout_ms;
5652
ssl->cfg.non_block = true;
5753
ssl->ssl_initialized = true;
@@ -70,9 +66,7 @@ static int ssl_connect_async(esp_transport_handle_t t, const char *host, int por
7066
static int ssl_connect(esp_transport_handle_t t, const char *host, int port, int timeout_ms)
7167
{
7268
transport_ssl_t *ssl = esp_transport_get_context_data(t);
73-
if (ssl->cfg.cacert_pem_buf) {
74-
ssl->verify_server = true;
75-
}
69+
7670
ssl->cfg.timeout_ms = timeout_ms;
7771
ssl->ssl_initialized = true;
7872
ssl->tls = esp_tls_conn_new(host, strlen(host), port, &ssl->cfg);
@@ -146,7 +140,6 @@ static int ssl_close(esp_transport_handle_t t)
146140
if (ssl->ssl_initialized) {
147141
esp_tls_conn_delete(ssl->tls);
148142
ssl->ssl_initialized = false;
149-
ssl->verify_server = false;
150143
}
151144
return ret;
152145
}
@@ -168,6 +161,24 @@ void esp_transport_ssl_set_cert_data(esp_transport_handle_t t, const char *data,
168161
}
169162
}
170163

164+
void esp_transport_ssl_set_client_cert_data(esp_transport_handle_t t, const char *data, int len)
165+
{
166+
transport_ssl_t *ssl = esp_transport_get_context_data(t);
167+
if (t && ssl) {
168+
ssl->cfg.clientcert_pem_buf = (void *)data;
169+
ssl->cfg.clientcert_pem_bytes = len + 1;
170+
}
171+
}
172+
173+
void esp_transport_ssl_set_client_key_data(esp_transport_handle_t t, const char *data, int len)
174+
{
175+
transport_ssl_t *ssl = esp_transport_get_context_data(t);
176+
if (t && ssl) {
177+
ssl->cfg.clientkey_pem_buf = (void *)data;
178+
ssl->cfg.clientkey_pem_bytes = len + 1;
179+
}
180+
}
181+
171182
esp_transport_handle_t esp_transport_ssl_init()
172183
{
173184
esp_transport_handle_t t = esp_transport_init();
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# The following four lines of boilerplate have to be in your project's CMakeLists
2+
# in this exact order for cmake to work correctly
3+
cmake_minimum_required(VERSION 3.5)
4+
5+
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
6+
7+
project(mqtt_ssl_mutual_auth)
8+
9+
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/client.crt" TEXT)
10+
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/client.key" TEXT)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#
2+
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
3+
# project subdirectory.
4+
#
5+
PROJECT_NAME := mqtt_ssl_mutual_auth
6+
7+
include $(IDF_PATH)/make/project.mk
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# ESP-MQTT SSL Sample application (mutual authentication)
2+
3+
(See the README.md file in the upper level 'examples' directory for more information about examples.)
4+
5+
This example connects to the broker test.mosquitto.org using ssl transport with client certificate and as a demonstration subscribes/unsubscribes and send a message on certain topic.
6+
7+
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
8+
9+
## How to use example
10+
11+
### Hardware Required
12+
13+
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
14+
15+
### Configure the project
16+
17+
```
18+
make menuconfig
19+
```
20+
21+
* Set serial port under Serial Flasher Options.
22+
23+
* Set ssid and password for the board to connect to AP.
24+
25+
* Generate your client keys and certificate
26+
27+
Navigate to the main directory
28+
29+
```
30+
cd main
31+
```
32+
33+
Generate a client key and a CSR. When you are generating the CSR, do not use the default values. At a minimum, the CSR must include the Country, Organisation and Common Name fields.
34+
35+
```
36+
openssl genrsa -out client.key
37+
openssl req -out client.csr -key client.key -new
38+
```
39+
40+
Paste the generated CSR in the [Mosquitto test certificate signer](https://test.mosquitto.org/ssl/index.php), click Submit and copy the downloaded `client.crt` in the `main` directory.
41+
42+
Please note, that the supplied files `client.crt` and `client.key` in the `main` directory are only placeholders for your client certificate and key (i.e. the example "as is" would compile but would not connect to the broker)
43+
44+
### Build and Flash
45+
46+
Build the project and flash it to the board, then run monitor tool to view serial output:
47+
48+
```
49+
make -j4 flash monitor
50+
```
51+
52+
(To exit the serial monitor, type ``Ctrl-]``.)
53+
54+
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
55+
56+
## Example Output
57+
58+
```
59+
I (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
60+
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
61+
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
62+
I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
63+
I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464
64+
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886
65+
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970
66+
I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241
67+
I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
68+
I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
69+
I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0
70+
I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
71+
I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0
72+
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
73+
I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA
74+
TOPIC=/topic/qos0
75+
DATA=data
76+
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
77+
I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA
78+
TOPIC=/topic/qos0
79+
DATA=data
80+
```
81+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
set(COMPONENT_SRCS "app_main.c")
2+
set(COMPONENT_ADD_INCLUDEDIRS ".")
3+
4+
register_component()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
menu "Example Configuration"
2+
3+
config WIFI_SSID
4+
string "WiFi SSID"
5+
default "myssid"
6+
help
7+
SSID (network name) for the example to connect to.
8+
9+
config WIFI_PASSWORD
10+
string "WiFi Password"
11+
default "mypassword"
12+
help
13+
WiFi password (WPA or WPA2) for the example to use.
14+
15+
endmenu

0 commit comments

Comments
 (0)