]> granicus.if.org Git - esp-idf/commitdiff
Feature: Support for global CA store.
authorChirag Atal <chirag.atal@espressif.com>
Thu, 4 Oct 2018 10:35:02 +0000 (16:05 +0530)
committerChirag Atal <chirag.atal@espressif.com>
Fri, 5 Oct 2018 14:05:57 +0000 (19:35 +0530)
Added a new API esp_tls_set_global_ca_store(esp_tls_cfg_t *cfg) which creates a global_cacert which can be used by multiple connections by setting the use_global_ca_store variable to true in their respective structure of esp_tls_cfg_t. Also changed the cacert in the structure of esp_tls_t to a pointer.

components/esp-tls/esp_tls.c
components/esp-tls/esp_tls.h

index 3ead8ef2e5e361184068d8b3547298d618209a4b..2cd7a447179ac4d84ca57a42a667f524141167e2 100644 (file)
@@ -25,6 +25,7 @@
 #include <errno.h>
 
 static const char *TAG = "esp-tls";
+static mbedtls_x509_crt *global_cacert = NULL;
 
 #ifdef ESP_PLATFORM
 #include <esp_log.h>
@@ -140,6 +141,46 @@ err_freeaddr:
     return ret;
 }
 
+esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes)
+{
+    if (cacert_pem_buf == NULL) {
+        ESP_LOGE(TAG, "cacert_pem_buf is null");
+        return ESP_ERR_INVALID_ARG;
+    }
+    if (global_cacert != NULL) {
+        mbedtls_x509_crt_free(global_cacert);
+    }
+    global_cacert = (mbedtls_x509_crt *)calloc(1, sizeof(mbedtls_x509_crt));
+    if (global_cacert == NULL) {
+        ESP_LOGE(TAG, "global_cacert not allocated");
+        return ESP_ERR_NO_MEM;
+    }
+    mbedtls_x509_crt_init(global_cacert);
+    int ret = mbedtls_x509_crt_parse(global_cacert, cacert_pem_buf, cacert_pem_bytes);
+    if (ret < 0) {
+        ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
+        mbedtls_x509_crt_free(global_cacert);
+        global_cacert = NULL;
+        return ESP_FAIL;
+    } else if (ret > 0) {
+        ESP_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d", ret);
+    }
+    return ESP_OK;
+}
+
+mbedtls_x509_crt *esp_tls_get_global_ca_store()
+{
+    return global_cacert;
+}
+
+void esp_tls_free_global_ca_store()
+{
+    if (global_cacert) {
+        mbedtls_x509_crt_free(global_cacert);
+        global_cacert = NULL;
+    }
+}
+
 static void verify_certificate(esp_tls_t *tls)
 {
     int flags;
@@ -159,7 +200,10 @@ static void mbedtls_cleanup(esp_tls_t *tls)
     if (!tls) {
         return;
     }
-    mbedtls_x509_crt_free(&tls->cacert);
+    if (tls->cacert_ptr != global_cacert) {
+        mbedtls_x509_crt_free(tls->cacert_ptr);
+    }
+    tls->cacert_ptr = NULL;
     mbedtls_entropy_free(&tls->entropy);
     mbedtls_ssl_config_free(&tls->conf);
     mbedtls_ctr_drbg_free(&tls->ctr_drbg);
@@ -209,15 +253,24 @@ static int create_ssl_handle(esp_tls_t *tls, const char *hostname, size_t hostle
         mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos);
     }
 
