Seed RNG with RNG from both SE's

This commit is contained in:
Peter D. Gray 2022-03-11 13:42:49 -05:00
parent d249f74d45
commit 01cb43f7e8
No known key found for this signature in database
GPG Key ID: F0E6CC6AFC16CF7B
9 changed files with 113 additions and 12 deletions

View File

@ -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

View File

@ -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

View File

@ -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])

View File

@ -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]);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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")