Skip to content

Commit

Permalink
Merge branch 'fix/fix_tlv_get_addr_api' into 'main'
Browse files Browse the repository at this point in the history
esp_secure_cert_mgr: Updated the API documentation and release v2.4.1

See merge request app-frameworks/esp_secure_cert_mgr!54
  • Loading branch information
AdityaHPatwardhan committed Nov 21, 2023
2 parents 3f6bb56 + 48ced8b commit ff3a51e
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 92 deletions.
16 changes: 15 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
# This file contains the list of changes across different versions

## v2.4.0
## v2.4.1
* Added a new API `esp_secure_cert_get_tlv_info` for obtaining TLV information
* Added `esp_secure_cert_free_tlv_info` API for freeing TLV information.
* Added `esp_secure_cert_iterate_to_next_tlv` API for iterating the TLV entries
* Updated the API documentation for available `esp_secure_cert_get_*` APIs

## v2.4.0 (yanked)
* Added support for multiple entries of the same type by adding a new field called subtype.
* Fixed API for obtaining CA cert for the legacy flash formats (9b091ee)

### Yank explanation
This version was later yanked due to following reason.

* The API `esp_secure_cert_tlv_get_addr` which was made public in this version has incorrect documentation and the respective free API was not present.
* The changes in this version also modifiy the behaviour of existing APIs to obtain the TLV entry of latest subtype. While no current users shall be affected, this may cause inconsistency in the available API usage going forward.

Please note that the yanked version does not affect any of existing users. The yanking is done due to future API usage considerations and to avoid any possible inconsistencies.

## v2.3.1
* Make esp_secure_cert_get_key_type API available for DS peripheral case as well.

Expand Down
17 changes: 17 additions & 0 deletions docs/format.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ Please note that, TLV format uses compact data representation and hence partitio
When flash encryption is enabled for the device it is imporatant to encrypt the `esp_secure_cert` partition as well. Adding the encrypted flag in the partition table as done above can ensure that this is done. When flash encryption is not enabled this flag shall be ignored.

## TLV storage algorithms

The `esp_secure_cert_mgr` component also supports following algorithms for TLV. In this case the TLV data is not stored directly but is stored by using one of the following algorithms. The information about the algorithms is a part of the TLV itself.

- HMAC based AES-GCM encryption:
In this case the first key stored on the device with purpose `HMAC_UP` is used to derive an AES key and the salt.
This key is used to encrypt the TLV contents.
This algorithm is suitable where the platform encryption is not enabled.

- HMAC based ECDSA key derivation:
In this case the ECDSA key is derived using following two values
- Salt: This is the salt stored in a different tlv with type `ESP_SECURE_CERT_HMAC_ECDSA_KEY_SALT`
- HMAC key: This is the first key stored on the device with purpose `HMAC_UP`.
Both of these entities are used as input for the pbkdf2 algorithm to generate the ECDSA key.

Please ensure that appropriate TLV flags are enabled to take care of the underlying security configuration for the given TLV entry. On top of these security configuration, if platform flash encryption is enabled then the secure cert partition contents shall be stored in an encrypted manner on the external flash storage

## Legacy formats for `esp_secure_cert` partition

`esp_secure_cert` partition also supports two legacy flash formats.
Expand Down
21 changes: 9 additions & 12 deletions examples/esp_secure_cert_app/main/app_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <inttypes.h>
#include "esp_log.h"
#include "esp_secure_cert_read.h"
#include "esp_secure_cert_tlv_read.h"

#include "mbedtls/ssl.h"
#include "mbedtls/pk.h"
Expand Down Expand Up @@ -242,19 +243,15 @@ void app_main()
ESP_LOGE(TAG, "Failed to obtain and verify the contents of the esp_secure_cert partition");
}

