Giter VIP home page Giter VIP logo

esp_secure_cert_mgr's Introduction

ESP Secure Certificate Manager

The esp_secure_cert_mgr provides a simplified interface to access the PKI credentials of a device pre-provisioned with the Espressif Provisioning Service. It provides the set of APIs that are required to access the contents of the esp_secure_cert partition. A demo example has also been provided with the esp_secure_cert_mgr, more details can be found out in the example README

Usage Guidelines

1) Include esp_secure_cert_mgr in your project

There are two ways to include esp_secure_cert_mgr in your project:

i) Add esp_secure_cert_mgr to your project with help of IDF component manager:

ii) Add esp_secure_cert_mgr as an extra component in your project.

  • Download esp_secure_cert_mgr with:
    git clone https://github.com/espressif/esp_secure_cert_mgr.git
  • Include esp_secure_cert_mgr in ESP-IDF with setting EXTRA_COMPONENT_DIRS in CMakeLists.txt/Makefile of your project.For reference see Optional Project Variables

2) Use the public API provided by esp_secure_cert_mgr in your project

  • The file esp_secure_cert_read.h contains the public APIs provided by the esp_secure_cert_mgr. Please include the file in your project to make use of the available APIs. The file also contains more details about the available APIs.

What is Pre-Provisioning?

With the Espressif Pre-Provisioning Service, the ESP modules are pre-provisioned with an encrypted RSA private key and respective X509 public certificate before they are shipped out to you. The PKI credentials can then be registered with the cloud service to establish a secure TLS channel for communication. With the pre-provisioning taking place in the factory, it provides a hassle-free PKI infrastructure to the Makers. You may use this repository to set up your test modules to validate that your firmware works with the pre-provisioned modules that you ordered through Espressif's pre-provisioning service.

ESP Secure Cert Partition

When a device is pre-provisioned that means the PKI credentials are generated for the device. The PKI credentials are then stored in a partition named esp_secure_cert.

The esp_secure_cert partition can be generated on host with help of configure_esp_secure_cert.py utility, more details about the utility can be found in the tools/README.

For esp devices that support DS peripheral, the pre-provisioning is done by leveraging the security benefit of the DS peripheral. In that case, all of the data which is present in the esp_secure_cert partition is completely secure.

When the device is pre-provisioned with help of the DS peripheral then by default the partition primarily contains the following data:

  1. Device certificate: It is the public key/ certificate for the device's private key. It is used in TLS authentication.
  2. CA certificate: This is the certificate of the CA which is used to sign the device cert.
  3. Ciphertext: This is the encrypted private key of the device. The ciphertext is encrypted using the DS peripheral, thus it is completely safe to store on the flash.

As listed above, the data only contains the public certificates and the encrypted private key and hence it is completely secure in itself. There is no need to further encrypt this data with any additional security algorithm.

Partition Format

The esp_secure_cert partition uses TLV format by default. Please take a look at the format document for more details.

esp_secure_cert_mgr's People

Contributors

adityahpatwardhan avatar aguilerag avatar danielb-idg avatar dhavalgujar avatar espressif-bot avatar laukik-hase avatar mahavirj avatar mohabdallah avatar nathanjphillips avatar shubhamdp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

esp_secure_cert_mgr's Issues

[Opinion] Hardcoded TLV format is not a good long term choice

Thanks for answering my previous questions =)

I just wanted to share this idea and why I ended up choosing against the custom TLV format. Instead, I store certs in a generic KLV format, that I already implemented for other purposes in my code base.

As alluded to in #2, I'm not a fan of using a custom hard coded TLV format. Personally, It's a deal-breaker.

Why?

  • hard coded type values are not future proof, and annoying to change
  • one-off formats increase code size
  • one-off formats increase code complexity
  • it is not extensible by 3rd parties. I can't add a lot of my own fields.
  • custom formats often die quickly, I want code to last. I don't want it to be deprecated.
  • its more annoying to document, because the format changes as types are added
  • types are not human readable

Instead, we really should:

  • move the format to its own *.c an *.h file
  • document it, so its not as proprietary
  • use a keyLen,key,dataLen,data format, so we don't need hardcoded type values
  • it should be generic and generally useful
  • it should support versioning
  • consider making it an ESP-IDF component

