Hash PIN w/ SE2 secrets

This commit is contained in:
Peter D. Gray 2022-03-01 11:51:14 -05:00
parent bf86c9e61b
commit e4ad63097c
No known key found for this signature in database
GPG Key ID: F0E6CC6AFC16CF7B
8 changed files with 96 additions and 13 deletions

View File

@ -111,6 +111,8 @@ $(OBJS): Makefile
$(TARGETS): $(TARGET_ELF) Makefile
version.o: version.h
# makes the .py from a shared header file
sigheader.py: mk-sigheader.py sigheader.h
python3 mk-sigheader.py

View File

@ -31,9 +31,6 @@ firewall_setup(void)
return;
}
#if 0
enabled firewall, even debg
#if RELEASE
// REMINDERS:
// - cannot debug anything in boot loader w/ firewall enabled (no readback, no bkpt)
@ -47,7 +44,6 @@ enabled firewall, even debg
#else
// for debug builds, never enable firewall
return;
#endif
#endif
extern int firewall_starts; // see startup.S ... aligned@256 (0x08000300)

View File

@ -27,12 +27,6 @@
// - solution: adjust both the target and counter (upwards)
#define MAX_TARGET_ATTEMPTS 13
// Pretty sure it doesn't matter, but adding some salt into our PIN->bytes[32] code
// based on the purpose of the PIN code.
//
#define PIN_PURPOSE_NORMAL 0x334d1858
#define PIN_PURPOSE_WORDS 0x2e6d6773
// Hash up a PIN for indicated purpose.
static void pin_hash(const char *pin, int pin_len, uint8_t result[32], uint32_t purpose);
@ -120,13 +114,16 @@ pin_hash(const char *pin, int pin_len, uint8_t result[32], uint32_t purpose)
SHA256_CTX ctx;
sha256_init(&ctx);
sha256_update(&ctx, rom_secrets->pairing_secret, 32);
sha256_update(&ctx, rom_secrets->hash_cache_secret, 32);
sha256_update(&ctx, (uint8_t *)&purpose, 4);
sha256_update(&ctx, (uint8_t *)pin, pin_len);
sha256_update(&ctx, rom_secrets->pairing_secret, 32);
sha256_final(&ctx, result);
// and run that thru SE2 as well
se2_pin_hash(result, purpose);
// and a second-sha256 on that, just in case.
sha256_single(result, 32, result);
}

View File

@ -91,6 +91,12 @@ enum {
EPIN_SE2_FAIL = -115, // (mk4) some issue w/ SE2
};
// Pretty sure it doesn't matter, but adding some salt into our PIN->bytes[32] code
// based on the purpose of the PIN code.
//
#define PIN_PURPOSE_NORMAL 0x334d1858
#define PIN_PURPOSE_WORDS 0x2e6d6773
// early setup
void pin_setup0(void);

View File

@ -462,6 +462,31 @@ se2_clear_volatile(void)
CHECK_RIGHT(se2_read1() == RC_SUCCESS);
}
// se2_set_counter()
//
// Can only be done once. Trusted env.
//
static void
se2_set_counter(uint32_t val)
{
uint8_t tmp[32];
se2_read_page(PGN_DEC_COUNTER, tmp, false);
// datasheet says will read as "random data" if not yet set, but
// observed 0xff, 0xff, 0xff, 0...0 (which is an illegal value, since only 17 bits)
if(tmp[2] == 0xff) {
tmp[0] = val & 0x0ff;
tmp[1] = (val >> 8) & 0x0ff;
tmp[2] = (val >> 16) & 0x01;
se2_write_page(PGN_DEC_COUNTER, tmp);
} else {
puts("ctr set?"); // not expected, but keep going
}
}
// se2_setup_config()
//
// One-time config and lockdown of the SE2 chip.
@ -507,7 +532,7 @@ se2_setup_config(void)
memcpy(_tbd.romid, tmp+24, 8);
// forget a secret - B (will not be used)
// forget a secret - B (will not be saved)
rng_buffer(tmp, 32);
se2_write_page(PGN_SECRET_B, tmp);
@ -560,6 +585,9 @@ se2_setup_config(void)
se2_set_protection(PGN_ROM_OPTIONS, PROT_APH); // not planning to change
// Need known value in counter, write once.
se2_set_counter(128);
// NOTE: PGN_SE2_HARD_KEY and PUBKEY_C not yet known
}
@ -1214,4 +1242,52 @@ se2_decrypt_secret(uint8_t secret[], int secret_len, int offset,
aes_done(&ctx, secret, secret_len, aes_key, nonce);
}
// se2_pin_hash()
//
// Hash up a PIN code for login attempt: to tie it into SE2's contents.
//
void
se2_pin_hash(uint8_t digest_io[32], uint32_t purpose)
{
se2_setup();
if((setjmp(error_env))) {
oled_show(screen_se2_issue);
LOCKUP_FOREVER();
}
uint8_t tmp[32];
HMAC_CTX ctx;
// HMAC(key=tpin_key, msg=given hash so far)
hmac_sha256_init(&ctx);
hmac_sha256_update(&ctx, digest_io, 32);
hmac_sha256_update(&ctx, (uint8_t *)&purpose, 4);
hmac_sha256_final(&ctx, SE2_SECRETS->tpin_key, tmp);
// NOTE: exposed as cleartext here
se2_write_buffer(tmp, 32);
// HMAC(key=secret-B (we dont know it, but set random), msg=pubkeyA+buffer+junk)
// - result put in secret-S (ram)
CALL_CHECK(se2_write2(0x3c, (2<<6) | (1<<4) | PGN_SECRET_B, 0));
CHECK_RIGHT(se2_read1() == RC_SUCCESS);
// .. HMAC(key=S, msg=counter), so we have something to read out
se2_write_buffer(tmp, 32);
CALL_CHECK(se2_write1(0xa5, (2<<5) | PGN_DEC_COUNTER));
uint8_t rx[34];
CHECK_RIGHT(se2_read_n(sizeof(rx), rx) == RC_SUCCESS);
CHECK_RIGHT(rx[1] == RC_SUCCESS);
memcpy(digest_io, rx+2, 32);
// 12-12 => 606ad30d10c4683b7478aa6ffd09c644e7de6091d2cdcfb58bb698c7cfa90934
//puts2("md: ");
//hex_dump(digest_io, 32);
}
// EOF

View File

@ -61,6 +61,9 @@ void se2_save_auth_pubkey(const uint8_t pubkey[64]);
// call if a completely unknown PIN is provided
void se2_handle_bad_pin(int num_fails);
// hash up a PIN code for login attempt: to tie it into SE2's contents
void se2_pin_hash(uint8_t digest_io[32], uint32_t purpose);
#if 0
// secp256r1 curve functions.
bool p256_verify(const uint8_t pubkey[64], const uint8_t digest[32], const uint8_t signature[64]);

View File

@ -769,6 +769,9 @@ fast_brick(void)
// brick SE1 for future
ae_brick_myself();
// NOTE: could brick SE1 (somewhat) by dec'ing the counter, which will
// invalidate all PIN hashes
// no going back from that -- but for privacy, wipe more stuff
oled_show(screen_brick);
puts2("fast brick... ");

View File

@ -5,7 +5,7 @@
#include <stdint.h>
// Public version number for humans. Lots more version data added by Makefile.
#define RELEASE_VERSION "3.0.4"
#define RELEASE_VERSION "3.1.0"
extern const char version_string[];