1 // Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 /**
16  * @file
17  * @brief Checksum interface implemetation
18  *
19  * This file is an implementation for the coredump checksum interface defined
20  * in "core_dump_checksum.h".
21  * Please refer to this file for more information about the functions.
22  */
23 
24 #include <stddef.h>
25 #include "esp_core_dump_port_impl.h"
26 #include "esp_core_dump_types.h"
27 #include "core_dump_checksum.h"
28 #include "esp_attr.h"
29 
30 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
31 #include "esp_rom_crc.h"
32 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
33 #include "mbedtls/sha256.h"
34 #endif
35 
36 #if CONFIG_ESP_COREDUMP_ENABLE
37 
38 const static DRAM_ATTR char TAG[] __attribute__((unused)) = "esp_core_dump_checksum";
39 
40 #define COREDUMP_SHA256_LEN                 32
41 
42 typedef uint32_t core_dump_crc_t;
43 
44 struct core_dump_checksum_ctx {
45 #if CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
46     mbedtls_sha256_context  ctx;
47     uint8_t sha_output[COREDUMP_SHA256_LEN];
48 #elif CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
49     core_dump_crc_t crc;
50 #endif
51     /* Number of bytes used to calculate the checksum */
52     uint32_t total_bytes_checksum;
53 };
54 
55 static core_dump_checksum_ctx s_checksum_context = { 0 };
56 
57 /**
58  * Get ELF core dump version.
59  * Please check esp checksum interface for more details.
60  */
esp_core_dump_elf_version(void)61 uint32_t esp_core_dump_elf_version(void)
62 {
63 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
64     return COREDUMP_VERSION_ELF_CRC32;
65 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
66     return COREDUMP_VERSION_ELF_SHA256;
67 #endif
68 }
69 
esp_core_dump_checksum_init(core_dump_checksum_ctx ** out_ctx)70 void esp_core_dump_checksum_init(core_dump_checksum_ctx** out_ctx)
71 {
72     if (out_ctx) {
73 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
74         s_checksum_context.crc = 0;
75 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
76         mbedtls_sha256_init(&s_checksum_context.ctx);
77         (void)mbedtls_sha256_starts_ret(&s_checksum_context.ctx, 0);
78 #endif
79         s_checksum_context.total_bytes_checksum = 0;
80 
81         *out_ctx = &s_checksum_context;
82     }
83 }
84 
85 
esp_core_dump_checksum_update(core_dump_checksum_ctx * cks_ctx,void * data,size_t data_len)86 void esp_core_dump_checksum_update(core_dump_checksum_ctx* cks_ctx, void* data, size_t data_len)
87 {
88     ESP_COREDUMP_DEBUG_ASSERT(cks_ctx);
89 
90     if (data) {
91 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
92         cks_ctx->crc = esp_rom_crc32_le(cks_ctx->crc, data, data_len);
93 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
94 #if CONFIG_MBEDTLS_HARDWARE_SHA
95         // set software mode of SHA calculation
96         cks_ctx->ctx.mode = ESP_MBEDTLS_SHA256_SOFTWARE;
97 #endif
98         (void)mbedtls_sha256_update_ret(&cks_ctx->ctx, data, data_len);
99 #endif
100         // keep counter of cashed bytes
101         cks_ctx->total_bytes_checksum += data_len;
102     } else {
103         ESP_COREDUMP_LOGE("Empty data to add to checksum calculation!");
104     }
105 }
106 
107 
esp_core_dump_checksum_finish(core_dump_checksum_ctx * cks_ctx,core_dump_checksum_bytes * chs_ptr)108 uint32_t esp_core_dump_checksum_finish(core_dump_checksum_ctx* cks_ctx, core_dump_checksum_bytes* chs_ptr)
109 {
110     uint32_t chs_len = 0;
111 
112     /* cks_ctx pointer can be NULL only if chs_ptr is also NULL. */
113     ESP_COREDUMP_DEBUG_ASSERT(cks_ctx != NULL || chs_ptr == NULL);
114 
115 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
116     if (chs_ptr != NULL) {
117         *chs_ptr = (core_dump_checksum_bytes) &cks_ctx->crc;
118     }
119     chs_len = sizeof(cks_ctx->crc);
120 
121 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
122     if (chs_ptr != NULL) {
123         (void)mbedtls_sha256_finish_ret(&cks_ctx->ctx, (uint8_t*)&cks_ctx->sha_output);
124         *chs_ptr = &cks_ctx->sha_output[0];
125         mbedtls_sha256_free(&cks_ctx->ctx);
126     }
127     chs_len = sizeof(cks_ctx->sha_output);
128 
129 #endif
130 
131     if (cks_ctx) {
132         ESP_COREDUMP_LOG_PROCESS("Total length of hashed data: %d", cks_ctx->total_bytes_checksum);
133     }
134 
135     return chs_len;
136 }
137 
138 
139 /**
140  * Returns the size, in bytes, of the checksums.
141  * Currently, this function is just an alias to esp_core_dump_checksum_finish
142  * function, which can return the size of the checksum if given parameters
143  * are NULL. However, the implementation can evolve in the future independently
144  * from esp_core_dump_checksum_finish function.
145  */
esp_core_dump_checksum_size(void)146 uint32_t esp_core_dump_checksum_size(void)
147 {
148     return esp_core_dump_checksum_finish(NULL, NULL);
149 }
150 
151 
152 #if CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
153 
esp_core_dump_print_sha256(const char * msg,const uint8_t * sha_output)154 static void esp_core_dump_print_sha256(const char* msg, const uint8_t* sha_output)
155 {
156     /* As this function is only called by `esp_core_dump_print_checksum`, we
157      * have the guarantee that sha_output is not NULL. */
158     if (msg != NULL) {
159         esp_rom_printf(DRAM_STR("%s='"), msg);
160     }
161 
162     for (int i = 0; i < COREDUMP_SHA256_LEN; i++) {
163         esp_rom_printf(DRAM_STR("%02x"), sha_output[i]);
164     }
165     esp_rom_printf(DRAM_STR("'\r\n"));
166 }
167 
168 #endif
169 
170 
171 /**
172  * Prints a message and a checksum given as parameters.
173  * This function is useful when the caller isn't explicitly aware of which
174  * checksum type (CRC32, SHA256, etc) is being used.
175  */
esp_core_dump_print_checksum(const char * msg,core_dump_checksum_bytes checksum)176 void esp_core_dump_print_checksum(const char* msg, core_dump_checksum_bytes checksum)
177 {
178     ESP_COREDUMP_DEBUG_ASSERT(checksum != NULL);
179 
180 #if CONFIG_ESP_COREDUMP_CHECKSUM_CRC32
181     if (msg != NULL) {
182         esp_rom_printf(DRAM_STR("%s='"), msg);
183     }
184     esp_rom_printf(DRAM_STR("%08x"), *((const uint32_t*) checksum));
185     esp_rom_printf(DRAM_STR("'\r\n"));
186 #elif CONFIG_ESP_COREDUMP_CHECKSUM_SHA256
187     esp_core_dump_print_sha256(msg, (const uint8_t*) checksum);
188 #endif
189 }
190 
191 
192 #endif
193