esp_ds.c
1 // Copyright 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 #include <stdlib.h> 16 #include <string.h> 17 #include <assert.h> 18 19 #include "esp32s2/rom/aes.h" 20 #include "esp32s2/rom/sha.h" 21 #include "esp32s2/rom/hmac.h" 22 #include "esp32s2/rom/digital_signature.h" 23 24 #include "freertos/FreeRTOS.h" 25 #include "freertos/task.h" 26 #include "soc/soc_memory_layout.h" 27 #include "esp_crypto_lock.h" 28 #include "esp_hmac.h" 29 30 #include "esp_ds.h" 31 32 struct esp_ds_context { 33 const ets_ds_data_t *data; 34 }; 35 36 /** 37 * The vtask delay \c esp_ds_sign() is using while waiting for completion of the signing operation. 38 */ 39 #define ESP_DS_SIGN_TASK_DELAY_MS 10 40 41 #define RSA_LEN_MAX 127 42 43 /* 44 * Check that the size of esp_ds_data_t and ets_ds_data_t is the same because both structs are converted using 45 * raw casts. 46 */ 47 _Static_assert(sizeof(esp_ds_data_t) == sizeof(ets_ds_data_t), 48 "The size and structure of esp_ds_data_t and ets_ds_data_t must match exactly, they're used in raw casts"); 49 50 /* 51 * esp_digital_signature_length_t is used in esp_ds_data_t in contrast to ets_ds_data_t, where unsigned is used. 52 * Check esp_digital_signature_length_t's width here because it's converted to unsigned using raw casts. 53 */ 54 _Static_assert(sizeof(esp_digital_signature_length_t) == sizeof(unsigned), 55 "The size of esp_digital_signature_length_t and unsigned has to be the same"); 56 57 static void ds_acquire_enable(void) { 58 /* Lock AES, SHA and RSA peripheral */ 59 esp_crypto_dma_lock_acquire(); 60 esp_crypto_mpi_lock_acquire(); 61 ets_hmac_enable(); 62 ets_ds_enable(); 63 } 64 65 static void ds_disable_release(void) { 66 ets_ds_disable(); 67 ets_hmac_disable(); 68 esp_crypto_mpi_lock_release(); 69 esp_crypto_dma_lock_release(); 70 } 71 72 esp_err_t esp_ds_sign(const void *message, 73 const esp_ds_data_t *data, 74 hmac_key_id_t key_id, 75 void *signature) 76 { 77 // Need to check signature here, otherwise the signature is only checked when the signing has finished and fails 78 // but the signing isn't uninitialized and the mutex is still locked. 79 if (!signature) return ESP_ERR_INVALID_ARG; 80 81 esp_ds_context_t *context; 82 esp_err_t result = esp_ds_start_sign(message, data, key_id, &context); 83 if (result != ESP_OK) return result; 84 85 while (esp_ds_is_busy()) 86 vTaskDelay(ESP_DS_SIGN_TASK_DELAY_MS / portTICK_PERIOD_MS); 87 88 return esp_ds_finish_sign(signature, context); 89 } 90 91 esp_err_t esp_ds_start_sign(const void *message, 92 const esp_ds_data_t *data, 93 hmac_key_id_t key_id, 94 esp_ds_context_t **esp_ds_ctx) 95 { 96 if (!message || !data || !esp_ds_ctx) return ESP_ERR_INVALID_ARG; 97 if (key_id >= HMAC_KEY_MAX) return ESP_ERR_INVALID_ARG; 98 if (!(data->rsa_length == ESP_DS_RSA_1024 99 || data->rsa_length == ESP_DS_RSA_2048 100 || data->rsa_length == ESP_DS_RSA_3072 101 || data->rsa_length == ESP_DS_RSA_4096)) { 102 return ESP_ERR_INVALID_ARG; 103 } 104 105 ds_acquire_enable(); 106 107 // initiate hmac 108 int r = ets_hmac_calculate_downstream(ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id, 109 ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE); 110 if (r != ETS_OK) { 111 ds_disable_release(); 112 return ESP_ERR_HW_CRYPTO_DS_HMAC_FAIL; 113 } 114 115 esp_ds_context_t *context = malloc(sizeof(esp_ds_context_t)); 116 if (!context) { 117 ds_disable_release(); 118 return ESP_ERR_NO_MEM; 119 } 120 121 ets_ds_data_t *ds_data = (ets_ds_data_t*) data; 122 123 // initiate signing 124 ets_ds_result_t result = ets_ds_start_sign(message, ds_data); 125 126 // ETS_DS_INVALID_PARAM only happens if a parameter is NULL or data->rsa_length is wrong 127 // We checked all of that already 128 assert(result != ETS_DS_INVALID_PARAM); 129 130 if (result == ETS_DS_INVALID_KEY) { 131 ds_disable_release(); 132 return ESP_ERR_HW_CRYPTO_DS_INVALID_KEY; 133 } 134 135 context->data = ds_data; 136 *esp_ds_ctx = context; 137 138 return ESP_OK; 139 } 140 141 bool esp_ds_is_busy(void) 142 { 143 return ets_ds_is_busy(); 144 } 145 146 esp_err_t esp_ds_finish_sign(void *signature, esp_ds_context_t *esp_ds_ctx) 147 { 148 if (!signature || !esp_ds_ctx) return ESP_ERR_INVALID_ARG; 149 150 const ets_ds_data_t *ds_data = esp_ds_ctx->data; 151 152 ets_ds_result_t result = ets_ds_finish_sign(signature, ds_data); 153 154 esp_err_t return_value = ESP_OK; 155 156 // we checked all the parameters 157 assert(result != ETS_DS_INVALID_PARAM); 158 159 if (result == ETS_DS_INVALID_DIGEST) return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_DIGEST; 160 if (result == ETS_DS_INVALID_PADDING) return_value = ESP_ERR_HW_CRYPTO_DS_INVALID_PADDING; 161 162 free(esp_ds_ctx); 163 164 // should not fail if called with correct purpose 165 assert(ets_hmac_invalidate_downstream(ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_DIGITAL_SIGNATURE) == ETS_OK); 166 167 ds_disable_release(); 168 169 return return_value; 170 } 171 172 esp_err_t esp_ds_encrypt_params(esp_ds_data_t *data, 173 const void *iv, 174 const esp_ds_p_data_t *p_data, 175 const void *key) 176 { 177 // p_data has to be valid, in internal memory and word aligned 178 if (!p_data) return ESP_ERR_INVALID_ARG; 179 assert(esp_ptr_internal(p_data) && esp_ptr_word_aligned(p_data)); 180 181 esp_err_t result = ESP_OK; 182 183 esp_crypto_dma_lock_acquire(); 184 ets_aes_enable(); 185 ets_sha_enable(); 186 187 ets_ds_data_t *ds_data = (ets_ds_data_t*) data; 188 const ets_ds_p_data_t *ds_plain_data = (const ets_ds_p_data_t*) p_data; 189 190 ets_ds_result_t ets_result = ets_ds_encrypt_params(ds_data, iv, ds_plain_data, key, ETS_DS_KEY_HMAC); 191 192 if (ets_result == ETS_DS_INVALID_PARAM) result = ESP_ERR_INVALID_ARG; 193 194 ets_sha_disable(); 195 ets_aes_disable(); 196 esp_crypto_dma_lock_release(); 197 198 return result; 199 }