Merge pull request #173 from solokeys/fix_u2f_on_fido2

Fix u2f on fido2
pull/176/head 2.2.0
Conor Patrick 2019-04-17 22:42:38 -04:00 zatwierdzone przez GitHub
commit 6068fb9868
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 80 dodań i 20 usunięć

Wyświetl plik

@ -11,6 +11,7 @@
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "u2f.h"
#include "ctaphid.h" #include "ctaphid.h"
#include "ctap_parse.h" #include "ctap_parse.h"
#include "ctap_errors.h" #include "ctap_errors.h"
@ -431,6 +432,12 @@ static int ctap_make_extensions(CTAP_extensions * ext, uint8_t * ext_encoder_buf
return 0; return 0;
} }
static unsigned int get_credential_id_size(CTAP_credentialDescriptor * cred)
{
if (cred->type == PUB_KEY_CRED_CTAP1)
return U2F_KEY_HANDLE_SIZE;
return sizeof(CredentialId);
}
static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo) static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * auth_data_buf, uint32_t * len, CTAP_credInfo * credInfo)
{ {
@ -655,11 +662,25 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
// Return 1 if credential belongs to this token // Return 1 if credential belongs to this token
int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc) int ctap_authenticate_credential(struct rpId * rp, CTAP_credentialDescriptor * desc)
{ {
uint8_t rpIdHash[32];
uint8_t tag[16]; uint8_t tag[16];
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag); switch(desc->type)
{
case PUB_KEY_CRED_PUB_KEY:
make_auth_tag(desc->credential.id.rpIdHash, desc->credential.id.nonce, desc->credential.id.count, tag);
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0);
break;
case PUB_KEY_CRED_CTAP1:
printf1(TAG_CTAP,"PUB_KEY_CRED_CTAP1\r\n");
crypto_sha256_init();
crypto_sha256_update(rp->id, rp->size);
crypto_sha256_final(rpIdHash);
return u2f_authenticate_credential((struct u2f_key_handle *)&desc->credential.id, rpIdHash);
break;
}
return (memcmp(desc->credential.id.tag, tag, CREDENTIAL_TAG_SIZE) == 0); return 0;
} }
@ -806,7 +827,8 @@ static uint8_t ctap_add_credential_descriptor(CborEncoder * map, CTAP_credential
ret = cbor_encode_text_string(&desc, "id", 2); ret = cbor_encode_text_string(&desc, "id", 2);
check_ret(ret); check_ret(ret);
ret = cbor_encode_byte_string(&desc, (uint8_t*)&cred->credential.id, sizeof(CredentialId)); ret = cbor_encode_byte_string(&desc, (uint8_t*)&cred->credential.id,
get_credential_id_size(cred));
check_ret(ret); check_ret(ret);
} }
@ -1021,7 +1043,8 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
check_ret(ret); check_ret(ret);
} }
crypto_ecc256_load_key((uint8_t*)&cred->credential.id, sizeof(CredentialId), NULL, 0); unsigned int cred_size = get_credential_id_size(cred);
crypto_ecc256_load_key((uint8_t*)&cred->credential.id, cred_size, NULL, 0);
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
if ( extend_fido2(&cred->credential.id, sigder) ) if ( extend_fido2(&cred->credential.id, sigder) )
@ -1170,8 +1193,6 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.id.count); printf1(TAG_GA,"CRED ID (# %d)\n", GA.creds[j].credential.id.count);
} }
CTAP_credentialDescriptor * cred = &GA.creds[validCredCount - 1]; CTAP_credentialDescriptor * cred = &GA.creds[validCredCount - 1];
GA.extensions.hmac_secret.credential = &cred->credential; GA.extensions.hmac_secret.credential = &cred->credential;
@ -1181,8 +1202,6 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
#ifdef ENABLE_U2F_EXTENSIONS #ifdef ENABLE_U2F_EXTENSIONS
if ( is_extension_request((uint8_t*)&GA.creds[validCredCount - 1].credential.id, sizeof(CredentialId)) ) if ( is_extension_request((uint8_t*)&GA.creds[validCredCount - 1].credential.id, sizeof(CredentialId)) )
{ {
ret = cbor_encode_int(&map,RESP_authData); // 2
check_ret(ret);
memset(auth_data_buf,0,sizeof(CTAP_authDataHeader)); memset(auth_data_buf,0,sizeof(CTAP_authDataHeader));
auth_data_buf_sz = sizeof(CTAP_authDataHeader); auth_data_buf_sz = sizeof(CTAP_authDataHeader);
} }

