kopia lustrzana https://github.com/solokeys/solo1
commit
6068fb9868
35
fido2/ctap.c
35
fido2/ctap.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
12
fido2/u2f.c
12
fido2/u2f.c
|
@ -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
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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)) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Ładowanie…
Reference in New Issue