The generic KLV format I use looks like this:

Edit: also worth considering using DER format.

[EKLV]         (4 bytes) // magic value, "espKeyLengthValue"
[versionMajor] (1 bytes)
[versionMinor] (1 bytes)
[totalItemsLen] (8 bytes) // total items length in bytes

// item 1
[keyLenLen] (1 byte)    // keyLen size is configurable
[keyLen]    (X bytes)
[key]       (X bytes)
[padLen]     (2 bytes)   // for aligning 'data'
[pad]        (X bytes)
[dataLenLen] (1 byte)    // dataLen size is configurable
[dataLen]    (X bytes)
[data]       (X bytes)

// item 2
[keyLenLen] (1 byte) 
[keyLen]    (X bytes)
[key]       (X bytes)
[padLen]     (2 bytes) 
[pad]        (X bytes)
[dataLenLen] (1 byte) 
[dataLen]    (X bytes)
[data]       (X bytes)

...repeat...

The TLV format currently used here is a deal-breaker for me.

[Question] Is there a recommended way to generate the DS peripheral's RSA private/public keys on device?

Generating on device brings a few advantages:

  1. generally simpler
  2. the host PC just needs to sign the public key with the CA
  3. less reliance for your build system to generate keys in "just the right way"
  4. private keys never leave the device

Can you recommend a way to generate the private/public keys (Y,M,Rb,MPrime variables )on device? Using mbedTLS for instance?

If not, Espressif should consider adding a library to ESP-IDF which does that.

Problem with bitstring on Python 3.10

BitString was renamed to BitStream in Python 3.7+. I renamed in the IDF source and it seems to work.

jonsmirl@ares:~/aosp/esp-matter/examples/lowpan$ configure_esp_secure_cert.py -p /dev/ttyACM0 --keep_ds_data_on_host --efuse_key_id 1 --ca-cert cacert.pem --device-cert client.crt --private-key client.key --target_chip esp32c3 --secure_cert_type cust_flash_tlv --configure_ds
Traceback (most recent call last):
File "/home/jonsmirl/esp/esp-idf/components/esptool_py/esptool/espefuse.py", line 15, in
import espressif.efuse.esp32 as esp32_efuse
File "/home/jonsmirl/esp/esp-idf/components/esptool_py/esptool/espressif/efuse/esp32/init.py", line 1, in
from . import operations
File "/home/jonsmirl/esp/esp-idf/components/esptool_py/esptool/espressif/efuse/esp32/operations.py", line 18, in
from . import fields
File "/home/jonsmirl/esp/esp-idf/components/esptool_py/esptool/espressif/efuse/esp32/fields.py", line 17, in
from .. import base_fields
File "/home/jonsmirl/esp/esp-idf/components/esptool_py/esptool/espressif/efuse/base_fields.py", line 14, in
from bitstring import BitArray, BitString, CreationError
ImportError: cannot import name 'BitString' from 'bitstring' (/home/jonsmirl/.espressif/python_env/idf4.4_py3.10_env/lib/python3.10/site-packages/bitstring.py)

[ESP DS Params] add a way to generate ESP-DS Params on device

Note: I realize this should probably go in the ESP-IDF repo. But just continuing the discussion from before.

@AdityaHPatwardhan. Please add functions to generate ESP-DS Peripheral Params on device.

This is more secure than generating private keys in Python, and copying to device. It should be an option that users have.

Most important (RSA -> DS Params):
esp_err_t esp_ds_mbedtls_generate_params(const mbedtls_rsa_context* rsa, esp_ds_p_data_t* params);

Super Convenient (generate new rsa key & burn fuses & output pubKeyPem):
esp_err_t esp_ds_mbedtls_generate_keypair_and_burn_fuses(char* pubKeyPemBuf, size_t bufLen);

I've already done some of the code, tested working.