esp_ret = esp_secure_cert_tlv_get_addr(ESP_SECURE_CERT_USER_DATA_1, ESP_SECURE_CERT_SUBTYPE_0, &addr, &len);
esp_secure_cert_tlv_config_t tlv_config = {};
tlv_config.type = ESP_SECURE_CERT_DEV_CERT_TLV;
tlv_config.subtype = ESP_SECURE_CERT_SUBTYPE_0;
esp_secure_cert_tlv_info_t tlv_info = {};
esp_ret = esp_secure_cert_get_tlv_info(&tlv_config, &tlv_info);
if (esp_ret == ESP_OK) {
ESP_LOG_BUFFER_HEX(TAG, addr, len);
}

esp_ret = esp_secure_cert_tlv_get_addr(ESP_SECURE_CERT_DEV_CERT_TLV, ESP_SECURE_CERT_SUBTYPE_1, &addr, &len);
if (esp_ret == ESP_OK) {
printf("Device Cert: \n%s", addr);
}

esp_ret = esp_secure_cert_tlv_get_addr(ESP_SECURE_CERT_PRIV_KEY_TLV, ESP_SECURE_CERT_SUBTYPE_1, &addr, &len);
if (esp_ret == ESP_OK) {
printf("Priv Key: \n%s", addr);
ESP_LOGI(TAG, "Device Cert: \nLength: %"PRIu32"\n%s", tlv_info.length, tlv_info.data);
}

ESP_LOGI(TAG, "Printing a list of TLV entries");
esp_secure_cert_list_tlv_entries();
}
2 changes: 1 addition & 1 deletion idf_component.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version: "2.4.0"
version: "2.4.1"
description: "ESP Secure Cert Manager"
url: /~https://github.com/espressif/esp_secure_cert_mgr
dependencies:
Expand Down
62 changes: 30 additions & 32 deletions include/esp_secure_cert_read.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#pragma once
#include "esp_err.h"

