Merge branch 'feature/mqtt_unit_test' into 'master'

mqtt: basic set of unit tests, modify example tests to check ssl connect

See merge request espressif/esp-idf!7393
This commit is contained in:
Angus Gratton 2020-02-10 15:10:56 +08:00
commit 59c39173f2
32 changed files with 1052 additions and 336 deletions

@ -1 +1 @@
Subproject commit 86fc8b7584f7f3aebf422843d84a26655e485fbe
Subproject commit 9e20c7ae3d6951cab3ed8dc66a0467da5bf37f16

View file

@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES unity test_utils mqtt nvs_flash app_update)

View file

@ -0,0 +1,4 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View file

@ -0,0 +1,70 @@
#include "test_utils.h"
#include "mqtt_client.h"
#include "unity.h"
#include <sys/time.h>
#include "nvs_flash.h"
#include "esp_ota_ops.h"
static void test_leak_setup(const char * file, long line)
{
uint8_t mac[6];
struct timeval te;
gettimeofday(&te, NULL); // get current time
esp_read_mac(mac, ESP_MAC_WIFI_STA);
printf("%s:%ld: time=%ld.%lds, mac:" MACSTR "\n", file, line, te.tv_sec, te.tv_usec, MAC2STR(mac));
unity_reset_leak_checks();
}
static const char* this_bin_addr(void)
{
spi_flash_mmap_handle_t out_handle;
const void *binary_address;
const esp_partition_t* partition = esp_ota_get_running_partition();
esp_partition_mmap(partition, 0, partition->size, SPI_FLASH_MMAP_DATA, &binary_address, &out_handle);
return binary_address;
}
TEST_CASE("mqtt init with invalid url", "[mqtt][leaks=0]")
{
test_leak_setup(__FILE__, __LINE__);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "INVALID",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_EQUAL(NULL, client );
}
TEST_CASE("mqtt init and deinit", "[mqtt][leaks=0]")
{
test_leak_setup(__FILE__, __LINE__);
const esp_mqtt_client_config_t mqtt_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.uri = "mqtts://localhost:8883",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_NOT_EQUAL(NULL, client );
esp_mqtt_client_destroy(client);
}
TEST_CASE("mqtt enqueue and destroy outbox", "[mqtt][leaks=0]")
{
const char * bin_addr = this_bin_addr();
test_leak_setup(__FILE__, __LINE__);
const int messages = 20;
const int size = 2000;
const esp_mqtt_client_config_t mqtt_cfg = {
// no connection takes place, but the uri has to be valid for init() to succeed
.uri = "mqtts://localhost:8883",
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
TEST_ASSERT_NOT_EQUAL(NULL, client );
int bytes_before = esp_get_free_heap_size();
for (int i=0; i<messages; ++i) {
esp_mqtt_client_publish(client, "test", bin_addr, size, 1, 0);
}
int bytes_after = esp_get_free_heap_size();
// check that outbox allocated all messages on heap
TEST_ASSERT_GREATER_OR_EQUAL(messages*size, bytes_before - bytes_after);
esp_mqtt_client_destroy(client);
}

View file

@ -2,7 +2,6 @@ from __future__ import print_function
from __future__ import unicode_literals
from builtins import str
import re
import os
import sys
import ssl
import paho.mqtt.client as mqtt
@ -128,12 +127,7 @@ def test_weekend_mqtt_publish(env, extra_data):
3. Test evaluates python client received correct qos0 message
4. Test ESP32 client received correct qos0 message
"""
dut1 = env.get_dut("mqtt_publish", "examples/protocols/mqtt/publish_test")
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, "mqtt_publish.bin")
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance("mqtt_publish_bin_size", "{}KB".format(bin_size // 1024))
ttfw_idf.check_performance("mqtt_publish_size", bin_size // 1024)
dut1 = env.get_dut("mqtt_publish_connect_test", "examples/protocols/mqtt/publish_connect_test")
# Look for host:port in sdkconfig
try:
# python client subscribes to the topic to which esp client publishes and vice versa

View file

@ -1,13 +0,0 @@
# 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_publish)
target_add_binary_data(mqtt_publish.elf "main/mqtt_eclipse_org.pem" TEXT)

View file

@ -1,85 +0,0 @@
# ESP-MQTT advanced published test
(See the README.md file in the upper level 'examples' directory for more information about examples.)
Main purpose of this example is to test the MQTT library to correctly publish and receive messages (of different size and sequences) over different transports.
It is possible to run this example manually without any test to exercise how the MQTT library deals with
- reception of fragmented messages
- runtime updates of URI
## How to use example
This example waits for user input to provide these parameters:
- transport: string parameter, one of: tcp, ssl, ws, wss
- pattern: sample string to be transmitted as message
- pattern repeats: number of repeats of pattern in one MQTT message
- repeated: number of repeats ESP32 publishes the message, also ESP32 expects to receive the same message the same number of repeats
- qos: number specifying qos, one of: 0, 1, 2
### Hardware Required
This example can be executed on any ESP32 board, the only required interface is WiFi and connection to internet.
### 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`.
* Set brokers for all 4 transports (TCP, SSL, WS, WSS), also set certificate if needed
* Set topics for publishing from and to ESP32
### 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 (4730) event: sta ip: 192.168.0.125, mask: 255.255.255.0, gw: 192.168.0.2
I (4730) PUBLISH_TEST: [APP] Free memory: 236728 bytes
I (4730) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
D (4740) MQTT_CLIENT: MQTT client_id=ESP32_09885C
I (31360) PUBLISH_TEST: PATTERN:1234 REPEATED:10 PUBLISHED:10
```
- User enters "tcp 1234 10 10 1"
```
EXPECTED STRING 1234123412341234123412341234123412341234, SIZE:40
W (31360) MQTT_CLIENT: Client asked to stop, but was not started
I (31360) PUBLISH_TEST: [TCP transport] Startup..
D (31370) MQTT_CLIENT: Core selection disabled
I (31370) PUBLISH_TEST: Note free memory: 224652 bytes
I (31370) PUBLISH_TEST: Other event id:7
D (31390) MQTT_CLIENT: Transport connected to mqtt://192.168.0.163:1883
I (31400) MQTT_CLIENT: Sending MQTT CONNECT message, type: 1, id: 0000
D (31410) MQTT_CLIENT: Connected
I (31410) PUBLISH_TEST: MQTT_EVENT_CONNECTED
D (31410) MQTT_CLIENT: mqtt_enqueue id: 31184, type=8 successful
D (31410) OUTBOX: ENQUEUE msgid=31184, msg_type=8, len=20, size=20
D (31420) MQTT_CLIENT: Sent subscribe topic=/xxx.topic123, id: 31184, type=8 successful
I (31430) PUBLISH_TEST: sent subscribe successful, msg_id=31184
D (31440) MQTT_CLIENT: mqtt_enqueue id: 16584, type=3 successful
D (31440) OUTBOX: ENQUEUE msgid=16584, msg_type=3, len=59, size=79
I (31450) PUBLISH_TEST: [16584] Publishing...
D (31450) MQTT_CLIENT: msg_type=9, msg_id=31184
D (31460) MQTT_CLIENT: pending_id=16584, pending_msg_count = 2
D (31460) OUTBOX: DELETED msgid=31184, msg_type=8, remain size=59
D (31470) MQTT_CLIENT: Subscribe successful
I (31470) PUBLISH_TEST: MQTT_EVENT_SUBSCRIBED, msg_id=31184
D (31480) MQTT_CLIENT: msg_type=4, msg_id=16584
D (31480) MQTT_CLIENT: pending_id=16584, pending_msg_count = 1
D (31490) OUTBOX: DELETED msgid=16584, msg_type=3, remain size=0
D (31500) MQTT_CLIENT: received MQTT_MSG_TYPE_PUBACK, finish QoS1 publish
I (31500) PUBLISH_TEST: MQTT_EVENT_PUBLISHED, msg_id=16584
D (31510) MQTT_CLIENT: mqtt_enqueue id: 44615, type=3 successful
D (31520) OUTBOX: ENQUEUE msgid=44615, msg_type=3, len=59, size=59
I (31530) PUBLISH_TEST: [44615] Publishing...
...
```

View file

@ -1,2 +0,0 @@
idf_component_register(SRCS "publish_test.c"
INCLUDE_DIRS ".")

View file

@ -1 +0,0 @@
COMPONENT_EMBED_TXTFILES := mqtt_eclipse_org.pem

View file

@ -1,226 +0,0 @@
/* MQTT publish test
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 "freertos/event_groups.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "PUBLISH_TEST";
static EventGroupHandle_t mqtt_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_mqtt_client_handle_t mqtt_client = NULL;
static char *expected_data = NULL;
static char *actual_data = NULL;
static size_t expected_size = 0;
static size_t expected_published = 0;
static size_t actual_published = 0;
static int qos_test = 0;
#if CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDDEN == 1
static const uint8_t mqtt_eclipse_org_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
#else
extern const uint8_t mqtt_eclipse_org_pem_start[] asm("_binary_mqtt_eclipse_org_pem_start");
#endif
extern const uint8_t mqtt_eclipse_org_pem_end[] asm("_binary_mqtt_eclipse_org_pem_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
static int msg_id = 0;
static int actual_len = 0;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
msg_id = esp_mqtt_client_subscribe(client, CONFIG_EXAMPLE_SUBSCIBE_TOPIC, qos_test);
ESP_LOGI(TAG, "sent subscribe 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);
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);
printf("ID=%d, total_len=%d, data_len=%d, current_data_offset=%d\n", event->msg_id, event->total_data_len, event->data_len, event->current_data_offset);
if (event->topic) {
actual_len = event->data_len;
msg_id = event->msg_id;
} else {
actual_len += event->data_len;
// check consisency with msg_id across multiple data events for single msg
if (msg_id != event->msg_id) {
ESP_LOGI(TAG, "Wrong msg_id in chunked message %d != %d", msg_id, event->msg_id);
abort();
}
}
memcpy(actual_data + event->current_data_offset, event->data, event->data_len);
if (actual_len == event->total_data_len) {
if (0 == memcmp(actual_data, expected_data, expected_size)) {
printf("OK!");
memset(actual_data, 0, expected_size);
actual_published ++;
if (actual_published == expected_published) {
printf("Correct pattern received exactly x times\n");
ESP_LOGI(TAG, "Test finished correctly!");
}
} else {
printf("FAILED!");
abort();
}
}
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;
}
static void mqtt_app_start(void)
{
mqtt_event_group = xEventGroupCreate();
const esp_mqtt_client_config_t mqtt_cfg = {
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)mqtt_eclipse_org_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
}
static void get_string(char *line, size_t size)
{
int count = 0;
while (count < size) {
int c = fgetc(stdin);
if (c == '\n') {
line[count] = '\0';
break;
} else if (c > 0 && c < 127) {
line[count] = c;
++count;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
char line[256];
char pattern[32];
char transport[32];
int repeat = 0;
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();
while (1) {
get_string(line, sizeof(line));
sscanf(line, "%s %s %d %d %d", transport, pattern, &repeat, &expected_published, &qos_test);
ESP_LOGI(TAG, "PATTERN:%s REPEATED:%d PUBLISHED:%d\n", pattern, repeat, expected_published);
int pattern_size = strlen(pattern);
free(expected_data);
free(actual_data);
actual_published = 0;
expected_size = pattern_size * repeat;
expected_data = malloc(expected_size);
actual_data = malloc(expected_size);
for (int i = 0; i < repeat; i++) {
memcpy(expected_data + i * pattern_size, pattern, pattern_size);
}
printf("EXPECTED STRING %.*s, SIZE:%d\n", expected_size, expected_data, expected_size);
esp_mqtt_client_stop(mqtt_client);
if (0 == strcmp(transport, "tcp")) {
ESP_LOGI(TAG, "[TCP transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_TCP_URI);
} else if (0 == strcmp(transport, "ssl")) {
ESP_LOGI(TAG, "[SSL transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_SSL_URI);
} else if (0 == strcmp(transport, "ws")) {
ESP_LOGI(TAG, "[WS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_WS_URI);
} else if (0 == strcmp(transport, "wss")) {
ESP_LOGI(TAG, "[WSS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_WSS_URI);
} else {
ESP_LOGE(TAG, "Unexpected transport");
abort();
}
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
esp_mqtt_client_start(mqtt_client);
ESP_LOGI(TAG, "Note free memory: %d bytes", esp_get_free_heap_size());
xEventGroupWaitBits(mqtt_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
for (int i = 0; i < expected_published; i++) {
int msg_id = esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_PUBLISH_TOPIC, expected_data, expected_size, qos_test, 0);
ESP_LOGI(TAG, "[%d] Publishing...", msg_id);
}
}
}

View file

@ -308,6 +308,12 @@ test_app_test_001:
- ESP32
- test_jtag_arm
test_app_test_002:
extends: .test_app_template
tags:
- ESP32
- Example_WIFI
example_test_011:
extends: .example_debug_template
tags:

View file

@ -0,0 +1,19 @@
# 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_publish_connect_test)
target_add_binary_data(mqtt_publish_connect_test.elf "main/mqtt_eclipse_org.pem" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "ca.crt" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "ca.der" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.key" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_pwd.crt" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_no_pwd.key" TEXT)
target_add_binary_data(mqtt_publish_connect_test.elf "client_inv.crt" TEXT)

View file

@ -2,7 +2,7 @@
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := mqtt_publish
PROJECT_NAME := mqtt_publish_connect_test
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common

View file

@ -0,0 +1,22 @@
# ESP-MQTT advanced publish and connect test project
Main purpose of this application is to test the MQTT library to correctly publish and receive messages (of different size and sequences) over different transports.
It is possible to run this example manually without any test to exercise how the MQTT library deals with
- reception of fragmented messages
- runtime updates of URI
## Runtime settings
This app waits for user input to provide these parameters:
- test-type: "conn" if connection test (host, port, test-case number)
- publish test:
* transport: string parameter, one of: tcp, ssl, ws, wss
* pattern: sample string to be transmitted as message
* pattern repeats: number of repeats of pattern in one MQTT message
* repeated: number of repeats ESP32 publishes the message, also ESP32 expects to receive the same message the same number of repeats
* qos: number specifying qos, one of: 0, 1, 2
## Hardware Required
This test-app can be executed on any ESP32 board, the only required interface is WiFi and connection to a local network, then depending on the test either a mqtt test broker or a tls server.

View file

@ -0,0 +1,230 @@
from __future__ import print_function
from __future__ import unicode_literals
import re
import os
import socket
import select
import subprocess
from threading import Thread, Event
import ttfw_idf
import ssl
def _path(f):
return os.path.join(os.path.dirname(os.path.realpath(__file__)),f)
def set_server_cert_cn(ip):
arg_list = [
['openssl', 'req', '-out', _path('srv.csr'), '-key', _path('server.key'),'-subj', "/CN={}".format(ip), '-new'],
['openssl', 'x509', '-req', '-in', _path('srv.csr'), '-CA', _path('ca.crt'),
'-CAkey', _path('ca.key'), '-CAcreateserial', '-out', _path('srv.crt'), '-days', '360']]
for args in arg_list:
if subprocess.check_call(args) != 0:
raise("openssl command {} failed".format(args))
def get_my_ip():
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
# doesn't even have to be reachable
s.connect(('10.255.255.255', 1))
IP = s.getsockname()[0]
except Exception:
IP = '127.0.0.1'
finally:
s.close()
return IP
# Simple server for mqtt over TLS connection
class TlsServer:
def __init__(self, port, client_cert=False, refuse_connection=False, use_alpn=False):
self.port = port
self.socket = socket.socket()
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.socket.settimeout(10.0)
self.shutdown = Event()
self.client_cert = client_cert
self.refuse_connection = refuse_connection
self.ssl_error = None
self.use_alpn = use_alpn
self.negotiated_protocol = None
def __enter__(self):
try:
self.socket.bind(('', self.port))
except socket.error as e:
print("Bind failed:{}".format(e))
raise
self.socket.listen(1)
self.server_thread = Thread(target=self.run_server)
self.server_thread.start()
return self
def __exit__(self, exc_type, exc_value, traceback):
self.shutdown.set()
self.server_thread.join()
self.socket.close()
if (self.conn is not None):
self.conn.close()
def get_last_ssl_error(self):
return self.ssl_error
def get_negotiated_protocol(self):
return self.negotiated_protocol
def run_server(self):
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
if self.client_cert:
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(cafile=_path("ca.crt"))
context.load_cert_chain(certfile=_path("srv.crt"), keyfile=_path("server.key"))
if self.use_alpn:
context.set_alpn_protocols(["mymqtt", "http/1.1"])
self.socket = context.wrap_socket(self.socket, server_side=True)
try:
self.conn, address = self.socket.accept() # accept new connection
self.socket.settimeout(10.0)
print(" - connection from: {}".format(address))
if self.use_alpn:
self.negotiated_protocol = self.conn.selected_alpn_protocol()
print(" - negotiated_protocol: {}".format(self.negotiated_protocol))
self.handle_conn()
except ssl.SSLError as e:
self.conn = None
self.ssl_error = str(e)
print(" - SSLError: {}".format(str(e)))
def handle_conn(self):
while not self.shutdown.is_set():
r,w,e = select.select([self.conn], [], [], 1)
try:
if self.conn in r:
self.process_mqtt_connect()
except socket.error as err:
print(" - error: {}".format(err))
raise
def process_mqtt_connect(self):
try:
data = bytearray(self.conn.recv(1024))
message = ''.join(format(x, '02x') for x in data)
if message[0:16] == '101800044d515454':
if self.refuse_connection is False:
print(" - received mqtt connect, sending ACK")
self.conn.send(bytearray.fromhex("20020000"))
else:
# injecting connection not authorized error
print(" - received mqtt connect, sending NAK")
self.conn.send(bytearray.fromhex("20020005"))
else:
raise Exception(" - error process_mqtt_connect unexpected connect received: {}".format(message))
finally:
# stop the server after the connect message in happy flow, or if any exception occur
self.shutdown.set()
@ttfw_idf.idf_custom_test(env_tag="Example_WIFI", group="test-apps")
def test_examples_protocol_mqtt_publish_connect(env, extra_data):
"""
steps:
1. join AP
2. connect to uri specified in the config
3. send and receive data
"""
dut1 = env.get_dut("mqtt_publish_connect_test", "tools/test_apps/protocols/mqtt/publish_connect_test", dut_class=ttfw_idf.ESP32DUT)
# check and log bin size
binary_file = os.path.join(dut1.app.binary_path, "mqtt_publish_connect_test.bin")
bin_size = os.path.getsize(binary_file)
ttfw_idf.log_performance("mqtt_publish_connect_test_bin_size", "{}KB".format(bin_size // 1024))
ttfw_idf.check_performance("mqtt_publish_connect_test_bin_size_vin_size", bin_size // 1024)
# Look for test case symbolic names
cases = {}
try:
for i in ["CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT",
"CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT",
"CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH",
"CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT",
"CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT",
"CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD",
"CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT",
"CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN"]:
cases[i] = dut1.app.get_sdkconfig()[i]
except Exception:
print('ENV_TEST_FAILURE: Some mandatory test case not found in sdkconfig')
raise
dut1.start_app()
esp_ip = dut1.expect(re.compile(r" IPv4 address: ([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)"), timeout=30)
print("Got IP={}".format(esp_ip[0]))
#
# start connection test
ip = get_my_ip()
set_server_cert_cn(ip)
server_port = 2222
def start_case(case, desc):
print("Starting {}: {}".format(case, desc))
case_id = cases[case]
dut1.write("conn {} {} {}".format(ip, server_port, case_id))
dut1.expect("Test case:{} started".format(case_id))
return case_id
for case in ["CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT", "CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT", "CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT"]:
# All these cases connect to the server with no server verification or with server only verification
with TlsServer(server_port):
test_nr = start_case(case, "default server - expect to connect normally")
dut1.expect("MQTT_EVENT_CONNECTED: Test={}".format(test_nr), timeout=30)
with TlsServer(server_port, refuse_connection=True):
test_nr = start_case(case, "ssl shall connect, but mqtt sends connect refusal")
dut1.expect("MQTT_EVENT_ERROR: Test={}".format(test_nr), timeout=30)
dut1.expect("MQTT ERROR: 0x5") # expecting 0x5 ... connection not authorized error
with TlsServer(server_port, client_cert=True) as s:
test_nr = start_case(case, "server with client verification - handshake error since client presents no client certificate")
dut1.expect("MQTT_EVENT_ERROR: Test={}".format(test_nr), timeout=30)
dut1.expect("ESP-TLS ERROR: 0x8010") # expect ... handshake error (PEER_DID_NOT_RETURN_A_CERTIFICATE)
if "PEER_DID_NOT_RETURN_A_CERTIFICATE" not in s.get_last_ssl_error():
raise("Unexpected ssl error from the server {}".format(s.get_last_ssl_error()))
for case in ["CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH", "CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD"]:
# These cases connect to server with both server and client verification (client key might be password protected)
with TlsServer(server_port, client_cert=True):
test_nr = start_case(case, "server with client verification - expect to connect normally")
dut1.expect("MQTT_EVENT_CONNECTED: Test={}".format(test_nr), timeout=30)
case = "CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT"
with TlsServer(server_port) as s:
test_nr = start_case(case, "invalid server certificate on default server - expect ssl handshake error")
dut1.expect("MQTT_EVENT_ERROR: Test={}".format(test_nr), timeout=30)
dut1.expect("ESP-TLS ERROR: 0x8010") # expect ... handshake error (TLSV1_ALERT_UNKNOWN_CA)
if "alert unknown ca" not in s.get_last_ssl_error():
raise Exception("Unexpected ssl error from the server {}".format(s.get_last_ssl_error()))
case = "CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT"
with TlsServer(server_port, client_cert=True) as s:
test_nr = start_case(case, "Invalid client certificate on server with client verification - expect ssl handshake error")
dut1.expect("MQTT_EVENT_ERROR: Test={}".format(test_nr), timeout=30)
dut1.expect("ESP-TLS ERROR: 0x8010") # expect ... handshake error (CERTIFICATE_VERIFY_FAILED)
if "CERTIFICATE_VERIFY_FAILED" not in s.get_last_ssl_error():
raise Exception("Unexpected ssl error from the server {}".format(s.get_last_ssl_error()))
for case in ["CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT", "CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN"]:
with TlsServer(server_port, use_alpn=True) as s:
test_nr = start_case(case, "server with alpn - expect connect, check resolved protocol")
dut1.expect("MQTT_EVENT_CONNECTED: Test={}".format(test_nr), timeout=30)
if case == "CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT" and s.get_negotiated_protocol() is None:
print(" - client with alpn off, no negotiated protocol: OK")
elif case == "CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN" and s.get_negotiated_protocol() == "mymqtt":
print(" - client with alpn on, negotiated protocol resolved: OK")
else:
raise Exception("Unexpected negotiated protocol {}".format(s.get_negotiated_protocol()))
if __name__ == '__main__':
test_examples_protocol_mqtt_publish_connect()

View file

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIUNI5wldYysh6rtCzYmda6H414aRswDQYJKoZIhvcNAQEL
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMB4X
DTIwMDEyMTA5MDk0NloXDTI1MDEyMDA5MDk0NlowWTELMAkGA1UEBhMCQVUxEzAR
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lBiMAV
3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrhY+Tc
kAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHeZj8h
bIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFAjPc4
7C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJPzssU
BBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABo1MwUTAdBgNVHQ4EFgQUGYLV
EkgWzxjpltE6texha7zZVxowHwYDVR0jBBgwFoAUGYLVEkgWzxjpltE6texha7zZ
VxowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb2EF4Zg2XWNb
eZHnzupCDd9jAhwPqkt7F1OXvxJa/RFUSB9+2izGvikGGhuKY4f0iLuqF+bhExD9
sapDcdFO2Suh4J3onbwEvmKvsv56K3xhapYg8WwPofpkVirnkwFjpQXGzrYxPujg
BPmSy3psQrhvOr/WH7SefJv2qr4ikaugfE+3enY4PL+C1dSQAuNo1QGgWsZIu0c8
TZybNZ13vNVMA+tgj2CM8FR3Etaabwtu3TTcAnO7aoBTix/bLBTuZoczhN8/MhG3
GylmDzFI8a6aKxQL3Fi4PsM82hRKWu3gfs39sR1Ci4V22v8uO5EWBPK0QZvDSc1a
KwwxI4zA0w==
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lB
iMAV3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrh
Y+TckAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHe
Zj8hbIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFA
jPc47C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJP
zssUBBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABAoIBAQDEKH7NWcohBGUj
sxp/ZcvH5+FP4qVqtHBLGYyohBsE+Zb4dgl4xBnAWRGEgrYXkxM+KOI1MmgJ/CQF
JujNmarqEVI8PIRdmG6O/D1lKfALnkq+/8Umji87745iUji1iU4rXHEydznMYMYq
TgzrgDu9O3CsDBhElFLktgsbxY2flhRiQ9s/MJTXlfkHYVMbzB+WzbgwglZmzRRB
V9P7GDc1RPs3iUuab2BC0ajWSVWPCIE+WRQ8OTxeSz/Trp0S1y1WtxdMUDhg6wIe
xbTCYF6L6CRjdnnAiaFZuW+ECaeLOyy8sOTtzxIU/8in++x3+CJBaMLsvAG1e2K9
7OLzz4KZAoGBAObHebhxfC9ue3hGC5IbE7BOaXBBdyHboXvajJKtyqpIDq7QLk2j
ktTuatigrzyCA8GgJUZCuOeWe/JhuzpFAsXN/lVs7ugw/6vQ+RGtJZkxzsYQDQjw
/3f4uWevsj3b28idxdMgstsw12a92pmH3TtKu7mMX2jJhYSu3wqbnCj/AoGBAN+w
/6nH4jLhSobunV+JT3YxwsMdyffLcdwXTcwjJrwGLwNvhPfAGtCCXidneYELCwCF
TbemR5VZadZrCdURWqwyHw8YMHBfN1hArD3MKqck+XK5Spxxr3pfNHvU3YIKWI1l
2h5sKoaPNUTQerLsJh9XG/zyc2Nl88hlFZucTGitAoGAPnKf518eIZ+d3Y/mtaSK
EV1Gfs/YMttBuUgMXeyVOLrC7l77CJtIskHJu9DPWmo8Jfr12ytW6aP46j+z8DKY
a3owZmFRzJbluFKV80iNMgUeVM4nGNJN7uLpGLucWczSjljTHSxt+Y4f23doXb88
CD1SywTHFI3jiWHgjPhKq3UCgYATBZUoFeRJWVkiEkZ1qlKEhYS/XNgg5z7+bUjj
VBXmJUx4KVKQUti05HEnPqhZbdv4pl1OgahSrfDPF/kVEk24mOaFPRRZae9l5NIA
y0zRO9auh80tcoluiYwH/7j6ZvDSzVd4ANC48pKgEG5uqqAvSBQMNX3UdQX/A4GL
4wWoXQKBgBqtbOYpsoAbLTNV4e7AMZCCKlPYFvRDALbO2E/8MjdaIqBWQSiZBkQ6
ALFYQaKJOwiLVXVv5B1FHz8MblqDOIaUpaujoA4NxdhYFLh2ui3fzuGTdGiPzOry
QHcIGifGSef45KnrF1LGvGvLMzX7Jx3xnAFOblJikN10wt1MLdNG
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDGTCCAgECFBhepE4kbe+jKn9Qa4Fq7o73PL/AMA0GCSqGSIb3DQEBCwUAMIGD
MQswCQYDVQQGEwJDWjEOMAwGA1UECAwFQ3plY2gxDTALBgNVBAcMBEJybm8xEjAQ
BgNVBAoMCUVzcHJlc3NpZjELMAkGA1UECwwCU1cxFDASBgNVBAMMCzE5Mi4xNjgu
Mi4xMR4wHAYJKoZIhvcNAQkBFg9kYXZpZEBjZXJtYWsuY3owHhcNMjAwMTIyMTAy
MDM5WhcNMjkxMTMwMTAyMDM5WjAOMQwwCgYDVQQDDANlc3AwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQCtphtVYl80g2ldpmNY0NKcmabqWKGRC5PmabDU
wrqErvyOko68fpfw24bO2ndUyXdIgWtf4mbAFmIKajrNrACzMlDtfcZM2uYgJZdn
CYu/NNfDaFEb/ZyHIgkmVskLNxtv8QFTfaNCKK5Fhzz0iaFJnFAuQVX3kXIgOEN2
8EmNxP53Eb9FeauVX+PBHhwJcGBruvWLPz8bfybHl51b80lCfddbow3z1zqGLESh
AzGc1j/5AEgEgL+iP3QX4qoLKYBgs/olv3rYor8I7oCYfsIpFCcvr/LEoaVYtCJP
PxbGu6KPx3p+r3MjaDStevdhLmzrKr35KczzTpUdOU3wgJA/AgMBAAEwDQYJKoZI
hvcNAQELBQADggEBABVwInNI7NPozIKXsshp6hfM0hchrAozYRT5sZSwusxQJ80t
Xhva0+RnBn3uaYG2YWULu+4QSgzjJ9vdRsFysuNN+7YpihwZrFHwvoRWes5C4ERE
Mzh5xeoZT1VNdz72KHvBytBUwb+h5FZQpfZ9O3yr2wBVHsi4d7/X5LVEmTxLte89
sxoMGmSbqTKj7/UOfGZjBi2IuiHs1xOZxaZWW7RTgJiz9VGrhSpwb4j6G55HDhYA
4YODy3+epyVXAHVuy4zosQ8CCgdZgN0exB7pEwVQ21zIuyzrcQgQFPGQFbkXH0ow
1mgONA6PZ9YUZftJBmqBZoTVPLLQuE1aKbhBTAA=
-----END CERTIFICATE-----

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAraYbVWJfNINpXaZjWNDSnJmm6lihkQuT5mmw1MK6hK78jpKO
vH6X8NuGztp3VMl3SIFrX+JmwBZiCmo6zawAszJQ7X3GTNrmICWXZwmLvzTXw2hR
G/2chyIJJlbJCzcbb/EBU32jQiiuRYc89ImhSZxQLkFV95FyIDhDdvBJjcT+dxG/
RXmrlV/jwR4cCXBga7r1iz8/G38mx5edW/NJQn3XW6MN89c6hixEoQMxnNY/+QBI
BIC/oj90F+KqCymAYLP6Jb962KK/CO6AmH7CKRQnL6/yxKGlWLQiTz8Wxruij8d6
fq9zI2g0rXr3YS5s6yq9+SnM806VHTlN8ICQPwIDAQABAoIBAA4G8wJMtgAZ9XL5
M+FCzSCVUORxUGvVEZd1RjGJoWOCdyhVMm6Lk16DfTpMb4NL2vTib3gJY990b2sD
9cgTcuMG1363wEMJE7nZD4flP4KslBlW3eZy8CgCWdbc/9SGGRNL1p2V8pAvlRRM
vmHKlFrL47Y41ObwutVbdievdWGcPBdF/sjpzskemVrEIPg7knHJ+MyxuIsjyaLV
Xdf3RR8yqtRggl+EP6m7JP4mbdlb/key8JTOHhe135JbuIwjUKTvm7UI+r9HwrDF
/4ysd6uEqAq4vD73VJ+7UR1LSWJ1hqoVyNP96QWPsReID/PB8TxbCPNOMX8WKz7U
WXOVomECgYEA1+54rF8QT/cpuqxR3ChbPaRGfwform0/nXZY7Xna4SqifQ2/gd6S
I97cktKCQzsnxqxrq8lV8kBlVBnqYWib+546WNjez32DUTsSu/0cIat649izbhw/
a9piOttup3OSAmc6LZGgPtLB/Jhupl9F25SbwAxnYyUUSomqK4zSOvkCgYEAzd8O
MNZUGHREjD43UuoM+qyMa1vanZk+0mcNt6cL4MTKVHNyEPdCOg01QcAGTH5pumbs
mxU4yEPGn6RylQuXDi1UwFBsPLQTDRCnbjWkYBSNY3qKD0MlN+UIQ6/zUMaYHVL8
xEfvJKxMiMdU4FhgDqoCTsK7BjnJ/bzgEdrHevcCgYAS7pOh+UvC1xbPiSA8P0WQ
qACOTrE16do0AhZV6+Mm7sgEUtpBlrQVdQq9zLsjDeK05pUiIKrqbH712rfUBon2
i67t70XJx2VmD9napZx7zz8dDvjcZJmi6SjHpEmVYOqiT06ohCYam/vqG6tH5v6G
/AaT1gKSjMO0rVFAND6ScQKBgF459ZjMwHjg3m8CGvhMP9yMFUkeJZV0iphqqpCg
WINsDt9QZ6j0Qs+nM/UAGuHwChxS94CT2gVvX/25mug1AdJvVRcguCmgkges07VR
wAZp4bziXUZXCTXoEjxI0CjsfLsPPLnp4r76TZ1c/rAgQvbzQVMjNc7HrHgCdtw1
MpBJAoGAEdeW0t5kHrHHYlFqwUHYnwD6DbNl4TzTumZrI+uEkrH1EAQ4BpIk5Gwx
OOWw8m+x2AMtBk+XcElMGZbX98msB2KcHbQMuxLF3xbCB5ihm6sKxk0HLvf2kygP
k+DYz710yKq9zRwoGOeM52oTrA4hIpQKBnpjCXg9QigD0yoWOjI=
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC7jCCAdYCFDLr5uidhcbJKmiKv+FoJ2lyh2ZkMA0GCSqGSIb3DQEBCwUAMFkx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yMDAx
MjIxMDA1MThaFw0yOTExMzAxMDA1MThaMA4xDDAKBgNVBAMMA2VzcDCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2mG1ViXzSDaV2mY1jQ0pyZpupYoZEL
k+ZpsNTCuoSu/I6Sjrx+l/Dbhs7ad1TJd0iBa1/iZsAWYgpqOs2sALMyUO19xkza
5iAll2cJi78018NoURv9nIciCSZWyQs3G2/xAVN9o0IorkWHPPSJoUmcUC5BVfeR
ciA4Q3bwSY3E/ncRv0V5q5Vf48EeHAlwYGu69Ys/Pxt/JseXnVvzSUJ911ujDfPX
OoYsRKEDMZzWP/kASASAv6I/dBfiqgspgGCz+iW/etiivwjugJh+wikUJy+v8sSh
pVi0Ik8/Fsa7oo/Hen6vcyNoNK1692EubOsqvfkpzPNOlR05TfCAkD8CAwEAATAN
BgkqhkiG9w0BAQsFAAOCAQEAxRyJBo1GP5K5BFvJDeXcAJjUbzFUqY4pUsbodkIZ
NJj69ZulxARISKsqaVhjR0m4CXZMRVhimRUJJBnjgTYidWF/xsbxgmEoURqV9SAL
puYMOm3t9Fi/81iQSzvT6ZLq5bQmxCFpZ6jl+nM28KqqldhRJApgXLOvc9i/N1FW
7ceZPw33vfzKxk91rVl9vv+wBLS/jeF++6wscIeFW+HjDj2F84JEENltoEpQz4Y1
VWYJ2G5Fu0MaxObwMrEqIxKAq7X96pyIocO6vINg0UWNp3kbPBSzD1i5FLqx96fQ
kfykJJN1kUsrJk1PskxnWq2vckdSv+jLOiF7hoHRG7+69A==
-----END CERTIFICATE-----

View file

@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,6FFF58C7A652F8E0D7E31F0CCAA27E98
ZUeJ8iCLa7bDf8xQsL3NtDK/oR2z8EWapoqGru/zOvxAeHWoLdMko1bouMkEXn+h
g4GigyXo9f3jdyFKeqf9TtXonL6vguWczFc+81ynE5w3iqqcmdP8SD8k3o07lBc/
hfRIwsg4Ywda3luQBWT63LIx7GnQjHRjK/KkPkFkYG6LDwshWyf1L7NxRMCrkejA
3B7KqlRTEia9xR0WH//ZGOdipp2MSyUGC46BgXJQ1rDJo1D+3NUTZ8RmMkqZNmJK
z3HMMflB4khmh2HkdM10VaErpiphitP52aTbGu/aschDOvSHFYMNf916u8UlyGQJ
4m/pgSz+aAfReGRDqCcojkAf/BR4+n7QYfFtxjJ5P4ul4ZnhB30synknet6+9bKU
Ht1SkavyJmruW2sfIcvPadLVm+xROnGr3ZWs82BGdPPu4wIYRWBn4S7huELXSSC2
qLCTWeLB+pV//+9E9EmrvwsTJBNMCkjAmmTdmofm8UisAGsZlvyIDJVlpUsUKOoU
cHGc2x9hj5OhgK++0JOY2ftowFX69FNRYNYHB5Vw6/5Teo3eGxVYoMeosADo7pXa
j17g7dywDLRBZuTfIkFcYyfRV4A/xcagZJ8m/rnSDphGHYkM1d+MoXAPhj6A+iAa
2qZkPyYdd0OkWvCY42F2xsjxzYjmxvkkNLDiYa7zj3ofb/1mqdNc8/k2AbFObX4v
LenDFyqmzeYfzHcJ2Z4edwx1TFFMlHb+knuYjSzcBceWoQ5nOi+uipgZVJEEKC8o
vTUBeaDnRblNIGlvuWnZFN0OHV1BduF5TyKUh2YGBw/X4qgCgrnCR2I8HGZMkUNe
UTDF9vpxnDke5BEhzkwb2R34Kvn7ac1p4NDdXOrCwEqZTt93FgQTgOuklPb39CcZ
yQHfl1Vr0EgfOlcE+ngbUrU93/qsEADXyjM8D4ZGB5+tQZGWlz9nc8PqldC3txux
Hce4bk98hOgZUy/fEozE6fODxBJCuIi2ab/6WU8j62UAIumw7fvgti+zor6eJdas
QCS+UVj5fJtYc5E/7Urih7Ixkltu0atqR5p81xn8U94/6KGYUCcsaZ7UZnWfD4dF
0qEkdHravD82Z38eBpt/kqIE7bHs3orvt7WSCBYZQtkdQysYy+lXEAwF3eIpCqAW
EcdHZ10zENvSHfzot1yK2rk9uuD+KqyK80xCSh9auLBSdJHCNeMtaozpCg5jLhYu
mW4zSQA4awuD58k/+xAnOzXtNCPg6TPQ7GNzX/33W9R2ceRtkbNmd68YEmkZ7tZo
s/3DAuxjid5W+wbsJHBvnUQh9g5BMF18k0SYS3bFPy62eycQziGfEQIwcgaHqAt5
SX4URYqDLN0k+68CAQfm2JAS8kOBdo9TAKsluThp/uRC1oh3DW/D0xctDAApDbdd
oNnK44XSYfMsBaGjm+NFQYTndFDpSd4+eQcVWAaXTdyRGMC6jbc9XijdzJnnKbEP
M38+5dUaZFPyONieb7VfciH1WKM0GfxHAFxpiEgXd0dwS8Jqq9sLY6drKZP5+b9a
9KMXI3jBLVqPg9yvx8E7THjF9ihsheVhEcJ6Nywhopab9Et+wvFa9upl2TJ2xGIj
-----END RSA PRIVATE KEY-----

View file

@ -0,0 +1,2 @@
idf_component_register(SRCS "publish_test.c" "connect_test.c" "publish_connect_test.c"
INCLUDE_DIRS ".")

View file

@ -47,4 +47,39 @@ menu "Example Configuration"
bool
default y if EXAMPLE_BROKER_CERTIFICATE_OVERRIDE != ""
config EXAMPLE_CONNECT_CASE_NO_CERT
# Note: All the below config values (EXAMPLE_CONNECT_CASE...) are hidden and
# used to give symbolic names to test cases, which are then referenced from both
# the embedded C code as well as the test counterpart in python
int
default 1
config EXAMPLE_CONNECT_CASE_SERVER_CERT
int
default 2
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH
int
default 3
config EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT
int
default 4
config EXAMPLE_CONNECT_CASE_SERVER_DER_CERT
int
default 5
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD
int
default 6
config EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT
int
default 7
config EXAMPLE_CONNECT_CASE_NO_CERT_ALPN
int
default 8
endmenu

View file

@ -0,0 +1 @@
COMPONENT_EMBED_TXTFILES := mqtt_eclipse_org.pem ../ca.crt ../ca.der ../client_pwd.key ../client_pwd.crt ../client_no_pwd.key ../client_inv.crt

View file

@ -0,0 +1,237 @@
/* MQTT connect test
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 <stdint.h>
#include "esp_netif.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "esp_tls.h"
#if (!defined(CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT)) || \
(!defined(CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN))
#error "Some mandatory test case not defined!"
#endif
extern const uint8_t ca_local_crt[] asm("_binary_ca_crt_start");
extern const uint8_t ca_der_start[] asm("_binary_ca_der_start");
extern const uint8_t ca_der_end[] asm("_binary_ca_der_end");
extern const uint8_t client_pwd_crt[] asm("_binary_client_pwd_crt_start");
extern const uint8_t client_pwd_key[] asm("_binary_client_pwd_key_start");
extern const uint8_t client_inv_crt[] asm("_binary_client_inv_crt_start");
extern const uint8_t client_no_pwd_key[] asm("_binary_client_no_pwd_key_start");
static const char *TAG = "CONNECT_TEST";
static esp_mqtt_client_handle_t mqtt_client = NULL;
static int running_test_case = 0;
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_mqtt_event_handle_t event = event_data;
ESP_LOGD(TAG, "Event: %d, Test case: %d", event->event_id, running_test_case);
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED: Test=%d", running_test_case);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR: Test=%d", running_test_case);
if (event->error_handle->error_type == MQTT_ERROR_TYPE_ESP_TLS) {
ESP_LOGI(TAG, "ESP-TLS ERROR: 0x%x", event->error_handle->esp_tls_last_esp_err);
} else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) {
ESP_LOGI(TAG, "MQTT ERROR: 0x%x", event->error_handle->connect_return_code);
} else {
ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type);
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
static void create_client(void)
{
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = "mqtts://127.0.0.1:1234"
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
mqtt_client = client;
esp_mqtt_client_start(client);
}
static void connect_no_certs(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_client_key_password(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)ca_local_crt,
.client_cert_pem = (const char *)client_pwd_crt,
.client_key_pem = (const char *)client_pwd_key,
.clientkey_password = "esp32",
.clientkey_password_len = 5
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_server_der_cert(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)ca_der_start,
.cert_len = ca_der_end - ca_der_start,
.client_cert_pem = "NULL",
.client_key_pem = "NULL"
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_wrong_server_cert(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)client_pwd_crt,
.client_cert_pem = "NULL",
.client_key_pem = "NULL"
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_server_cert(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)ca_local_crt,
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_server_client_certs(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)ca_local_crt,
.client_cert_pem = (const char *)client_pwd_crt,
.client_key_pem = (const char *)client_no_pwd_key
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_invalid_client_certs(const char *host, const int port)
{
char uri[64];
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.cert_pem = (const char *)ca_local_crt,
.client_cert_pem = (const char *)client_inv_crt,
.client_key_pem = (const char *)client_no_pwd_key
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
static void connect_with_alpn(const char *host, const int port)
{
char uri[64];
const char *alpn_protos[] = { "mymqtt", NULL };
sprintf(uri, "mqtts://%s:%d", host, port);
const esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.alpn_protos = alpn_protos
};
esp_mqtt_set_config(mqtt_client, &mqtt_cfg);
esp_mqtt_client_disconnect(mqtt_client);
esp_mqtt_client_reconnect(mqtt_client);
}
void connection_test(const char* line)
{
char test_type[32];
char host[32];
int port;
int test_case;
sscanf(line, "%s %s %d %d", test_type, host, &port, &test_case);
if (mqtt_client == NULL) {
create_client();
}
ESP_LOGI(TAG, "CASE:%d, connecting to mqtts://%s:%d ", test_case, host, port);
running_test_case = test_case;
switch (test_case) {
case CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT:
connect_no_certs(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_SERVER_CERT:
connect_with_server_cert(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH:
connect_with_server_client_certs(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_INVALID_SERVER_CERT:
connect_with_wrong_server_cert(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_SERVER_DER_CERT:
connect_with_server_der_cert(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_KEY_PWD:
connect_with_client_key_password(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_MUTUAL_AUTH_BAD_CRT:
connect_with_invalid_client_certs(host, port);
break;
case CONFIG_EXAMPLE_CONNECT_CASE_NO_CERT_ALPN:
connect_with_alpn(host, port);
break;
default:
ESP_LOGE(TAG, "Unknown test case %d ", test_case);
break;
}
ESP_LOGI(TAG, "Test case:%d started", test_case);
}

View file

@ -0,0 +1,76 @@
/* MQTT publish-connect test
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 <stddef.h>
#include <string.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
static const char *TAG = "PUBLISH_CONNECT_TEST";
void connection_test(const char* line);
void publish_test(const char* line);
static void get_string(char *line, size_t size)
{
int count = 0;
while (count < size) {
int c = fgetc(stdin);
if (c == '\n') {
line[count] = '\0';
break;
} else if (c > 0 && c < 127) {
line[count] = c;
++count;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
char line[256];
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());
while (1) {
get_string(line, sizeof(line));
if (memcmp(line, "conn", 4) == 0) {
// line starting with "conn" indicate connection tests
connection_test(line);
get_string(line, sizeof(line));
continue;
} else {
publish_test(line);
}
}
}

View file

@ -0,0 +1,175 @@
/* MQTT publish test
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_system.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "mqtt_client.h"
static const char *TAG = "PUBLISH_TEST";
static EventGroupHandle_t mqtt_event_group;
const static int CONNECTED_BIT = BIT0;
static esp_mqtt_client_handle_t mqtt_client = NULL;
static char *expected_data = NULL;
static char *actual_data = NULL;
static size_t expected_size = 0;
static size_t expected_published = 0;
static size_t actual_published = 0;
static int qos_test = 0;
#if CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDDEN == 1
static const uint8_t mqtt_eclipse_org_pem_start[] = "-----BEGIN CERTIFICATE-----\n" CONFIG_EXAMPLE_BROKER_CERTIFICATE_OVERRIDE "\n-----END CERTIFICATE-----";
#else
extern const uint8_t mqtt_eclipse_org_pem_start[] asm("_binary_mqtt_eclipse_org_pem_start");
#endif
extern const uint8_t mqtt_eclipse_org_pem_end[] asm("_binary_mqtt_eclipse_org_pem_end");
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
{
esp_mqtt_client_handle_t client = event->client;
static int msg_id = 0;
static int actual_len = 0;
// your_context_t *context = event->context;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_event_group, CONNECTED_BIT);
msg_id = esp_mqtt_client_subscribe(client, CONFIG_EXAMPLE_SUBSCIBE_TOPIC, qos_test);
ESP_LOGI(TAG, "sent subscribe 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);
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);
printf("ID=%d, total_len=%d, data_len=%d, current_data_offset=%d\n", event->msg_id, event->total_data_len, event->data_len, event->current_data_offset);
if (event->topic) {
actual_len = event->data_len;
msg_id = event->msg_id;
} else {
actual_len += event->data_len;
// check consisency with msg_id across multiple data events for single msg
if (msg_id != event->msg_id) {
ESP_LOGI(TAG, "Wrong msg_id in chunked message %d != %d", msg_id, event->msg_id);
abort();
}
}
memcpy(actual_data + event->current_data_offset, event->data, event->data_len);
if (actual_len == event->total_data_len) {
if (0 == memcmp(actual_data, expected_data, expected_size)) {
printf("OK!");
memset(actual_data, 0, expected_size);
actual_published ++;
if (actual_published == expected_published) {
printf("Correct pattern received exactly x times\n");
ESP_LOGI(TAG, "Test finished correctly!");
}
} else {
printf("FAILED!");
abort();
}
}
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;
}
static void mqtt_app_start(void)
{
mqtt_event_group = xEventGroupCreate();
const esp_mqtt_client_config_t mqtt_cfg = {
.event_handle = mqtt_event_handler,
.cert_pem = (const char *)mqtt_eclipse_org_pem_start,
};
ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
}
void publish_test(const char* line)
{
char pattern[32];
char transport[32];
int repeat = 0;
static bool is_mqtt_init = false;
if (!is_mqtt_init) {
mqtt_app_start();
is_mqtt_init = true;
}
sscanf(line, "%s %s %d %d %d", transport, pattern, &repeat, &expected_published, &qos_test);
ESP_LOGI(TAG, "PATTERN:%s REPEATED:%d PUBLISHED:%d\n", pattern, repeat, expected_published);
int pattern_size = strlen(pattern);
free(expected_data);
free(actual_data);
actual_published = 0;
expected_size = pattern_size * repeat;
expected_data = malloc(expected_size);
actual_data = malloc(expected_size);
for (int i = 0; i < repeat; i++) {
memcpy(expected_data + i * pattern_size, pattern, pattern_size);
}
printf("EXPECTED STRING %.*s, SIZE:%d\n", expected_size, expected_data, expected_size);
esp_mqtt_client_stop(mqtt_client);
if (0 == strcmp(transport, "tcp")) {
ESP_LOGI(TAG, "[TCP transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_TCP_URI);
} else if (0 == strcmp(transport, "ssl")) {
ESP_LOGI(TAG, "[SSL transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_SSL_URI);
} else if (0 == strcmp(transport, "ws")) {
ESP_LOGI(TAG, "[WS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_WS_URI);
} else if (0 == strcmp(transport, "wss")) {
ESP_LOGI(TAG, "[WSS transport] Startup..");
esp_mqtt_client_set_uri(mqtt_client, CONFIG_EXAMPLE_BROKER_WSS_URI);
} else {
ESP_LOGE(TAG, "Unexpected transport");
abort();
}
xEventGroupClearBits(mqtt_event_group, CONNECTED_BIT);
esp_mqtt_client_start(mqtt_client);
ESP_LOGI(TAG, "Note free memory: %d bytes", esp_get_free_heap_size());
xEventGroupWaitBits(mqtt_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
for (int i = 0; i < expected_published; i++) {
int msg_id = esp_mqtt_client_publish(mqtt_client, CONFIG_EXAMPLE_PUBLISH_TOPIC, expected_data, expected_size, qos_test, 0);
ESP_LOGI(TAG, "[%d] Publishing...", msg_id);
}
}

View file

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
-----END RSA PRIVATE KEY-----