/** * Copyright (c) 2016-2017 Robert Totte * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ /** * * ** This copyright applies to some of the code in this file ** * * Copyright (c) 2015 Atmel Corporation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of Atmel may not be used to endorse or promote products derived * from this software without specific prior written permission. * * 4. This software may only be redistributed and used in connection with an * Atmel integrated circuit. * * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "AtCryptoAuthLib.h" #include "atca_command.h" #include "atcacert/atcacert_host_hw.h" extern "C" void hexdump(const void *buffer, uint32_t len, uint8_t cols); extern const atcacert_def_t my_signer_cert_def; extern const atcacert_def_t my_device_cert_def; #ifdef LIB_DEBUG #include static char g_printf_buf[90]; #define AWS_PRINTF(...) \ { \ snprintf(g_printf_buf, 90, __VA_ARGS__); \ Serial.print(g_printf_buf); \ Serial.flush(); \ } #else #define AWS_PRINTF(...) #endif // Get a pointer to the default configuration based on the compiler switch #ifdef ATCA_HAL_KIT_CDC ATCAIfaceCfg* gCfg = &cfg_ecc508_kitcdc_default; #elif ATCA_HAL_KIT_HID ATCAIfaceCfg* gCfg = &cfg_ecc508_kithid_default; #else //#elif ATCA_HAL_I2C ATCAIfaceCfg* gCfg = &cfg_ateccx08a_i2c_default; #endif AtCryptoAuthLib::AtCryptoAuthLib() : sha256_init(false) { } AtCryptoAuthLib::~AtCryptoAuthLib() { } ATCA_STATUS AtCryptoAuthLib::init(const uint8_t *access_key) { bool lockstate; ATCA_STATUS ret; ret = atcatls_init(gCfg); if (ret != ATCA_SUCCESS) return ret; if (access_key == NULL) { set_enc_key(ENC_KEY); } else { set_enc_key(access_key); } ret = config_locked(lockstate); if ((ret != ATCA_SUCCESS) || !lockstate) return ret; return atca_tls_init_enc_key(); } ATCA_STATUS AtCryptoAuthLib::random(uint8_t rand_out[32]) { return atcatls_random(rand_out); } ATCA_STATUS AtCryptoAuthLib::get_pub_key(SlotCfg slot, uint8_t pubKey[64]) { switch (slot) { case AUTH_PRIV: case AUTH_PRIV_2: case ECDHE_PRIV: case ECC_KEY_1: case ECC_KEY_2: case ECC_KEY_3: return atcab_get_pubkey((uint16_t)slot, pubKey); case SIGNER_PUBKEY: case SIGNER_CERT: case FEATURE_CERT: case PKICA_PUBKEY: case AUTH_CERT_DATA: return atcab_read_pubkey((uint16_t)slot, pubKey); default: break; } return ATCA_BAD_PARAM; } ATCA_STATUS AtCryptoAuthLib::gen_key(SlotCfg slot, uint8_t pubKey[64]) { switch (slot) { case AUTH_PRIV: case AUTH_PRIV_2: case ECDHE_PRIV: case ECC_KEY_1: case ECC_KEY_2: case ECC_KEY_3: return atcab_genkey((uint16_t)slot, pubKey); default: break; } return ATCA_BAD_PARAM; } ATCA_STATUS AtCryptoAuthLib::priv_key_write(SlotCfg slot, const uint8_t priv_key[32]) { int i; uint8_t pad_key[36]; switch (slot) { case ECC_KEY_1: case ECC_KEY_2: case ECC_KEY_3: break; default: return ATCA_BAD_PARAM; } for (i = 0; i < 32; i++) { pad_key[i+4] = priv_key[i]; } pad_key[0] = 0; pad_key[1] = 0; pad_key[2] = 0; pad_key[3] = 0; return atcab_priv_write(slot, pad_key, ENC_PARENT, m_enc_key); } ATCA_STATUS AtCryptoAuthLib::write_pub_key(SlotCfg slot, const uint8_t pubKey[64]) { switch (slot) { case SIGNER_PUBKEY: case SIGNER_CERT: case FEATURE_CERT: case PKICA_PUBKEY: case AUTH_CERT_DATA: return atcab_write_pubkey((uint16_t)slot, pubKey); default: break; } return ATCA_BAD_PARAM; } ATCA_STATUS AtCryptoAuthLib::sign(SlotCfg slot, const uint8_t to_sign[32], uint8_t signature[64]) { switch (slot) { case AUTH_PRIV: case AUTH_PRIV_2: case ECDHE_PRIV: case ECC_KEY_1: case ECC_KEY_2: case ECC_KEY_3: return atcab_sign((uint16_t)slot, to_sign, signature); default: break; } return ATCA_BAD_PARAM; } ATCA_STATUS AtCryptoAuthLib::sign(const uint8_t to_sign[32], uint8_t signature[64]) { return sign(AUTH_PRIV, to_sign, signature); } ATCA_STATUS AtCryptoAuthLib::verify(const uint8_t key[64], const uint8_t to_verify[32], const uint8_t signature[64], bool &verify_success) { bool is_verif = false; ATCA_STATUS ret; ret = atcab_verify_extern(to_verify, signature, key, &is_verif); if (ret == ATCA_SUCCESS) verify_success = is_verif; return ret; } ATCA_STATUS AtCryptoAuthLib::verify(SlotCfg slot, const uint8_t to_verify[32], const uint8_t signature[64], bool &verify_success) { ATCA_STATUS ret; uint8_t key[64]; ret = get_pub_key(slot, key); if (ret != ATCA_SUCCESS) { return ret; } return verify(key, to_verify, signature, verify_success); } ATCA_STATUS AtCryptoAuthLib::verify(const uint8_t to_verify[64], const uint8_t signature[64], bool &verify_success) { return verify(AUTH_PRIV, to_verify, signature, verify_success); } /* Doesn't work ATCA_STATUS AtCryptoAuthLib::verify_stored(SlotCfg slot, const uint8_t to_verify[32], const uint8_t signature[64], bool &verify_success) { bool is_verif = false; ATCA_STATUS ret; ret = atcab_verify_stored(to_verify, signature, (uint16_t)slot, &is_verif); if (ret == ATCA_SUCCESS) verify_success = is_verif; return ret; } */ ATCA_STATUS AtCryptoAuthLib::hash_start() { ATCA_STATUS ret; if (sha256_init) return ATCA_BAD_PARAM; ret = (ATCA_STATUS)atcab_hw_sha2_256_init(&sha256_ctx); if (ret == ATCA_SUCCESS) sha256_init = true; return ret; } ATCA_STATUS AtCryptoAuthLib::hash_update(const uint8_t* data, size_t data_size) { if (!sha256_init) return ATCA_BAD_PARAM; return (ATCA_STATUS)atcab_hw_sha2_256_update(&sha256_ctx, data, data_size); } ATCA_STATUS AtCryptoAuthLib::hash_finish(uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]) { if (!sha256_init) { sha256_init = false; return ATCA_BAD_PARAM; } sha256_init = false; return (ATCA_STATUS)atcab_hw_sha2_256_finish(&sha256_ctx, digest); } ATCA_STATUS AtCryptoAuthLib::hash(const uint8_t* data, size_t data_size, uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]) { ATCA_STATUS ret; ret = hash_start(); if (ret != ATCA_SUCCESS) return ret; ret = hash_update(data, data_size); if (ret != ATCA_SUCCESS) return ret; return hash_finish(digest); } ATCA_STATUS AtCryptoAuthLib::hmac_start(uint8_t *hmac_key, size_t key_size) { ATCA_STATUS ret; uint8_t pad[32]; int i; if (sha256_init) return ATCA_BAD_PARAM; if (key_size > 32) { ret = atcab_hw_sha2_256(hmac_key, key_size, m_hmac_key); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: AtCryptoAuthLib::hmac_start @%d %d\n", __LINE__, ret); return ret; } } else { memset(m_hmac_key, 0, 32); memcpy(m_hmac_key, hmac_key, key_size); } memset(pad, 0x36, 32); for (i = 0; i < 32; i++) m_hmac_key[i] = m_hmac_key[i] ^ 0x36; ret = atcab_hw_sha2_256_init(&sha256_ctx); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: SHA_MODE_SHA256_START @%d %d\n", __LINE__, (int)ret); return ret; } ret = atcab_hw_sha2_256_update(&sha256_ctx, m_hmac_key, 32); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: SHA_MODE_SHA256_UPDATE @%d %d\n", __LINE__, (int)ret); return ret; } ret = atcab_hw_sha2_256_update(&sha256_ctx, pad, 32); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: SHA_MODE_SHA256_UPDATE @%d %d\n", __LINE__, (int)ret); return ret; } sha256_init = true; return ATCA_SUCCESS; } ATCA_STATUS AtCryptoAuthLib::hmac_update(const uint8_t* data, size_t data_size) { if (!sha256_init) return ATCA_BAD_PARAM; return atcab_hw_sha2_256_update(&sha256_ctx, data, data_size); } ATCA_STATUS AtCryptoAuthLib::hmac_finish(uint8_t digest[ATCA_SHA2_256_DIGEST_SIZE]) { ATCA_STATUS ret; uint8_t pad[96]; int i; if (!sha256_init) { return ATCA_BAD_PARAM; } sha256_init = false; memset(pad, 0x5c, 64); for (i = 0; i < 32; i++) pad[i] = m_hmac_key[i] ^ (0x5c ^ 0x36); ret = atcab_hw_sha2_256_finish(&sha256_ctx, &(pad[64])); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: AtCryptoAuthLib::hmac_finish @%d %d\n", __LINE__, (int)ret); return ret; } memset(&sha256_ctx, 0, sizeof(sha256_ctx)); memset(m_hmac_key, 0, 32); return atcab_hw_sha2_256(pad, 96, digest); } ATCA_STATUS AtCryptoAuthLib::ecdh_gen_key(uint8_t key[64]) { return gen_key(ECDHE_PRIV, key); } ATCA_STATUS AtCryptoAuthLib::ecdh(const uint8_t other_key[64], uint8_t pmk[32], SlotCfg sl) { // sends an encrypted command for slot ECDHE_PRIV only switch (sl) { case AUTH_PRIV: case AUTH_PRIV_2: case ECC_KEY_1: case ECC_KEY_2: case ECC_KEY_3: return atcab_ecdh((uint8_t)sl, other_key, pmk); case ECDHE_PRIV: return atcab_ecdh_enc((uint8_t)sl, other_key, pmk, m_enc_key, ENC_PARENT); default: break; } return ATCA_BAD_PARAM; } //uint8_t AtCryptoAuthLib::m_enc_key[ATCA_KEY_SIZE] = {0}; const uint8_t AtCryptoAuthLib::ENC_KEY[ATCA_KEY_SIZE] = { 0xF9, 0x47, 0x2C, 0xBD, 0x33, 0x1D, 0x51, 0x00, 0x0C, 0x45, 0x36, 0x34, 0x81, 0x37, 0x2F, 0xD8, 0x5D, 0x5F, 0xB4, 0xB7, 0x25, 0x21, 0xF8, 0x90, 0x52, 0xFA, 0xFC, 0x41, 0x02, 0x40, 0xE6, 0xF5, }; ATCA_STATUS AtCryptoAuthLib::set_enc_key(const uint8_t* key) { memcpy(m_enc_key, key, ATCA_KEY_SIZE); return ATCA_SUCCESS; } ATCA_STATUS AtCryptoAuthLib::atca_tls_init_enc_key() { ATCA_STATUS ret = ATCA_SUCCESS; do { // ret = atcatls_set_enckey((uint8_t*)m_enc_key, ENC_PARENT, false); // if (ret != ATCA_SUCCESS) { break; } ret = atcatlsfn_set_get_enckey(atca_tls_set_enc_key, this); if (ret != ATCA_SUCCESS) { break; } } while(0); return ret; } ATCA_STATUS AtCryptoAuthLib::atca_tls_set_enc_key(uint8_t* outKey, int16_t keysize, void *ctx) { AtCryptoAuthLib *lib = static_cast(ctx); ATCA_STATUS ret = ATCA_SUCCESS; do { if (outKey == NULL || keysize != ATCA_KEY_SIZE || lib == NULL) { break; } memcpy(outKey, lib->m_enc_key, keysize); } while(0); return ret; } size_t AtCryptoAuthLib::slot_size(SlotCfg slot) { switch (slot) { case ENC_STORE: return 416; case ENC_STORE_9: case AUTH_CERT: case SIGNER_PUBKEY: case SIGNER_CERT: case FEATURE_CERT: case PKICA_PUBKEY: case AUTH_CERT_DATA: return 72; case ECDH_PMK: case ENC_PARENT: return 36; default: break; } return 0; } bool AtCryptoAuthLib::slot_encrypted(SlotCfg slot) { switch (slot) { case ENC_STORE: case ENC_STORE_9: case ECDH_PMK: return true; default: break; } return false; } ATCA_STATUS AtCryptoAuthLib::read_slot(SlotCfg slot, uint8_t *data, size_t offs, size_t len) { ATCA_STATUS ret = ATCA_SUCCESS; uint8_t dataout[32] = { 0 }; uint8_t block; size_t i; size_t dptr; if ((len + offs) > slot_size(slot)) { return ATCA_BAD_PARAM; } block = offs/32; i = offs % 32; dptr = 0; /* if (slot_encrypted(slot)) { ret = atcab_write_zone(ATCA_ZONE_DATA, ENC_PARENT, 0, 0, m_enc_key, ATCA_BLOCK_SIZE); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcatls_set_enckey %d\n", ret); return ret;; } } */ memset(data, 0, len); while (dptr < len) { if (slot_encrypted(slot)) { ret = atcab_read_enc(slot, block, dataout, m_enc_key, ENC_PARENT); } else { ret = atcab_read_zone(ATCA_ZONE_DATA, slot, block, 0, dataout, 32); } if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_read %d\n", ret); break; } for ( ; (i < 32) && (dptr < len); i++) { data[dptr++] = dataout[i]; } i = 0; block++; } memset(dataout, 0, 32); return ret; } ATCA_STATUS AtCryptoAuthLib::write_slot(SlotCfg slot, uint8_t *data, size_t offs, size_t len) { ATCA_STATUS ret = ATCA_SUCCESS; uint8_t dataout[32] = { 0 }; uint8_t block; size_t i; size_t dptr; if ((len + offs) > slot_size(slot)) { return ATCA_BAD_PARAM; } block = offs/32; i = offs % 32; dptr = 0; while (dptr < len) { if ((i == 0) && ((len-dptr) >= 32)) { // write entire block memcpy(dataout, &(data[dptr]), 32); dptr += 32; } else { // read-modify-write if (slot_encrypted(slot)) { ret = atcab_read_enc(slot, block, dataout, m_enc_key, ENC_PARENT); } else { ret = atcab_read_zone(ATCA_ZONE_DATA, slot, block, 0, dataout, 32); } if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_read %d\n", ret); break; } for ( ; (i < 32) && (dptr < len); i++) { dataout[i] = data[dptr++]; } i = 0; } if (slot_encrypted(slot)) { ret = atcab_write_enc(slot, block, dataout, m_enc_key, ENC_PARENT); } else { ret = atcab_write_zone(ATCA_ZONE_DATA, slot, block, 0, dataout, 32); } if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_write %d\n", ret); break; } block++; } memset(dataout, 0, 32); return ret; } bool AtCryptoAuthLib::verify_cert_chain(uint8_t *caPubKey, uint8_t *signerCert, size_t *signerCertSize, uint8_t *deviceCert, size_t *deviceCertSize) { ATCA_STATUS status = ATCA_GEN_FAIL; uint8_t signerPubkey[64] = { 0 }; do { // Get the signer certificate - ATCACERT_E_WRONG_CERT_DEF status = atcatls_get_cert(&my_signer_cert_def, caPubKey, signerCert, signerCertSize); if (status == ATCACERT_E_WRONG_CERT_DEF) { AWS_PRINTF("ERROR: atcatls_get_cert signer Wrong Cert Def\n"); } else if (status != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcatls_get_cert signer %x\n", status); break; } // Verify the signer certificate status = (ATCA_STATUS)atcacert_verify_cert_hw(&my_signer_cert_def, signerCert, *signerCertSize, caPubKey); if (status != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcacert_verify_cert_hw signer %d\n", status); break; } // Get the signer public key from the signer certificate status = (ATCA_STATUS)atcacert_get_subj_public_key(&my_signer_cert_def, signerCert, *signerCertSize, signerPubkey); if (status != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcacert_get_subj_public_key %d\n", status); break; } // Get the device certificate status = atcatls_get_cert(&my_device_cert_def, signerPubkey, deviceCert, deviceCertSize); if (status == ATCACERT_E_WRONG_CERT_DEF) { AWS_PRINTF("ERROR: atcatls_get_cert device Wrong Cert Def\n"); } else if (status != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcatls_get_cert device %d\n", status); break; } // Verify the device certificate status = (ATCA_STATUS)atcacert_verify_cert_hw(&my_device_cert_def, deviceCert, *deviceCertSize, signerPubkey); if (status != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcacert_verify_cert_hw device %d\n", status); break; } } while (0); if (status == ATCA_SUCCESS) { AWS_PRINTF("Verify Cert PASS %d\n", __LINE__); return true; } else { AWS_PRINTF("Verify Cert FAIL %d\n", __LINE__); return false; } } // modified W25 ECC508 configuration // (slot 7 has external sign turned on for cert testing) const uint8_t AtCryptoAuthLib::golden_ecc_configdata[ATCA_CONFIG_SIZE] = { // block 0 // Not Written: First 16 bytes are not written 0x01, 0x23, 0x00, 0x00, // SN 0x00, 0x00, 0x50, 0x00, // rev num 0x04, 0x05, 0x06, 0x07, // SN 0xEE, 0x00, 0x01, 0x00, // SN, I2C en // I2C, reserved, OtpMode, ChipMode 0xC0, 0x00, 0x55, 0x00, // SlotConfig 0x87, 0x20, // slot 0 - TLS_SLOT_AUTH_PRIV (0) 0x87, 0x20, // slot 0 - TLS_SLOT_AUTH_PRIV (1) 0x8F, 0x20, // slot 2 - TLS_SLOT_ECDHE_PRIV (2) 0xC4, 0x44, // slot 3 - TLS_SLOT_ECDH_PMK (3) 0x8F, 0x0F, // slot 4 - TLS_SLOT_ENC_PARENT (4) 0x87, 0x64, // slot 7 - TLS_SLOT_FEATURE_PRIV (5) 0x87, 0x64, // slot 7 - TLS_SLOT_FEATURE_PRIV (6) 0x87, 0x64, // slot 7 - TLS_SLOT_FEATURE_PRIV (7) 0xC4, 0x44, // slot 8 - TLS_SLOT8_ENC_STORE (8) 0xC4, 0x44, // slot 9 - TLS_SLOT9_ENC_STORE (9) 0x0F, 0x0F, // slot 10 - TLS_SLOT_AUTH_CERT (A) 0x0F, 0x0F, // slot 11 - TLS_SLOT_SIGNER_PUBKEY (B) 0x0F, 0x0F, // slot 12 - TLS_SLOT_SIGNER_CERT (C) 0x0F, 0x0F, // slot 13 - TLS_SLOT_FEATURE_CERT (D) 0x0F, 0x0F, // slot 14 - TLS_SLOT_PKICA_PUBKEY (E) 0x0F, 0x0F, // slot 15 - TLS_SLOT_DEVICE_CERT (F) // Counters 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Last Key Use 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Not Written: UserExtra, Selector, LockValue, LockConfig (word offset = 5) 0x00, 0x00, 0x00, 0x00, // -- end of common sha204 data -- (88 bytes) // SlotLock[2], RFU[2] 0xFF, 0xFF, 0x00, 0x00, // X.509 Format 0x00, 0x00, 0x00, 0x00, // KeyConfig 0x13, 0x00, // slot 0 - TLS_SLOT_AUTH_PRIV (0) 0x13, 0x00, // slot 0 - TLS_SLOT_AUTH_PRIV (1) 0x33, 0x00, // slot 2 - TLS_SLOT_ECDHE_PRIV (2) 0x1C, 0x00, // slot 3 - TLS_SLOT_ECDH_PMK (3) 0x3C, 0x00, // slot 4 - TLS_SLOT_ENC_PARENT (4) 0x33, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (5) 0x33, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (6) 0x33, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (7) 0x1C, 0x00, // slot 8 - TLS_SLOT8_ENC_STORE (8) 0x1C, 0x00, // slot 9 - TLS_SLOT9_ENC_STORE (9) 0x3C, 0x00, // slot 10 - TLS_SLOT_AUTH_CERT (A) 0x3C, 0x00, // slot 11 - TLS_SLOT_SIGNER_PUBKEY (B) 0x3C, 0x00, // slot 12 - TLS_SLOT_SIGNER_CERT (C) 0x3C, 0x00, // slot 13 - TLS_SLOT_FEATURE_CERT (D) 0x3C, 0x00, // slot 14 - TLS_SLOT_PKICA_PUBKEY (E) 0x3C, 0x00, // slot 15 - TLS_SLOT_DEVICE_CERT (F) }; /* Config notes slot 0,1,5,6,7 can do unencrypted ECDH slot 2 writes encrypted ECDH to slot+1 slot 5,6,7 allows priv_write */ // minimal config without encrypted slots const uint8_t AtCryptoAuthLib::minimal_ecc_configdata[ATCA_CONFIG_SIZE] = { // block 0 // Not Written: First 16 bytes are not written 0x01, 0x23, 0x00, 0x00, // SN 0x00, 0x00, 0x50, 0x00, // rev num 0x04, 0x05, 0x06, 0x07, // SN 0xEE, 0x00, 0x01, 0x00, // SN, I2C en // I2C, reserved, OtpMode, ChipMode 0xC0, 0x00, 0x55, 0x00, // SlotConfig 0x87, 0x20, // slot 0 - TLS_SLOT_AUTH_PRIV (0) 0x87, 0x20, // slot 0 - TLS_SLOT_AUTH_PRIV (1) 0x87, 0x20, // slot 2 - TLS_SLOT_ECDHE_PRIV (2) 0x87, 0x20, // slot 3 - TLS_SLOT_ECDH_PMK (3) 0x87, 0x20, // slot 4 - TLS_SLOT_ENC_PARENT (4) 0x87, 0x20, // slot 7 - TLS_SLOT_FEATURE_PRIV (5) 0x87, 0x20, // slot 7 - TLS_SLOT_FEATURE_PRIV (6) 0x87, 0x20, // slot 7 - TLS_SLOT_FEATURE_PRIV (7) 0x0F, 0x0F, // slot 8 - TLS_SLOT8_ENC_STORE (8) 0x0F, 0x0F, // slot 9 - TLS_SLOT9_ENC_STORE (9) 0x0F, 0x0F, // slot 10 - TLS_SLOT_AUTH_CERT (A) 0x0F, 0x0F, // slot 11 - TLS_SLOT_SIGNER_PUBKEY (B) 0x0F, 0x0F, // slot 12 - TLS_SLOT_SIGNER_CERT (C) 0x0F, 0x0F, // slot 13 - TLS_SLOT_FEATURE_CERT (D) 0x0F, 0x0F, // slot 14 - TLS_SLOT_PKICA_PUBKEY (E) 0x0F, 0x0F, // slot 15 - TLS_SLOT_DEVICE_CERT (F) // Counters 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, // Last Key Use 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Not Written: UserExtra, Selector, LockValue, LockConfig (word offset = 5) 0x00, 0x00, 0x00, 0x00, // -- end of common sha204 data -- (88 bytes) // SlotLock[2], RFU[2] 0xFF, 0xFF, 0x00, 0x00, // X.509 Format 0x00, 0x00, 0x00, 0x00, // KeyConfig 0x13, 0x00, // slot 0 - TLS_SLOT_AUTH_PRIV (0) 0x13, 0x00, // slot 0 - TLS_SLOT_AUTH_PRIV (1) 0x13, 0x00, // slot 2 - TLS_SLOT_ECDHE_PRIV (2) 0x13, 0x00, // slot 3 - TLS_SLOT_ECDH_PMK (3) 0x13, 0x00, // slot 4 - TLS_SLOT_ENC_PARENT (4) 0x13, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (5) 0x13, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (6) 0x13, 0x00, // slot 7 - TLS_SLOT_FEATURE_PRIV (7) 0x3C, 0x00, // slot 8 - TLS_SLOT8_ENC_STORE (8) 0x3C, 0x00, // slot 9 - TLS_SLOT9_ENC_STORE (9) 0x3C, 0x00, // slot 10 - TLS_SLOT_AUTH_CERT (A) 0x3C, 0x00, // slot 11 - TLS_SLOT_SIGNER_PUBKEY (B) 0x3C, 0x00, // slot 12 - TLS_SLOT_SIGNER_CERT (C) 0x3C, 0x00, // slot 13 - TLS_SLOT_FEATURE_CERT (D) 0x3C, 0x00, // slot 14 - TLS_SLOT_PKICA_PUBKEY (E) 0x3C, 0x00, // slot 15 - TLS_SLOT_DEVICE_CERT (F) }; ATCA_STATUS AtCryptoAuthLib::config_locked(bool &lockstate) { ATCA_STATUS ret = ATCA_SUCCESS; bool ls = 0; do { ret = atcab_is_locked(LOCK_ZONE_CONFIG, &ls); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_is_locked(LOCK_ZONE_CONFIG %d\n", ret); break; } lockstate = ls; } while (0); return ret; } ATCA_STATUS AtCryptoAuthLib::check_config(bool &match) { ATCA_STATUS ret = ATCA_SUCCESS; uint8_t configdata[ATCA_CONFIG_SIZE] = { 0 }; bool lock; match = false; do { ret = config_locked(lock); if ((ret != ATCA_SUCCESS) || !lock) { break; } ret = atcab_read_ecc_config_zone((uint8_t*)configdata); if (ret != ATCA_SUCCESS) { break; } if (memcmp(&(configdata[20]), &(golden_ecc_configdata[20]), ATCA_CONFIG_SIZE-20) == 0) { match = true; } } while (0); return ret; } ATCA_STATUS AtCryptoAuthLib::config_chip(const uint8_t *access_key) { ATCA_STATUS ret = ATCA_SUCCESS; bool lockstate = 0; uint8_t lock_response; uint8_t configdata[ATCA_CONFIG_SIZE] = { 0 }; if (access_key != NULL) set_enc_key(access_key); do { // Check the lock state of the config zone. If unlocked, then write and lock. ret = atcab_is_locked(LOCK_ZONE_CONFIG, &lockstate); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_is_locked(LOCK_ZONE_CONFIG %d\n", ret); break; } if (!lockstate) { ret = atcab_write_ecc_config_zone(golden_ecc_configdata); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_write_ecc_config_zone %d\n", ret); break; } ret = atcab_lock_config_zone(&lock_response); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_lock_config_zone %d\n", ret); break; } } else { AWS_PRINTF("Already Locked\n"); } // Refresh the configuration zone data with the bytes that are now on the device ret = atcab_read_ecc_config_zone((uint8_t*)&configdata); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_read_ecc_config_zone %d\n", ret); break; } // Check the Data zone lock ret = atcab_is_locked(LOCK_ZONE_DATA, &lockstate); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_is_locked(LOCK_ZONE_DATA %d\n", ret); break; } if (!lockstate) { uint8_t pubKey[64]; ret = atcab_write_zone(DEVZONE_DATA, ENC_PARENT, 0, 0, m_enc_key, 32); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_write_zone(DEVZONE_DATA %d\n", ret); break; } ret = atcab_genkey((uint16_t)AUTH_PRIV, pubKey); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_genkey AUTH_PRIV %d\n", ret); break; } ret = atcab_lock_data_zone(&lock_response); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcab_lock_data_zone %d\n", ret); break; } } } while (0); return ret; } /* extern "C" void atca_delay_ms(uint32_t d) { delay(d); } */ // ** Provision With Device Stored Certs ** #include "atcacert/atcacert_def.h" #include "atcacert/atcacert_client.h" #define CERT_DEF_DEVICE (&my_device_cert_def) #define CERT_DEF_SIGNER (&my_signer_cert_def) #define AWS_CERT_LENGH_MAX (1024) #define AWS_ROOT_CERT_ID (uint8_t)(0x00) // Root Cert Identifier #define AWS_SIGNER_CERT_ID (uint8_t)(0x01) // Signer Cert Identifier #define AWS_VERIF_CERT_ID (uint8_t)(0x02) // Verification Cert Identifier #define AWS_DEVICE_CERT_ID (uint8_t)(0x03) // Device Cert Identifier int AtCryptoAuthLib::provision_load_signer_cert( const char *pem_cert, size_t pem_cert_len, uint8_t *tbs_data, // ATCA_SHA_DIGEST_SIZE uint8_t signer_id[2], const atcacert_tm_utc_t *issue_date) { int ret = ATCA_SUCCESS; uint8_t der_cert[AWS_CERT_LENGH_MAX]; size_t der_cert_len; uint8_t signer_pub_key[ATCA_PUB_KEY_SIZE] = { 0 }; do { der_cert_len = AWS_CERT_LENGH_MAX; ret = atcacert_decode_pem_cert(pem_cert, pem_cert_len, der_cert, &der_cert_len); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcatls_random %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); ret = atcacert_get_subj_public_key(CERT_DEF_SIGNER, der_cert, der_cert_len, signer_pub_key); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcacert_get_subj_public_key %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); ret = atcacert_get_signer_id(CERT_DEF_SIGNER, der_cert, der_cert_len, signer_id); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: atcacert_get_signer_id %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); ret = aws_prov_save_cert(AWS_SIGNER_CERT_ID, pem_cert, pem_cert_len); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: aws_prov_save_cert %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); ret = aws_prov_save_signer_public_key(signer_pub_key); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: aws_prov_save_signer_public_key %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); ret = aws_prov_build_device_tbs(tbs_data, signer_pub_key, signer_id, issue_date); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: aws_prov_build_device_tbs %d\n", ret); break; } AWS_PRINTF("provision_load_signer_cert %d\n", __LINE__); } while(0); return ret; } uint8_t AtCryptoAuthLib::aws_prov_save_cert( uint8_t cert_id, const char *cert_pem, size_t cert_pem_len) { uint8_t status = ATCA_SUCCESS; const atcacert_def_t* cert_def; uint8_t der_cert[AWS_CERT_LENGH_MAX]; size_t der_cert_size = sizeof(der_cert); char* start_pem = NULL; char* end_pem = NULL; uint16_t buffer_length = 0; do { if (cert_id == AWS_SIGNER_CERT_ID) cert_def = CERT_DEF_SIGNER; else if (cert_id == AWS_DEVICE_CERT_ID) cert_def = CERT_DEF_DEVICE; else break; start_pem = strstr(cert_pem, PEM_CERT_BEGIN); end_pem = strstr(cert_pem, PEM_CERT_END); buffer_length = end_pem - start_pem + sizeof(PEM_CERT_END) + 1; status = atcacert_decode_pem_cert((const char*)start_pem, buffer_length, der_cert, &der_cert_size); if (status != ATCA_SUCCESS) break; status = atcacert_write_cert(cert_def, der_cert, der_cert_size); if (status != ATCA_SUCCESS) break; } while (0); return status; } uint8_t AtCryptoAuthLib::aws_prov_save_signer_public_key(const uint8_t* public_key) { uint8_t ret = ATCA_SUCCESS; size_t end_block = 3, start_block = 0; uint8_t padded_public_key[96]; memset(padded_public_key, 0x00, sizeof(padded_public_key)); memmove(&padded_public_key[40], &public_key[32], 32); memset(&padded_public_key[36], 0, 4); memmove(&padded_public_key[4], &public_key[0], 32); memset(&padded_public_key[0], 0, 4); for (; start_block < end_block; start_block++) { ret = atcab_write_zone(DEVZONE_DATA, SIGNER_PUBKEY, start_block, 0, &padded_public_key[(start_block - 0) * 32], 32); if (ret != ATCA_SUCCESS) return ret; } return ret; } uint8_t AtCryptoAuthLib::aws_prov_build_device_tbs( uint8_t *tbs_digest, const uint8_t signer_public_key[64], const uint8_t signer_id[2], const atcacert_tm_utc_t* issue_date) { uint8_t status = ATCA_SUCCESS; bool lockstate = false; uint8_t device_public_key[ATCA_PUB_KEY_SIZE] = { 0 }; uint8_t device_cert[AWS_CERT_LENGH_MAX]; size_t device_cert_size = sizeof(device_cert); uint8_t configdata[ATCA_CONFIG_SIZE]; do { status = atcab_is_locked(LOCK_ZONE_CONFIG, &lockstate); if (status != ATCA_SUCCESS || !lockstate) break; status = atcab_read_config_zone(configdata); if (status != ATCA_SUCCESS) break; status = atcab_genkey(AUTH_PRIV, device_public_key); if (status != ATCA_SUCCESS) break; status = atcab_get_pubkey(AUTH_PRIV, device_public_key); if (status != ATCA_SUCCESS) break; status = aws_prov_build_tbs_cert_digest(CERT_DEF_DEVICE, device_cert, &device_cert_size, signer_public_key, device_public_key, signer_id, issue_date, configdata, tbs_digest); if (status != ATCA_SUCCESS) break; status = aws_prov_save_signer_public_key(signer_public_key); if (status != ATCA_SUCCESS) break; } while(0); return status; } uint8_t AtCryptoAuthLib::aws_prov_build_tbs_cert_digest( const atcacert_def_t* cert_def, uint8_t* cert, size_t* cert_size, const uint8_t ca_public_key[64], const uint8_t public_key[64], const uint8_t signer_id[2], const atcacert_tm_utc_t* issue_date, const uint8_t config32[32], uint8_t* tbs_digest) { int ret = ATCACERT_E_SUCCESS; uint8_t key_id[20]; atcacert_build_state_t build_state; atcacert_tm_utc_t expire_date; expire_date.tm_year = issue_date->tm_year + cert_def->expire_years; expire_date.tm_mon = issue_date->tm_mon; expire_date.tm_mday = issue_date->tm_mday; expire_date.tm_hour = issue_date->tm_hour; expire_date.tm_min = 0; expire_date.tm_sec = 0; atcacert_device_loc_t config32_dev_loc; config32_dev_loc.zone = DEVZONE_CONFIG; config32_dev_loc.offset = 0; config32_dev_loc.count = 32; if (cert_def->expire_years == 0) { ret = atcacert_date_get_max_date(cert_def->expire_date_format, &expire_date); if (ret != ATCACERT_E_SUCCESS) return ret; } ret = atcacert_get_key_id(ca_public_key, key_id); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_cert_build_start(&build_state, cert_def, cert, cert_size, ca_public_key); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_set_subj_public_key(build_state.cert_def, build_state.cert, *build_state.cert_size, public_key); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_set_issue_date(build_state.cert_def, build_state.cert, *build_state.cert_size, issue_date); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_set_expire_date(build_state.cert_def, build_state.cert, *build_state.cert_size, &expire_date); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_set_signer_id(build_state.cert_def, build_state.cert, *build_state.cert_size, signer_id); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_cert_build_process(&build_state, &config32_dev_loc, config32); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_cert_build_finish(&build_state); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_get_tbs_digest(build_state.cert_def, build_state.cert, *build_state.cert_size, tbs_digest); if (ret != ATCACERT_E_SUCCESS) return ret; return ret; } int AtCryptoAuthLib::provision_save_signature( const uint8_t cert_signature[ATCA_SIG_SIZE], const uint8_t signer_id[2], const atcacert_tm_utc_t *issue_date) { int ret = ATCA_SUCCESS; do { ret = aws_prov_save_signature(AWS_DEVICE_CERT_ID, cert_signature, signer_id, issue_date); if (ret != ATCA_SUCCESS) { AWS_PRINTF("ERROR: aws_prov_save_signature %d\n", ret); break; } } while(0); return ret; } uint8_t AtCryptoAuthLib::aws_prov_save_signature( uint8_t cert_id, const uint8_t cert_signature[ATCA_SIG_SIZE], const uint8_t signer_id[2], const atcacert_tm_utc_t *issue_date) { uint8_t status = ATCA_SUCCESS; do { if (cert_id != AWS_SIGNER_CERT_ID && cert_id != AWS_DEVICE_CERT_ID) break; status = aws_prov_build_and_save_cert(cert_signature, cert_id, signer_id, issue_date); if (status != ATCA_SUCCESS) break; } while (0); return status; } uint8_t AtCryptoAuthLib::aws_prov_build_and_save_cert( const uint8_t* signature, uint8_t cert_id, const uint8_t signer_id[2], const atcacert_tm_utc_t *issue_date) { uint8_t ret = ATCA_SUCCESS; uint8_t cert[AWS_CERT_LENGH_MAX] = {0}, tbs_digest[ATCA_SHA_DIGEST_SIZE]; const atcacert_def_t* cert_def = (cert_id == AWS_SIGNER_CERT_ID) ? CERT_DEF_SIGNER : CERT_DEF_DEVICE; size_t cert_size = sizeof(cert); size_t max_cert_size = cert_size; uint8_t pub_key[ATCA_PUB_KEY_SIZE] = { 0 }; uint8_t signer_pub_key[ATCA_PUB_KEY_SIZE] = { 0 }; uint8_t configdata[ATCA_CONFIG_SIZE]; atcacert_device_loc_t device_locs[4]; size_t device_locs_count = 0; size_t i; do { ret = atcab_read_config_zone(configdata); if (ret != ATCA_SUCCESS) break; ret = atcab_get_pubkey(AUTH_PRIV, pub_key); if (ret != ATCA_SUCCESS) break; ret = aws_prov_get_signer_public_key(signer_pub_key); if (ret != ATCA_SUCCESS) break; ret = aws_prov_build_tbs_cert_digest(cert_def, cert, &cert_size, signer_pub_key, pub_key, signer_id, issue_date, configdata, tbs_digest); if (ret != ATCACERT_E_SUCCESS) break; ret = atcacert_set_signature(cert_def, cert, &cert_size, max_cert_size, signature); if (ret != ATCACERT_E_SUCCESS) return ret; ret = atcacert_get_device_locs(cert_def, device_locs, &device_locs_count, sizeof(device_locs) / sizeof(device_locs[0]), 32); if (ret != ATCACERT_E_SUCCESS) return ret; for (i = 0; i < device_locs_count; i++) { size_t end_block, start_block, block; uint8_t data[96]; if (device_locs[i].zone == DEVZONE_CONFIG) continue; if (device_locs[i].zone == DEVZONE_DATA && device_locs[i].is_genkey) continue; ret = atcacert_get_device_data(cert_def, cert, cert_size, &device_locs[i], data); if (ret != ATCACERT_E_SUCCESS) return ret; start_block = device_locs[i].offset / 32; end_block = (device_locs[i].offset + device_locs[i].count) / 32; for (block = start_block; block < end_block; block++) { ret = atcab_write_zone(device_locs[i].zone, device_locs[i].slot, (uint8_t)block, 0, &data[(block - start_block) * 32], 32); if (ret != ATCA_SUCCESS) return ret; } } } while (0); return ret; } uint8_t AtCryptoAuthLib::aws_prov_get_signer_public_key(uint8_t* public_key) { uint8_t ret = ATCA_SUCCESS; size_t end_block = 3, start_block = 0; uint8_t padded_public_key[96]; memset(padded_public_key, 0x00, sizeof(padded_public_key)); for (; start_block < end_block; start_block++) { ret = atcab_read_zone(DEVZONE_DATA, SIGNER_PUBKEY, start_block, 0, &padded_public_key[(start_block - 0) * 32], 32); if (ret != ATCA_SUCCESS) return ret; } memcpy(&public_key[32], &padded_public_key[40], 32); memcpy(&public_key[0], &padded_public_key[4], 32); return ret; } int AtCryptoAuthLib::build_signer_cert(uint8_t *signer_der, size_t *signer_der_size, uint8_t *signer_pem, size_t *signer_pem_size) { int ret = ATCACERT_E_SUCCESS; do { if (signer_der == NULL || signer_pem == NULL) { AWS_PRINTF("atca_tls_build_signer_cert: Failed: invalid param\n"); break; } ret = atcatls_get_cert(&my_signer_cert_def, NULL, signer_der, signer_der_size); if (ret != ATCACERT_E_SUCCESS) { AWS_PRINTF("Failed: read signer certificate %d\n", ret); break; } ret = atcacert_encode_pem_cert(signer_der, *signer_der_size, (char*)signer_pem, signer_pem_size); if (signer_pem_size <= 0) { AWS_PRINTF("Failed: convert signer certificate %d\n", ret); break; } } while(0); return ret; } /** * \brief Build device certificate. */ int AtCryptoAuthLib::build_device_cert(uint8_t *device_der, size_t *device_der_size, uint8_t *device_pem, size_t *device_pem_size) { uint8_t device_pubkey[64]; uint8_t signer_pubkey[64]; int ret = ATCA_SUCCESS; // read signer pub key do { if (device_der == NULL || device_pem == NULL) { AWS_PRINTF("Failed: invalid param"); break; } ret = aws_prov_get_signer_public_key(signer_pubkey); if (ret != ATCACERT_E_SUCCESS) { AWS_PRINTF("Failed: read signer certificate %d\n", ret); break; } ret = atcatls_get_cert(&my_device_cert_def, signer_pubkey, device_der, device_der_size); if (ret != ATCACERT_E_SUCCESS) { AWS_PRINTF("Failed: read device certificate %d\n", ret); break; } ret = atcacert_encode_pem_cert(device_der, *device_der_size, (char*)device_pem, device_pem_size); if (device_pem_size <= 0) { AWS_PRINTF("Failed: convert device certificate %d\n", ret); break; } ret = atcacert_get_subj_public_key(&my_device_cert_def, device_der, *device_der_size, device_pubkey); if (ret != ATCACERT_E_SUCCESS) { AWS_PRINTF("Failed: read device public key %d\n", ret); break; } } while(0); return ret; }