kopia lustrzana https://github.com/solokeys/solo1
POC: add ed25519 support based on libsodium (PC) or salty (solo).
For now: - libsodium(-dev) is expected to be preinstalled on build system for PC buildpull/478/head
rodzic
398943d6c8
commit
fe24b9edd1
4
Makefile
4
Makefile
|
@ -22,7 +22,7 @@ ifeq ($(shell uname -s),Darwin)
|
||||||
else
|
else
|
||||||
export LDFLAGS = -Wl,--gc-sections
|
export LDFLAGS = -Wl,--gc-sections
|
||||||
endif
|
endif
|
||||||
LDFLAGS += $(LIBSOLO) $(LIBCBOR)
|
LDFLAGS += $(LIBSOLO) $(LIBCBOR) -lsodium
|
||||||
|
|
||||||
|
|
||||||
CFLAGS = -O2 -fdata-sections -ffunction-sections -g
|
CFLAGS = -O2 -fdata-sections -ffunction-sections -g
|
||||||
|
@ -140,4 +140,4 @@ test-docker:
|
||||||
travis:
|
travis:
|
||||||
$(MAKE) test VENV=". ../../venv/bin/activate;"
|
$(MAKE) test VENV=". ../../venv/bin/activate;"
|
||||||
$(MAKE) test-docker
|
$(MAKE) test-docker
|
||||||
$(MAKE) black
|
$(MAKE) black
|
||||||
|
|
|
@ -13,10 +13,14 @@
|
||||||
#define COSE_KEY_LABEL_X -2
|
#define COSE_KEY_LABEL_X -2
|
||||||
#define COSE_KEY_LABEL_Y -3
|
#define COSE_KEY_LABEL_Y -3
|
||||||
|
|
||||||
|
#define COSE_KEY_KTY_OKP 1
|
||||||
#define COSE_KEY_KTY_EC2 2
|
#define COSE_KEY_KTY_EC2 2
|
||||||
|
|
||||||
#define COSE_KEY_CRV_P256 1
|
#define COSE_KEY_CRV_P256 1
|
||||||
|
#define COSE_KEY_CRV_ED25519 6
|
||||||
|
|
||||||
#define COSE_ALG_ES256 -7
|
#define COSE_ALG_ES256 -7
|
||||||
|
#define COSE_ALG_EDDSA -8
|
||||||
#define COSE_ALG_ECDH_ES_HKDF_256 -25
|
#define COSE_ALG_ECDH_ES_HKDF_256 -25
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// copied, modified, or distributed except according to those terms.
|
// copied, modified, or distributed except according to those terms.
|
||||||
/*
|
/*
|
||||||
* Wrapper for crypto implementation on device.
|
* Wrapper for crypto implementation on device.
|
||||||
*
|
*
|
||||||
* Can be replaced with different crypto implementation by
|
* Can be replaced with different crypto implementation by
|
||||||
* defining EXTERNAL_SOLO_CRYPTO
|
* defining EXTERNAL_SOLO_CRYPTO
|
||||||
*
|
*
|
||||||
|
@ -31,6 +31,11 @@
|
||||||
#include APP_CONFIG
|
#include APP_CONFIG
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
#if defined(STM32L432xx)
|
||||||
|
#include "salty.h"
|
||||||
|
#else
|
||||||
|
#include <sodium/crypto_sign_ed25519.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
|
@ -358,5 +363,65 @@ void crypto_aes256_encrypt(uint8_t * buf, int length)
|
||||||
AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
|
AES_CBC_encrypt_buffer(&aes_ctx, buf, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void crypto_ed25519_derive_public_key(uint8_t * data, int len, uint8_t * x)
|
||||||
|
{
|
||||||
|
#if defined(STM32L432xx)
|
||||||
|
|
||||||
|
uint8_t seed[salty_SECRETKEY_SEED_LENGTH];
|
||||||
|
|
||||||
|
generate_private_key(data, len, NULL, 0, seed);
|
||||||
|
salty_public_key(seed, x);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
uint8_t seed[crypto_sign_ed25519_SEEDBYTES];
|
||||||
|
uint8_t sk[crypto_sign_ed25519_SECRETKEYBYTES];
|
||||||
|
|
||||||
|
generate_private_key(data, len, NULL, 0, seed);
|
||||||
|
crypto_sign_ed25519_seed_keypair(x, sk, seed);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ed25519_load_key(uint8_t * data, int len)
|
||||||
|
{
|
||||||
|
#if defined(STM32L432xx)
|
||||||
|
|
||||||
|
static uint8_t seed[salty_SECRETKEY_SEED_LENGTH];
|
||||||
|
|
||||||
|
generate_private_key(data, len, NULL, 0, seed);
|
||||||
|
|
||||||
|
_signing_key = seed;
|
||||||
|
_key_len = salty_SECRETKEY_SEED_LENGTH;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
uint8_t seed[crypto_sign_ed25519_SEEDBYTES];
|
||||||
|
uint8_t pk[crypto_sign_ed25519_PUBLICKEYBYTES];
|
||||||
|
static uint8_t sk[crypto_sign_ed25519_SECRETKEYBYTES];
|
||||||
|
|
||||||
|
generate_private_key(data, len, NULL, 0, seed);
|
||||||
|
crypto_sign_ed25519_seed_keypair(pk, sk, seed);
|
||||||
|
|
||||||
|
_signing_key = sk;
|
||||||
|
_key_len = crypto_sign_ed25519_SECRETKEYBYTES;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ed25519_sign(uint8_t * data, int len, uint8_t * sig)
|
||||||
|
{
|
||||||
|
#if defined(STM32L432xx)
|
||||||
|
|
||||||
|
// TODO: check that correct load_key() had been called?
|
||||||
|
salty_sign(_signing_key, data, len, sig);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// TODO: check that correct load_key() had been called?
|
||||||
|
crypto_sign_ed25519_detached(sig, NULL, data, len, _signing_key);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,6 +31,9 @@ void crypto_load_external_key(uint8_t * key, int len);
|
||||||
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig);
|
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig);
|
||||||
void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID);
|
void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID);
|
||||||
|
|
||||||
|
void crypto_ed25519_derive_public_key(uint8_t * data, int len, uint8_t * x);
|
||||||
|
void crypto_ed25519_sign(uint8_t * data1, int len1, uint8_t * sig);
|
||||||
|
void crypto_ed25519_load_key(uint8_t * data, int len);
|
||||||
|
|
||||||
void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey);
|
void generate_private_key(uint8_t * data, int len, uint8_t * data2, int len2, uint8_t * privkey);
|
||||||
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
void crypto_ecc256_make_key_pair(uint8_t * pubkey, uint8_t * privkey);
|
||||||
|
|
135
fido2/ctap.c
135
fido2/ctap.c
|
@ -41,13 +41,13 @@ struct _getAssertionState getAssertionState;
|
||||||
// Generate a mask to keep the confidentiality of the "metadata" field in the credential ID.
|
// Generate a mask to keep the confidentiality of the "metadata" field in the credential ID.
|
||||||
// Mask = hmac(device-secret, 14-random-bytes-in-credential-id)
|
// Mask = hmac(device-secret, 14-random-bytes-in-credential-id)
|
||||||
// Masked_output = Mask ^ metadata
|
// Masked_output = Mask ^ metadata
|
||||||
static void add_masked_metadata_for_credential(CredentialId * credential, uint32_t cred_protect){
|
static void add_masked_metadata_for_credential(CredentialId * credential, uint32_t metadata){
|
||||||
uint8_t mask[32];
|
uint8_t mask[32];
|
||||||
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, mask);
|
crypto_sha256_hmac_init(CRYPTO_TRANSPORT_KEY, 0, mask);
|
||||||
crypto_sha256_update(credential->entropy.nonce, CREDENTIAL_NONCE_SIZE - 4);
|
crypto_sha256_update(credential->entropy.nonce, CREDENTIAL_NONCE_SIZE - 4);
|
||||||
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY,0, mask);
|
crypto_sha256_hmac_final(CRYPTO_TRANSPORT_KEY,0, mask);
|
||||||
|
|
||||||
credential->entropy.metadata.value = *((uint32_t*)mask) ^ cred_protect;
|
credential->entropy.metadata.value = *((uint32_t*)mask) ^ metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t read_metadata_from_masked_credential(CredentialId * credential){
|
static uint32_t read_metadata_from_masked_credential(CredentialId * credential){
|
||||||
|
@ -59,11 +59,29 @@ static uint32_t read_metadata_from_masked_credential(CredentialId * credential){
|
||||||
return credential->entropy.metadata.value ^ *((uint32_t*)mask);
|
return credential->entropy.metadata.value ^ *((uint32_t*)mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t read_cred_protect_from_masked_credential(CredentialId * credential)
|
||||||
|
|
||||||
uint8_t check_credential_metadata(CredentialId * credential, uint8_t is_verified, uint8_t is_from_credid_list)
|
|
||||||
{
|
{
|
||||||
uint32_t cred_protect = read_metadata_from_masked_credential(credential);
|
return read_metadata_from_masked_credential(credential) & 0xffffU;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int32_t read_cose_alg_from_masked_credential(CredentialId * credential)
|
||||||
|
{
|
||||||
|
uint8_t alg = (read_metadata_from_masked_credential(credential) >> 16) & 0xffU;
|
||||||
|
|
||||||
|
switch (alg)
|
||||||
|
{
|
||||||
|
default: // what else?
|
||||||
|
case CREDID_ALG_ES256:
|
||||||
|
return COSE_ALG_ES256;
|
||||||
|
case CREDID_ALG_EDDSA:
|
||||||
|
return COSE_ALG_EDDSA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t check_credential_metadata(CredentialId * credential, uint8_t is_verified, uint8_t is_from_credid_list)
|
||||||
|
{
|
||||||
|
uint32_t cred_protect = read_cred_protect_from_masked_credential(credential);
|
||||||
|
|
||||||
switch (cred_protect){
|
switch (cred_protect){
|
||||||
case EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID:
|
case EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID:
|
||||||
if (!is_from_credid_list) {
|
if (!is_from_credid_list) {
|
||||||
|
@ -80,6 +98,7 @@ uint8_t check_credential_metadata(CredentialId * credential, uint8_t is_verified
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,7 +269,7 @@ uint8_t ctap_get_info(CborEncoder * encoder)
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cbor_encode_uint(&map, 0x08); // maxCredentialIdLength
|
ret = cbor_encode_uint(&map, 0x08); // maxCredentialIdLength
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
{
|
{
|
||||||
ret = cbor_encode_uint(&map, 128);
|
ret = cbor_encode_uint(&map, 128);
|
||||||
|
@ -271,14 +290,14 @@ static int ctap_add_cose_key(CborEncoder * cose_key, uint8_t * x, uint8_t * y, u
|
||||||
int ret;
|
int ret;
|
||||||
CborEncoder map;
|
CborEncoder map;
|
||||||
|
|
||||||
ret = cbor_encoder_create_map(cose_key, &map, 5);
|
ret = cbor_encoder_create_map(cose_key, &map, algtype != COSE_ALG_EDDSA? 5 : 4);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
ret = cbor_encode_int(&map, COSE_KEY_LABEL_KTY);
|
ret = cbor_encode_int(&map, COSE_KEY_LABEL_KTY);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
ret = cbor_encode_int(&map, COSE_KEY_KTY_EC2);
|
ret = cbor_encode_int(&map, algtype != COSE_ALG_EDDSA? COSE_KEY_KTY_EC2 : COSE_KEY_KTY_OKP);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,7 +311,7 @@ static int ctap_add_cose_key(CborEncoder * cose_key, uint8_t * x, uint8_t * y, u
|
||||||
{
|
{
|
||||||
ret = cbor_encode_int(&map, COSE_KEY_LABEL_CRV);
|
ret = cbor_encode_int(&map, COSE_KEY_LABEL_CRV);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
ret = cbor_encode_int(&map, COSE_KEY_CRV_P256);
|
ret = cbor_encode_int(&map, algtype != COSE_ALG_EDDSA? COSE_KEY_CRV_P256: COSE_KEY_CRV_ED25519);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +323,7 @@ static int ctap_add_cose_key(CborEncoder * cose_key, uint8_t * x, uint8_t * y, u
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (algtype != COSE_ALG_EDDSA)
|
||||||
{
|
{
|
||||||
ret = cbor_encode_int(&map, COSE_KEY_LABEL_Y);
|
ret = cbor_encode_int(&map, COSE_KEY_LABEL_Y);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
@ -332,6 +352,11 @@ static int ctap_generate_cose_key(CborEncoder * cose_key, uint8_t * hmac_input,
|
||||||
crypto_ecc256_derive_public_key(hmac_input, len, x, y);
|
crypto_ecc256_derive_public_key(hmac_input, len, x, y);
|
||||||
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||||
break;
|
break;
|
||||||
|
case COSE_ALG_EDDSA:
|
||||||
|
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_FAST);
|
||||||
|
crypto_ed25519_derive_public_key(hmac_input, len, x);
|
||||||
|
if (device_is_nfc() == NFC_IS_ACTIVE) device_set_clock_rate(DEVICE_LOW_POWER_IDLE);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype);
|
printf2(TAG_ERR,"Error, COSE alg %d not supported\n", algtype);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -627,8 +652,8 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||||
check_retr(but);
|
check_retr(but);
|
||||||
authData->head.flags = (1 << 0); // User presence
|
authData->head.flags = (1 << 0); // User presence
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
device_set_status(CTAPHID_STATUS_PROCESSING);
|
device_set_status(CTAPHID_STATUS_PROCESSING);
|
||||||
|
|
||||||
authData->head.flags |= (ctap_is_pin_set() << 2);
|
authData->head.flags |= (ctap_is_pin_set() << 2);
|
||||||
|
@ -648,7 +673,9 @@ static int ctap_make_auth_data(struct rpId * rp, CborEncoder * map, uint8_t * au
|
||||||
memset((uint8_t*)&authData->attest.id, 0, sizeof(CredentialId));
|
memset((uint8_t*)&authData->attest.id, 0, sizeof(CredentialId));
|
||||||
|
|
||||||
ctap_generate_rng(authData->attest.id.entropy.nonce, CREDENTIAL_NONCE_SIZE);
|
ctap_generate_rng(authData->attest.id.entropy.nonce, CREDENTIAL_NONCE_SIZE);
|
||||||
add_masked_metadata_for_credential(&authData->attest.id, extensions->cred_protect);
|
|
||||||
|
uint8_t alg = credInfo->COSEAlgorithmIdentifier == COSE_ALG_EDDSA? CREDID_ALG_EDDSA : CREDID_ALG_ES256;
|
||||||
|
add_masked_metadata_for_credential(&authData->attest.id, extensions->cred_protect | (alg << 16));
|
||||||
|
|
||||||
authData->attest.id.count = count;
|
authData->attest.id.count = count;
|
||||||
|
|
||||||
|
@ -755,22 +782,32 @@ int ctap_encode_der_sig(const uint8_t * const in_sigbuf, uint8_t * const out_sig
|
||||||
}
|
}
|
||||||
|
|
||||||
// require load_key prior to this
|
// require load_key prior to this
|
||||||
// @data data to hash before signature
|
// @data data to hash before signature, MUST have room to append clientDataHash for ED25519
|
||||||
// @clientDataHash for signature
|
// @clientDataHash for signature
|
||||||
// @tmp buffer for hash. (can be same as data if data >= 32 bytes)
|
// @tmp buffer for hash. (can be same as data if data >= 32 bytes)
|
||||||
// @sigbuf OUT location to deposit signature (must be 64 bytes)
|
// @sigbuf OUT location to deposit signature (must be 64 bytes)
|
||||||
// @sigder OUT location to deposit der signature (must be 72 bytes)
|
// @sigder OUT location to deposit der signature (must be 72 bytes)
|
||||||
// @return length of der signature
|
// @return length of der signature
|
||||||
int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHash, uint8_t * hashbuf, uint8_t * sigbuf, uint8_t * sigder)
|
int ctap_calculate_signature(uint8_t * data, int datalen, uint8_t * clientDataHash, uint8_t * hashbuf, uint8_t * sigbuf, uint8_t * sigder, int32_t alg)
|
||||||
{
|
{
|
||||||
// calculate attestation sig
|
// calculate attestation sig
|
||||||
crypto_sha256_init();
|
if (alg == COSE_ALG_EDDSA)
|
||||||
crypto_sha256_update(data, datalen);
|
{
|
||||||
crypto_sha256_update(clientDataHash, CLIENT_DATA_HASH_SIZE);
|
// ED25519 signing needs message in one chunk
|
||||||
crypto_sha256_final(hashbuf);
|
memmove(data + datalen, clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||||
|
crypto_ed25519_sign(data, datalen + CLIENT_DATA_HASH_SIZE, sigder); // not DER, just plain binary!
|
||||||
|
return 64;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(data, datalen);
|
||||||
|
crypto_sha256_update(clientDataHash, CLIENT_DATA_HASH_SIZE);
|
||||||
|
crypto_sha256_final(hashbuf);
|
||||||
|
|
||||||
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
crypto_ecc256_sign(hashbuf, 32, sigbuf);
|
||||||
return ctap_encode_der_sig(sigbuf,sigder);
|
return ctap_encode_der_sig(sigbuf,sigder);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
||||||
|
@ -783,7 +820,7 @@ uint8_t ctap_add_attest_statement(CborEncoder * map, uint8_t * sigder, int len)
|
||||||
return CTAP2_ERR_PROCESSING;
|
return CTAP2_ERR_PROCESSING;
|
||||||
}
|
}
|
||||||
device_attestation_read_cert_der(cert);
|
device_attestation_read_cert_der(cert);
|
||||||
|
|
||||||
CborEncoder stmtmap;
|
CborEncoder stmtmap;
|
||||||
CborEncoder x5carr;
|
CborEncoder x5carr;
|
||||||
|
|
||||||
|
@ -866,7 +903,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||||
CTAP_makeCredential MC;
|
CTAP_makeCredential MC;
|
||||||
int ret;
|
int ret;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
uint8_t auth_data_buf[310];
|
uint8_t auth_data_buf[310 + CLIENT_DATA_HASH_SIZE];
|
||||||
CTAP_credentialDescriptor * excl_cred = (CTAP_credentialDescriptor *) auth_data_buf;
|
CTAP_credentialDescriptor * excl_cred = (CTAP_credentialDescriptor *) auth_data_buf;
|
||||||
uint8_t * sigbuf = auth_data_buf + 32;
|
uint8_t * sigbuf = auth_data_buf + 32;
|
||||||
uint8_t * sigder = auth_data_buf + 32 + 64;
|
uint8_t * sigder = auth_data_buf + 32 + 64;
|
||||||
|
@ -975,7 +1012,7 @@ uint8_t ctap_make_credential(CborEncoder * encoder, uint8_t * request, int lengt
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto_ecc256_load_attestation_key();
|
crypto_ecc256_load_attestation_key();
|
||||||
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder);
|
int sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_sz, MC.clientDataHash, auth_data_buf, sigbuf, sigder, COSE_ALG_ES256);
|
||||||
printf1(TAG_MC,"der sig [%d]: ", sigder_sz); dump_hex1(TAG_MC, sigder, sigder_sz);
|
printf1(TAG_MC,"der sig [%d]: ", sigder_sz); dump_hex1(TAG_MC, sigder, sigder_sz);
|
||||||
|
|
||||||
ret = ctap_add_attest_statement(&map, sigder, sigder_sz);
|
ret = ctap_add_attest_statement(&map, sigder, sigder_sz);
|
||||||
|
@ -1136,14 +1173,14 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
int protection_status =
|
int protection_status =
|
||||||
check_credential_metadata(&GA->creds[i].credential.id, getAssertionState.user_verified, 1);
|
check_credential_metadata(&GA->creds[i].credential.id, getAssertionState.user_verified, 1);
|
||||||
|
|
||||||
if (protection_status != 0) {
|
if (protection_status != 0) {
|
||||||
printf1(TAG_GREEN,"skipping protected wrapped credential.\r\n");
|
printf1(TAG_GREEN,"skipping protected wrapped credential.\r\n");
|
||||||
GA->creds[i].credential.id.count = 0; // invalidate
|
GA->creds[i].credential.id.count = 0; // invalidate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add user info if it exists
|
// add user info if it exists
|
||||||
add_existing_user_info(&GA->creds[i]);
|
add_existing_user_info(&GA->creds[i]);
|
||||||
|
@ -1170,7 +1207,7 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
|
||||||
|
|
||||||
printf1(TAG_GREEN, "rpIdHash%d: ", i); dump_hex1(TAG_GREEN, rk.id.rpIdHash, 32);
|
printf1(TAG_GREEN, "rpIdHash%d: ", i); dump_hex1(TAG_GREEN, rk.id.rpIdHash, 32);
|
||||||
|
|
||||||
int protection_status =
|
int protection_status =
|
||||||
check_credential_metadata(&rk.id, getAssertionState.user_verified, 0);
|
check_credential_metadata(&rk.id, getAssertionState.user_verified, 0);
|
||||||
|
|
||||||
if (protection_status != 0) {
|
if (protection_status != 0) {
|
||||||
|
@ -1200,8 +1237,8 @@ int ctap_filter_invalid_credentials(CTAP_getAssertion * GA)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int8_t save_credential_list( uint8_t * clientDataHash,
|
static int8_t save_credential_list( uint8_t * clientDataHash,
|
||||||
CTAP_credentialDescriptor * creds,
|
CTAP_credentialDescriptor * creds,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
CTAP_extensions * extensions)
|
CTAP_extensions * extensions)
|
||||||
{
|
{
|
||||||
|
@ -1258,7 +1295,15 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cred_size = get_credential_id_size(cred->type);
|
unsigned int cred_size = get_credential_id_size(cred->type);
|
||||||
crypto_ecc256_load_key((uint8_t*)&cred->credential.id, cred_size, NULL, 0);
|
int32_t cose_alg = read_cose_alg_from_masked_credential(&cred->credential.id);
|
||||||
|
if (cose_alg == COSE_ALG_EDDSA)
|
||||||
|
{
|
||||||
|
crypto_ed25519_load_key((uint8_t*)&cred->credential.id, cred_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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) )
|
||||||
|
@ -1268,9 +1313,11 @@ uint8_t ctap_end_get_assertion(CborEncoder * map, CTAP_credentialDescriptor * cr
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_buf_sz, clientDataHash, auth_data_buf, sigbuf, sigder);
|
sigder_sz = ctap_calculate_signature(auth_data_buf, auth_data_buf_sz, clientDataHash, auth_data_buf, sigbuf, sigder, cose_alg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf1(TAG_GREEN, "sigder_sz = %d\n", sigder_sz);
|
||||||
|
|
||||||
{
|
{
|
||||||
ret = cbor_encode_int(map, RESP_signature); // 3
|
ret = cbor_encode_int(map, RESP_signature); // 3
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
@ -1341,9 +1388,9 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ctap_end_get_assertion(&map, cred,
|
ret = ctap_end_get_assertion(&map, cred,
|
||||||
(uint8_t *)&getAssertionState.buf.authData,
|
(uint8_t *)&getAssertionState.buf.authData,
|
||||||
sizeof(CTAP_authDataHeader) + ext_encoder_buf_size,
|
sizeof(CTAP_authDataHeader) + ext_encoder_buf_size,
|
||||||
getAssertionState.clientDataHash);
|
getAssertionState.clientDataHash);
|
||||||
|
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
@ -1428,12 +1475,14 @@ uint8_t ctap_cred_rk(CborEncoder * encoder, int rk_ind, int rk_count)
|
||||||
ctap_load_rk(rk_ind, &rk);
|
ctap_load_rk(rk_ind, &rk);
|
||||||
|
|
||||||
uint32_t cred_protect = read_metadata_from_masked_credential(&rk.id);
|
uint32_t cred_protect = read_metadata_from_masked_credential(&rk.id);
|
||||||
if ( cred_protect == 0 || cred_protect > 3 )
|
if ( cred_protect == 0 || cred_protect > 3 )
|
||||||
{
|
{
|
||||||
// Take default value of userVerificationOptional
|
// Take default value of userVerificationOptional
|
||||||
cred_protect = EXT_CRED_PROTECT_OPTIONAL;
|
cred_protect = EXT_CRED_PROTECT_OPTIONAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t cose_alg = read_cose_alg_from_masked_credential(&rk.id);
|
||||||
|
|
||||||
CborEncoder map;
|
CborEncoder map;
|
||||||
size_t map_size = rk_count > 0 ? 5 : 4;
|
size_t map_size = rk_count > 0 ? 5 : 4;
|
||||||
int ret = cbor_encoder_create_map(encoder, &map, map_size);
|
int ret = cbor_encoder_create_map(encoder, &map, map_size);
|
||||||
|
@ -1456,7 +1505,7 @@ uint8_t ctap_cred_rk(CborEncoder * encoder, int rk_ind, int rk_count)
|
||||||
ret = cbor_encode_int(&map, 8);
|
ret = cbor_encode_int(&map, 8);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
{
|
{
|
||||||
ctap_generate_cose_key(&map, (uint8_t*)&rk.id, sizeof(CredentialId), PUB_KEY_CRED_PUB_KEY, COSE_ALG_ES256);
|
ctap_generate_cose_key(&map, (uint8_t*)&rk.id, sizeof(CredentialId), PUB_KEY_CRED_PUB_KEY, cose_alg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rk_count > 0)
|
if (rk_count > 0)
|
||||||
|
@ -1479,8 +1528,8 @@ uint8_t ctap_cred_rk(CborEncoder * encoder, int rk_ind, int rk_count)
|
||||||
|
|
||||||
uint8_t ctap_cred_mgmt_pinauth(CTAP_credMgmt *CM)
|
uint8_t ctap_cred_mgmt_pinauth(CTAP_credMgmt *CM)
|
||||||
{
|
{
|
||||||
if (CM->cmd != CM_cmdMetadata &&
|
if (CM->cmd != CM_cmdMetadata &&
|
||||||
CM->cmd != CM_cmdRPBegin &&
|
CM->cmd != CM_cmdRPBegin &&
|
||||||
CM->cmd != CM_cmdRKBegin &&
|
CM->cmd != CM_cmdRKBegin &&
|
||||||
CM->cmd != CM_cmdRKDelete)
|
CM->cmd != CM_cmdRKDelete)
|
||||||
{
|
{
|
||||||
|
@ -1548,7 +1597,7 @@ static int scan_for_next_rp(int index){
|
||||||
occurs_previously = 0;
|
occurs_previously = 0;
|
||||||
|
|
||||||
index++;
|
index++;
|
||||||
if ((unsigned int)index >= ctap_rk_size())
|
if ((unsigned int)index >= ctap_rk_size())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1598,7 +1647,7 @@ static int scan_for_next_rk(int index, uint8_t * initialRpIdHash){
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
index++;
|
index++;
|
||||||
if ((unsigned int)index >= ctap_rk_size())
|
if ((unsigned int)index >= ctap_rk_size())
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1870,8 +1919,8 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
||||||
ret = cbor_encoder_close_container(encoder, &map);
|
ret = cbor_encoder_close_container(encoder, &map);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
ret = save_credential_list( GA.clientDataHash,
|
ret = save_credential_list( GA.clientDataHash,
|
||||||
GA.creds + 1 /* skip first credential*/,
|
GA.creds + 1 /* skip first credential*/,
|
||||||
validCredCount - 1,
|
validCredCount - 1,
|
||||||
&GA.extensions);
|
&GA.extensions);
|
||||||
check_retr(ret);
|
check_retr(ret);
|
||||||
|
@ -2365,7 +2414,7 @@ static void ctap_state_init()
|
||||||
|
|
||||||
/** Overwrite master secret from external source.
|
/** Overwrite master secret from external source.
|
||||||
* @param keybytes an array of KEY_SPACE_BYTES length.
|
* @param keybytes an array of KEY_SPACE_BYTES length.
|
||||||
*
|
*
|
||||||
* This function should only be called from a privilege mode.
|
* This function should only be called from a privilege mode.
|
||||||
*/
|
*/
|
||||||
void ctap_load_external_keys(uint8_t * keybytes){
|
void ctap_load_external_keys(uint8_t * keybytes){
|
||||||
|
|
|
@ -78,6 +78,9 @@
|
||||||
#define EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID 0x02
|
#define EXT_CRED_PROTECT_OPTIONAL_WITH_CREDID 0x02
|
||||||
#define EXT_CRED_PROTECT_REQUIRED 0x03
|
#define EXT_CRED_PROTECT_REQUIRED 0x03
|
||||||
|
|
||||||
|
#define CREDID_ALG_ES256 0x0
|
||||||
|
#define CREDID_ALG_EDDSA 0x1
|
||||||
|
|
||||||
#define RESP_versions 0x1
|
#define RESP_versions 0x1
|
||||||
#define RESP_extensions 0x2
|
#define RESP_extensions 0x2
|
||||||
#define RESP_aaguid 0x3
|
#define RESP_aaguid 0x3
|
||||||
|
@ -357,10 +360,10 @@ typedef struct
|
||||||
|
|
||||||
|
|
||||||
struct _getAssertionState {
|
struct _getAssertionState {
|
||||||
// Room for both authData struct and extensions
|
// Room for both authData struct and extensions + clientDataHash for efficient ED25519 signature generation
|
||||||
struct {
|
struct {
|
||||||
CTAP_authDataHeader authData;
|
CTAP_authDataHeader authData;
|
||||||
uint8_t extensions[80];
|
uint8_t extensions[80 + CLIENT_DATA_HASH_SIZE];
|
||||||
} __attribute__((packed)) buf;
|
} __attribute__((packed)) buf;
|
||||||
CTAP_extensions extensions;
|
CTAP_extensions extensions;
|
||||||
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
|
||||||
|
|
|
@ -256,7 +256,7 @@ static int pub_key_cred_param_supported(uint8_t cred, int32_t alg)
|
||||||
{
|
{
|
||||||
if (cred == PUB_KEY_CRED_PUB_KEY)
|
if (cred == PUB_KEY_CRED_PUB_KEY)
|
||||||
{
|
{
|
||||||
if (alg == COSE_ALG_ES256)
|
if (alg == COSE_ALG_ES256 || alg == COSE_ALG_EDDSA)
|
||||||
{
|
{
|
||||||
return CREDENTIAL_IS_SUPPORTED;
|
return CREDENTIAL_IS_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
@ -1025,7 +1025,7 @@ static uint8_t parse_cred_mgmt_subcommandparams(CborValue * val, CTAP_credMgmt *
|
||||||
|
|
||||||
ret = cbor_value_enter_container(val,&map);
|
ret = cbor_value_enter_container(val,&map);
|
||||||
check_ret(ret);
|
check_ret(ret);
|
||||||
|
|
||||||
const uint8_t * start_byte = cbor_value_get_next_byte(&map) - 1;
|
const uint8_t * start_byte = cbor_value_get_next_byte(&map) - 1;
|
||||||
|
|
||||||
ret = cbor_value_get_map_length(val, &map_length);
|
ret = cbor_value_get_map_length(val, &map_length);
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
version=$1
|
version=$1
|
||||||
|
|
||||||
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
export PREFIX=/opt/gcc-arm-none-eabi-8-2019-q3-update/bin/
|
||||||
|
source ${CARGO_HOME}/env
|
||||||
|
|
||||||
cd /solo/targets/stm32l432
|
cd /solo/targets/stm32l432
|
||||||
ls
|
ls
|
||||||
|
|
||||||
make cbor
|
make cbor
|
||||||
|
make salty
|
||||||
|
|
||||||
out_dir="/builds"
|
out_dir="/builds"
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ BOOTMAKE=build/bootloader.mk VERSION_FULL=${VERSION_FULL}
|
||||||
|
|
||||||
merge_hex=solo mergehex
|
merge_hex=solo mergehex
|
||||||
|
|
||||||
.PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor test
|
.PHONY: all all-hacker all-locked debugboot-app debugboot-boot boot-sig-checking boot-no-sig build-release-locked build-release build-release build-hacker build-debugboot clean clean2 flash flash_dfu flashboot detach cbor salty test
|
||||||
|
|
||||||
|
|
||||||
# The following are the main targets for reproducible builds.
|
# The following are the main targets for reproducible builds.
|
||||||
|
@ -55,13 +55,13 @@ boot-sig-checking:
|
||||||
boot-no-sig:
|
boot-no-sig:
|
||||||
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
|
$(MAKE) -f $(BOOTMAKE) -j8 bootloader.hex PREFIX=$(PREFIX) EXTRA_DEFINES='-DSOLO_HACKER' DEBUG=0
|
||||||
|
|
||||||
build-release-locked: cbor clean2 boot-sig-checking clean all-locked
|
build-release-locked: salty cbor clean2 boot-sig-checking clean all-locked
|
||||||
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
||||||
|
|
||||||
build-release: cbor clean2 boot-sig-checking clean all
|
build-release: salty cbor clean2 boot-sig-checking clean all
|
||||||
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
||||||
|
|
||||||
build-hacker: cbor clean2 boot-no-sig clean all-hacker
|
build-hacker: salty cbor clean2 boot-no-sig clean all-hacker
|
||||||
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
$(VENV) $(merge_hex) solo.hex bootloader.hex all.hex
|
||||||
|
|
||||||
build-debugboot: clean2 debugboot-boot clean debugboot-app
|
build-debugboot: clean2 debugboot-boot clean debugboot-app
|
||||||
|
@ -107,6 +107,9 @@ solo.hex:
|
||||||
cbor:
|
cbor:
|
||||||
$(MAKE) -f $(APPMAKE) -j8 cbor
|
$(MAKE) -f $(APPMAKE) -j8 cbor
|
||||||
|
|
||||||
|
salty:
|
||||||
|
$(MAKE) -f $(APPMAKE) -j8 salty
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(MAKE) build-release-locked
|
$(MAKE) build-release-locked
|
||||||
$(MAKE) build-release
|
$(MAKE) build-release
|
||||||
|
|
|
@ -24,12 +24,13 @@ OBJ=$(OBJ1:.s=.o)
|
||||||
|
|
||||||
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/
|
INC = -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/
|
||||||
|
|
||||||
INC+= -I../../fido2/ -I../../fido2/extensions
|
INC += -I../../fido2/ -I../../fido2/extensions
|
||||||
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
||||||
INC += -I../../crypto/tiny-AES-c
|
INC += -I../../crypto/tiny-AES-c
|
||||||
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
|
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
|
||||||
|
INC += -I../../crypto/salty/c-api
|
||||||
|
|
||||||
SEARCH=-L../../tinycbor/lib
|
SEARCH=-L../../tinycbor/lib -L../../crypto/salty/c-api
|
||||||
|
|
||||||
ifndef LDSCRIPT
|
ifndef LDSCRIPT
|
||||||
LDSCRIPT=linker/stm32l4xx.ld
|
LDSCRIPT=linker/stm32l4xx.ld
|
||||||
|
@ -52,7 +53,7 @@ DEFINES = -DDEBUG_LEVEL=$(DEBUG) -D$(CHIP) -DAES256=1 -DUSE_FULL_LL_DRIVER -DAP
|
||||||
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \
|
CFLAGS=$(INC) -c $(DEFINES) -Wall -Wextra -Wno-unused-parameter -Wno-missing-field-initializers -fdata-sections -ffunction-sections \
|
||||||
-fomit-frame-pointer $(HW) -g $(VERSION_FLAGS)
|
-fomit-frame-pointer $(HW) -g $(VERSION_FLAGS)
|
||||||
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
|
LDFLAGS_LIB=$(HW) $(SEARCH) -specs=nano.specs -specs=nosys.specs -Wl,--gc-sections -lnosys
|
||||||
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor
|
LDFLAGS=$(HW) $(LDFLAGS_LIB) -T$(LDSCRIPT) -Wl,-Map=$(TARGET).map,--cref -Wl,-Bstatic -ltinycbor -lsalty
|
||||||
|
|
||||||
ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0
|
ECC_CFLAGS = $(CFLAGS) -DuECC_PLATFORM=5 -DuECC_OPTIMIZATION_LEVEL=4 -DuECC_SQUARE_FUNC=1 -DuECC_SUPPORT_COMPRESSED_POINT=0
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ INC = -Ibootloader/ -Isrc/ -Isrc/cmsis/ -Ilib/ -Ilib/usbd/ -I../../fido2/ -I../.
|
||||||
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
INC += -I../../tinycbor/src -I../../crypto/sha256 -I../../crypto/micro-ecc
|
||||||
INC += -I../../crypto/tiny-AES-c
|
INC += -I../../crypto/tiny-AES-c
|
||||||
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
|
INC += -I../../crypto/cifra/src -I../../crypto/cifra/src/ext
|
||||||
|
INC += -I../../crypto/salty/c-api
|
||||||
|
|
||||||
ifndef LDSCRIPT
|
ifndef LDSCRIPT
|
||||||
LDSCRIPT=linker/bootloader_stm32l4xx.ld
|
LDSCRIPT=linker/bootloader_stm32l4xx.ld
|
||||||
|
|
Ładowanie…
Reference in New Issue