#include "esp_secure_cert_tlv_config.h"
#include "soc/soc_caps.h"
#ifdef CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL
#include "rsa_sign_alt.h"
Expand Down Expand Up @@ -38,26 +37,6 @@ typedef enum key_type {
*/
esp_err_t esp_secure_cert_init_nvs_partition(void);

/*
* Get the flash address of the data of a TLV entry
*
* Note: This API also validates the crc of the respective tlv before returning the offset. The offset is not the physical address but the address where it is mapped in the memory space.
* @input
* type Type of the TLV entry
* subtype Subtype of the TLV entry (index)
* buffer Pointer to the buffer to store the data address
* len Pointer to store the length of the data
*
* Note: If tlv type = ESP_SECURE_CERT_TLV_END then the address returned shall be the end address of current tlv formatted data.
* If tlv subtype = ESP_SECURE_CERT_SUBTYPE_MAX then the the address of tlv of given type and highest subtype found shall be returned.
* @return
*
* - ESP_OK On success
* - ESP_FAIL/other relevant esp error code
* On failure
*/
esp_err_t esp_secure_cert_tlv_get_addr(esp_secure_cert_tlv_type_t type, esp_secure_cert_tlv_subtype_t subtype, char **buffer, uint32_t *len);

/* @info
* Get the device cert from the esp_secure_cert partition
*
Expand All @@ -66,8 +45,14 @@ esp_err_t esp_secure_cert_tlv_get_addr(esp_secure_cert_tlv_type_t type, esp_secu
* the required memory to store the device cert and return the pointer.
* The pointer can be freed in this case (NVS) using respective free API
*
* In case of cust_flash partition, a read only flash pointer shall be returned here. This pointer should not be freed
* This API shall provide latest entry of the given type. Latest entry shall be considered as the entry with given type and highest value of subtype field.
* In case of cust_flash partition, a read only flash pointer shall be returned here.
*
* A respective call to the esp_secure_cert_free_device_cert() should be made to free any memory (if allocated)
*
* IMPORTANT: This API shall provide only the first entry of type Device cert (ESP_SECURE_CERT_DEV_CERT_TLV) present in the esp_secure_cert partition with subtype set as 0.
* If you have multiple entries of the given type with different subtypes then please use the generic API esp_secure_cert_get_tlv_info with the appropriate type and subtype.
* The type in this case shall be ESP_SECURE_CERT_DEV_CERT_TLV
* and the subtype shall be the index of the device cert that needs to be obtained.
*
* @params
* - buffer(out) This value shall be filled with the device cert address
Expand Down Expand Up @@ -107,7 +92,11 @@ esp_err_t esp_secure_cert_free_device_cert(char *buffer);
*
* The esp_secure_cert_free_ca_cert API needs to be called in order to free the memory.
* The API shall only free the memory if it has been dynamically allocated.
* This API shall provide latest entry of the given type. Latest entry shall be considered as the entry with given type and highest value of subtype field.
*
* IMPORTANT: This API shall provide only the first entry of type CA cert (ESP_SECURE_CERT_CA_CERT_TLV) present in the esp_secure_cert partition subtype set as 0.
* If you have multiple entries of the given type with different subtypes then please use the generic API esp_secure_cert_get_tlv_info with the appropriate type and subtype.
* The type in this case shall be ESP_SECURE_CERT_CA_CERT_TLV
* and the subtype shall be the index of the device cert that needs to be obtained.
*
* @params
* - buffer(out) This value shall be filled with the ca cert address
Expand Down Expand Up @@ -149,8 +138,10 @@ esp_err_t esp_secure_cert_free_ca_cert(char *buffer);
* The esp_secure_cert_free_priv_key API needs to be called in order to free the memory.
* The API shall only free the memory if it has been dynamically allocated.
*
* The private key(buffer) shall be returned as NULL when private key type is ESP_SECURE_CERT_ECDSA_PERIPHERAL_KEY.
* This API shall provide latest entry of the given type. Latest entry shall be considered as the entry with given type and highest value of subtype field.
* IMPORTANT: This API shall provide only the first entry of type private key (ESP_SECURE_CERT_PRIV_KEY_TLV) present in the esp_secure_cert partition with subtype set as 0.
* If you have multiple entries of the given type with different subtypes then please use the generic API esp_secure_cert_get_tlv_info with the appropriate type and subtype.
* The type in this case shall be ESP_SECURE_CERT_PRIV_KEY_TLV
* and the subtype shall be the index of the device cert that needs to be obtained.
*
* @params
* - buffer(out) This value shall be filled with the private key address
Expand Down Expand Up @@ -182,30 +173,36 @@ esp_err_t esp_secure_cert_free_priv_key(char *buffer);
* This function returns the flash esp_ds_context which can then be
* directly provided to an esp-tls connection through its config structure.
* The memory for the context is dynamically allocated.
* @note
* This shall generate the DS context only for the
* TLV entry with subtype 0 (First TLV entry for DS context)
* Internally this API assumes that the TLV entries with
* type ESP_SECURE_CERT_DS_CTX_TLV and ESP_SECURE_CERT_DS_DATA_TLV and subtype 0
* are present.
* A call to esp_secure_cert_free_ds_ctx() should be made
* to free the allocated memory
*
* @params
* - ds_ctx The pointer to the DS context
* @return
* - ds_ctx The pointer to the DS context, On success
* - NULL On failure
*/
esp_ds_data_ctx_t *esp_secure_cert_get_ds_ctx(void);

/*
*@info
* Free the ds context
* @info
* Free the DS context
*/

void esp_secure_cert_free_ds_ctx(esp_ds_data_ctx_t *ds_ctx);
#endif /* CONFIG_ESP_SECURE_CERT_DS_PERIPHERAL */

#ifndef CONFIG_ESP_SECURE_CERT_SUPPORT_LEGACY_FORMATS

/* @info
* Get the private key type from the esp_secure_cert partition
* This API shall provide latest entry of the given type. Latest entry shall be considered as the entry with given type and highest value of subtype field.
*
* @note
* The API is only supported for the TLV format
* This API shall only provide information for the private key with subtype set to ESP_SECURE_CERT_TLV_SUBTYPE_0 (first entry)
*
* @params
* - priv_key_type(out) Pointer to store the obtained key type
Expand All @@ -221,6 +218,7 @@ esp_err_t esp_secure_cert_get_priv_key_type(esp_secure_cert_key_type_t *priv_key
* @note
* The API is only supported for the TLV format.
* For now only ECDSA type of private key can be stored in the efuse block
* This API shall only provide information for the private key with subtype set to ESP_SECURE_CERT_TLV_SUBTYPE_0 (first entry)
*
* @params
* - efuse_block_id(out) Pointer to store the obtained efuse block id
Expand Down
6 changes: 4 additions & 2 deletions include/esp_secure_cert_tlv_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ typedef enum esp_secure_cert_tlv_type {
ESP_SECURE_CERT_USER_DATA_3 = 53,
ESP_SECURE_CERT_USER_DATA_4 = 54,
ESP_SECURE_CERT_USER_DATA_5 = 54,
ESP_SECURE_CERT_TLV_MAX = 255,
ESP_SECURE_CERT_TLV_MAX = 254, /* Max TLV entry identifier (should not be assigned to a TLV entry) */
ESP_SECURE_CERT_TLV_INVALID = 255, /* Invalid TLV type */
} esp_secure_cert_tlv_type_t;

