/ components / esp32s2 / esp_ds.c
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  }