From f3043d2606f0aab92d58cf45152239919e4b2c05 Mon Sep 17 00:00:00 2001 From: Conor Date: Sat, 12 Mar 2016 11:36:31 -0500 Subject: [PATCH] omg it works --- firmware/inc/u2f.h | 21 +++++-- firmware/src/main.c | 37 +------------ firmware/src/u2f-atecc.c | 31 +++++++++-- firmware/src/u2f.c | 117 ++++++++++++++++++++++++++++----------- firmware/src/u2f_hid.c | 23 ++++---- 5 files changed, 141 insertions(+), 88 deletions(-) diff --git a/firmware/inc/u2f.h b/firmware/inc/u2f.h index 417cee2..ababbe4 100644 --- a/firmware/inc/u2f.h +++ b/firmware/inc/u2f.h @@ -10,10 +10,6 @@ #include -#define SW_NO_ERROR 0x00 -#define SW_CONDITIONS_NOT_SATISFIED 0x01 -#define SW_WRONG_DATA 0x02 - #define U2F_EC_FMT_UNCOMPRESSED 0x04 #define U2F_EC_POINT_SIZE 32 @@ -37,6 +33,9 @@ #define U2F_REGISTER_ID 0x05 #define U2F_REGISTER_HASH_ID 0x00 +// U2F Authenticate +#define U2F_AUTHENTICATE_CHECK 0x7 + struct u2f_request_apdu { @@ -63,6 +62,14 @@ struct u2f_register_request uint8_t app[U2F_APPLICATION_SIZE]; }; +struct u2f_authenticate_request +{ + uint8_t chal[U2F_CHALLENGE_SIZE]; + uint8_t app[U2F_APPLICATION_SIZE]; + uint8_t khl; + uint8_t kh[U2F_KEY_HANDLE_SIZE]; +} ; + void u2f_request(struct u2f_request_apdu* req); @@ -123,6 +130,12 @@ int8_t u2f_ecdsa_sign(uint8_t * dest, uint8_t * handle); // @return -1 for failure, 0 for success int8_t u2f_new_keypair(uint8_t * handle, uint8_t * pubkey); +// Load a key into memory or check to see that the handle exists +// @handle the key handle to check +// @len the length of key handle in bytes +// @return -1 if it doesn't exist, 0 for success +int8_t u2f_load_key(uint8_t * handle, uint8_t len); + // method to return pointer to attestation cert uint8_t * u2f_get_attestation_cert(); diff --git a/firmware/src/main.c b/firmware/src/main.c index 363741e..ee53d1f 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -45,7 +45,7 @@ void dump_eeprom() // 0xF800 - 0xFB7F uint16_t i = 0xF800; uint8_t eep; - for (; i <= 0xF800 + 196; i++) + for (; i <= 0xF800 + 4 * 16; i++) { eeprom_read(i,&eep,1); u2f_putb(eep); @@ -56,40 +56,7 @@ void dump_eeprom() int8_t test_app() { -// uint8_t i[] = {0x5,U2F_EC_FMT_UNCOMPRESSED}; -// -// uint8_t key_handle[U2F_KEY_HANDLE_SIZE]; -// uint8_t pubkey[64]; -// -// u2f_prints("u2f_register\r\n"); -// -// if (u2f_get_user_feedback() != 0) -// { -// u2f_prints("u2f_get_user_feedback fail\r\n"); -// return U2F_SW_CONDITIONS_NOT_SATISFIED; -// } -// -// u2f_prints("u2f_new_keypair\r\n"); -// if ( u2f_new_keypair(key_handle, pubkey) == -1) -// { -// u2f_prints("u2f_new_keypair fail\r\n"); -// return U2F_SW_CONDITIONS_NOT_SATISFIED; -// } -// -// u2f_prints("u2f_sha\r\n"); -// u2f_sha256_start(); -// u2f_sha256_update(i,1); -// u2f_sha256_update(pubkey,32); -// u2f_sha256_update(pubkey,32); -// u2f_sha256_update(key_handle,U2F_KEY_HANDLE_SIZE); -// u2f_sha256_update(i+1,1); -// u2f_sha256_update(pubkey,64); -// u2f_sha256_finish(); -// if (u2f_ecdsa_sign(pubkey, U2F_ATTESTATION_HANDLE) == -1) -// { -// return SW_WRONG_DATA; -// } - + dump_eeprom(); return 0; } diff --git a/firmware/src/u2f-atecc.c b/firmware/src/u2f-atecc.c index 1951805..70fcda4 100644 --- a/firmware/src/u2f-atecc.c +++ b/firmware/src/u2f-atecc.c @@ -134,7 +134,7 @@ int8_t u2f_ecdsa_sign(uint8_t * dest, uint8_t * handle) { struct atecc_response res; struct key_handle k; - uint16_t keyslot = ((struct key_handle *)handle)->index; + uint16_t keyslot = (uint16_t)((struct key_handle *)handle)->index; if (keyslot > U2F_NUM_KEYS) { return -1; @@ -147,6 +147,7 @@ int8_t u2f_ecdsa_sign(uint8_t * dest, uint8_t * handle) { keyslot--; } + atecc_send_recv(ATECC_CMD_SIGN, ATECC_SIGN_EXTERNAL, keyslot, NULL, 0, appdata.tmp, sizeof(appdata.tmp), &res); @@ -156,7 +157,7 @@ int8_t u2f_ecdsa_sign(uint8_t * dest, uint8_t * handle) eeprom_read(U2F_KEY_ADDR(keyslot), (uint8_t* )&k, U2F_KEY_HANDLE_SIZE); if ( - ((struct key_handle *)handle)->index-1 != k.index || + ((struct key_handle *)handle)->index != k.index || ((struct key_handle *)handle)->entropy[0] != k.entropy[0] || ((struct key_handle *)handle)->entropy[1] != k.entropy[1] || ((struct key_handle *)handle)->entropy[2] != k.entropy[2] @@ -189,12 +190,12 @@ int8_t u2f_new_keypair(uint8_t * handle, uint8_t * pubkey) memmove(pubkey, res.buf, 64); eeprom_read(U2F_KEY_ADDR(keyslot), (uint8_t* )&k, U2F_KEY_HANDLE_SIZE); - if (k.index != keyslot) + if (k.index-1 != keyslot) { + k.index = keyslot; set_app_error(ERROR_BAD_KEY_STORE); } - k.index++; memmove(handle, &k, U2F_KEY_HANDLE_SIZE); key_store.num_issued++; flush_key_store(); @@ -202,6 +203,28 @@ int8_t u2f_new_keypair(uint8_t * handle, uint8_t * pubkey) return 0; } +int8_t u2f_load_key(uint8_t * handle, uint8_t len) +{ + struct key_handle k; + uint8_t keyslot = handle[0]-1; + if (keyslot >= U2F_NUM_KEYS) + { + return -1; + } + eeprom_read(U2F_KEY_ADDR(keyslot), (uint8_t* )&k, U2F_KEY_HANDLE_SIZE); + + if ( + handle[0] != k.index || + ((struct key_handle *)handle)->entropy[0] != k.entropy[0] || + ((struct key_handle *)handle)->entropy[1] != k.entropy[1] || + ((struct key_handle *)handle)->entropy[2] != k.entropy[2] + ) + { + return -1; + } + return 0; +} + code char __attest[] = "\x30\x82\x01\x5b\x30\x82\x01\x00\x02\x01\x01\x30\x0a\x06\x08\x2a\x86\x48\xce\x3d" "\x04\x03\x02\x30\x39\x31\x0b\x30\x09\x06\x03\x55\x04\x06\x13\x02\x56\x41\x31\x14" diff --git a/firmware/src/u2f.c b/firmware/src/u2f.c index dc12e06..6b90ad9 100644 --- a/firmware/src/u2f.c +++ b/firmware/src/u2f.c @@ -14,6 +14,7 @@ // void u2f_response_writeback(uint8_t * buf, uint8_t len); static int16_t u2f_register(struct u2f_register_request * req); static int16_t u2f_version(); +static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control); void u2f_request(struct u2f_request_apdu * req) { @@ -27,6 +28,7 @@ void u2f_request(struct u2f_request_apdu * req) break; case U2F_AUTHENTICATE: u2f_prints("U2F_AUTHENTICATE\r\n"); + *rcode = u2f_authenticate((struct u2f_authenticate_request*)req->payload, req->p1); break; case U2F_VERSION: u2f_prints("U2F_VERSION\r\n"); @@ -39,21 +41,96 @@ void u2f_request(struct u2f_request_apdu * req) u2f_prints("U2F_VENDOR_LAST\r\n"); break; default: - break; } u2f_response_writeback((uint8_t*)rcode,2); u2f_response_flush(); } +static uint8_t get_signature_length(uint8_t * sig) +{ + return 0x46 + ((sig[32] & 0x80) == 0x80) + ((sig[0] & 0x80) == 0x80); +} + +static void dump_signature_der(uint8_t * sig) +{ + uint8_t pad_s = (sig[32] & 0x80) == 0x80; + uint8_t pad_r = (sig[0] & 0x80) == 0x80; + uint8_t i[] = {0x30, 0x44}; + i[1] += (pad_s + pad_r); + + + // DER encoded signature + // write der sequence + // has to be minimum distance and padded with 0x00 if MSB is a 1. + u2f_response_writeback(i,2); + i[1] = 0; + + // length of R value plus 0x00 pad if necessary + u2f_response_writeback("\x02",1); + i[0] = 0x20 + pad_r; + u2f_response_writeback(i,1 + pad_r); + + // R value + u2f_response_writeback(sig, 32); + + // length of S value plus 0x00 pad if necessary + u2f_response_writeback("\x02",1); + i[0] = 0x20 + pad_s; + u2f_response_writeback(i,1 + pad_s); + + // S value + u2f_response_writeback(sig+32, 32); +} + +// TODO replace with atecc +static uint32_t _count = 1; + +static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) +{ + + uint8_t up = 1; + if (u2f_load_key(req->kh, req->khl) != 0) + { + u2f_hid_set_len(2); + return U2F_SW_WRONG_DATA; + } + else if (control == U2F_AUTHENTICATE_CHECK) + { + u2f_hid_set_len(2); + return U2F_SW_CONDITIONS_NOT_SATISFIED; + } + _count++; + + u2f_sha256_start(); + u2f_sha256_update(req->app,32); + u2f_sha256_update(&up,1); + u2f_sha256_update(&_count,4); + u2f_sha256_update(req->chal,32); + + u2f_sha256_finish(); + + if (u2f_ecdsa_sign((uint8_t*)req, req->kh) == -1) + { + return U2F_SW_WRONG_DATA; + } + + u2f_hid_set_len(7 + get_signature_length((uint8_t*)req)); + + u2f_response_writeback(&up,1); + u2f_response_writeback(&_count,4); + dump_signature_der((uint8_t*)req); + + return U2F_SW_NO_ERROR; +} + static int16_t u2f_register(struct u2f_register_request * req) { uint8_t i[] = {0x0,U2F_EC_FMT_UNCOMPRESSED}; uint8_t key_handle[U2F_KEY_HANDLE_SIZE]; uint8_t pubkey[64]; - uint8_t pad_s = 0; - uint8_t pad_r = 0; + const uint16_t attest_size = u2f_attestation_cert_size(); @@ -66,14 +143,13 @@ static int16_t u2f_register(struct u2f_register_request * req) { return U2F_SW_CONDITIONS_NOT_SATISFIED; } + u2f_sha256_start(); u2f_sha256_update(i,1); u2f_sha256_update(req->app,32); - u2f_sha256_update(req->chal,32); - u2f_sha256_update(key_handle,U2F_KEY_HANDLE_SIZE); u2f_sha256_update(i+1,1); u2f_sha256_update(pubkey,64); @@ -81,13 +157,10 @@ static int16_t u2f_register(struct u2f_register_request * req) if (u2f_ecdsa_sign((uint8_t*)req, U2F_ATTESTATION_HANDLE) == -1) { - return SW_WRONG_DATA; + return U2F_SW_WRONG_DATA; } - pad_r = (((uint8_t*)req)[0] & 0x80) == 0x80; - pad_s = (((uint8_t*)req)[32] & 0x80) == 0x80; - - u2f_hid_set_len(139 + pad_s + pad_r + U2F_KEY_HANDLE_SIZE + u2f_attestation_cert_size()); + u2f_hid_set_len(69 + get_signature_length((uint8_t*)req) + U2F_KEY_HANDLE_SIZE + u2f_attestation_cert_size()); i[0] = 0x5; u2f_response_writeback(i,2); u2f_response_writeback(pubkey,64); @@ -97,29 +170,7 @@ static int16_t u2f_register(struct u2f_register_request * req) u2f_response_writeback(u2f_get_attestation_cert(),u2f_attestation_cert_size()); - // DER encoding - // write der sequence - // has to be minimum distance and padded with 0x00 if MSB is a 1. - i[0] = 0x30; - i[1] = 0x44 + pad_r + pad_s; - u2f_response_writeback(i,2); - i[1] = 0; - - // length of R value plus 0x00 pad if necessary - u2f_response_writeback("\x02",1); - i[0] = 0x20 + pad_r; - u2f_response_writeback(i,1 + pad_r); - - // R value - u2f_response_writeback((uint8_t*)req, 32); - - // length of S value plus 0x00 pad if necessary - u2f_response_writeback("\x02",1); - i[0] = 0x20 + pad_s; - u2f_response_writeback(i,1 + pad_s); - - // S value - u2f_response_writeback(((uint8_t*)req)+32, 32); + dump_signature_der((uint8_t*)req); return U2F_SW_NO_ERROR; diff --git a/firmware/src/u2f_hid.c b/firmware/src/u2f_hid.c index 1876f4c..8b25c46 100644 --- a/firmware/src/u2f_hid.c +++ b/firmware/src/u2f_hid.c @@ -82,7 +82,6 @@ void u2f_hid_set_len(uint16_t len) static void u2f_hid_reset_packet() { - u2f_prints("HID RESET\r\n"); _hid_seq = 0; _hid_offset = 0; _hid_in_session = 0; @@ -253,7 +252,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) switch(hid_layer.current_cmd) { case U2FHID_INIT: - u2f_printlx("got init packet ",1,req->cid); + //u2f_printlx("got init packet ",1,req->cid); if (U2FHID_LEN(req) != 8) { // this one is safe @@ -263,7 +262,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) } u2f_hid_set_len(17); - u2f_printlx("cid: ",1,hid_layer.current_cid); + //u2f_printlx("cid: ",1,hid_layer.current_cid); if (hid_layer.current_cid == 0) { u2f_prints("out of cid's\r\n"); @@ -293,7 +292,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) u2f_prints("invalid len msg\r\n"); goto fail; } - u2f_prints("U2FHID_MSG\r\n"); + //u2f_prints("U2FHID_MSG\r\n"); // buffer 2 payloads (120 bytes) to get full U2F message // assuming key handle is < 45 bytes // 7 bytes for apdu header @@ -317,7 +316,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) break; case U2FHID_PING: - u2f_prints("U2F PING\r\n"); + //u2f_prints("U2F PING\r\n"); if (!u2f_hid_busy()) { @@ -333,7 +332,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) break; case U2FHID_WINK: - u2f_prints("U2F WINK\r\n"); + //u2f_prints("U2F WINK\r\n"); if (U2FHID_LEN(req) != 0) { // this one is safe @@ -347,7 +346,7 @@ static void hid_u2f_parse(struct u2f_hid_msg* req) break; case U2FHID_LOCK: // TODO - u2f_prints("U2F LOCK\r\n"); + //u2f_prints("U2F LOCK\r\n"); break; default: u2f_printb("invalid cmd: ", hid_layer.current_cmd); @@ -380,7 +379,7 @@ void u2f_hid_request(struct u2f_hid_msg* req) else { // Ignore CID's we did not allocate. - u2f_printlx("ignoring pkt ",1,req->cid); + //u2f_printlx("ignoring pkt ",1,req->cid); return; } @@ -393,7 +392,7 @@ void u2f_hid_request(struct u2f_hid_msg* req) { if (U2FHID_LEN(req) > U2FHID_MAX_PAYLOAD_SIZE) { - u2f_prints("length too big\r\n"); + //u2f_prints("length too big\r\n"); stamp_error(req->cid, ERR_INVALID_LEN); return; } @@ -419,7 +418,7 @@ void u2f_hid_request(struct u2f_hid_msg* req) if (req->pkt.init.cmd & TYPE_INIT) { // TODO - u2f_prints("this should resync but im lazy\r\n"); + //u2f_prints("this should resync but im lazy\r\n"); } hid_layer.last_buffered = get_ms(); // TODO verify packets arrive in ascending order @@ -428,7 +427,7 @@ void u2f_hid_request(struct u2f_hid_msg* req) else if (U2FHID_TIMEOUT(&hid_layer)) { // return timeout error for old channel and run again for new channel - u2f_prints("timeout, switching\r\n"); + //u2f_prints("timeout, switching\r\n"); hid_layer.state = HID_READY; u2f_hid_reset_packet(); stamp_error(hid_layer.current_cid, ERR_MSG_TIMEOUT); @@ -440,7 +439,7 @@ void u2f_hid_request(struct u2f_hid_msg* req) // Current application may not be interrupted // TODO this will be bad stamp_error(req->cid, ERR_CHANNEL_BUSY); - u2f_printlx("ERR_CHANNEL_BUSY ", 2, req->cid, hid_layer.current_cid); + //u2f_printlx("ERR_CHANNEL_BUSY ", 2, req->cid, hid_layer.current_cid); return; } break;