vtcsec_summit
Conor 2016-03-12 11:36:31 -05:00
rodzic fc7ddd6ff1
commit f3043d2606
5 zmienionych plików z 141 dodań i 88 usunięć

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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

Wyświetl plik

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