Seed RNG with RNG from both SE's
This commit is contained in:
parent
d249f74d45
commit
01cb43f7e8
@ -105,4 +105,13 @@ def mcu_key_usage():
|
||||
ckcc.gate(25, arg, 0);
|
||||
return unpack('3I', arg)
|
||||
|
||||
def read_rng(source=2):
|
||||
# return random bytes from a secure source
|
||||
# - first byte is # of valid random bytes
|
||||
arg = bytearray(33)
|
||||
rv = ckcc.gate(26, arg, source);
|
||||
assert not rv
|
||||
return arg[1:1+arg[0]]
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
@ -39,6 +39,19 @@ COLDCARD Virtual Disk
|
||||
# generally, leave it unmounted
|
||||
os.umount('/psram')
|
||||
|
||||
def rng_seeding():
|
||||
# seed our RNG with entropy from secure elements
|
||||
import callgate, ngu, ustruct
|
||||
|
||||
a = callgate.read_rng(1) # SE1
|
||||
b = callgate.read_rng(2) # SE2
|
||||
|
||||
n = ngu.hash.sha256d(a+b)
|
||||
n, = ustruct.unpack('I', n[0:4])
|
||||
|
||||
ngu.random.reseed(n)
|
||||
|
||||
|
||||
def init0():
|
||||
# called very early
|
||||
try:
|
||||
@ -57,6 +70,9 @@ def init0():
|
||||
import sim_display
|
||||
except: pass
|
||||
|
||||
# seed RNGs with entropy from secure elements
|
||||
rng_seeding()
|
||||
|
||||
async def dev_enable_repl(*a):
|
||||
# Mk4: Enable serial port connection. You'll have to break case open.
|
||||
from ux import ux_show_story
|
||||
|
||||
@ -670,11 +670,11 @@ ae_send_n(aeopcode_t opcode, uint8_t p1, uint16_t p2, const uint8_t *data, uint8
|
||||
}
|
||||
|
||||
#if 0
|
||||
// RISKY - Easy for Mitm to control value.
|
||||
|
||||
// ae_random()
|
||||
//
|
||||
// Get a fresh random number.
|
||||
//
|
||||
// RISKY - Easy for Mitm to control value.
|
||||
//
|
||||
int
|
||||
ae_random(uint8_t randout[32])
|
||||
@ -690,6 +690,29 @@ ae_random(uint8_t randout[32])
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// ae_secure_random()
|
||||
//
|
||||
// Generate a random number, using nonces generated by chip and by us.
|
||||
// Verify the result was not modified by MitM.
|
||||
//
|
||||
int
|
||||
ae_secure_random(uint8_t randout[32])
|
||||
{
|
||||
// Generate a digest of pairing secret slot, which will include
|
||||
// a nonce from chip.
|
||||
int rv = ae_gendig_slot(KEYNUM_pairing, rom_secrets->pairing_secret, randout);
|
||||
|
||||
// Verify digest was made using inputs we think.
|
||||
if(rv || !ae_is_correct_tempkey(randout)) {
|
||||
fatal_mitm();
|
||||
}
|
||||
|
||||
// since that value is "tempkey" inside the secure element, it feels
|
||||
// wrong to share that directly, so hash it up.
|
||||
sha256_single(randout, 32, randout);
|
||||
}
|
||||
|
||||
// ae_get_info()
|
||||
//
|
||||
// Do Info(p1=2) command, and return result.
|
||||
@ -825,7 +848,7 @@ ae_is_correct_tempkey(const uint8_t expected_tempkey[32])
|
||||
//
|
||||
// Check the chip produces a hash over various things the same way we would
|
||||
// meaning that we both know the shared secret and the state of stuff in
|
||||
// the 508a is what we expect.
|
||||
// the chip is what we expect.
|
||||
//
|
||||
int
|
||||
ae_checkmac_hard(uint8_t keynum, const uint8_t secret[32])
|
||||
|
||||
@ -88,7 +88,8 @@ int ae_delay_time(aeopcode_t opcode);
|
||||
void ae_keep_alive(void);
|
||||
|
||||
// Pick a fresh random number.
|
||||
int ae_random(uint8_t randout[32]);
|
||||
//int ae_random(uint8_t randout[32]);
|
||||
int ae_secure_random(uint8_t randout[32]);
|
||||
|
||||
// Pick a EC keypair and return public part; private saved.
|
||||
int ae_gen_ecc_key(uint8_t keynum, uint8_t pubkey_out[64]);
|
||||
|
||||
@ -562,6 +562,33 @@ firewall_dispatch(int method_num, uint8_t *buf_io, int len_in,
|
||||
break;
|
||||
}
|
||||
|
||||
case 26: {
|
||||
// Read some random bytes from various sources, like SE's.
|
||||
REQUIRE_OUT(33);
|
||||
|
||||
switch(arg2) {
|
||||
case 1: // for SE1
|
||||
// LIMITATION: this has no MitM protection, subject to tampering
|
||||
ae_setup();
|
||||
int rv = ae_secure_random(&buf_io[1]);
|
||||
if(rv) fatal_mitm();
|
||||
buf_io[0] = 32;
|
||||
break;
|
||||
|
||||
case 2: // for SE2
|
||||
// secure, requires knowledge of pairing secret
|
||||
se2_read_rng(&buf_io[1]);
|
||||
buf_io[0] = 8;
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = ERANGE;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#if 0
|
||||
// p256r1 test code
|
||||
case 130: { // verify signature
|
||||
|
||||
@ -1273,8 +1273,6 @@ se2_pin_hash(uint8_t digest_io[32], uint32_t purpose)
|
||||
uint8_t tmp[32];
|
||||
HMAC_CTX ctx;
|
||||
|
||||
//sdcard_light(true);
|
||||
|
||||
// HMAC(key=tpin_key, msg=given hash so far)
|
||||
hmac_sha256_init(&ctx);
|
||||
hmac_sha256_update(&ctx, digest_io, 32);
|
||||
@ -1308,14 +1306,24 @@ se2_pin_hash(uint8_t digest_io[32], uint32_t purpose)
|
||||
hmac_sha256_update(&ctx, rx+2, 32);
|
||||
hmac_sha256_update(&ctx, digest_io, 32);
|
||||
hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, digest_io);
|
||||
#if 0
|
||||
sdcard_light(false);
|
||||
}
|
||||
|
||||
puts2("md: ");
|
||||
hex_dump(digest_io, 32);
|
||||
// se2_read_rng()
|
||||
//
|
||||
// Read some random bytes, which we know cannot be MitM'ed.
|
||||
//
|
||||
void
|
||||
se2_read_rng(uint8_t value[8])
|
||||
{
|
||||
// funny business means MitM here
|
||||
se2_setup();
|
||||
if(setjmp(error_env)) fatal_mitm();
|
||||
|
||||
memset(digest_io, 0x1, 32);
|
||||
#endif
|
||||
// read a field with "RPS" bytes, and verify those were read true
|
||||
uint8_t tmp[32];
|
||||
se2_read_page(PGN_ROM_OPTIONS, tmp, true);
|
||||
|
||||
memcpy(value, &tmp[4], 8);
|
||||
}
|
||||
|
||||
// EOF
|
||||
|
||||
@ -86,4 +86,7 @@ void se2_decrypt_secret(uint8_t secret[], int secret_len, int offset,
|
||||
const uint8_t main_slot[], const uint8_t *check_value,
|
||||
const uint8_t pin_digest[32], bool *is_valid);
|
||||
|
||||
// Read some random bytes, which we know cannot be MitM'ed.
|
||||
void se2_read_rng(uint8_t value[8]);
|
||||
|
||||
// EOF
|
||||
|
||||
@ -160,6 +160,18 @@ def gate(method, buf_io, arg2):
|
||||
ustruct.pack_into('3I', buf_io, 0, N-5, 1, N)
|
||||
return 0
|
||||
|
||||
if method == 26:
|
||||
# read RNG (not) from SE (not)
|
||||
if arg2 == 1:
|
||||
buf_io[0] = 32
|
||||
buf_io[1:1+32] = bytes(range(32))
|
||||
elif arg2 == 2:
|
||||
buf_io[0] = 8
|
||||
buf_io[1:1+8] = bytes(range(8))
|
||||
else:
|
||||
return ERANGE;
|
||||
return 0
|
||||
|
||||
return ENOENT
|
||||
|
||||
def oneway(method, arg2):
|
||||
|
||||
@ -18,6 +18,8 @@ def _init0():
|
||||
import sim_nfc
|
||||
sys.modules['nfc'] = sim_nfc
|
||||
|
||||
mk4.rng_seeding()
|
||||
|
||||
mk4.init0 = _init0
|
||||
mk4.make_flash_fs = lambda: print("Would rebuild /flash")
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user