]> granicus.if.org Git - esp-idf/commitdiff
esp-tls: Basic structure
authorKedar Sovani <kedars@gmail.com>
Sat, 3 Feb 2018 03:31:45 +0000 (09:01 +0530)
committerJitin George <jitin@espressif.com>
Fri, 6 Apr 2018 11:43:14 +0000 (17:13 +0530)
Purpose:
1. TLS calls can be too many, and require a user to know the expected behaviour. A simple TLS socket wrapper that can be used in any higher level protocol.
2. Uses OpenSSL compatibility layer, so applications using esp-tls can be built on the host, and it should just work on ESP

components/esp-tls/component.mk [new file with mode: 0644]
components/esp-tls/esp-tls.c [new file with mode: 0644]
components/esp-tls/esp-tls.h [new file with mode: 0644]

diff --git a/components/esp-tls/component.mk b/components/esp-tls/component.mk
new file mode 100644 (file)
index 0000000..7267d5f
--- /dev/null
@@ -0,0 +1,3 @@
+COMPONENT_SRCDIRS := .
+
+COMPONENT_ADD_INCLUDEDIRS := .
diff --git a/components/esp-tls/esp-tls.c b/components/esp-tls/esp-tls.c
new file mode 100644 (file)
index 0000000..6867272
--- /dev/null
@@ -0,0 +1,150 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include "esp-tls.h"
+
+
+static const char *TAG = "esp-tls";
+
+#ifdef ESP_PLATFORM
+#include <esp_log.h>
+#else
+#define ESP_LOGD(TAG, ...) //printf(__VA_ARGS__);
+#define ESP_LOGE(TAG, ...) printf(__VA_ARGS__);
+#endif
+
+static struct addrinfo *resolve_host_name(const char *host, size_t hostlen, int port)
+{
+    struct addrinfo hints;
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    char *use_host = (char *)calloc(1, hostlen  + 1);
+    if (!use_host) {
+        return NULL;
+    }
+    strncpy(use_host, host, hostlen);
+    use_host[hostlen] = '\0';
+
+    char service[6];
+    snprintf(service, sizeof(service), "%d", port);
+
+    ESP_LOGD(TAG, "port is :%s: host:%s: strlen %zu\n", service, use_host, hostlen);
+    struct addrinfo *res;
+    if (getaddrinfo(use_host, service, &hints, &res)) {
+        ESP_LOGE(TAG, "couldn't get hostname for :%s:\n", use_host);
+        free(use_host);
+        return NULL;
+    }
+    free(use_host);
+    return res;
+}
+
+static int esp_tcp_connect(const char *host, int hostlen, int port)
+{
+    struct addrinfo *res = resolve_host_name(host, hostlen, port);
+    if (!res) {
+        return -1;
+    }
+
+    int ret = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+    if (ret < 0) {
+        goto err_freeaddr;
+    }
+
+    int fd = ret;
+    ret = connect(fd, res->ai_addr, res->ai_addrlen);
+    if (ret < 0) {
+        goto err_freesocket;
+    }
+
+    freeaddrinfo(res);
+    return fd;
+
+err_freesocket:
+    close(fd);
+err_freeaddr:
+    freeaddrinfo(res);
+    return -1;
+}
+
+static int create_ssl_handle(struct esp_tls *tls)
+{
+    int ret;
+
+    SSL_CTX *ssl_ctx = SSL_CTX_new(TLSv1_2_client_method());
+    if (!ssl_ctx) {
+        return -1;
+    }
+#ifdef __APPLE__
+    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
+    SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+    SSL *ssl = SSL_new(ssl_ctx);
+    if (!ssl) {
+        SSL_CTX_free(ssl_ctx);
+        return -1;
+    }
+
+    SSL_set_fd(ssl, tls->sockfd);
+    ret = SSL_connect(ssl);
+    if (ret < 1) {
+        ESP_LOGE(TAG, "SSL handshake failed");
+        SSL_free(ssl);
+        SSL_CTX_free(ssl_ctx);
+        return -1;
+    }
+
+    tls->ctx = ssl_ctx;
+    tls->ssl = ssl;
+    return 0;
+}
+
+void esp_tls_conn_delete(struct esp_tls *tls)
+{
+    if (!tls) {
+        return;
+    }
+    if (tls->ssl) {
+        SSL_free(tls->ssl);
+    }
+    if (tls->ctx) {
+        SSL_CTX_free(tls->ctx);
+    }
+    if (tls->sockfd) {
+        close(tls->sockfd);
+    }
+    free(tls);
+};
+
+struct esp_tls *esp_tls_conn_new(const char *hostname, int hostlen, int port, bool is_tls)
+{
+    int sockfd = esp_tcp_connect(hostname, hostlen, port);
+    if (sockfd < 0) {
+        return NULL;
+    }
+
+    struct esp_tls *tls = (struct esp_tls *)calloc(1, sizeof(struct esp_tls));
+    if (!tls) {
+        close(sockfd);
+        return NULL;
+    }
+    tls->sockfd = sockfd;
+
+    if (is_tls) {
+        if (create_ssl_handle(tls) != 0) {
+            esp_tls_conn_delete(tls);
+            return NULL;
+        }
+    }
+    return tls;
+}
+
diff --git a/components/esp-tls/esp-tls.h b/components/esp-tls/esp-tls.h
new file mode 100644 (file)
index 0000000..655edc0
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _ESP_TLS_H_
+#define _ESP_TLS_H_
+
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <openssl/ssl.h>
+
+struct esp_tls {
+    SSL_CTX *ctx;
+    SSL     *ssl;
+    int      sockfd;
+};
+
+struct esp_tls *esp_tls_conn_new(const char *hostname, int hostlen, int port, bool is_tls);
+
+static inline ssize_t esp_tls_conn_write(struct esp_tls *tls, const char *data, size_t datalen)
+{
+    if (tls->ssl) {
+        return SSL_write(tls->ssl, data, datalen);
+    } else {
+        return send(tls->sockfd, data, datalen, 0);
+    }
+}
+
+static inline ssize_t esp_tls_conn_read(struct esp_tls *tls, char *data, size_t datalen)
+{
+    if (tls->ssl) {
+        return SSL_read(tls->ssl, data, datalen);
+    } else {
+        return recv(tls->sockfd, data, datalen, 0);
+    }
+}
+
+void esp_tls_conn_delete(struct esp_tls *tls);
+
+#endif /* ! _ESP_TLS_H_ */