-    if (cfg->cacert_pem_buf != NULL) {
-        mbedtls_x509_crt_init(&tls->cacert);
-        ret = mbedtls_x509_crt_parse(&tls->cacert, cfg->cacert_pem_buf, cfg->cacert_pem_bytes);
+    if (cfg->use_global_ca_store == true) {
+        if (global_cacert == NULL) {
+            ESP_LOGE(TAG, "global_cacert is NULL");
+            goto exit;
+        }
+        tls->cacert_ptr = global_cacert;
+        mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
+        mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
+    } else if (cfg->cacert_pem_buf != NULL) {
+        tls->cacert_ptr = &tls->cacert;
+        mbedtls_x509_crt_init(tls->cacert_ptr);
+        ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cfg->cacert_pem_buf, cfg->cacert_pem_bytes);
         if (ret < 0) {
             ESP_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%x\n\n", -ret);
             goto exit;
         }
         mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
-        mbedtls_ssl_conf_ca_chain(&tls->conf, &tls->cacert, NULL);
+        mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
     } else {
         mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
     }
@@ -344,7 +397,7 @@ static int esp_tls_low_level_conn(const char *hostname, int hostlen, int port, c
             } else {
                 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
                     ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
-                    if (cfg->cacert_pem_buf != NULL) {
+                    if (cfg->cacert_pem_buf != NULL || cfg->use_global_ca_store == true) {
                         /* This is to check whether handshake failed due to invalid certificate*/
                         verify_certificate(tls);
                     }
index f6a4a7c509463b63b7ae03cd6294c0dd6ff6f963..eaa03531224590174209400f5671cfafd8ef1ae1 100644 (file)
@@ -66,6 +66,9 @@ typedef struct esp_tls_cfg {
                                                  blocking mode after tls session is established */
 
     int timeout_ms;                         /*!< Network timeout in milliseconds */
+
+    bool use_global_ca_store;               /*!< Use a global ca_store for all the connections in which
+                                                 this bool is set. */
 } esp_tls_cfg_t;
 
 /**
@@ -88,6 +91,8 @@ typedef struct esp_tls {
  
     mbedtls_x509_crt cacert;                                                    /*!< Container for an X.509 certificate */
  
+    mbedtls_x509_crt *cacert_ptr;                                               /*!< Pointer to the cacert being used. */
+
     int sockfd;                                                                 /*!< Underlying socket file descriptor. */
  
     ssize_t (*read)(struct esp_tls  *tls, char *data, size_t datalen);          /*!< Callback function for reading data from TLS/SSL
@@ -232,6 +237,45 @@ void esp_tls_conn_delete(esp_tls_t *tls);
  */
 size_t esp_tls_get_bytes_avail(esp_tls_t *tls);
 
+/**
+ * @brief      Create a global CA store with the buffer provided in cfg.
+ *
+ * This function should be called if the application wants to use the same CA store for
+ * multiple connections. The application must call this function before calling esp_tls_conn_new().
+ *
+ * @param[in]  cacert_pem_buf    Buffer which has certificates in pem format. This buffer
+ *                               is used for creating a global CA store, which can be used
+ *                               by other tls connections.
+ * @param[in]  cacert_pem_bytes  Length of the buffer.
+ *
+ * @return
+ *             - ESP_OK  if creating global CA store was successful.
+ *             - Other   if an error occured or an action must be taken by the calling process.
+ */
+esp_err_t esp_tls_set_global_ca_store(const unsigned char *cacert_pem_buf, const unsigned int cacert_pem_bytes);
+
+/**
+ * @brief      Get the pointer to the global CA store currently being used.
+ *
+ * The application must first call esp_tls_set_global_ca_store(). Then the same
+ * CA store could be used by the application for APIs other than esp_tls.
+ *
+ * @note       Modifying the pointer might cause a failure in verifying the certificates.
+ *
+ * @return
+ *             - Pointer to the global CA store currently being used    if successful.
+ *             - NULL                                                   if there is no global CA store set.
+ */
+mbedtls_x509_crt *esp_tls_get_global_ca_store();
+
+/**
+ * @brief      Free the global CA store currently being used.
+ *
+ * The memory being used by the global CA store to store all the parsed certificates is
+ * freed up. The application can call this API if it no longer needs the global CA store.
+ */
+void esp_tls_free_global_ca_store();
+
 
 #ifdef __cplusplus
 }