Wyświetl plik

@ -112,6 +112,7 @@
#define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes #define CREDENTIAL_ENC_SIZE 176 // pad to multiple of 16 bytes
#define PUB_KEY_CRED_PUB_KEY 0x01 #define PUB_KEY_CRED_PUB_KEY 0x01
#define PUB_KEY_CRED_CTAP1 0x41
#define PUB_KEY_CRED_UNKNOWN 0x3F #define PUB_KEY_CRED_UNKNOWN 0x3F
#define CREDENTIAL_IS_SUPPORTED 1 #define CREDENTIAL_IS_SUPPORTED 1

Wyświetl plik

@ -9,6 +9,7 @@
#include "cbor.h" #include "cbor.h"
#include "ctap.h" #include "ctap.h"
#include "u2f.h"
#include "ctap_parse.h" #include "ctap_parse.h"
#include "ctap_errors.h" #include "ctap_errors.h"
#include "cose_key.h" #include "cose_key.h"
@ -890,10 +891,15 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
buflen = sizeof(CredentialId); buflen = sizeof(CredentialId);
cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL); cbor_value_copy_byte_string(&val, (uint8_t*)&cred->credential.id, &buflen, NULL);
if (buflen != sizeof(CredentialId))
if (buflen == U2F_KEY_HANDLE_SIZE)
{
printf2(TAG_PARSE,"CTAP1 credential\n");
cred->type = PUB_KEY_CRED_CTAP1;
}
else if (buflen != sizeof(CredentialId))
{ {
printf2(TAG_ERR,"Ignoring credential is incorrect length\n"); printf2(TAG_ERR,"Ignoring credential is incorrect length\n");
//return CTAP2_ERR_CBOR_UNEXPECTED_TYPE; // maybe just skip it instead of fail?
} }
ret = cbor_value_map_find_value(arr, "type", &val); ret = cbor_value_map_find_value(arr, "type", &val);
@ -906,11 +912,15 @@ uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor *
} }
buflen = sizeof(type); buflen = sizeof(type);
cbor_value_copy_text_string(&val, type, &buflen, NULL); ret = cbor_value_copy_text_string(&val, type, &buflen, NULL);
check_ret(ret);
if (strncmp(type, "public-key",11) == 0) if (strncmp(type, "public-key",11) == 0)
{ {
cred->type = PUB_KEY_CRED_PUB_KEY; if (PUB_KEY_CRED_CTAP1 != cred->type)
{
cred->type = PUB_KEY_CRED_PUB_KEY;
}
} }
else else
{ {

Wyświetl plik

@ -183,21 +183,21 @@ int8_t u2f_new_keypair(struct u2f_key_handle * kh, uint8_t * appid, uint8_t * pu
} }
// Return 1 if authenticate, 0 if not.
static int8_t u2f_appid_eq(struct u2f_key_handle * kh, uint8_t * appid) int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid)
{ {
uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE]; uint8_t tag[U2F_KEY_HANDLE_TAG_SIZE];
u2f_make_auth_tag(kh, appid, tag); u2f_make_auth_tag(kh, appid, tag);
if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0) if (memcmp(kh->tag, tag, U2F_KEY_HANDLE_TAG_SIZE) == 0)
{ {
return 0; return 1;
} }
else else
{ {
printf1(TAG_U2F, "key handle + appid not authentic\n"); printf1(TAG_U2F, "key handle + appid not authentic\n");
printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "calc tag: \n"); dump_hex1(TAG_U2F,tag, U2F_KEY_HANDLE_TAG_SIZE);
printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE); printf1(TAG_U2F, "inp tag: \n"); dump_hex1(TAG_U2F,kh->tag, U2F_KEY_HANDLE_TAG_SIZE);
return -1; return 0;
} }
} }
@ -214,7 +214,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if (control == U2F_AUTHENTICATE_CHECK) if (control == U2F_AUTHENTICATE_CHECK)
{ {
printf1(TAG_U2F, "CHECK-ONLY\r\n"); printf1(TAG_U2F, "CHECK-ONLY\r\n");
if (u2f_appid_eq(&req->kh, req->app) == 0) if (u2f_authenticate_credential(&req->kh, req->app))
{ {
return U2F_SW_CONDITIONS_NOT_SATISFIED; return U2F_SW_CONDITIONS_NOT_SATISFIED;
} }
@ -226,7 +226,7 @@ static int16_t u2f_authenticate(struct u2f_authenticate_request * req, uint8_t c
if ( if (
(control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) || (control != U2F_AUTHENTICATE_SIGN && control != U2F_AUTHENTICATE_SIGN_NO_USER) ||
req->khl != U2F_KEY_HANDLE_SIZE || req->khl != U2F_KEY_HANDLE_SIZE ||
u2f_appid_eq(&req->kh, req->app) != 0 || // Order of checks is important (!u2f_authenticate_credential(&req->kh, req->app)) || // Order of checks is important
u2f_load_key(&req->kh, req->app) != 0 u2f_load_key(&req->kh, req->app) != 0
) )

Wyświetl plik

@ -103,6 +103,7 @@ void u2f_request(struct u2f_request_apdu* req, CTAP_RESPONSE * resp);
// @len data length // @len data length
void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp); void u2f_request_nfc(uint8_t * req, int len, CTAP_RESPONSE * resp);
int8_t u2f_authenticate_credential(struct u2f_key_handle * kh, uint8_t * appid);
int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len); int8_t u2f_response_writeback(const uint8_t * buf, uint16_t len);
void u2f_reset_response(); void u2f_reset_response();

Wyświetl plik

@ -27,7 +27,7 @@ void _putchar(char c)
int _write (int fd, const void *buf, unsigned long int len) int _write (int fd, const void *buf, unsigned long int len)
{ {
uint8_t * data = (uint8_t *) buf; uint8_t * data = (uint8_t *) buf;
#if DEBUG_LEVEL>1 #if DEBUG_LEVEL>0
// static uint8_t logbuf[1000] = {0}; // static uint8_t logbuf[1000] = {0};
// static int logbuflen = 0; // static int logbuflen = 0;
// if (logbuflen + len > sizeof(logbuf)) { // if (logbuflen + len > sizeof(logbuf)) {

Wyświetl plik

@ -7,13 +7,14 @@ from functools import cmp_to_key
from fido2 import cbor from fido2 import cbor
from fido2.ctap import CtapError from fido2.ctap import CtapError
from fido2.ctap2 import ES256, PinProtocolV1 from fido2.ctap2 import ES256, PinProtocolV1, AttestedCredentialData
from fido2.utils import sha256, hmac_sha256 from fido2.utils import sha256, hmac_sha256
from fido2.attestation import Attestation from fido2.attestation import Attestation
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from .u2f import U2FTests
from .tester import Tester, Test from .tester import Tester, Test
from .util import shannon_entropy from .util import shannon_entropy
@ -880,6 +881,34 @@ class FIDO2Tests(Tester):
allow_list + [{"type": b"public-key"}], allow_list + [{"type": b"public-key"}],
) )
self.testReset()
appid = sha256(rp["id"].encode("utf8"))
chal = sha256(challenge.encode("utf8"))
with Test("Send CTAP1 register request"):
u2f = U2FTests(self)
reg = u2f.register(chal, appid)
reg.verify(appid, chal)
with Test("Authenticate CTAP1"):
auth = u2f.authenticate(chal, appid, reg.key_handle)
auth.verify(appid, chal, reg.public_key)
auth = self.testGA(
"Authenticate CTAP1 registration with CTAP2",
rp["id"],
cdh,
[{"id": reg.key_handle, "type": "public-key"}],
expectedError=CtapError.ERR.SUCCESS,
)
with Test("Check assertion is correct"):
credential_data = AttestedCredentialData.from_ctap1(
reg.key_handle, reg.public_key
)
auth.verify(cdh, credential_data.public_key)
assert auth.credential["id"] == reg.key_handle
def test_rk(self, pin_code=None): def test_rk(self, pin_code=None):
pin_auth = None pin_auth = None