From 52cc61a57575ff6950578bd141f5d6f4906d0a68 Mon Sep 17 00:00:00 2001 From: Conor Patrick Date: Sat, 26 May 2018 11:36:34 -0400 Subject: [PATCH] encrypt credential with aes for start --- crypto.c | 99 ++++++++++++++++++++++++++-------------------------- ctap.c | 99 ++++++++++++++++++++++++++++++---------------------- ctap.h | 20 ++++++----- ctap_parse.c | 4 +-- 4 files changed, 120 insertions(+), 102 deletions(-) diff --git a/crypto.c b/crypto.c index fee5579..3007cd9 100644 --- a/crypto.c +++ b/crypto.c @@ -28,10 +28,14 @@ static SHA256_CTX sha256_ctx; static const struct uECC_Curve_t * _es256_curve = NULL; static const uint8_t * _signing_key = NULL; -// Secret for testing only +// Secrets for testing only static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff" "\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x77\x66\x55\x44\x33\x22\x11\x00"; +static uint8_t transport_secret[32] = "\x10\x01\x22\x33\x44\x55\x66\x77\x87\x90\x0a\xbb\x3c\xd8\xee\xff" + "\xff\xee\x8d\x1c\x3b\xfa\x99\x88\x77\x86\x55\x44\xd3\xff\x33\x00"; + + void crypto_sha256_init() { @@ -65,6 +69,12 @@ void crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac) int i; memset(buf, 0, sizeof(buf)); + if (key == CRYPTO_MASTER_KEY) + { + key = master_secret; + klen = sizeof(master_secret); + } + if(klen > 64) { printf("Error, key size must be <= 64\n"); @@ -88,6 +98,12 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac) int i; crypto_sha256_final(hmac); memset(buf, 0, sizeof(buf)); + if (key == CRYPTO_MASTER_KEY) + { + key = master_secret; + klen = sizeof(master_secret); + } + if(klen > 64) { @@ -107,44 +123,6 @@ void crypto_sha256_hmac_final(uint8_t * key, uint32_t klen, uint8_t * hmac) crypto_sha256_final(hmac); } -/*void crypto_sha256_hmac(uint8_t * key, uint32_t klen, uint8_t * data, uint32_t datalen, uint8_t * hmac)*/ -/*{*/ - /*uint8_t buf[64];*/ - /*int i;*/ - /*memset(buf, 0, sizeof(buf));*/ - - /*if(klen > 64)*/ - /*{*/ - /*printf("Error, key size must be <= 64\n");*/ - /*exit(1);*/ - /*}*/ - - /*memmove(buf, key, klen);*/ - - /*for (i = 0; i < sizeof(buf); i++)*/ - /*{*/ - /*buf[i] = buf[i] ^ 0x36;*/ - /*}*/ - - /*crypto_sha256_init();*/ - /*crypto_sha256_update(buf, 64);*/ - /*crypto_sha256_update(data, datalen);*/ - /*crypto_sha256_final(hmac);*/ - - /*memset(buf, 0, sizeof(buf));*/ - /*memmove(buf, key, klen);*/ - - /*for (i = 0; i < sizeof(buf); i++)*/ - /*{*/ - /*buf[i] = buf[i] ^ 0x5c;*/ - /*}*/ - - /*crypto_sha256_init();*/ - /*crypto_sha256_update(buf, 64);*/ - /*crypto_sha256_update(hmac, 32);*/ - /*crypto_sha256_final(hmac);*/ -/*}*/ - void crypto_ecc256_init() { @@ -169,12 +147,11 @@ void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig) void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey) { - // poor man's hmac - crypto_sha256_init(); + crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey); crypto_sha256_update(data, len); crypto_sha256_update(data2, len2); crypto_sha256_update(master_secret, 32); - crypto_sha256_final(privkey); + crypto_sha256_hmac_final(CRYPTO_MASTER_KEY, 0, privkey); } @@ -192,10 +169,10 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8 memmove(y,pubkey+32,32); } -void crypto_ecc256_load_key(uint8_t * data, int len) +void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2) { static uint8_t privkey[32]; - generate_private_key(data,len,NULL,0,privkey); + generate_private_key(data,len,data2,len2,privkey); _signing_key = privkey; } @@ -218,16 +195,38 @@ void crypto_ecc256_shared_secret(const uint8_t * pubkey, const uint8_t * privkey } -static struct AES_ctx aes_ctx; -void crypto_aes256_init(uint8_t * key) +struct AES_ctx aes_ctx; +void crypto_aes256_init(uint8_t * key, uint8_t * nonce) { - AES_init_ctx(&aes_ctx, key); - memset(aes_ctx.Iv, 0, 16); + if (key == CRYPTO_TRANSPORT_KEY) + { + AES_init_ctx(&aes_ctx, transport_secret); + } + else + { + AES_init_ctx(&aes_ctx, key); + } + if (nonce == NULL) + { + memset(aes_ctx.Iv, 0, 16); + } + else + { + memmove(aes_ctx.Iv, nonce, 16); + } } -void crypto_aes256_reset_iv() +// prevent round key recomputation +void crypto_aes256_reset_iv(uint8_t * nonce) { - memset(aes_ctx.Iv, 0, 16); + if (nonce == NULL) + { + memset(aes_ctx.Iv, 0, 16); + } + else + { + memmove(aes_ctx.Iv, nonce, 16); + } } void crypto_aes256_decrypt(uint8_t * buf, int length) diff --git a/ctap.c b/ctap.c index a0eeb96..7158edb 100644 --- a/ctap.c +++ b/ctap.c @@ -242,13 +242,12 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input, void make_auth_tag(struct rpId * rp, CTAP_userEntity * user, uint32_t count, uint8_t * tag) { uint8_t hashbuf[32]; - crypto_sha256_init(); + crypto_sha256_hmac_init(NULL, 0, hashbuf); crypto_sha256_update(rp->id, rp->size); crypto_sha256_update(user->id, user->id_size); crypto_sha256_update(user->name, strnlen(user->name, USER_NAME_LIMIT)); crypto_sha256_update((uint8_t*)&count, 4); - crypto_sha256_update_secret(); - crypto_sha256_final(hashbuf); + crypto_sha256_hmac_final(NULL,0,hashbuf); memmove(tag, hashbuf, CREDENTIAL_TAG_SIZE); } @@ -300,19 +299,21 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au authData->attest.credLenL = CREDENTIAL_ID_SIZE & 0x00FF; authData->attest.credLenH = (CREDENTIAL_ID_SIZE & 0xFF00) >> 8; -#if CREDENTIAL_ID_SIZE != 150 +#if CREDENTIAL_ID_SIZE != 168 #error "need to double check credential ID layout" #else - memset(authData->attest.credential.id, 0, CREDENTIAL_ID_SIZE); + memset((uint8_t*)&authData->attest.credential, 0, sizeof(struct Credential)); // Make a tag we can later check to make sure this is a token we made - make_auth_tag(rp, user, count, authData->attest.credential.fields.tag); + make_auth_tag(rp, user, count, authData->attest.credential.tag); - memmove(&authData->attest.credential.fields.user, user, sizeof(CTAP_userEntity)); //TODO encrypt this + memmove(&authData->attest.credential.enc.user, user, sizeof(CTAP_userEntity)); //TODO encrypt this + authData->attest.credential.enc.count = count; - authData->attest.credential.fields.count = count; + crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); + crypto_aes256_encrypt((uint8_t*)&authData->attest.credential.enc, CREDENTIAL_ENC_SIZE); - ctap_generate_cose_key(&cose_key, authData->attest.credential.id, CREDENTIAL_ID_SIZE, credtype, algtype); + ctap_generate_cose_key(&cose_key, (uint8_t*)&authData->attest.credential, sizeof(struct Credential), credtype, algtype); printf1(TAG_MC,"COSE_KEY: "); dump_hex1(TAG_MC, cose_key_buf, cbor_encoder_get_buffer_size(&cose_key, cose_key_buf)); @@ -436,9 +437,9 @@ int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * d return 0; } - make_auth_tag(rp, &desc->credential.fields.user, desc->credential.fields.count, tag); + make_auth_tag(rp, &desc->credential.enc.user, desc->credential.enc.count, tag); - return (memcmp(desc->credential.fields.tag, tag, CREDENTIAL_TAG_SIZE) == 0); + return (memcmp(desc->credential.tag, tag, CREDENTIAL_TAG_SIZE) == 0); } @@ -529,7 +530,7 @@ static int pick_first_authentic_credential(CTAP_getAssertion * GA) int i; for (i = 0; i < GA->credLen; i++) { - if (GA->creds[i].credential.fields.count != 0) + if (GA->creds[i].credential.enc.count != 0) { return i; } @@ -557,7 +558,7 @@ static uint8_t ctap_add_credential_descriptor(CborEncoder * map, CTAP_credential ret = cbor_encode_text_string(&desc, "id", 2); check_ret(ret); - ret = cbor_encode_byte_string(&desc, cred->credential.id, CREDENTIAL_ID_SIZE); + ret = cbor_encode_byte_string(&desc, (uint8_t*)&cred->credential, sizeof(struct Credential)); check_ret(ret); } @@ -603,7 +604,7 @@ static int cred_cmp_func(const void * _a, const void * _b) { CTAP_credentialDescriptor * a = (CTAP_credentialDescriptor * )_a; CTAP_credentialDescriptor * b = (CTAP_credentialDescriptor * )_b; - return b->credential.fields.count - a->credential.fields.count; + return b->credential.enc.count - a->credential.enc.count; } // @return the number of valid credentials @@ -612,19 +613,24 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA) { int i; int count = 0; + crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); + + for (i = 0; i < GA->credLen; i++) { + crypto_aes256_reset_iv(NULL); + crypto_aes256_decrypt((uint8_t*)&GA->creds[i].credential.enc, CREDENTIAL_ENC_SIZE); if (! ctap_authenticate_credential(&GA->rp, &GA->creds[i])) { - printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.fields.count); - GA->creds[i].credential.fields.count = 0; // invalidate + printf1(TAG_GA, "CRED #%d is invalid\n", GA->creds[i].credential.enc.count); + GA->creds[i].credential.enc.count = 0; // invalidate } else { count++; } } - printf("qsort length: %d\n", GA->credLen); + printf1(TAG_GA, "qsort length: %d\n", GA->credLen); qsort(GA->creds, GA->credLen, sizeof(CTAP_credentialDescriptor), cred_cmp_func); return count; } @@ -634,6 +640,11 @@ static void save_credential_list(CTAP_authDataHeader * head, uint8_t * clientDat { if(count) { + if (count > ALLOW_LIST_MAX_SIZE-1) + { + printf2(TAG_ERR, "ALLOW_LIST_MAX_SIZE Exceeded\n"); + exit(1); + } memmove(getAssertionState.clientDataHash, clientDataHash, CLIENT_DATA_HASH_SIZE); memmove(&getAssertionState.authData, head, sizeof(CTAP_authDataHeader)); memmove(getAssertionState.creds, creds, sizeof(CTAP_credentialDescriptor) * (count)); @@ -661,18 +672,22 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr uint8_t sigbuf[64]; uint8_t sigder[72]; + ret = ctap_add_user_entity(map, &cred->credential.enc.user); + check_retr(ret); + + // Re-encrypt the credential + crypto_aes256_init(CRYPTO_TRANSPORT_KEY, NULL); + crypto_aes256_encrypt((uint8_t*)&cred->credential.enc, CREDENTIAL_ENC_SIZE); + // ret = ctap_add_credential_descriptor(map, cred); check_retr(ret); - ret = ctap_add_user_entity(map, &cred->credential.fields.user); - check_retr(ret); + crypto_ecc256_load_key((uint8_t*)&cred->credential, sizeof(struct Credential), NULL, 0); - crypto_ecc256_load_key(cred->credential.id, CREDENTIAL_ID_SIZE); - - printf1(TAG_GREEN,"auth_data_buf: "); dump_hex1(TAG_DUMP, auth_data_buf, sizeof(CTAP_authDataHeader)); - printf1(TAG_GREEN,"clientdatahash: "); dump_hex1(TAG_DUMP, clientDataHash, 32); - printf1(TAG_GREEN,"credential: # %d\n", cred->credential.fields.count); + /*printf1(TAG_GREEN,"auth_data_buf: "); dump_hex1(TAG_DUMP, auth_data_buf, sizeof(CTAP_authDataHeader));*/ + /*printf1(TAG_GREEN,"clientdatahash: "); dump_hex1(TAG_DUMP, clientDataHash, 32);*/ + /*printf1(TAG_GREEN,"credential: # %d\n", cred->credential.enc.count);*/ /*dump_hex1(TAG_DUMP, clientDataHash, 32);*/ int sigder_sz = ctap_calculate_signature(auth_data_buf, sizeof(CTAP_authDataHeader), clientDataHash, auth_data_buf, sigbuf, sigder); @@ -755,19 +770,19 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) ctap_make_auth_data(&GA.rp, &map, auth_data_buf, sizeof(auth_data_buf), NULL, 0,0); printf1(TAG_GA, "ALLOW_LIST has %d creds\n", GA.credLen); - for (int j = 0; j < GA.credLen; j++) - { - printf1(TAG_GA,"CRED ID (# %d): ", GA.creds[j].credential.fields.count); - dump_hex1(TAG_GA, GA.creds[j].credential.id, CREDENTIAL_ID_SIZE); - if (ctap_authenticate_credential(&GA.rp, &GA.creds[j])) // warning encryption will break this - { - printf1(TAG_GA," Authenticated.\n"); - } - else - { - printf1(TAG_GA," NOT authentic.\n"); - } - } + /*for (int j = 0; j < GA.credLen; j++)*/ + /*{*/ + /*printf1(TAG_GA,"CRED ID (# %d): ", GA.creds[j].credential.enc.count);*/ + /*dump_hex1(TAG_GA, (uint8_t*)&GA.creds[j].credential, sizeof(struct Credential));*/ + /*if (ctap_authenticate_credential(&GA.rp, &GA.creds[j])) // warning encryption will break this*/ + /*{*/ + /*printf1(TAG_GA," Authenticated.\n");*/ + /*}*/ + /*else*/ + /*{*/ + /*printf1(TAG_GA," NOT authentic.\n");*/ + /*}*/ + /*}*/ // Decrypt here @@ -786,7 +801,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length) printf1(TAG_RED,"resulting order of creds:\n"); for (int j = 0; j < GA.credLen; j++) { - printf1(TAG_RED,"CRED ID (# %d)\n", GA.creds[j].credential.fields.count); + printf1(TAG_RED,"CRED ID (# %d)\n", GA.creds[j].credential.enc.count); } { @@ -839,7 +854,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor return CTAP2_ERR_PIN_AUTH_INVALID; } - crypto_aes256_init(shared_secret); + crypto_aes256_init(shared_secret, NULL); while((len & 0xf) != 0) // round up to nearest AES block size multiple { @@ -864,7 +879,7 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor if (ctap_is_pin_set()) { - crypto_aes256_reset_iv(); + crypto_aes256_reset_iv(NULL); crypto_aes256_decrypt(pinHashEnc, 16); if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0) { @@ -894,7 +909,7 @@ uint8_t ctap_add_pin_if_verified(CborEncoder * map, uint8_t * platform_pubkey, u crypto_sha256_update(shared_secret, 32); crypto_sha256_final(shared_secret); - crypto_aes256_init(shared_secret); + crypto_aes256_init(shared_secret, NULL); crypto_aes256_decrypt(pinHashEnc, 16); @@ -911,7 +926,7 @@ uint8_t ctap_add_pin_if_verified(CborEncoder * map, uint8_t * platform_pubkey, u } ctap_reset_pin_attempts(); - crypto_aes256_reset_iv(); + crypto_aes256_reset_iv(NULL); // reuse share_secret memory for encrypted pinToken memmove(shared_secret, PIN_TOKEN, PIN_TOKEN_SIZE); diff --git a/ctap.h b/ctap.h index ea3dd02..59370ad 100644 --- a/ctap.h +++ b/ctap.h @@ -91,8 +91,11 @@ #define CTAP_MAX_MESSAGE_SIZE 1024 #define CREDENTIAL_TAG_SIZE 16 +#define CREDENTIAL_NONCE_SIZE 8 #define CREDENTIAL_COUNTER_SIZE (4) -#define CREDENTIAL_ID_SIZE (CREDENTIAL_TAG_SIZE + USER_ID_MAX_SIZE + USER_NAME_LIMIT + CREDENTIAL_COUNTER_SIZE + 1) +#define CREDENTIAL_ENC_SIZE 144 // pad to multiple of 16 bytes +#define CREDENTIAL_PAD_SIZE (CREDENTIAL_ENC_SIZE - (USER_ID_MAX_SIZE + USER_NAME_LIMIT + CREDENTIAL_COUNTER_SIZE + 1)) +#define CREDENTIAL_ID_SIZE (CREDENTIAL_TAG_SIZE + CREDENTIAL_NONCE_SIZE + CREDENTIAL_ENC_SIZE) #define PUB_KEY_CRED_PUB_KEY 0x01 #define PUB_KEY_CRED_UNKNOWN 0x3F @@ -109,15 +112,16 @@ typedef struct uint8_t id[USER_ID_MAX_SIZE]; uint8_t id_size; uint8_t name[USER_NAME_LIMIT]; -} CTAP_userEntity; +}__attribute__((packed)) CTAP_userEntity; -union _credential { +struct Credential { + uint8_t tag[CREDENTIAL_TAG_SIZE]; + uint8_t nonce[CREDENTIAL_NONCE_SIZE]; struct { - uint8_t tag[CREDENTIAL_TAG_SIZE]; CTAP_userEntity user; uint32_t count; - }__attribute__((packed)) fields; - uint8_t id[CREDENTIAL_ID_SIZE]; + uint8_t _pad[CREDENTIAL_PAD_SIZE]; + } __attribute__((packed)) enc; }; typedef struct @@ -125,7 +129,7 @@ typedef struct uint8_t aaguid[16]; uint8_t credLenH; uint8_t credLenL; - union _credential credential; + struct Credential credential; } __attribute__((packed)) CTAP_attestHeader; typedef struct @@ -179,7 +183,7 @@ typedef struct typedef struct { uint8_t type; - union _credential credential; + struct Credential credential; } CTAP_credentialDescriptor; typedef struct diff --git a/ctap_parse.c b/ctap_parse.c index f59ba88..86c6239 100644 --- a/ctap_parse.c +++ b/ctap_parse.c @@ -637,8 +637,8 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * return CTAP2_ERR_MISSING_PARAMETER; } - buflen = CREDENTIAL_ID_SIZE; - cbor_value_copy_byte_string(&val, cred->credential.id, &buflen, NULL); + buflen = sizeof(struct Credential); + cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential, &buflen, NULL); if (buflen != CREDENTIAL_ID_SIZE) { printf2(TAG_ERR,"Error, credential is incorrect length\n");