1 /*
2  * SPDX-FileCopyrightText: 2017-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <esp_https_ota.h>
11 #include <esp_log.h>
12 #include <esp_ota_ops.h>
13 #include <errno.h>
14 #include <sys/param.h>
15 
16 #define IMAGE_HEADER_SIZE sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t) + 1
17 #define DEFAULT_OTA_BUF_SIZE IMAGE_HEADER_SIZE
18 #define DEFAULT_REQUEST_SIZE (64 * 1024)
19 static const char *TAG = "esp_https_ota";
20 
21 typedef enum {
22     ESP_HTTPS_OTA_INIT,
23     ESP_HTTPS_OTA_BEGIN,
24     ESP_HTTPS_OTA_IN_PROGRESS,
25     ESP_HTTPS_OTA_SUCCESS,
26 } esp_https_ota_state;
27 
28 struct esp_https_ota_handle {
29     esp_ota_handle_t update_handle;
30     const esp_partition_t *update_partition;
31     esp_http_client_handle_t http_client;
32     char *ota_upgrade_buf;
33     size_t ota_upgrade_buf_size;
34     int binary_file_len;
35     int image_length;
36     int max_http_request_size;
37     esp_https_ota_state state;
38     bool bulk_flash_erase;
39     bool partial_http_download;
40 };
41 
42 typedef struct esp_https_ota_handle esp_https_ota_t;
43 
process_again(int status_code)44 static bool process_again(int status_code)
45 {
46     switch (status_code) {
47         case HttpStatus_MovedPermanently:
48         case HttpStatus_Found:
49         case HttpStatus_TemporaryRedirect:
50         case HttpStatus_Unauthorized:
51             return true;
52         default:
53             return false;
54     }
55     return false;
56 }
57 
_http_handle_response_code(esp_http_client_handle_t http_client,int status_code)58 static esp_err_t _http_handle_response_code(esp_http_client_handle_t http_client, int status_code)
59 {
60     esp_err_t err;
61     if (status_code == HttpStatus_MovedPermanently || status_code == HttpStatus_Found || status_code == HttpStatus_TemporaryRedirect) {
62         err = esp_http_client_set_redirection(http_client);
63         if (err != ESP_OK) {
64             ESP_LOGE(TAG, "URL redirection Failed");
65             return err;
66         }
67     } else if (status_code == HttpStatus_Unauthorized) {
68         esp_http_client_add_auth(http_client);
69     } else if(status_code == HttpStatus_NotFound || status_code == HttpStatus_Forbidden) {
70         ESP_LOGE(TAG, "File not found(%d)", status_code);
71         return ESP_FAIL;
72     } else if (status_code >= HttpStatus_BadRequest && status_code < HttpStatus_InternalError) {
73         ESP_LOGE(TAG, "Client error (%d)", status_code);
74         return ESP_FAIL;
75     } else if (status_code >= HttpStatus_InternalError) {
76         ESP_LOGE(TAG, "Server error (%d)", status_code);
77         return ESP_FAIL;
78     }
79 
80     char upgrade_data_buf[DEFAULT_OTA_BUF_SIZE];
81     // process_again() returns true only in case of redirection.
82     if (process_again(status_code)) {
83         while (1) {
84             /*
85              *  In case of redirection, esp_http_client_read() is called
86              *  to clear the response buffer of http_client.
87              */
88             int data_read = esp_http_client_read(http_client, upgrade_data_buf, DEFAULT_OTA_BUF_SIZE);
89             if (data_read <= 0) {
90                 return ESP_OK;
91             }
92         }
93     }
94     return ESP_OK;
95 }
96 
_http_connect(esp_http_client_handle_t http_client)97 static esp_err_t _http_connect(esp_http_client_handle_t http_client)
98 {
99     esp_err_t err = ESP_FAIL;
100     int status_code, header_ret;
101     do {
102         char *post_data = NULL;
103         /* Send POST request if body is set.
104          * Note: Sending POST request is not supported if partial_http_download
105          * is enabled
106          */
107         int post_len = esp_http_client_get_post_field(http_client, &post_data);
108         err = esp_http_client_open(http_client, post_len);
109         if (err != ESP_OK) {
110             ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
111             return err;
112         }
113         if (post_len) {
114             int write_len = 0;
115             while (post_len > 0) {
116                 write_len = esp_http_client_write(http_client, post_data, post_len);
117                 if (write_len < 0) {
118                     ESP_LOGE(TAG, "Write failed");
119                     return ESP_FAIL;
120                 }
121                 post_len -= write_len;
122                 post_data += write_len;
123             }
124         }
125         header_ret = esp_http_client_fetch_headers(http_client);
126         if (header_ret < 0) {
127             return header_ret;
128         }
129         status_code = esp_http_client_get_status_code(http_client);
130         err = _http_handle_response_code(http_client, status_code);
131         if (err != ESP_OK) {
132             return err;
133         }
134     } while (process_again(status_code));
135     return err;
136 }
137 
_http_cleanup(esp_http_client_handle_t client)138 static void _http_cleanup(esp_http_client_handle_t client)
139 {
140     esp_http_client_close(client);
141     esp_http_client_cleanup(client);
142 }
143 
_ota_write(esp_https_ota_t * https_ota_handle,const void * buffer,size_t buf_len)144 static esp_err_t _ota_write(esp_https_ota_t *https_ota_handle, const void *buffer, size_t buf_len)
145 {
146     if (buffer == NULL || https_ota_handle == NULL) {
147         return ESP_FAIL;
148     }
149     esp_err_t err = esp_ota_write(https_ota_handle->update_handle, buffer, buf_len);
150     if (err != ESP_OK) {
151         ESP_LOGE(TAG, "Error: esp_ota_write failed! err=0x%x", err);
152     } else {
153         https_ota_handle->binary_file_len += buf_len;
154         ESP_LOGD(TAG, "Written image length %d", https_ota_handle->binary_file_len);
155         err = ESP_ERR_HTTPS_OTA_IN_PROGRESS;
156     }
157     return err;
158 }
159 
is_server_verification_enabled(esp_https_ota_config_t * ota_config)160 static bool is_server_verification_enabled(esp_https_ota_config_t *ota_config) {
161     return  (ota_config->http_config->cert_pem
162             || ota_config->http_config->use_global_ca_store
163             || ota_config->http_config->crt_bundle_attach != NULL);
164 }
165 
esp_https_ota_begin(esp_https_ota_config_t * ota_config,esp_https_ota_handle_t * handle)166 esp_err_t esp_https_ota_begin(esp_https_ota_config_t *ota_config, esp_https_ota_handle_t *handle)
167 {
168     esp_err_t err;
169 
170     if (handle == NULL || ota_config == NULL || ota_config->http_config == NULL) {
171         ESP_LOGE(TAG, "esp_https_ota_begin: Invalid argument");
172         if (handle) {
173             *handle = NULL;
174         }
175         return ESP_ERR_INVALID_ARG;
176     }
177 
178     if (!is_server_verification_enabled(ota_config)) {
179 #if CONFIG_OTA_ALLOW_HTTP
180         ESP_LOGW(TAG, "Continuing with insecure option because CONFIG_OTA_ALLOW_HTTP is set.");
181 #else
182         ESP_LOGE(TAG, "No option for server verification is enabled in esp_http_client config.");
183         *handle = NULL;
184         return ESP_ERR_INVALID_ARG;
185 #endif
186     }
187 
188     esp_https_ota_t *https_ota_handle = calloc(1, sizeof(esp_https_ota_t));
189     if (!https_ota_handle) {
190         ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
191         *handle = NULL;
192         return ESP_ERR_NO_MEM;
193     }
194 
195     https_ota_handle->partial_http_download = ota_config->partial_http_download;
196     https_ota_handle->max_http_request_size = (ota_config->max_http_request_size == 0) ? DEFAULT_REQUEST_SIZE : ota_config->max_http_request_size;
197 
198     /* Initiate HTTP Connection */
199     https_ota_handle->http_client = esp_http_client_init(ota_config->http_config);
200     if (https_ota_handle->http_client == NULL) {
201         ESP_LOGE(TAG, "Failed to initialise HTTP connection");
202         err = ESP_FAIL;
203         goto failure;
204     }
205 
206     if (https_ota_handle->partial_http_download) {
207         esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_HEAD);
208         err = esp_http_client_perform(https_ota_handle->http_client);
209         if (err == ESP_OK) {
210             int status = esp_http_client_get_status_code(https_ota_handle->http_client);
211             if (status != HttpStatus_Ok) {
212                 ESP_LOGE(TAG, "Received incorrect http status %d", status);
213                 err = ESP_FAIL;
214                 goto http_cleanup;
215             }
216         } else {
217             ESP_LOGE(TAG, "ESP HTTP client perform failed: %d", err);
218             goto http_cleanup;
219         }
220 
221         https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
222         esp_http_client_close(https_ota_handle->http_client);
223 
224         if (https_ota_handle->image_length > https_ota_handle->max_http_request_size) {
225             char *header_val = NULL;
226             asprintf(&header_val, "bytes=0-%d", https_ota_handle->max_http_request_size - 1);
227             if (header_val == NULL) {
228                 ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
229                 err = ESP_ERR_NO_MEM;
230                 goto http_cleanup;
231             }
232             esp_http_client_set_header(https_ota_handle->http_client, "Range", header_val);
233             free(header_val);
234         }
235         esp_http_client_set_method(https_ota_handle->http_client, HTTP_METHOD_GET);
236     }
237 
238     if (ota_config->http_client_init_cb) {
239         err = ota_config->http_client_init_cb(https_ota_handle->http_client);
240         if (err != ESP_OK) {
241             ESP_LOGE(TAG, "http_client_init_cb returned 0x%x", err);
242             goto http_cleanup;
243         }
244     }
245 
246     err = _http_connect(https_ota_handle->http_client);
247     if (err != ESP_OK) {
248         ESP_LOGE(TAG, "Failed to establish HTTP connection");
249         goto http_cleanup;
250     }
251 
252     if (!https_ota_handle->partial_http_download) {
253         https_ota_handle->image_length = esp_http_client_get_content_length(https_ota_handle->http_client);
254     }
255 
256     https_ota_handle->update_partition = NULL;
257     ESP_LOGI(TAG, "Starting OTA...");
258     https_ota_handle->update_partition = esp_ota_get_next_update_partition(NULL);
259     if (https_ota_handle->update_partition == NULL) {
260         ESP_LOGE(TAG, "Passive OTA partition not found");
261         err = ESP_FAIL;
262         goto http_cleanup;
263     }
264     ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
265         https_ota_handle->update_partition->subtype, https_ota_handle->update_partition->address);
266 
267     const int alloc_size = MAX(ota_config->http_config->buffer_size, DEFAULT_OTA_BUF_SIZE);
268     https_ota_handle->ota_upgrade_buf = (char *)malloc(alloc_size);
269     if (!https_ota_handle->ota_upgrade_buf) {
270         ESP_LOGE(TAG, "Couldn't allocate memory to upgrade data buffer");
271         err = ESP_ERR_NO_MEM;
272         goto http_cleanup;
273     }
274     https_ota_handle->ota_upgrade_buf_size = alloc_size;
275     https_ota_handle->bulk_flash_erase = ota_config->bulk_flash_erase;
276     https_ota_handle->binary_file_len = 0;
277     *handle = (esp_https_ota_handle_t)https_ota_handle;
278     https_ota_handle->state = ESP_HTTPS_OTA_BEGIN;
279     return ESP_OK;
280 
281 http_cleanup:
282     _http_cleanup(https_ota_handle->http_client);
283 failure:
284     free(https_ota_handle);
285     *handle = NULL;
286     return err;
287 }
288 
read_header(esp_https_ota_t * handle)289 static esp_err_t read_header(esp_https_ota_t *handle)
290 {
291     /*
292      * `data_read_size` holds number of bytes needed to read complete header.
293      * `bytes_read` holds number of bytes read.
294      */
295     int data_read_size = IMAGE_HEADER_SIZE;
296     int data_read = 0, bytes_read = 0;
297     /*
298      * while loop is added to download complete image headers, even if the headers
299      * are not sent in a single packet.
300      */
301     while (data_read_size > 0 && !esp_http_client_is_complete_data_received(handle->http_client)) {
302         data_read = esp_http_client_read(handle->http_client,
303                                           (handle->ota_upgrade_buf + bytes_read),
304                                           data_read_size);
305         /*
306          * As esp_http_client_read doesn't return negative error code if select fails, we rely on
307          * `errno` to check for underlying transport connectivity closure if any
308          */
309         if (errno == ENOTCONN || errno == ECONNRESET || errno == ECONNABORTED || data_read < 0) {
310             ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
311             break;
312         }
313         data_read_size -= data_read;
314         bytes_read += data_read;
315     }
316     if (data_read_size > 0) {
317         ESP_LOGE(TAG, "Complete headers were not received");
318         return ESP_FAIL;
319     }
320     handle->binary_file_len = bytes_read;
321     return ESP_OK;
322 }
323 
esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle,esp_app_desc_t * new_app_info)324 esp_err_t esp_https_ota_get_img_desc(esp_https_ota_handle_t https_ota_handle, esp_app_desc_t *new_app_info)
325 {
326     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
327     if (handle == NULL || new_app_info == NULL)  {
328         ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid argument");
329         return ESP_ERR_INVALID_ARG;
330     }
331     if (handle->state < ESP_HTTPS_OTA_BEGIN) {
332         ESP_LOGE(TAG, "esp_https_ota_read_img_desc: Invalid state");
333         return ESP_FAIL;
334     }
335     if (read_header(handle) != ESP_OK) {
336         return ESP_FAIL;
337     }
338     memcpy(new_app_info, &handle->ota_upgrade_buf[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
339     return ESP_OK;
340 }
341 
esp_ota_verify_chip_id(void * arg)342 static esp_err_t esp_ota_verify_chip_id(void *arg)
343 {
344     esp_image_header_t *data = (esp_image_header_t*)(arg);
345     if (data->chip_id != CONFIG_IDF_FIRMWARE_CHIP_ID) {
346         ESP_LOGE(TAG, "Mismatch chip id, expected %d, found %d", CONFIG_IDF_FIRMWARE_CHIP_ID, data->chip_id);
347         return ESP_ERR_INVALID_VERSION;
348     }
349     return ESP_OK;
350 }
351 
esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)352 esp_err_t esp_https_ota_perform(esp_https_ota_handle_t https_ota_handle)
353 {
354     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
355     if (handle == NULL) {
356         ESP_LOGE(TAG, "esp_https_ota_perform: Invalid argument");
357         return ESP_ERR_INVALID_ARG;
358     }
359     if (handle->state < ESP_HTTPS_OTA_BEGIN) {
360         ESP_LOGE(TAG, "esp_https_ota_perform: Invalid state");
361         return ESP_FAIL;
362     }
363 
364     esp_err_t err;
365     int data_read;
366     const int erase_size = handle->bulk_flash_erase ? OTA_SIZE_UNKNOWN : OTA_WITH_SEQUENTIAL_WRITES;
367     switch (handle->state) {
368         case ESP_HTTPS_OTA_BEGIN:
369             err = esp_ota_begin(handle->update_partition, erase_size, &handle->update_handle);
370             if (err != ESP_OK) {
371                 ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
372                 return err;
373             }
374             handle->state = ESP_HTTPS_OTA_IN_PROGRESS;
375             /* In case `esp_https_ota_read_img_desc` was invoked first,
376                then the image data read there should be written to OTA partition
377                */
378             int binary_file_len = 0;
379             if (handle->binary_file_len) {
380                 /*
381                  * Header length gets added to handle->binary_file_len in _ota_write
382                  * Clear handle->binary_file_len to avoid additional 289 bytes in binary_file_len
383                  */
384                 binary_file_len = handle->binary_file_len;
385                 handle->binary_file_len = 0;
386             } else {
387                 if (read_header(handle) != ESP_OK) {
388                     return ESP_FAIL;
389                 }
390                 binary_file_len = IMAGE_HEADER_SIZE;
391             }
392             err = esp_ota_verify_chip_id(handle->ota_upgrade_buf);
393             if (err != ESP_OK) {
394                 return err;
395             }
396             return _ota_write(handle, (const void *)handle->ota_upgrade_buf, binary_file_len);
397         case ESP_HTTPS_OTA_IN_PROGRESS:
398             data_read = esp_http_client_read(handle->http_client,
399                                              handle->ota_upgrade_buf,
400                                              handle->ota_upgrade_buf_size);
401             if (data_read == 0) {
402                 /*
403                  *  esp_http_client_is_complete_data_received is added to check whether
404                  *  complete image is received.
405                  */
406                 bool is_recv_complete = esp_http_client_is_complete_data_received(handle->http_client);
407                 /*
408                  * As esp_http_client_read doesn't return negative error code if select fails, we rely on
409                  * `errno` to check for underlying transport connectivity closure if any.
410                  * Incase the complete data has not been received but the server has sent
411                  * an ENOTCONN or ECONNRESET, failure is returned. We close with success
412                  * if complete data has been received.
413                  */
414                 if ((errno == ENOTCONN || errno == ECONNRESET || errno == ECONNABORTED) && !is_recv_complete) {
415                     ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
416                     return ESP_FAIL;
417                 } else if (!is_recv_complete) {
418                     return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
419                 }
420                 ESP_LOGD(TAG, "Connection closed");
421             } else if (data_read > 0) {
422                 return _ota_write(handle, (const void *)handle->ota_upgrade_buf, data_read);
423             } else {
424                 ESP_LOGE(TAG, "data read %d, errno %d", data_read, errno);
425                 return ESP_FAIL;
426             }
427             if (!handle->partial_http_download || (handle->partial_http_download && handle->image_length == handle->binary_file_len)) {
428                 handle->state = ESP_HTTPS_OTA_SUCCESS;
429             }
430             break;
431          default:
432             ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
433             return ESP_FAIL;
434             break;
435     }
436     if (handle->partial_http_download) {
437         if (handle->state == ESP_HTTPS_OTA_IN_PROGRESS && handle->image_length > handle->binary_file_len) {
438             esp_http_client_close(handle->http_client);
439             char *header_val = NULL;
440             if ((handle->image_length - handle->binary_file_len) > handle->max_http_request_size) {
441                 asprintf(&header_val, "bytes=%d-%d", handle->binary_file_len, (handle->binary_file_len + handle->max_http_request_size - 1));
442             } else {
443                 asprintf(&header_val, "bytes=%d-", handle->binary_file_len);
444             }
445             if (header_val == NULL) {
446                 ESP_LOGE(TAG, "Failed to allocate memory for HTTP header");
447                 return ESP_ERR_NO_MEM;
448             }
449             esp_http_client_set_header(handle->http_client, "Range", header_val);
450             free(header_val);
451             err = _http_connect(handle->http_client);
452             if (err != ESP_OK) {
453                 ESP_LOGE(TAG, "Failed to establish HTTP connection");
454                 return ESP_FAIL;
455             }
456             ESP_LOGD(TAG, "Connection start");
457             return ESP_ERR_HTTPS_OTA_IN_PROGRESS;
458         }
459     }
460     return ESP_OK;
461 }
462 
esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)463 bool esp_https_ota_is_complete_data_received(esp_https_ota_handle_t https_ota_handle)
464 {
465     bool ret = false;
466     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
467     if (handle->partial_http_download) {
468         ret = (handle->image_length == handle->binary_file_len);
469     } else {
470         ret = esp_http_client_is_complete_data_received(handle->http_client);
471     }
472     return ret;
473 }
474 
esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)475 esp_err_t esp_https_ota_finish(esp_https_ota_handle_t https_ota_handle)
476 {
477     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
478     if (handle == NULL) {
479         return ESP_ERR_INVALID_ARG;
480     }
481     if (handle->state < ESP_HTTPS_OTA_BEGIN) {
482         return ESP_FAIL;
483     }
484 
485     esp_err_t err = ESP_OK;
486     switch (handle->state) {
487         case ESP_HTTPS_OTA_SUCCESS:
488         case ESP_HTTPS_OTA_IN_PROGRESS:
489             err = esp_ota_end(handle->update_handle);
490             /* falls through */
491         case ESP_HTTPS_OTA_BEGIN:
492             if (handle->ota_upgrade_buf) {
493                 free(handle->ota_upgrade_buf);
494             }
495             if (handle->http_client) {
496                 _http_cleanup(handle->http_client);
497             }
498             break;
499         default:
500             ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
501             break;
502     }
503 
504     if ((err == ESP_OK) && (handle->state == ESP_HTTPS_OTA_SUCCESS)) {
505         esp_err_t err = esp_ota_set_boot_partition(handle->update_partition);
506         if (err != ESP_OK) {
507             ESP_LOGE(TAG, "esp_ota_set_boot_partition failed! err=0x%x", err);
508         }
509     }
510     free(handle);
511     return err;
512 }
513 
esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle)514 esp_err_t esp_https_ota_abort(esp_https_ota_handle_t https_ota_handle)
515 {
516     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
517     if (handle == NULL) {
518         return ESP_ERR_INVALID_ARG;
519     }
520 
521     if (handle->state < ESP_HTTPS_OTA_BEGIN) {
522         return ESP_FAIL;
523     }
524 
525     esp_err_t err = ESP_OK;
526     switch (handle->state) {
527         case ESP_HTTPS_OTA_SUCCESS:
528         case ESP_HTTPS_OTA_IN_PROGRESS:
529             err = esp_ota_abort(handle->update_handle);
530             /* falls through */
531         case ESP_HTTPS_OTA_BEGIN:
532             if (handle->ota_upgrade_buf) {
533                 free(handle->ota_upgrade_buf);
534             }
535             if (handle->http_client) {
536                 _http_cleanup(handle->http_client);
537             }
538             break;
539         default:
540             err = ESP_ERR_INVALID_STATE;
541             ESP_LOGE(TAG, "Invalid ESP HTTPS OTA State");
542             break;
543     }
544     free(handle);
545     return err;
546 }
547 
esp_https_ota_get_image_len_read(esp_https_ota_handle_t https_ota_handle)548 int esp_https_ota_get_image_len_read(esp_https_ota_handle_t https_ota_handle)
549 {
550     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
551     if (handle == NULL) {
552         return -1;
553     }
554     if (handle->state < ESP_HTTPS_OTA_IN_PROGRESS) {
555         return -1;
556     }
557     return handle->binary_file_len;
558 }
559 
esp_https_ota_get_image_size(esp_https_ota_handle_t https_ota_handle)560 int esp_https_ota_get_image_size(esp_https_ota_handle_t https_ota_handle)
561 {
562     esp_https_ota_t *handle = (esp_https_ota_t *)https_ota_handle;
563     if (handle == NULL) {
564         return -1;
565     }
566     if (handle->state < ESP_HTTPS_OTA_BEGIN) {
567         return -1;
568     }
569     return handle->image_length;
570 }
571 
esp_https_ota(const esp_http_client_config_t * config)572 esp_err_t esp_https_ota(const esp_http_client_config_t *config)
573 {
574     if (!config) {
575         ESP_LOGE(TAG, "esp_http_client config not found");
576         return ESP_ERR_INVALID_ARG;
577     }
578 
579     esp_https_ota_config_t ota_config = {
580         .http_config = config,
581     };
582 
583     esp_https_ota_handle_t https_ota_handle = NULL;
584     esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
585     if (https_ota_handle == NULL) {
586         return ESP_FAIL;
587     }
588 
589     while (1) {
590         err = esp_https_ota_perform(https_ota_handle);
591         if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
592             break;
593         }
594     }
595 
596     if (err != ESP_OK) {
597         esp_https_ota_abort(https_ota_handle);
598         return err;
599     }
600 
601     esp_err_t ota_finish_err = esp_https_ota_finish(https_ota_handle);
602     if (ota_finish_err != ESP_OK) {
603         return ota_finish_err;
604     }
605     return ESP_OK;
606 }
607