You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

263 lines
6.0 KiB

// SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
// SPDX-License-Identifier: GPL-3.0-or-later
//
// SPDX-FileCopyrightText: 2018 Coinkite, Inc. <coldcardwallet.com>
// SPDX-License-Identifier: GPL-3.0-only
//
/*
* (c) Copyright 2018 by Coinkite Inc. This file is part of Coldcard <coldcardwallet.com>
* and is covered by GPLv3 license found in COPYING.
*
* SPDX-FileCopyrightText: 2020 Foundation Devices, Inc. <hello@foundationdevices.com>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_uart.h"
#include "stm32h7xx_hal_uart_ex.h"
#include "utils.h"
#include "pprng.h"
#include "sha256.h"
#include "secrets.h"
#include "se.h"
#include "se-config.h"
#include "se-atecc608a.h"
// Selectable debug level; keep them as comments regardless
#if 0
// break on any error: not helpful since some are normal
# define ERR(msg) BREAKPOINT;
# define ERRV(val, msg) BREAKPOINT;
#else
# define ERR(msg)
# define ERRV(val, msg)
#endif
// Must be exactly 32 chars:
// static const char *copyright_msg = "Copyright 2020- by Foundati Inc.";
// keep this in place.
#define RET_IF_BAD(rv) do { if(rv) return rv; } while(0)
bool se_probe()
{
int chk;
se_sleep();
se_wake();
// Expect 0x11
chk = se_read1();
if (chk != SE_AFTER_WAKE)
return false;
se_sleep();
return true;
}
// Do Info(p1=2) command, and return result.
//
uint16_t se_get_info(void)
{
int rc;
// not doing error checking here
se_write(OP_Info, 0x2, 0, NULL, 0);
// note: always returns 4 bytes, but most are garbage and unused.
uint8_t tmp[4];
rc = se_read(tmp, 4);
se_sleep();
if (rc < 0)
return -1;
return (tmp[0] << 8) | tmp[1];
}
// Load Tempkey with a specific value. Resulting Tempkey cannot be
// used with many commands/keys, but is needed for signing.
//
int se_load_nonce(uint8_t *nonce)
{
uint8_t rc;
// p1=3
se_write(OP_Nonce, 3, 0, nonce, 32); // 608a ok
rc = se_read1();
se_sleep();
if (rc != 0)
return -1;
return 0;
}
// Sign a message (already digested)
//
int se_sign(uint8_t keynum, uint8_t msg_hash[32], uint8_t signature[64])
{
int rc;
rc = se_load_nonce(msg_hash);
if (rc < 0)
return -1;
se_write(OP_Sign, 0x80, keynum, NULL, 0);
rc = se_read(signature, 64);
se_sleep();
if (rc < 0)
return -1;
return 0;
}
// Use old SHA256 command from 508A, but with new flags.
//
int se_hmac32(uint8_t keynum, uint8_t msg[32], uint8_t digest[32])
{
int rc;
// Start SHA w/ HMAC setup
se_write(OP_SHA, 4, keynum, NULL, 0); // 4 = HMAC_Init
rc = se_read1();
if (rc != 0)
return -1;
// send the contents to be hashed
se_write(OP_SHA, (3<<6) | 2, 32, msg, 32); // 2 = Finalize, 3=Place output
rc = se_read(digest, 32);
se_sleep();
return rc;
}
// Return the serial number: it's 9 bytes, altho 3 are fixed.
//
int se_get_serial(uint8_t serial[6])
{
int rc;
uint8_t temp[32];
se_write(OP_Read, 0x80, 0x0, NULL, 0);
rc = se_read(temp, 32);
se_sleep();
if (rc < 0)
return -1;
// reformat to 9 bytes.
uint8_t ts[9];
memcpy(ts, &temp[0], 4);
memcpy(&ts[4], &temp[8], 5);
// check the hard-coded values
if ((ts[0] != 0x01) || (ts[1] != 0x23) || (ts[8] != 0xEE)) return 1;
// save only the unique bits.
memcpy(serial, ts+2, 6);
return 0;
}
int se_destroy_key(int keynum)
{
int rc;
uint8_t numin[20];
// Load tempkey with a known (random) nonce value
rng_buffer(numin, sizeof(numin));
se_write(OP_Nonce, 0, 0, numin, 20);
// Nonce command returns the RNG result, not contents of TempKey,
// but since we are destroying, no need to calculate what it is.
uint8_t randout[32];
rc = se_read(randout, 32);
if (rc < 0)
return -1;
// do a "DeriveKey" operation, based on that!
se_write(OP_DeriveKey, 0x00, keynum, NULL, 0);
rc = se_read1();
se_sleep();
if (rc != 0)
return -1;
return 0;
}
// Do on-chip hashing, with lots of iterations.
//
// - using HMAC-SHA256 with keys that are known only to the 608a.
// - rate limiting factor here is communication time w/ 608a, not algos.
// - caution: result here is not confidential
// - cost of each iteration, approximately: 8ms
// - but our time to do each iteration is limited by software SHA256 in se_pair_unlock
//
int se_stretch_iter(
const uint8_t *start,
uint8_t *end,
int iterations
)
{
if (start == end) {
return -1;
}
memcpy(end, start, 32);
for (int i = 0; i < iterations; i++) {
// must unlock again, because pin_stretch is an auth'd key
if (se_pair_unlock())
return -2;
int rv = se_hmac32(KEYNUM_pin_stretch, end, end);
if (rv < 0)
return -1;
}
return 0;
}
// Apply HMAC using secret in chip as a HMAC key, then encrypt
// the result a little because read in clear over bus.
//
int se_mixin_key(
uint8_t keynum,
uint8_t *start,
uint8_t *end
)
{
int rc;
if (start == end) {
return -1;
}
rc = se_pair_unlock();
if (rc < 0)
return -1;
if (keynum != 0) {
rc = se_hmac32(keynum, start, end);
if (rc < 0)
return -1;
} else {
memset(end, 0, 32);
}
// Final value was just read over bus w/o any protection, but
// we won't be using that, instead, mix in the pairing secret.
//
// Concern: what if mitm gave us some zeros or other known pattern here. We will
// use the value provided in cleartext[sic--it's not] write back shortly (to test it).
// Solution: one more SHA256, and to be safe, mixin lots of values!
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, rom_secrets->pairing_secret, 32);
sha256_update(&ctx, start, 32);
sha256_update(&ctx, &keynum, 1);
sha256_update(&ctx, end, 32);
sha256_final(&ctx, end);
return 0;
}