|
| 1 | +/* |
| 2 | + * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD |
| 3 | + * |
| 4 | + * SPDX-License-Identifier: Unlicense OR CC0-1.0 |
| 5 | + */ |
| 6 | +#include <sys/socket.h> |
| 7 | +#include <netdb.h> |
| 8 | +#include <unistd.h> |
| 9 | +#include "esp_log.h" |
| 10 | +#include "mbedtls_wrap.hpp" |
| 11 | + |
| 12 | +static auto const *TAG = "simple_udp_example"; |
| 13 | + |
| 14 | +const unsigned char servercert[] = "-----BEGIN CERTIFICATE-----\n" |
| 15 | + "MIIDKzCCAhOgAwIBAgIUBxM3WJf2bP12kAfqhmhhjZWv0ukwDQYJKoZIhvcNAQEL\n" |
| 16 | + "BQAwJTEjMCEGA1UEAwwaRVNQMzIgSFRUUFMgc2VydmVyIGV4YW1wbGUwHhcNMTgx\n" |
| 17 | + "MDE3MTEzMjU3WhcNMjgxMDE0MTEzMjU3WjAlMSMwIQYDVQQDDBpFU1AzMiBIVFRQ\n" |
| 18 | + "UyBzZXJ2ZXIgZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\n" |
| 19 | + "ALBint6nP77RCQcmKgwPtTsGK0uClxg+LwKJ3WXuye3oqnnjqJCwMEneXzGdG09T\n" |
| 20 | + "sA0SyNPwrEgebLCH80an3gWU4pHDdqGHfJQa2jBL290e/5L5MB+6PTs2NKcojK/k\n" |
| 21 | + "qcZkn58MWXhDW1NpAnJtjVniK2Ksvr/YIYSbyD+JiEs0MGxEx+kOl9d7hRHJaIzd\n" |
| 22 | + "GF/vO2pl295v1qXekAlkgNMtYIVAjUy9CMpqaQBCQRL+BmPSJRkXBsYk8GPnieS4\n" |
| 23 | + "sUsp53DsNvCCtWDT6fd9D1v+BB6nDk/FCPKhtjYOwOAZlX4wWNSZpRNr5dfrxKsb\n" |
| 24 | + "jAn4PCuR2akdF4G8WLUeDWECAwEAAaNTMFEwHQYDVR0OBBYEFMnmdJKOEepXrHI/\n" |
| 25 | + "ivM6mVqJgAX8MB8GA1UdIwQYMBaAFMnmdJKOEepXrHI/ivM6mVqJgAX8MA8GA1Ud\n" |
| 26 | + "EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADiXIGEkSsN0SLSfCF1VNWO3\n" |
| 27 | + "emBurfOcDq4EGEaxRKAU0814VEmU87btIDx80+z5Dbf+GGHCPrY7odIkxGNn0DJY\n" |
| 28 | + "W1WcF+DOcbiWoUN6DTkAML0SMnp8aGj9ffx3x+qoggT+vGdWVVA4pgwqZT7Ybntx\n" |
| 29 | + "bkzcNFW0sqmCv4IN1t4w6L0A87ZwsNwVpre/j6uyBw7s8YoJHDLRFT6g7qgn0tcN\n" |
| 30 | + "ZufhNISvgWCVJQy/SZjNBHSpnIdCUSJAeTY2mkM4sGxY0Widk8LnjydxZUSxC3Nl\n" |
| 31 | + "hb6pnMh3jRq4h0+5CZielA4/a+TdrNPv/qok67ot/XJdY3qHCCd8O2b14OVq9jo=\n" |
| 32 | + "-----END CERTIFICATE-----"; |
| 33 | +const unsigned char prvtkey[] = "-----BEGIN PRIVATE KEY-----\n" |
| 34 | + "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCwYp7epz++0QkH\n" |
| 35 | + "JioMD7U7BitLgpcYPi8Cid1l7snt6Kp546iQsDBJ3l8xnRtPU7ANEsjT8KxIHmyw\n" |
| 36 | + "h/NGp94FlOKRw3ahh3yUGtowS9vdHv+S+TAfuj07NjSnKIyv5KnGZJ+fDFl4Q1tT\n" |
| 37 | + "aQJybY1Z4itirL6/2CGEm8g/iYhLNDBsRMfpDpfXe4URyWiM3Rhf7ztqZdveb9al\n" |
| 38 | + "3pAJZIDTLWCFQI1MvQjKamkAQkES/gZj0iUZFwbGJPBj54nkuLFLKedw7DbwgrVg\n" |
| 39 | + "0+n3fQ9b/gQepw5PxQjyobY2DsDgGZV+MFjUmaUTa+XX68SrG4wJ+DwrkdmpHReB\n" |
| 40 | + "vFi1Hg1hAgMBAAECggEAaTCnZkl/7qBjLexIryC/CBBJyaJ70W1kQ7NMYfniWwui\n" |
| 41 | + "f0aRxJgOdD81rjTvkINsPp+xPRQO6oOadjzdjImYEuQTqrJTEUnntbu924eh+2D9\n" |
| 42 | + "Mf2CAanj0mglRnscS9mmljZ0KzoGMX6Z/EhnuS40WiJTlWlH6MlQU/FDnwC6U34y\n" |
| 43 | + "JKy6/jGryfsx+kGU/NRvKSru6JYJWt5v7sOrymHWD62IT59h3blOiP8GMtYKeQlX\n" |
| 44 | + "49om9Mo1VTIFASY3lrxmexbY+6FG8YO+tfIe0tTAiGrkb9Pz6tYbaj9FjEWOv4Vc\n" |
| 45 | + "+3VMBUVdGJjgqvE8fx+/+mHo4Rg69BUPfPSrpEg7sQKBgQDlL85G04VZgrNZgOx6\n" |
| 46 | + "pTlCCl/NkfNb1OYa0BELqWINoWaWQHnm6lX8YjrUjwRpBF5s7mFhguFjUjp/NW6D\n" |
| 47 | + "0EEg5BmO0ePJ3dLKSeOA7gMo7y7kAcD/YGToqAaGljkBI+IAWK5Su5yldrECTQKG\n" |
| 48 | + "YnMKyQ1MWUfCYEwHtPvFvE5aPwKBgQDFBWXekpxHIvt/B41Cl/TftAzE7/f58JjV\n" |
| 49 | + "MFo/JCh9TDcH6N5TMTRS1/iQrv5M6kJSSrHnq8pqDXOwfHLwxetpk9tr937VRzoL\n" |
| 50 | + "CuG1Ar7c1AO6ujNnAEmUVC2DppL/ck5mRPWK/kgLwZSaNcZf8sydRgphsW1ogJin\n" |
| 51 | + "7g0nGbFwXwKBgQCPoZY07Pr1TeP4g8OwWTu5F6dSvdU2CAbtZthH5q98u1n/cAj1\n" |
| 52 | + "noak1Srpa3foGMTUn9CHu+5kwHPIpUPNeAZZBpq91uxa5pnkDMp3UrLIRJ2uZyr8\n" |
| 53 | + "4PxcknEEh8DR5hsM/IbDcrCJQglM19ZtQeW3LKkY4BsIxjDf45ymH407IQKBgE/g\n" |
| 54 | + "Ul6cPfOxQRlNLH4VMVgInSyyxWx1mODFy7DRrgCuh5kTVh+QUVBM8x9lcwAn8V9/\n" |
| 55 | + "nQT55wR8E603pznqY/jX0xvAqZE6YVPcw4kpZcwNwL1RhEl8GliikBlRzUL3SsW3\n" |
| 56 | + "q30AfqEViHPE3XpE66PPo6Hb1ymJCVr77iUuC3wtAoGBAIBrOGunv1qZMfqmwAY2\n" |
| 57 | + "lxlzRgxgSiaev0lTNxDzZkmU/u3dgdTwJ5DDANqPwJc6b8SGYTp9rQ0mbgVHnhIB\n" |
| 58 | + "jcJQBQkTfq6Z0H6OoTVi7dPs3ibQJFrtkoyvYAbyk36quBmNRjVh6rc8468bhXYr\n" |
| 59 | + "v/t+MeGJP/0Zw8v/X2CFll96\n" |
| 60 | + "-----END PRIVATE KEY-----"; |
| 61 | + |
| 62 | + |
| 63 | +class SecureLink: public Tls { |
| 64 | +public: |
| 65 | + explicit SecureLink() : Tls(), addr("localhost", 3333, AF_INET, SOCK_DGRAM) {} |
| 66 | + ~SecureLink() override |
| 67 | + { |
| 68 | + if (sock >= 0) { |
| 69 | + ::close(sock); |
| 70 | + } |
| 71 | + } |
| 72 | + int send(const unsigned char *buf, size_t len) override |
| 73 | + { |
| 74 | + return sendto(sock, buf, len, 0, addr, ai_size); |
| 75 | + } |
| 76 | + int recv(unsigned char *buf, size_t len) override |
| 77 | + { |
| 78 | + socklen_t socklen = sizeof(sockaddr); |
| 79 | + return recvfrom(sock, buf, len, 0, addr, &socklen); |
| 80 | + } |
| 81 | + int recv_tout(unsigned char *buf, size_t len, int timeout) override |
| 82 | + { |
| 83 | + struct timeval tv { |
| 84 | + timeout / 1000, (timeout % 1000 ) * 1000 |
| 85 | + }; |
| 86 | + fd_set read_fds; |
| 87 | + FD_ZERO( &read_fds ); |
| 88 | + FD_SET( sock, &read_fds ); |
| 89 | + |
| 90 | + int ret = select(sock + 1, &read_fds, nullptr, nullptr, timeout == 0 ? nullptr : &tv); |
| 91 | + if (ret == 0) { |
| 92 | + return MBEDTLS_ERR_SSL_TIMEOUT; |
| 93 | + } |
| 94 | + if (ret < 0) { |
| 95 | + if (errno == EINTR) { |
| 96 | + return MBEDTLS_ERR_SSL_WANT_READ; |
| 97 | + } |
| 98 | + return ret; |
| 99 | + } |
| 100 | + return recv(buf, len); |
| 101 | + } |
| 102 | + bool open(bool server_not_client) |
| 103 | + { |
| 104 | + if (!addr) { |
| 105 | + ESP_LOGE(TAG, "Failed to resolve endpoint"); |
| 106 | + return false; |
| 107 | + } |
| 108 | + sock = addr.get_sock(); |
| 109 | + if (sock < 0) { |
| 110 | + ESP_LOGE(TAG, "Failed to create socket"); |
| 111 | + return false; |
| 112 | + } |
| 113 | + if (server_not_client) { |
| 114 | + int err = bind(sock, addr, ai_size); |
| 115 | + if (err < 0) { |
| 116 | + ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); |
| 117 | + return false; |
| 118 | + } |
| 119 | + } |
| 120 | + if (!init(is_server{server_not_client}, do_verify{false})) { |
| 121 | + return false; |
| 122 | + } |
| 123 | + |
| 124 | + return handshake() == 0; |
| 125 | + } |
| 126 | + |
| 127 | +private: |
| 128 | + int sock{-1}; |
| 129 | + /** |
| 130 | + * RAII wrapper of the address_info |
| 131 | + */ |
| 132 | + struct addr_info { |
| 133 | + struct addrinfo *ai = nullptr; |
| 134 | + explicit addr_info(const char *host, int port, int family, int type) |
| 135 | + { |
| 136 | + struct addrinfo hints {}; |
| 137 | + hints.ai_family = family; |
| 138 | + hints.ai_socktype = type; |
| 139 | + if (getaddrinfo(host, nullptr, &hints, &ai) < 0) { |
| 140 | + freeaddrinfo(ai); |
| 141 | + ai = nullptr; |
| 142 | + } |
| 143 | + auto *p = (struct sockaddr_in *)ai->ai_addr; |
| 144 | + p->sin_port = htons(port); |
| 145 | + } |
| 146 | + ~addr_info() |
| 147 | + { |
| 148 | + freeaddrinfo(ai); |
| 149 | + } |
| 150 | + explicit operator bool() const |
| 151 | + { |
| 152 | + return ai != nullptr; |
| 153 | + } |
| 154 | + operator sockaddr *() const |
| 155 | + { |
| 156 | + auto *p = (struct sockaddr_in *)ai->ai_addr; |
| 157 | + return (struct sockaddr *)p; |
| 158 | + } |
| 159 | + |
| 160 | + int get_sock() const |
| 161 | + { |
| 162 | + return socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); |
| 163 | + } |
| 164 | + } addr; |
| 165 | + const int ai_size{sizeof(struct sockaddr_in)}; |
| 166 | +}; |
| 167 | + |
| 168 | +static void tls_client() |
| 169 | +{ |
| 170 | + const unsigned char message[] = "Hello\n"; |
| 171 | + unsigned char reply[128]; |
| 172 | + SecureLink client; |
| 173 | + if (!client.open(false)) { |
| 174 | + ESP_LOGE(TAG, "Failed to CONNECT! %d", errno); |
| 175 | + return; |
| 176 | + } |
| 177 | + ESP_LOGI(TAG, "client opened..."); |
| 178 | + if (client.write(message, sizeof(message)) < 0) { |
| 179 | + ESP_LOGE(TAG, "Failed to write!"); |
| 180 | + return; |
| 181 | + } |
| 182 | + int len = client.read(reply, sizeof(reply)); |
| 183 | + if (len < 0) { |
| 184 | + ESP_LOGE(TAG, "Failed to read!"); |
| 185 | + return; |
| 186 | + } |
| 187 | + ESP_LOGI(TAG, "Successfully received: %.*s", len, reply); |
| 188 | +} |
| 189 | + |
| 190 | +static void tls_server() |
| 191 | +{ |
| 192 | + unsigned char message[128]; |
| 193 | + SecureLink server; |
| 194 | + const_buf cert{servercert, sizeof(servercert)}; |
| 195 | + const_buf key{prvtkey, sizeof(prvtkey)}; |
| 196 | + if (!server.set_own_cert(cert, key)) { |
| 197 | + ESP_LOGE(TAG, "Failed to set own cert"); |
| 198 | + return; |
| 199 | + } |
| 200 | + ESP_LOGI(TAG, "openning..."); |
| 201 | + if (!server.open(true)) { |
| 202 | + ESP_LOGE(TAG, "Failed to OPEN! %d", errno); |
| 203 | + return; |
| 204 | + } |
| 205 | + int len = server.read(message, sizeof(message)); |
| 206 | + if (len < 0) { |
| 207 | + ESP_LOGE(TAG, "Failed to read!"); |
| 208 | + return; |
| 209 | + } |
| 210 | + ESP_LOGI(TAG, "Received from client: %.*s", len, message); |
| 211 | + if (server.write(message, len) < 0) { |
| 212 | + ESP_LOGE(TAG, "Failed to write!"); |
| 213 | + return; |
| 214 | + } |
| 215 | + ESP_LOGI(TAG, "Written back"); |
| 216 | +} |
| 217 | + |
| 218 | + |
| 219 | +#if CONFIG_IDF_TARGET_LINUX |
| 220 | +/** |
| 221 | + * Linux target: We're already connected, just run the client |
| 222 | + */ |
| 223 | +#include <thread> |
| 224 | +int main() |
| 225 | +{ |
| 226 | + std::thread t2(tls_server); |
| 227 | + usleep(1000); |
| 228 | + std::thread t1(tls_client); |
| 229 | + t1.join(); |
| 230 | + t2.join(); |
| 231 | + return 0; |
| 232 | +} |
| 233 | +#else |
| 234 | +/** |
| 235 | + * ESP32 chipsets: Need to initialize system components |
| 236 | + * and connect to network |
| 237 | + */ |
| 238 | + |
| 239 | +#include "nvs_flash.h" |
| 240 | +#include "esp_event.h" |
| 241 | +#include "protocol_examples_common.h" |
| 242 | +#include "esp_netif.h" |
| 243 | + |
| 244 | +extern "C" void app_main() |
| 245 | +{ |
| 246 | + ESP_ERROR_CHECK(nvs_flash_init()); |
| 247 | + ESP_ERROR_CHECK(esp_netif_init()); |
| 248 | + ESP_ERROR_CHECK(esp_event_loop_create_default()); |
| 249 | + ESP_ERROR_CHECK(example_connect()); |
| 250 | + |
| 251 | + tls_client(); |
| 252 | +} |
| 253 | +#endif |
0 commit comments