kopia lustrzana https://github.com/conorpp/u2f-zero
omg it works
rodzic
fc7ddd6ff1
commit
f3043d2606
|
@ -10,10 +10,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Ładowanie…
Reference in New Issue