esp32s2/esp_ds: Added mqtt example for TLS using Digital Signature

This commit is contained in:
Aditya Patwardhan 2020-07-31 17:12:28 +05:30
parent 24b88a7d9b
commit b5c2fa632d
9 changed files with 708 additions and 0 deletions

View File

@ -0,0 +1,13 @@
# The following four 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(mqtt_ssl_ds)
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/client.crt" TEXT)
target_add_binary_data(${CMAKE_PROJECT_NAME}.elf "main/mosquitto.org.crt" TEXT)

View File

@ -0,0 +1,131 @@
| Supported Targets | ESP32-S2 |
# ESP-MQTT SSL Mutual Authentication with Digital Signature
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Espressif's ESP32-S2 MCU has a built-in Digital Signature (DS) Peripheral, which provides hardware acceleration for RSA signature. More details can be found at [Digital Signature with ESP-TLS](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/api-reference/protocols/esp_tls.html#digital-signature-with-esp-tls).
This example connects to the broker test.mosquitto.org using ssl transport with client certificate(RSA) and as a demonstration subscribes/unsubscribes and sends a message on certain topic.The RSA signature operation required in the ssl connection is performed with help of the Digital Signature (DS) peripheral.
(Please note that the public broker is maintained by the community so may not be always available, for details please visit http://test.mosquitto.org)
It uses ESP-MQTT library which implements mqtt client to connect to mqtt broker.
## How to use example
### Hardware Required
This example can be executed on any ESP32-S2 board (which has a built-in DS peripheral), the only required interface is WiFi and connection to internet.
### Configure the project
#### 1) Selecting the target
As the project is to be built for the target ESP32-S2, it should be selected with the following command
```
idf.py set-target esp32s2
```
More detials can be found at [Selecting the target](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/build-system.html#selecting-the-target).
#### 2) Generate your client key and certificate
Navigate to the main directory
```
cd main
```
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.
```
openssl genrsa -out client.key
openssl req -out client.csr -key client.key -new
```
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.
Please note, that the supplied file `client.crt` in the `main` directory is only a placeholder for your client certificate (i.e. the example "as is" would compile but would not connect to the broker)
#### 3) Configure the DS peripheral
* The DS peripheral can be configured with the python script [configure_ds.py](README.md#configure_ds-py) by executing the following command
```
python configure_ds.py --port /* USB COM port */ --private_key /* RSA priv key */
```
In the command USB COM port is nothing but the serial port to which the ESP32-S2 chip is connected. see
[check serial port](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/establish-serial-connection.html#check-port-on-windows) for more details.
RSA private key is nothing but the client private key ( RSA ) generated in Step 2.
#### 4) Connection cofiguration
* 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`.
### 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 (3714) event: sta ip: 192.168.0.139, mask: 255.255.255.0, gw: 192.168.0.2
I (3714) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (3964) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
I (4164) MQTTS_EXAMPLE: MQTT_EVENT_CONNECTED
I (4174) MQTTS_EXAMPLE: sent publish successful, msg_id=41464
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=17886
I (4174) MQTTS_EXAMPLE: sent subscribe successful, msg_id=42970
I (4184) MQTTS_EXAMPLE: sent unsubscribe successful, msg_id=50241
I (4314) MQTTS_EXAMPLE: MQTT_EVENT_PUBLISHED, msg_id=41464
I (4484) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=17886
I (4484) MQTTS_EXAMPLE: sent publish successful, msg_id=0
I (4684) MQTTS_EXAMPLE: MQTT_EVENT_SUBSCRIBED, msg_id=42970
I (4684) MQTTS_EXAMPLE: sent publish successful, msg_id=0
I (4884) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
I (4884) MQTTS_EXAMPLE: MQTT_EVENT_DATA
TOPIC=/topic/qos0
DATA=data
I (5194) MQTT_CLIENT: deliver_publish, message_length_read=19, message_length=19
I (5194) MQTTS_EXAMPLE: MQTT_EVENT_DATA
TOPIC=/topic/qos0
DATA=data
```
### configure_ds.py
The script [configure_ds.py](./configure_ds.py) is used for configuring the DS peripheral on the ESP32-S2 SoC. The steps in the script are based on technical details of certain operations in the Digital Signature calculation, which can be found at Digital Signature Section of [ESP32-S2 TRM](https://www.espressif.com/sites/default/files/documentation/esp32-s2_technical_reference_manual_en.pdf)
The configuration script performs the following steps -
1. Take the client private key ( RSA key ) as input.
(*required parameter for the script)
can be provided with
```
python configure_ds.py --private-key /* path to client (rsa) prv key */
```
2. Randomly Calculate the `HMAC_KEY` and the `initialization vector`(IV).Then calculate the encrypted private key parameters from client private key (step i) and newly generated parameters. These encrypted private key parameters are required for the DS peripheral to perform the Digital Signature operation.
3. Store `HMAC_KEY` in one of the efuse key blocks (in the hardware).
The ID of the efuse key block ( should be in range 1-5) can be provided with the following option. ( default value of 1 is used if not provided),
```
python configure_ds.py --efuse_key_id /* key id in range 1-5 */ --burn_key
```
Currently for development purposes, the `HMAC_KEY` is stored in the efuse key block without read protection so that read operation can be performed on the same key block.
> You can burn (write) a key on an efuse key block only once.Please use a different block ID, if you want to use a different `HMAC_KEY` for the DS operation.
4. Create an NVS partition of the name `pre_prov.csv` (in `esp_ds_data` folder) which contains the required encrypted private key parameters. A bin file of the nvs partition (`pre_prov.bin`) is also created and is flashed on the device. As we have added a custom partition, the example is set to use the custom partition table by adding the required option in `sdkconfig.defaults`.
5. (optional) The script can be made to print the summary of the efuse on the chip by providing the following option.When this option is enabled, no other operations in the script are performed.
```
python configure_ds.py --summary
```
> A list of all the supported options in the script can be obtained by executing `python configure_ds.py --help`.

View File

@ -0,0 +1,314 @@
#!/usr/bin/env python
# Copyright 2020 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.
# 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.
import argparse
import os
import sys
import hashlib
import hmac
import struct
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.utils import int_to_bytes
try:
import esptool
import espefuse
except ImportError:
idf_path = os.getenv("IDF_PATH")
if not idf_path or not os.path.exists(idf_path):
raise Exception("IDF_PATH not found")
sys.path.insert(0, os.path.join(idf_path, "components", "esptool_py", "esptool"))
import esptool
import espefuse
try:
import nvs_partition_gen as nvs_gen
except ImportError:
idf_path = os.getenv("IDF_PATH")
if not idf_path or not os.path.exists(idf_path):
raise Exception("IDF_PATH not found")
sys.path.insert(0, os.path.join(idf_path, "components", "nvs_flash", "nvs_partition_generator"))
import nvs_partition_gen as nvs_gen
esp_ds_data_dir = 'esp_ds_data'
# hmac_key_file is generated when HMAC_KEY is calculated, it is used when burning HMAC_KEY to efuse
hmac_key_file = esp_ds_data_dir + '/hmac_key.bin'
# csv and bin filenames are default filenames for nvs partition files created with this script
csv_filename = esp_ds_data_dir + '/pre_prov.csv'
bin_filename = esp_ds_data_dir + '/pre_prov.bin'
def load_privatekey(key_file_path, password=None):
key_file = open(key_file_path, 'rb')
key = key_file.read()
key_file.close()
return serialization.load_pem_private_key(key, password=password, backend=default_backend())
def number_as_bytes(number, pad_bits=None):
"""
Given a number, format as a little endian array of bytes
"""
result = int_to_bytes(number)[::-1]
while pad_bits is not None and len(result) < (pad_bits // 8):
result += b'\x00'
return result
def calculate_ds_parameters(privkey, priv_key_pass):
private_key = load_privatekey(privkey, priv_key_pass)
if not isinstance(private_key, rsa.RSAPrivateKey):
print("Only RSA private keys are supported")
sys.exit(-1)
priv_numbers = private_key.private_numbers()
pub_numbers = private_key.public_key().public_numbers()
Y = priv_numbers.d
M = pub_numbers.n
key_size = private_key.key_size
supported_key_size = [1024, 2048, 3072, 4096]
if key_size not in supported_key_size:
print("Key size not supported, supported sizes are" + str(supported_key_size))
sys.exit(-1)
hmac_key = os.urandom(32)
with open(hmac_key_file, 'wb') as key_file:
key_file.write(hmac_key)
iv = os.urandom(16)
rr = 1 << (key_size * 2)
rinv = rr % pub_numbers.n
mprime = - rsa._modinv(M, 1 << 32)
mprime &= 0xFFFFFFFF
length = key_size // 32 - 1
aes_key = hmac.HMAC(hmac_key, b"\xFF" * 32, hashlib.sha256).digest()
md_in = number_as_bytes(Y, 4096) + \
number_as_bytes(M, 4096) + \
number_as_bytes(rinv, 4096) + \
struct.pack("<II", mprime, length) + \
iv
assert len(md_in) == 12480 / 8
md = hashlib.sha256(md_in).digest()
# Y4096 || M4096 || Rb4096 || M_prime32 || LENGTH32 || MD256 || 0x08*8
p = number_as_bytes(Y, 4096) + \
number_as_bytes(M, 4096) + \
number_as_bytes(rinv, 4096) + \
md + \
struct.pack("<II", mprime, length) + \
b'\x08' * 8
assert len(p) == 12672 / 8
cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor()
c = encryptor.update(p) + encryptor.finalize()
return c, iv, key_size
class DefineArgs(object):
def __init__(self, attributes):
for key, value in attributes.items():
self.__setattr__(key, value)
def efuse_summary(esp,args):
efuses, _efuse_operations = espefuse.get_efuses(esp, esp.CHIP_NAME, False, False, False)
summary_args = DefineArgs({
'baud': 115200,
'before': 'default_reset',
'chip': esp.CHIP_NAME,
'debug': False,
'do_not_confirm': False,
'file': sys.stdout,
'mode':'w',
'encding': 'utf-8',
'format': 'summary',
'operation': 'summary',
'port':args.port,
})
print("\n\n\n\t---SUMMARY START---\n")
espefuse.summary(esp, efuses, summary_args)
print("\n\t---SUMMARY END---\n\n")
def efuse_burn_key(esp, args):
efuses, efuse_operations = espefuse.get_efuses(esp, esp.CHIP_NAME, False, False, False)
if args.efuse_key_id is None:
print("efuse Key id cannot be None")
sys.exit(-1)
key_file = open(hmac_key_file, 'rb')
# First element of _KEYBLOCKS is config data so add offset of 1
key_block = efuses._KEYBLOCKS[args.efuse_key_id + 1][0]
burn_key_args = DefineArgs({
'baud': 115200,
'before': 'default_reset',
'chip': esp.CHIP_NAME,
'debug': False,
'do_not_confirm': False,
'block': [key_block],
'keyfile': [key_file],
'keypurpose': ['HMAC_DOWN_DIGITAL_SIGNATURE'],
'operation': 'burn_key',
'force_write_always': False,
'no_read_protect': True,
'no_write_protect': False,
'port': args.port,
})
try:
efuse_operations.burn_key(esp, efuses, burn_key_args, None)
key_file.close()
except esptool.FatalError:
print("\nERROR: The provided key block already contains previously burned key, please use a different key block ID")
sys.exit(-1)
def generate_csv_file(c, iv, hmac_key_id, key_size, csv_file):
with open(csv_file, 'wt', encoding='utf8') as f:
f.write("# This is a generated csv file containing required parameters for the Digital Signature operaiton\n")
f.write("key,type,encoding,value\nesp_ds_ns,namespace,,\n")
f.write("esp_ds_c,data,hex2bin,%s\n" % (c.hex()))
f.write("esp_ds_iv,data,hex2bin,%s\n" % (iv.hex()))
f.write("esp_ds_key_id,data,u8,%d\n" % (hmac_key_id))
f.write("esp_ds_rsa_len,data,u16,%d\n" % (key_size))
def generate_nvs_partition(input_filename, output_filename):
nvs_args = DefineArgs({
'input': input_filename,
'outdir': os.getcwd(),
'output': output_filename,
'size': hex(0x3000),
'version': 2,
'keyfile':None,
})
nvs_gen.generate(nvs_args, is_encr_enabled=False, encr_key=None)
def flash_nvs_partition(bin_path, addr, esp):
esp.connect()
print(bin_path)
abs_bin_path = os.path.dirname(os.path.abspath(__file__)) + '/' + bin_path
print(abs_bin_path)
if (os.path.exists(abs_bin_path) is False):
print("NVS partition not found")
sys.exit(-1)
with open(bin_path, 'rb') as nvs_file:
flash_file = [(addr, nvs_file)]
flash_args = DefineArgs({
'flash_size': '4MB',
'flash_mode': 'qio',
'flash_freq': '80m',
'addr_filename': flash_file,
'no_stub': False,
'compress': False,
'verify': False,
'encrypt': False,
'erase_all': False,
})
esp.change_baud(baud=921600)
esptool.write_flash(esp, flash_args)
def main():
parser = argparse.ArgumentParser(description='''Provision the ESPWROOM32SE device with
device_certificate and signer_certificate required for TLS authentication''')
parser.add_argument(
'--private-key',
dest='privkey',
default='main/client.key',
metavar='relative/path/to/client-priv-key',
help='relative path(from secure_cert_mfg.py) to signer certificate private key')
parser.add_argument(
"--pwd", '--password',
dest='priv_key_pass',
metavar='[password]',
help='the password associated with the private key')
parser.add_argument(
'--summary',
dest='summary',action='store_true',
help='Provide this option to print efuse summary the chip')
parser.add_argument(
'--efuse_key_id',
dest='efuse_key_id', type=int, choices=range(1,6),
metavar='[key_id] ',
default=1,
help='Provide the efuse key_id which contains/will contain HMAC_KEY, default is 1')
parser.add_argument(
"--port", '-p',
dest='port',
metavar='[port]',
required=True,
help='UART com port to which ESP device is connected')
parser.add_argument(
'--overwrite',
dest='overwrite', action='store_true',
help='Overwrite previously generated keys')
args = parser.parse_args()
esp = esptool.ESPLoader.detect_chip(args.port,baud=115200)
if (esp.CHIP_NAME != 'ESP32-S2'):
print("Only ESP32S2 chip is supported")
sys.exit(-1)
if args.summary is not False:
efuse_summary(esp, args)
sys.exit(0)
if (os.path.exists(esp_ds_data_dir) is False):
os.makedirs(esp_ds_data_dir)
else:
if (args.overwrite is False):
print("WARNING: previous ecrypted private key data exists.\nIf you want to overwrite,"
" please execute your command with providing \"--overwrite\" option")
sys.exit(0)
else:
print("overwriting previous encrypted private key data, as you have provided \"--overwrite\" option")
c, iv, key_size = calculate_ds_parameters(args.privkey, args.priv_key_pass)
efuse_burn_key(esp, args)
generate_csv_file(c, iv, args.efuse_key_id, key_size, csv_filename)
generate_nvs_partition(csv_filename, bin_filename)
flash_nvs_partition(bin_filename, 0x10000, esp)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,3 @@
idf_component_register(SRCS "app_main.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,212 @@
/* MQTT Mutual Authentication Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
/* pre_prov - name of partition containing encrypted prv key parameters ( It is set as such to synchronize it with the pre provisioning service */
#define NVS_PARTITION_NAME "pre_prov"
/* esp_ds_ns - namespace used for defining values in esp_ds_nvs */
#define NVS_NAMESPACE "esp_ds_ns"
/* esp_ds_key_id - efuse key block id where 256 bit key is stored, which will be read by
* DS module to perform DS operation */
#define NVS_EFUSE_KEY_ID "esp_ds_key_id"
/* esp_ds_rsa_len - length of RSA private key (in bits) which is encrypted */
#define NVS_RSA_LEN "esp_ds_rsa_len"
/* following entries denote key(ASCII string) for particular value in key-value pair of esp_ds_nvs (which are defined in esp_ds_ns) */
/* ciphertext_c - encrypted RSA private key, see ESP32-S2 Techincal Reference Manual for more details */
#define NVS_CIPHER_C "esp_ds_c"
/* initialization vector (iv) - 256 bit value used to encrypt RSA private key (to generate ciphertext_c) */
#define NVS_IV "esp_ds_iv"
static const char *TAG = "MQTTS_EXAMPLE";
extern const uint8_t client_cert_pem_start[] asm("_binary_client_crt_start");
extern const uint8_t client_cert_pem_end[] asm("_binary_client_crt_end");
extern const uint8_t server_cert_pem_start[] asm("_binary_mosquitto_org_crt_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_mosquitto_org_crt_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
int msg_id;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos0", 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, "/topic/qos1", 1);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_unsubscribe(client, "/topic/qos1");
ESP_LOGI(TAG, "sent unsubscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
return ESP_OK;
}
void *esp_read_ds_data_from_nvs(void)
{
esp_ds_data_ctx_t *ds_data_ctx;
ds_data_ctx = (esp_ds_data_ctx_t *)malloc(sizeof(esp_ds_data_ctx_t));
if (ds_data_ctx == NULL) {
ESP_LOGE(TAG, "Error in allocating memory for esp_ds_data_context");
goto exit;
}
ds_data_ctx->esp_ds_data = (esp_ds_data_t *)calloc(1, sizeof(esp_ds_data_t));
if (ds_data_ctx->esp_ds_data == NULL) {
ESP_LOGE(TAG, "Could not allocate memory for DS data handle ");
goto exit;
}
nvs_handle_t esp_ds_nvs_handle;
esp_err_t esp_ret;
esp_ret = nvs_flash_init_partition(NVS_PARTITION_NAME);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Error in esp_ds_nvs partition init, returned %02x", esp_ret);
goto exit;
}
esp_ret = nvs_open_from_partition(NVS_PARTITION_NAME, NVS_NAMESPACE,
NVS_READONLY, &esp_ds_nvs_handle);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Error in esp_ds_nvs partition open, returned %02x", esp_ret);
goto exit;
}
esp_ret = nvs_get_u8(esp_ds_nvs_handle, NVS_EFUSE_KEY_ID, &ds_data_ctx->efuse_key_id);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Error in efuse_key_id value from nvs, returned %02x", esp_ret);
goto exit;
}
esp_ret = nvs_get_u16(esp_ds_nvs_handle, NVS_RSA_LEN, &ds_data_ctx->rsa_length_bits);
if (esp_ret != ESP_OK) {
ESP_LOGE(TAG, "Error in reading rsa key length value from nvs, returned %02x", esp_ret);
goto exit;
}
size_t blob_length = ESP_DS_C_LEN;
esp_ret = nvs_get_blob(esp_ds_nvs_handle, NVS_CIPHER_C, (void *)(ds_data_ctx->esp_ds_data->c), &blob_length);
if ((esp_ret != ESP_OK) || (blob_length != ESP_DS_C_LEN)) {
ESP_LOGE(TAG, "Error in reading initialization vector value from nvs,bytes_read = %d, returned %02x", blob_length, esp_ret);
goto exit;
}
blob_length = ESP_DS_IV_LEN;
esp_ret = nvs_get_blob(esp_ds_nvs_handle, NVS_IV, (void *)(ds_data_ctx->esp_ds_data->iv), &blob_length);
if ((esp_ret != ESP_OK) || (blob_length != ESP_DS_IV_LEN)) {
ESP_LOGE(TAG, "Error in reading initialization vector value from nvs,bytes_read = %d, returned %02x", blob_length, esp_ret);
goto exit;
}
return (void *)ds_data_ctx;
exit:
if (ds_data_ctx != NULL) {
free(ds_data_ctx->esp_ds_data);
}
free(ds_data_ctx);
return NULL;
}
static void mqtt_app_start(void)
{
/* The context is used by the DS peripheral, should not be freed */
void *ds_data = esp_read_ds_data_from_nvs();
if (ds_data == NULL) {
ESP_LOGE(TAG, "Error in reading DS data from NVS");
vTaskDelete(NULL);
}
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://test.mosquitto.org:8884",
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)server_cert_pem_start,
.client_cert_pem = (const char *)client_cert_pem_start,
.client_key_pem = NULL,
.ds_data = ds_data,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
}
void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());
esp_log_level_set("*", ESP_LOG_INFO);
esp_log_level_set("MQTT_CLIENT", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_TCP", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT_SSL", ESP_LOG_VERBOSE);
esp_log_level_set("TRANSPORT", ESP_LOG_VERBOSE);
esp_log_level_set("OUTBOX", ESP_LOG_VERBOSE);
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(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());
mqtt_app_start();
}

View File

@ -0,0 +1 @@
Please paste your client certificate here (follow instructions in README.md)

View File

@ -0,0 +1,25 @@
-----BEGIN CERTIFICATE-----
MIIEAzCCAuugAwIBAgIUBY1hlCGvdj4NhBXkZ/uLUZNILAwwDQYJKoZIhvcNAQEL
BQAwgZAxCzAJBgNVBAYTAkdCMRcwFQYDVQQIDA5Vbml0ZWQgS2luZ2RvbTEOMAwG
A1UEBwwFRGVyYnkxEjAQBgNVBAoMCU1vc3F1aXR0bzELMAkGA1UECwwCQ0ExFjAU
BgNVBAMMDW1vc3F1aXR0by5vcmcxHzAdBgkqhkiG9w0BCQEWEHJvZ2VyQGF0Y2hv
by5vcmcwHhcNMjAwNjA5MTEwNjM5WhcNMzAwNjA3MTEwNjM5WjCBkDELMAkGA1UE
BhMCR0IxFzAVBgNVBAgMDlVuaXRlZCBLaW5nZG9tMQ4wDAYDVQQHDAVEZXJieTES
MBAGA1UECgwJTW9zcXVpdHRvMQswCQYDVQQLDAJDQTEWMBQGA1UEAwwNbW9zcXVp
dHRvLm9yZzEfMB0GCSqGSIb3DQEJARYQcm9nZXJAYXRjaG9vLm9yZzCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAME0HKmIzfTOwkKLT3THHe+ObdizamPg
UZmD64Tf3zJdNeYGYn4CEXbyP6fy3tWc8S2boW6dzrH8SdFf9uo320GJA9B7U1FW
Te3xda/Lm3JFfaHjkWw7jBwcauQZjpGINHapHRlpiCZsquAthOgxW9SgDgYlGzEA
s06pkEFiMw+qDfLo/sxFKB6vQlFekMeCymjLCbNwPJyqyhFmPWwio/PDMruBTzPH
3cioBnrJWKXc3OjXdLGFJOfj7pP0j/dr2LH72eSvv3PQQFl90CZPFhrCUcRHSSxo
E6yjGOdnz7f6PveLIB574kQORwt8ePn0yidrTC1ictikED3nHYhMUOUCAwEAAaNT
MFEwHQYDVR0OBBYEFPVV6xBUFPiGKDyo5V3+Hbh4N9YSMB8GA1UdIwQYMBaAFPVV
6xBUFPiGKDyo5V3+Hbh4N9YSMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
BQADggEBAGa9kS21N70ThM6/Hj9D7mbVxKLBjVWe2TPsGfbl3rEDfZ+OKRZ2j6AC
6r7jb4TZO3dzF2p6dgbrlU71Y/4K0TdzIjRj3cQ3KSm41JvUQ0hZ/c04iGDg/xWf
+pp58nfPAYwuerruPNWmlStWAXf0UTqRtg4hQDWBuUFDJTuWuuBvEXudz74eh/wK
sMwfu1HFvjy5Z0iMDU8PUDepjVolOCue9ashlS4EB5IECdSR2TItnAIiIwimx839
LdUdRudafMu5T5Xma182OC0/u/xRlEm+tvKGGmfFcN0piqVl8OrSPBgIlb+1IKJE
m/XriWr/Cq4h/JfB7NTsezVslgkBaoU=
-----END CERTIFICATE-----
---

View File

@ -0,0 +1,7 @@
# ESP-IDF Partition Table
# Name, Type, SubType, Offset, Size, Flags
nvs,data,nvs,0x9000,24K,
phy_init,data,phy,0xf000,4K,
pre_prov,data,nvs,0x10000,0x3000,
factory,app,factory,0x20000,1M,
1 # ESP-IDF Partition Table
2 # Name, Type, SubType, Offset, Size, Flags
3 nvs,data,nvs,0x9000,24K,
4 phy_init,data,phy,0xf000,4K,
5 pre_prov,data,nvs,0x10000,0x3000,
6 factory,app,factory,0x20000,1M,

View File

@ -0,0 +1,2 @@
CONFIG_PARTITION_TABLE_CUSTOM=y