diff --git a/ctap_device.c b/ctap_device.c index a99fcfe..070ce95 100644 --- a/ctap_device.c +++ b/ctap_device.c @@ -63,3 +63,7 @@ int ctap_generate_rng(uint8_t * dst, size_t num) return 1; } + + + + diff --git a/ctaphid.c b/ctaphid.c index 60ca909..666f2cb 100644 --- a/ctaphid.c +++ b/ctaphid.c @@ -5,6 +5,7 @@ #include "ctaphid.h" #include "ctap.h" +#include "u2f.h" #include "time.h" #include "util.h" @@ -447,6 +448,28 @@ start_over: ctaphid_write(&wb, NULL, 0); break; + case CTAPHID_MSG: + printf("CTAPHID_CBOR\n"); + if (buffer_len() == 0) + { + printf("Error,invalid 0 length field for MSG/U2F packet\n"); + ctaphid_send_error(pkt->cid, ERR_INVALID_LEN); + ctaphid_init(); + return; + } + + ctaphid_write_buffer_init(&wb); + u2f_request(ctap_buffer); + + wb.cid = active_cid; + wb.cmd = CTAPHID_CBOR; + wb.bcnt = (ctap_resp.length+1); + + ctaphid_write(&wb, &status, 1); + ctaphid_write(&wb, ctap_resp.data, ctap_resp.length); + ctaphid_write(&wb, NULL, 0); + break; + default: printf("error, unimplemented HID cmd: %02x\r\n", buffer_cmd()); break; diff --git a/u2f.c b/u2f.c index af80b7e..4d62ea2 100644 --- a/u2f.c +++ b/u2f.c @@ -1,7 +1,6 @@ #include "u2f.h" #include "ctap.h" #include "crypto.h" -#if 0 // void u2f_response_writeback(uint8_t * buf, uint8_t len); static int16_t u2f_register(struct u2f_register_request * req); @@ -13,11 +12,9 @@ void u2f_request(struct u2f_request_apdu * req) uint16_t * rcode = (uint16_t *)req; uint32_t len = ((req->LC3) | ((uint32_t)req->LC2 << 8) | ((uint32_t)req->LC1 << 16)); - u2f_response_start(); - if (req->cla != 0) { - u2f_hid_set_len(2); + u2f_response_set_length(2); *rcode = U2F_SW_CLASS_NOT_SUPPORTED; goto end; } @@ -27,7 +24,7 @@ void u2f_request(struct u2f_request_apdu * req) case U2F_REGISTER: if (len != 64) { - u2f_hid_set_len(2); + u2f_response_set_length(2); *rcode = U2F_SW_WRONG_LENGTH; } else @@ -41,7 +38,7 @@ void u2f_request(struct u2f_request_apdu * req) case U2F_VERSION: if (len) { - u2f_hid_set_len(2); + u2f_response_set_length(2); *rcode = U2F_SW_WRONG_LENGTH; } else @@ -54,7 +51,7 @@ void u2f_request(struct u2f_request_apdu * req) *rcode = U2F_SW_NO_ERROR; break; default: - u2f_hid_set_len(2); + u2f_response_set_length(2); *rcode = U2F_SW_INS_NOT_SUPPORTED; break; } @@ -64,6 +61,27 @@ end: u2f_response_flush(); } + +void u2f_response_writeback(const uint8_t * buf, uint16_t len) +{ + +} + +// Set total length of U2F response. Must be done before any writebacks +extern void u2f_response_set_length(uint16_t len) +{ + +} + +// u2f_response_flush callback when u2f finishes and will +// indicate when all buffer data, if any, should be written +extern void u2f_response_flush() +{ + +} + + + static uint8_t get_signature_length(uint8_t * sig) { return 0x46 + ((sig[32] & 0x80) == 0x80) + ((sig[0] & 0x80) == 0x80); @@ -99,41 +117,55 @@ static void dump_signature_der(uint8_t * sig) // S value u2f_response_writeback(sig+32, 32); } - -int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid) +static int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t * appid) { - + crypto_ecc256_load_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, appid, U2F_APPLICATION_SIZE); return 0; } -int8_t u2f_load_key(struct u2f_key_handle * kh, uint8_t * appid) -{ - crypto_ecc256_load_key(kh->key, U2F_KEY_HANDLE_KEY_SIZE, appid, U2F_APPLICATION_SIZE); - return 0; -} - -void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * tag) +static void u2f_make_auth_tag(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * tag) { uint8_t hashbuf[32]; - crypto_sha256_hmac_init(NULL, 0, hashbuf); + crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, hashbuf); crypto_sha256_update(kh->key, U2F_KEY_HANDLE_KEY_SIZE); - crypto_sha256_update(appid, ); - crypto_sha256_hmac_final(hashbuf); - + crypto_sha256_update(appid, U2F_APPLICATION_SIZE); + crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0,hashbuf); memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); } +static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid) +{ + uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE]; + u2f_make_auth_tag(kh, appid, kh->tag); + if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0) + return 0; + else + return -1; +} + + + +static int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pubkey) +{ + ctap_generate_rng(kh->key, U2F_KEY_HANDLE_KEY_SIZE); + u2f_make_auth_tag(kh, appid, kh->tag); + crypto_ecc256_derive_public_key((uint8_t*)kh, U2F_KEY_HANDLE_SIZE, pubkey, pubkey+32); + return 0; +} + static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t control) { uint8_t up = 1; uint32_t count; + uint8_t hash[32]; + uint8_t * sig = (uint8_t*)req; if (control == U2F_AUTHENTICATE_CHECK) { - u2f_hid_set_len(2); + u2f_response_set_length(2); if (u2f_appid_eq(&req->kh, req->app) == 0) { return U2F_SW_CONDITIONS_NOT_SATISFIED; @@ -151,38 +183,37 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c ) { - u2f_hid_set_len(2); + u2f_response_set_length(2); return U2F_SW_WRONG_PAYLOAD; } - if (u2f_get_user_feedback()) + if (ctap_user_presence_test()) { - u2f_hid_set_len(2); + u2f_response_set_length(2); return U2F_SW_CONDITIONS_NOT_SATISFIED; } - count = u2f_count(); + count = ctap_atomic_count(0); - u2f_sha256_start(); - u2f_sha256_update(req->app,32); - u2f_sha256_update(&up,1); - u2f_sha256_update((uint8_t *)&count,4); - u2f_sha256_update(req->chal,32); + crypto_sha256_init(); - u2f_sha256_finish(); + crypto_sha256_update(req->app,32); + crypto_sha256_update(&up,1); + crypto_sha256_update((uint8_t *)&count,4); + crypto_sha256_update(req->chal,32); - if (u2f_ecdsa_sign((uint8_t*)req, req->kh, req->app) == -1) - { - return U2F_SW_WRONG_DATA+0x20; - } + crypto_sha256_final(hash); - u2f_hid_set_len(7 + get_signature_length((uint8_t*)req)); + crypto_ecc256_sign(hash, 32, sig); + + + u2f_response_set_length(7 + get_signature_length(sig)); u2f_response_writeback(&up,1); u2f_response_writeback((uint8_t *)&count,4); - dump_signature_der((uint8_t*)req); + dump_signature_der(sig); return U2F_SW_NO_ERROR; } @@ -191,49 +222,49 @@ 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]; + struct u2f_key_handle key_handle; uint8_t pubkey[64]; + uint8_t hash[32]; + uint8_t * sig = (uint8_t*)req; - const uint16_t attest_size = u2f_attestation_cert_size(); + const uint16_t attest_size = attestation_cert_der_size; - if (u2f_get_user_feedback()) + if (ctap_user_presence_test()) { - u2f_hid_set_len(2); + u2f_response_set_length(2); return U2F_SW_CONDITIONS_NOT_SATISFIED; } - if ( u2f_new_keypair(key_handle, req->app, pubkey) == -1) + if ( u2f_new_keypair(&key_handle, req->app, pubkey) == -1) { - u2f_hid_set_len(2); + u2f_response_set_length(2); return U2F_SW_INSUFFICIENT_MEMORY; } - u2f_sha256_start(); - u2f_sha256_update(i,1); - u2f_sha256_update(req->app,32); + crypto_sha256_init(); + crypto_sha256_update(i,1); + crypto_sha256_update(req->app,32); - u2f_sha256_update(req->chal,32); + crypto_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); - u2f_sha256_finish(); + crypto_sha256_update((uint8_t*)&key_handle,U2F_KEY_HANDLE_SIZE); + crypto_sha256_update(i+1,1); + crypto_sha256_update(pubkey,64); + crypto_sha256_final(hash); - if (u2f_ecdsa_sign((uint8_t*)req, U2F_ATTESTATION_HANDLE, req->app) == -1) - { - return U2F_SW_WRONG_DATA; - } + crypto_ecc256_load_attestation_key(); + crypto_ecc256_sign(hash, 32, sig); - u2f_hid_set_len(69 + get_signature_length((uint8_t*)req) + U2F_KEY_HANDLE_SIZE + u2f_attestation_cert_size()); + u2f_response_set_length(69 + get_signature_length((uint8_t*)req) + U2F_KEY_HANDLE_SIZE + attest_size); i[0] = 0x5; u2f_response_writeback(i,2); u2f_response_writeback(pubkey,64); i[0] = U2F_KEY_HANDLE_SIZE; u2f_response_writeback(i,1); - u2f_response_writeback(key_handle,U2F_KEY_HANDLE_SIZE); + u2f_response_writeback((uint8_t*)&key_handle,U2F_KEY_HANDLE_SIZE); - u2f_response_writeback(u2f_get_attestation_cert(),u2f_attestation_cert_size()); + u2f_response_writeback(attestation_cert_der,attest_size); dump_signature_der((uint8_t*)req); @@ -243,9 +274,8 @@ static int16_t u2f_register(struct u2f_register_request * req) static int16_t u2f_version() { - code const char version[] = "U2F_V2"; - u2f_hid_set_len(2 + sizeof(version)-1); + const char version[] = "U2F_V2"; + u2f_response_set_length(2 + sizeof(version)-1); u2f_response_writeback(version, sizeof(version)-1); return U2F_SW_NO_ERROR; } -#endif diff --git a/u2f.h b/u2f.h index ab36576..8a7c6d3 100644 --- a/u2f.h +++ b/u2f.h @@ -11,7 +11,7 @@ #define U2F_CHALLENGE_SIZE 32 #define U2F_APPLICATION_SIZE 32 #define U2F_KEY_HANDLE_TAG_SIZE 16 -#define U2F_KEY_HANDLE_KEY_SIZE 36 +#define U2F_KEY_HANDLE_KEY_SIZE 32 #define U2F_KEY_HANDLE_SIZE (U2F_KEY_HANDLE_KEY_SIZE+U2F_KEY_HANDLE_TAG_SIZE) #define U2F_REGISTER_REQUEST_SIZE (U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE) #define U2F_MAX_REQUEST_PAYLOAD (1 + U2F_CHALLENGE_SIZE+U2F_APPLICATION_SIZE + 1 + U2F_KEY_HANDLE_SIZE) @@ -99,14 +99,14 @@ void u2f_request(struct u2f_request_apdu* req); // u2f_response_writeback callback for u2f to send back response data // @buf data to write back // @len length of buf in bytes -extern void u2f_response_writeback(uint8_t * buf, uint16_t len); +extern void u2f_response_writeback(const uint8_t * buf, uint16_t len); + +// Set total length of U2F response. Must be done before any writebacks +extern void u2f_response_set_length(uint16_t len); // u2f_response_flush callback when u2f finishes and will // indicate when all buffer data, if any, should be written extern void u2f_response_flush(); -// set_response_length method to set the total length of the response for use by underlying layer -// @len the length of U2F response in bytes -extern void set_response_length(uint16_t len); #endif /* U2F_H_ */