typedef enum esp_secure_cert_tlv_subtype {
Expand All @@ -55,5 +56,6 @@ typedef enum esp_secure_cert_tlv_subtype {
ESP_SECURE_CERT_SUBTYPE_14 = 14,
ESP_SECURE_CERT_SUBTYPE_15 = 15,
ESP_SECURE_CERT_SUBTYPE_16 = 16,
ESP_SECURE_CERT_SUBTYPE_MAX = 255,
ESP_SECURE_CERT_SUBTYPE_MAX = 254, /* Max Subtype entry identifier (should not be assigned to a TLV entry) */
ESP_SECURE_CERT_SUBTYPE_INVALID = 255, /* Invalid TLV subtype */
} esp_secure_cert_tlv_subtype_t;
124 changes: 124 additions & 0 deletions include/esp_secure_cert_tlv_read.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include "esp_err.h"

#include "esp_secure_cert_tlv_config.h"

#ifdef __cplusplus
extern "C"
{
#endif

/*
* TLV config struct
*/
typedef struct tlv_config {
esp_secure_cert_tlv_type_t type; /* TLV type */
esp_secure_cert_tlv_subtype_t subtype; /* TLV subtype */
} esp_secure_cert_tlv_config_t;

/*
* TLV info struct
*/
typedef struct tlv_info {
esp_secure_cert_tlv_type_t type; /* Type of the TLV */
esp_secure_cert_tlv_subtype_t subtype; /* Subtype of the TLV */
char *data; /* Pointer to the buffer containting TLV data */
uint32_t length; /* TLV data length */
uint8_t flags;
} esp_secure_cert_tlv_info_t;

/*
* TLV iterator struct
*/
typedef struct tlv_iterator {
void *iterator; /* Opaque TLV iterator */
} esp_secure_cert_tlv_iterator_t;

/*
* Get the TLV information for given TLV configuration
*
* @note
* TLV Algorithms:
* If the TLV data is stored with some additional encryption then it first needs to be decrypted and the decrypted data is
* stored in a dynamically allocated buffer. This API automatically decrypts any encryption applied to the TLV by supported algorithms.
* For this the API may look for TLV entries of other types which store necessary information, these TLV entries must be of the same subtype as of the subtype field in the config struct.
* Please see documentation regarding supported TLV storage algorithms in the TLV documentation.
* A call to the esp_secure_cert_free_tlv_info() should be made to free any memory allocated while populating the tlv information object.
* This API also validates the crc of the respective tlv before returning the offset.
*
* If tlv type in the config struct is set to ESP_SECURE_CERT_TLV_END then the address returned shall be the end address of current tlv formatted data and the length returned shall be the total length of the valid TLV entries.
* @input
* tlv_config Pointer to a readable struct of type esp_secure_cert_tlv_config_t.
* The contents of the struct must be already filled by the caller,
* This information shall be used to find the appropriate TLV entry.
*
* tlv_info Pointer to a writable struct of type esp_secure_cert_tlv_info_t,
* If TLV entry defined by tlv_config is found then the TLV information shall be populated in this struct.
* @return
*
* - ESP_OK On success
* - ESP_FAIL/other relevant esp error code
* On failure
*/
esp_err_t esp_secure_cert_get_tlv_info(esp_secure_cert_tlv_config_t *tlv_config, esp_secure_cert_tlv_info_t *tlv_info);

/*
* Free the memory allocated while populating the tlv_info object
* @note
* Please note this does not free the tlv_info struct itself but only the memory allocated internally while populating this struct.
*/
esp_err_t esp_secure_cert_free_tlv_info(esp_secure_cert_tlv_info_t *tlv_info);

/*
* Iterate to the next valid TLV entry
* @note
* To obtain the first TLV entry, the tlv_iterator structure must be zero initialized
* @input
* tlv_iterator Pointer to a readable struct of type esp_secure_cert_tlv_iterator_t
*
* @return
* ESP_OK On success
* The iterator location shall be moved to point to the next TLV entry.
* ESP_FAIL/other relevant error codes
* On failure
*/
esp_err_t esp_secure_cert_iterate_to_next_tlv(esp_secure_cert_tlv_iterator_t *tlv_iterator);

/*
* Get the TLV information from a valid iterator location
*
* @note
* A call to the esp_secure_cert_free_tlv_info() should be made to free any memory allocated while populating the tlv information object.
*
* @input
* tlv_config Pointer to a readable struct of type esp_secure_cert_tlv_iterator_t.
* The iterator must be set to point to a valid TLV,
* by a previous call to esp_secure_cert_iterate_to_next_tlv();.
*
* tlv_info Pointer to a writable struct of type esp_secure_cert_tlv_info_t
* If TLV entry pointed by the iterator is valid then the TLV information shall be populated in this struct.
* @return
* ESP_OK On success
* The tlv_info object shall be populated with information of the TLV pointed by the iterator
* ESP_FAIL/other relevant error codes
* On failure
*/
esp_err_t esp_secure_cert_get_tlv_info_from_iterator(esp_secure_cert_tlv_iterator_t *tlv_iterator, esp_secure_cert_tlv_info_t *tlv_info);

/*
* List TLV entries
*
* This API serially traverses through all of the available
* TLV entries in the esp_secure_cert partition and logs
* brief information about each TLV entry.
*/
void esp_secure_cert_list_tlv_entries(void);

#ifdef __cplusplus
}
#endif
20 changes: 19 additions & 1 deletion private_include/esp_secure_cert_tlv_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,25 @@ const void *esp_secure_cert_get_mapped_addr(void);
*/
esp_err_t esp_secure_cert_find_tlv(const void *esp_secure_cert_addr, esp_secure_cert_tlv_type_t type, uint8_t subtype, void **tlv_address);


/*
* Get the flash address of the data of a TLV entry
*
* Note: This API also validates the crc of the respective tlv before returning the offset. The offset is not the physical address but the address where it is mapped in the memory space.
* @input
* type Type of the TLV entry
* subtype Subtype of the TLV entry (index)
* buffer Pointer to the buffer to store the data address
* len Pointer to store the length of the data
*
* Note: If tlv type = ESP_SECURE_CERT_TLV_END then the address returned shall be the end address of current tlv formatted data.
* If tlv subtype = ESP_SECURE_CERT_SUBTYPE_MAX then the the address of tlv of given type and highest subtype found shall be returned.
* @return
*
* - ESP_OK On success
* - ESP_FAIL/other relevant esp error code
* On failure
*/
esp_err_t esp_secure_cert_tlv_get_addr(esp_secure_cert_tlv_type_t type, esp_secure_cert_tlv_subtype_t subtype, char **buffer, uint32_t *len);

/*
* Identify if esp_secure_cert partition of type TLV is present.
Expand Down
Loading

0 comments on commit ff3a51e

Please sign in to comment.