// Generate RInv & MPrime from RSA private numbers
void esp_mbedtls_calculate_rinv_mprime(const mbedtls_rsa_context* rsa, mbedtls_mpi* rinv, uint32_t* mprime)
{
    // python equivalent code:
    //
    //    key_size = private_key.key_size # in bits
    //
    //    # calculate rinv == Rb
    //    rr = 1 << (key_size * 2)
    //    rinv = rr % pub_numbers.n # RSA r inverse operand
    //
    //    # calculate MPrime
    //    a = rsa._modinv(M, 1 << 32)
    //    mprime = (a * -1) & 0xFFFFFFFF # RSA M prime operand

    // rr = 1 << (key_size * 2) # in bits
    mbedtls_mpi rr;
    mbedtls_mpi_init(&rr);
    mbedtls_mpi_lset(&rr, 1);
    mbedtls_mpi_shift_l(&rr, sizeof(pd_4096_bit_t) * 8 * 2);

    // rinv = rr % rsa.N 
    mbedtls_mpi_mod_mpi(&rinv, &rr, &N);

    // ls32 = 1 << 32
    mbedtls_mpi ls32;
    mbedtls_mpi_init(&ls32);
    mbedtls_mpi_lset(&ls32, 1);
    mbedtls_mpi_shift_l(&ls32, 32);

    // a = rsa._modinv(N, 1 << 32)
    mbedtls_mpi a;
    mbedtls_mpi_init(&a);
    mbedtls_mpi_inv_mod(&a, &N, &ls32);

    // a32 = a 
    uint32_t a32 = 0;
    mbedtls_mpi_write_binary_le(&a, (uint8_t*) &a32, sizeof(uint32_t));

    // mprime
    *mprime = ((int32_t) a32 * -1) & 0xFFFFFFFF;

    //
    // Results
    //
    printMpi(&rinv, "RInv");
    printf("mprime: 0x%x\n", *mprime);
}

void printMpi(const mbedtls_mpi* mpi, const char* name)
{
    size_t olen = 0;
    uint32_t len = MBEDTLS_MPI_MAX_SIZE * 2 + 1;
    char* pp = (char*)calloc(1, len);
    mbedtls_mpi_write_string(mpi, 16, pp, len, &olen);
    printf("%s: %s\n", name, pp);
    free(pp);
}

configure_esp_secure_cert different device naming than espefuse for esp32s3

Device naming is different between espefuse and configure_esp_secure_cert for esp32s3.
espefuse uses: "esp32s3beta2"
configure_esp_secure_cert uses: "esp32s3"

configure_esp_secure_cert error message:
espefuse: error: argument --chip/-c: invalid choice: 'esp32s3' (choose from 'auto', 'esp32', 'esp32s2', 'esp32s3beta2', 'esp32c3')

Magic byte error

I have followed this example to write certs and keys to the ESP32-S3-WROOM-2 DEV KIT-C N32R8: https://github.com/FreeRTOS/iot-reference-esp32c3/blob/main/GettingStartedGuide.md

My question is what is the magic byte and is it something I should be writing?

I get the following error when I try to read using the latest version of this library:

E (2935) esp_secure_cert_tlv: Expected magic byte is BA5EBA11, obtained magic byte = 9058D003
E (2945) esp_secure_cert_tlv: Could not find the tlv of type 1
    uint32_t len = 0;
    char *addr = NULL;
    esp_err_t esp_ret = ESP_FAIL;
    esp_ret = esp_secure_cert_get_device_cert(&addr, &len);
    if (esp_ret == ESP_OK) {
        ESP_LOGI(TAG, "Device Cert: \nLength: %d\n%s", strlen((char *)addr), (char *)addr);
    } else {
        ESP_LOGE(TAG, "Failed to obtain flash address of device cert");
    }

Partition Map

# Name,   Type, SubType, Offset,   Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
# esp_secure_cert type custflash 0x3F
esp_secure_cert, 0x3F,    ,     0xD000,   0x6000,   encrypted
nvs,             data, nvs,     0x13000,  0x6000,   
otadata,         data, ota,     0x19000,  0x2000,   encrypted
phy_init,        data, phy,     0x1b000,  0x1000,   encrypted
factory,         app,  factory,        ,      5M,   encrypted
ota_0,           app,  ota_0,          ,      5M,   encrypted
ota_1,           app,  ota_1,          ,      5M,   encrypted
storage,         data, nvs,            , 0x10000,   encrypted
nvs_key,         data, nvs_keys,       , 0x1000,    encrypted

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.