all core functionality *works*
This commit is contained in:
@ -33,6 +33,7 @@ static mbedtls_ctr_drbg_context ctr_drbg;
|
|||||||
|
|
||||||
static const struct uECC_Curve_t * _es256_curve = NULL;
|
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||||
static const uint8_t * _signing_key = NULL;
|
static const uint8_t * _signing_key = NULL;
|
||||||
|
static int _external_key_len = 0;
|
||||||
|
|
||||||
// Secrets 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"
|
static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
|
||||||
@ -182,11 +183,15 @@ void crypto_ecc256_init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void crypto_ecc256_load_attestation_key()
|
void crypto_load_external_key(uint8_t * key, int len)
|
||||||
{
|
{
|
||||||
_signing_key = attestation_key;
|
_signing_key = key;
|
||||||
|
_external_key_len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Import a point from unsigned binary data
|
* \brief Import a point from unsigned binary data
|
||||||
*
|
*
|
||||||
@ -269,6 +274,48 @@ 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)
|
||||||
|
{
|
||||||
|
mbedtls_ecp_group grp; /*!< Elliptic curve and base point */
|
||||||
|
mbedtls_mpi d; /*!< our secret value */
|
||||||
|
//#define CRYPTO_ENABLE CMU->HFBUSCLKEN0 |= CMU_HFBUSCLKEN0_CRYPTO; \
|
||||||
|
// CRYPTO->IFC = _CRYPTO_IFC_MASK; \
|
||||||
|
// CRYPTO->CMD = CRYPTO_CMD_SEQSTOP; \
|
||||||
|
// CRYPTO->CTRL = CRYPTO_CTRL_DMA0RSEL_DDATA0; \
|
||||||
|
// CRYPTO->SEQCTRL = 0; \
|
||||||
|
// CRYPTO->SEQCTRLB = 0
|
||||||
|
//
|
||||||
|
//#define CRYPTO_DISABLE \
|
||||||
|
// CRYPTO->IEN = 0; \
|
||||||
|
// CMU->HFBUSCLKEN0 &= ~CMU_HFBUSCLKEN0_CRYPTO;
|
||||||
|
// CRYPTO_DISABLE;
|
||||||
|
// CRYPTO_ENABLE;
|
||||||
|
// mbedtls_ecp_group_init( &grp );
|
||||||
|
// mbedtls_mpi_init( &d );
|
||||||
|
// mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||||
|
// mbedtls_mpi_read_binary(&d, _signing_key, 32);
|
||||||
|
//
|
||||||
|
// mbedtls_mpi r,s;
|
||||||
|
// mbedtls_mpi_init(&r);
|
||||||
|
// mbedtls_mpi_init(&s);
|
||||||
|
//
|
||||||
|
// printf("signing..\n");
|
||||||
|
// dump_hex(data,len);
|
||||||
|
// mbedtls_ecdsa_sign_det( &grp, &r, &s, &d,
|
||||||
|
// data, 32, MBEDTLS_MD_SHA256 );// Issue: this will freeze on 13th iteration..
|
||||||
|
// printf("signed\n");
|
||||||
|
//
|
||||||
|
// mbedtls_mpi_write_binary(&r,sig,32);
|
||||||
|
// mbedtls_mpi_write_binary(&s,sig+32,32);
|
||||||
|
|
||||||
|
if ( uECC_sign(_signing_key, data, len, sig, _es256_curve) == 0)
|
||||||
|
{
|
||||||
|
printf("error, uECC failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate a keypair with configurable base point
|
* Generate a keypair with configurable base point
|
||||||
*/
|
*/
|
||||||
|
@ -17,6 +17,27 @@
|
|||||||
#include "uECC.h"
|
#include "uECC.h"
|
||||||
#include "aes.h"
|
#include "aes.h"
|
||||||
#include "ctap.h"
|
#include "ctap.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "app.h"
|
||||||
|
|
||||||
|
#ifdef USING_PC
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MBEDTLS_ECP_DP_NONE = 0,
|
||||||
|
MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */
|
||||||
|
MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||||
|
} mbedtls_ecp_group_id;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
const uint8_t attestation_cert_der[];
|
const uint8_t attestation_cert_der[];
|
||||||
@ -29,6 +50,7 @@ const uint16_t attestation_key_size;
|
|||||||
static SHA256_CTX sha256_ctx;
|
static SHA256_CTX sha256_ctx;
|
||||||
static const struct uECC_Curve_t * _es256_curve = NULL;
|
static const struct uECC_Curve_t * _es256_curve = NULL;
|
||||||
static const uint8_t * _signing_key = NULL;
|
static const uint8_t * _signing_key = NULL;
|
||||||
|
static int _key_len = 0;
|
||||||
|
|
||||||
// Secrets 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"
|
static uint8_t master_secret[32] = "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff"
|
||||||
@ -136,6 +158,7 @@ void crypto_ecc256_init()
|
|||||||
void crypto_ecc256_load_attestation_key()
|
void crypto_ecc256_load_attestation_key()
|
||||||
{
|
{
|
||||||
_signing_key = attestation_key;
|
_signing_key = attestation_key;
|
||||||
|
_key_len = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
||||||
@ -147,6 +170,55 @@ void crypto_ecc256_sign(uint8_t * data, int len, uint8_t * sig)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,data2,len2,privkey);
|
||||||
|
_signing_key = privkey;
|
||||||
|
_key_len = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
void crypto_ecdsa_sign(uint8_t * data, int len, uint8_t * sig, int MBEDTLS_ECP_ID)
|
||||||
|
{
|
||||||
|
|
||||||
|
const struct uECC_Curve_t * curve = NULL;
|
||||||
|
|
||||||
|
switch(MBEDTLS_ECP_ID)
|
||||||
|
{
|
||||||
|
case MBEDTLS_ECP_DP_SECP192R1:
|
||||||
|
curve = uECC_secp192r1();
|
||||||
|
if (_key_len != 24) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP224R1:
|
||||||
|
curve = uECC_secp224r1();
|
||||||
|
if (_key_len != 28) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP256R1:
|
||||||
|
curve = uECC_secp256r1();
|
||||||
|
if (_key_len != 32) goto fail;
|
||||||
|
break;
|
||||||
|
case MBEDTLS_ECP_DP_SECP256K1:
|
||||||
|
curve = uECC_secp256k1();
|
||||||
|
if (_key_len != 32) goto fail;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("error, invalid ECDSA alg specifier\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( uECC_sign(_signing_key, data, len, sig, curve) == 0)
|
||||||
|
{
|
||||||
|
printf("error, uECC failed\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
printf("error, invalid key length\n");
|
||||||
|
exit(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
|
crypto_sha256_hmac_init(CRYPTO_MASTER_KEY, 0, privkey);
|
||||||
@ -171,13 +243,13 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
|
|||||||
memmove(y,pubkey+32,32);
|
memmove(y,pubkey+32,32);
|
||||||
}
|
}
|
||||||
|
|
||||||
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2)
|
void crypto_load_external_key(uint8_t * key, int len)
|
||||||
{
|
{
|
||||||
static uint8_t privkey[32];
|
_signing_key = key;
|
||||||
generate_private_key(data,len,data2,len2,privkey);
|
_key_len = len;
|
||||||
_signing_key = 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)
|
||||||
{
|
{
|
||||||
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
if (uECC_make_key(pubkey, privkey, _es256_curve) != 1)
|
||||||
|
@ -19,7 +19,9 @@ void crypto_ecc256_derive_public_key(uint8_t * data, int len, uint8_t * x, uint8
|
|||||||
|
|
||||||
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
|
void crypto_ecc256_load_key(uint8_t * data, int len, uint8_t * data2, int len2);
|
||||||
void crypto_ecc256_load_attestation_key();
|
void crypto_ecc256_load_attestation_key();
|
||||||
|
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 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);
|
||||||
|
243
fido2/ctap.c
243
fido2/ctap.c
@ -15,15 +15,15 @@
|
|||||||
#include "app.h"
|
#include "app.h"
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
#define PIN_TOKEN_SIZE 16
|
#define PIN_TOKEN_SIZE 16
|
||||||
uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||||
uint8_t KEY_AGREEMENT_PUB[64];
|
uint8_t KEY_AGREEMENT_PUB[64];
|
||||||
static uint8_t KEY_AGREEMENT_PRIV[32];
|
static uint8_t KEY_AGREEMENT_PRIV[32];
|
||||||
static uint8_t PIN_CODE_SET = 0;
|
|
||||||
uint8_t PIN_CODE[NEW_PIN_ENC_MAX_SIZE];
|
|
||||||
static uint8_t PIN_CODE_HASH[32];
|
static uint8_t PIN_CODE_HASH[32];
|
||||||
static uint8_t DEVICE_LOCKOUT = 0;
|
|
||||||
|
AuthenticatorState STATE;
|
||||||
|
|
||||||
static struct {
|
static struct {
|
||||||
CTAP_authDataHeader authData;
|
CTAP_authDataHeader authData;
|
||||||
@ -766,7 +766,7 @@ uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PIN_CODE_SET == 1 && GA.pinAuthPresent == 0)
|
if (ctap_is_pin_set() && GA.pinAuthPresent == 0)
|
||||||
{
|
{
|
||||||
printf2(TAG_ERR,"pinAuth is required\n");
|
printf2(TAG_ERR,"pinAuth is required\n");
|
||||||
return CTAP2_ERR_PIN_REQUIRED;
|
return CTAP2_ERR_PIN_REQUIRED;
|
||||||
@ -851,6 +851,14 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
return CTAP1_ERR_OTHER;
|
return CTAP1_ERR_OTHER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctap_is_pin_set()) // Check first, prevent SCA
|
||||||
|
{
|
||||||
|
if (ctap_device_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret);
|
crypto_ecc256_shared_secret(platform_pubkey, KEY_AGREEMENT_PRIV, shared_secret);
|
||||||
|
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
@ -898,6 +906,10 @@ uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platfor
|
|||||||
|
|
||||||
if (ctap_is_pin_set())
|
if (ctap_is_pin_set())
|
||||||
{
|
{
|
||||||
|
if (ctap_device_locked())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
crypto_aes256_reset_iv(NULL);
|
crypto_aes256_reset_iv(NULL);
|
||||||
crypto_aes256_decrypt(pinHashEnc, 16);
|
crypto_aes256_decrypt(pinHashEnc, 16);
|
||||||
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
if (memcmp(pinHashEnc, PIN_CODE_HASH, 16) != 0)
|
||||||
@ -1111,7 +1123,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
|
|||||||
case CTAP_CLIENT_PIN:
|
case CTAP_CLIENT_PIN:
|
||||||
if (ctap_device_locked())
|
if (ctap_device_locked())
|
||||||
{
|
{
|
||||||
status = CTAP2_ERR_NOT_ALLOWED;
|
status = CTAP2_ERR_OPERATION_DENIED;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1207,12 +1219,69 @@ done:
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ctap_flush_state(int backup)
|
||||||
|
{
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
if (backup)
|
||||||
|
{
|
||||||
|
authenticator_write_state(&STATE, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ctap_state_init()
|
||||||
|
{
|
||||||
|
// Set to 0xff instead of 0x00 to be easier on flash
|
||||||
|
memset(&STATE, 0xff, sizeof(AuthenticatorState));
|
||||||
|
STATE.is_initialized = INITIALIZED_MARKER;
|
||||||
|
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||||
|
STATE.is_pin_set = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ctap_init()
|
void ctap_init()
|
||||||
{
|
{
|
||||||
crypto_ecc256_init();
|
crypto_ecc256_init();
|
||||||
ctap_reset_pin_attempts();
|
|
||||||
|
|
||||||
DEVICE_LOCKOUT = 0;
|
authenticator_read_state(&STATE);
|
||||||
|
|
||||||
|
if (STATE.is_initialized == INITIALIZED_MARKER)
|
||||||
|
{
|
||||||
|
printf1(TAG_STOR,"Auth state is initialized\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_STOR,"Auth state is NOT initialized. Initializing..\n");
|
||||||
|
if (authenticator_is_backup_initialized())
|
||||||
|
{
|
||||||
|
printf1(TAG_ERR,"Warning: memory corruption detected. restoring from backup..\n");
|
||||||
|
authenticator_read_backup_state(&STATE);
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctap_state_init();
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
authenticator_write_state(&STATE, 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctap_is_pin_set())
|
||||||
|
{
|
||||||
|
printf1(TAG_STOR,"pin code: \"%s\"\n", STATE.pin_code);
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(STATE.pin_code, strnlen(STATE.pin_code, NEW_PIN_ENC_MAX_SIZE));
|
||||||
|
crypto_sha256_final(PIN_CODE_HASH);
|
||||||
|
printf1(TAG_STOR, "attempts_left: %d\n", STATE.remaining_tries);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_STOR,"pin not set.\n");
|
||||||
|
}
|
||||||
|
if (ctap_device_locked())
|
||||||
|
{
|
||||||
|
printf1(TAG_ERR, "DEVICE LOCKED!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (ctap_generate_rng(PIN_TOKEN, PIN_TOKEN_SIZE) != 1)
|
if (ctap_generate_rng(PIN_TOKEN, PIN_TOKEN_SIZE) != 1)
|
||||||
{
|
{
|
||||||
@ -1230,12 +1299,12 @@ void ctap_init()
|
|||||||
|
|
||||||
uint8_t ctap_is_pin_set()
|
uint8_t ctap_is_pin_set()
|
||||||
{
|
{
|
||||||
return PIN_CODE_SET == 1;
|
return STATE.is_pin_set == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
uint8_t ctap_pin_matches(uint8_t * pin, int len)
|
||||||
{
|
{
|
||||||
return memcmp(pin, PIN_CODE, len) == 0;
|
return memcmp(pin, STATE.pin_code, len) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1247,30 +1316,35 @@ void ctap_update_pin(uint8_t * pin, int len)
|
|||||||
printf2(TAG_ERR, "Update pin fail length\n");
|
printf2(TAG_ERR, "Update pin fail length\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
memset(PIN_CODE,0,sizeof(PIN_CODE));
|
memset(STATE.pin_code, 0, NEW_PIN_ENC_MAX_SIZE);
|
||||||
memmove(PIN_CODE, pin, len);
|
memmove(STATE.pin_code, pin, len);
|
||||||
|
|
||||||
crypto_sha256_init();
|
crypto_sha256_init();
|
||||||
crypto_sha256_update(PIN_CODE, len);
|
crypto_sha256_update(STATE.pin_code, len);
|
||||||
crypto_sha256_final(PIN_CODE_HASH);
|
crypto_sha256_final(PIN_CODE_HASH);
|
||||||
|
|
||||||
PIN_CODE_SET = 1;
|
STATE.is_pin_set = 1;
|
||||||
|
|
||||||
printf1(TAG_CTAP, "New pin set: %s\n", PIN_CODE);
|
printf1(TAG_CTAP, "New pin set: %s\n", STATE.pin_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO flash
|
|
||||||
static int8_t _flash_tries;
|
|
||||||
uint8_t ctap_decrement_pin_attempts()
|
uint8_t ctap_decrement_pin_attempts()
|
||||||
{
|
{
|
||||||
if (_flash_tries > 0)
|
if (STATE.remaining_tries > 0)
|
||||||
{
|
{
|
||||||
_flash_tries--;
|
STATE.remaining_tries--;
|
||||||
printf1(TAG_CP, "ATTEMPTS left: %d\n", _flash_tries);
|
ctap_flush_state(0);
|
||||||
|
printf1(TAG_CP, "ATTEMPTS left: %d\n", STATE.remaining_tries);
|
||||||
|
|
||||||
|
if (STATE.remaining_tries == 0)
|
||||||
|
{
|
||||||
|
memset(PIN_TOKEN,0,sizeof(PIN_TOKEN));
|
||||||
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
|
printf1(TAG_CP, "Device locked!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEVICE_LOCKOUT = 1;
|
|
||||||
printf1(TAG_CP, "Device locked!\n");
|
printf1(TAG_CP, "Device locked!\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1279,17 +1353,18 @@ uint8_t ctap_decrement_pin_attempts()
|
|||||||
|
|
||||||
int8_t ctap_device_locked()
|
int8_t ctap_device_locked()
|
||||||
{
|
{
|
||||||
return DEVICE_LOCKOUT == 1;
|
return STATE.remaining_tries == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t ctap_leftover_pin_attempts()
|
int8_t ctap_leftover_pin_attempts()
|
||||||
{
|
{
|
||||||
return _flash_tries;
|
return STATE.remaining_tries;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_reset_pin_attempts()
|
void ctap_reset_pin_attempts()
|
||||||
{
|
{
|
||||||
_flash_tries = 8;
|
STATE.remaining_tries = PIN_LOCKOUT_ATTEMPTS;
|
||||||
|
ctap_flush_state(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_reset_state()
|
void ctap_reset_state()
|
||||||
@ -1297,15 +1372,119 @@ void ctap_reset_state()
|
|||||||
memset(&getAssertionState, 0, sizeof(getAssertionState));
|
memset(&getAssertionState, 0, sizeof(getAssertionState));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ctap_reset()
|
uint16_t ctap_keys_stored()
|
||||||
{
|
{
|
||||||
_flash_tries = 8;
|
int total = 0;
|
||||||
PIN_CODE_SET = 0;
|
int i;
|
||||||
DEVICE_LOCKOUT = 0;
|
for (i = 0; i < MAX_KEYS; i++)
|
||||||
ctap_reset_state();
|
{
|
||||||
memset(PIN_CODE,0,sizeof(PIN_CODE));
|
if (STATE.key_lens[i] != 0xffff)
|
||||||
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
{
|
||||||
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
total += 1;
|
||||||
crypto_reset_master_secret();
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t key_addr_offset(int index)
|
||||||
|
{
|
||||||
|
uint16_t offset = 0;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < index; i++)
|
||||||
|
{
|
||||||
|
if (STATE.key_lens[i] != 0xffff) offset += STATE.key_lens[i];
|
||||||
|
}
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t ctap_key_len(uint8_t index)
|
||||||
|
{
|
||||||
|
int i = ctap_keys_stored();
|
||||||
|
uint16_t offset;
|
||||||
|
if (i >= MAX_KEYS || index >= MAX_KEYS)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (STATE.key_lens[index] == 0xffff) return 0;
|
||||||
|
return STATE.key_lens[index];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ctap_store_key(uint8_t index, uint8_t * key, uint16_t len)
|
||||||
|
{
|
||||||
|
int i = ctap_keys_stored();
|
||||||
|
uint16_t offset;
|
||||||
|
if (i >= MAX_KEYS || index >= MAX_KEYS || !len)
|
||||||
|
{
|
||||||
|
return ERR_NO_KEY_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STATE.key_lens[index] != 0xffff)
|
||||||
|
{
|
||||||
|
return ERR_KEY_SPACE_TAKEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = key_addr_offset(index);
|
||||||
|
|
||||||
|
if ((offset + len) > KEY_SPACE_BYTES)
|
||||||
|
{
|
||||||
|
return ERR_NO_KEY_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
STATE.key_lens[index] = len;
|
||||||
|
|
||||||
|
memmove(STATE.key_space + offset, key, len);
|
||||||
|
|
||||||
|
ctap_flush_state(0);
|
||||||
|
ctap_flush_state(1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t ctap_load_key(uint8_t index, uint8_t * key)
|
||||||
|
{
|
||||||
|
int i = ctap_keys_stored();
|
||||||
|
uint16_t offset;
|
||||||
|
uint16_t len;
|
||||||
|
if (i >= MAX_KEYS || index >= MAX_KEYS)
|
||||||
|
{
|
||||||
|
return ERR_NO_KEY_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (STATE.key_lens[index] == 0)
|
||||||
|
{
|
||||||
|
return ERR_KEY_SPACE_EMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = key_addr_offset(index);
|
||||||
|
len = ctap_key_len(index);
|
||||||
|
|
||||||
|
if ((offset + len) > KEY_SPACE_BYTES)
|
||||||
|
{
|
||||||
|
return ERR_NO_KEY_SPACE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(key, STATE.key_space + offset, len);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void ctap_reset()
|
||||||
|
{
|
||||||
|
ctap_state_init();
|
||||||
|
authenticator_write_state(&STATE, 0);
|
||||||
|
authenticator_write_state(&STATE, 1);
|
||||||
|
|
||||||
|
ctap_reset_state();
|
||||||
|
memset(PIN_CODE_HASH,0,sizeof(PIN_CODE_HASH));
|
||||||
|
crypto_ecc256_make_key_pair(KEY_AGREEMENT_PUB, KEY_AGREEMENT_PRIV);
|
||||||
|
|
||||||
|
crypto_reset_master_secret(); // Not sure what the significance of this is??
|
||||||
}
|
}
|
||||||
|
|
||||||
|
14
fido2/ctap.h
14
fido2/ctap.h
@ -2,7 +2,6 @@
|
|||||||
#define _CTAP_H
|
#define _CTAP_H
|
||||||
|
|
||||||
#include "cbor.h"
|
#include "cbor.h"
|
||||||
#include "device.h"
|
|
||||||
|
|
||||||
#define CTAP_MAKE_CREDENTIAL 0x01
|
#define CTAP_MAKE_CREDENTIAL 0x01
|
||||||
#define CTAP_GET_ASSERTION 0x02
|
#define CTAP_GET_ASSERTION 0x02
|
||||||
@ -109,6 +108,8 @@
|
|||||||
|
|
||||||
#define CTAP_RESPONSE_BUFFER_SIZE 1024
|
#define CTAP_RESPONSE_BUFFER_SIZE 1024
|
||||||
|
|
||||||
|
#define PIN_LOCKOUT_ATTEMPTS 8
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t id[USER_ID_MAX_SIZE];
|
uint8_t id[USER_ID_MAX_SIZE];
|
||||||
@ -260,10 +261,19 @@ uint8_t ctap_pin_matches(uint8_t * pin, int len);
|
|||||||
void ctap_reset();
|
void ctap_reset();
|
||||||
int8_t ctap_device_locked();
|
int8_t ctap_device_locked();
|
||||||
|
|
||||||
|
// Key storage API
|
||||||
|
|
||||||
|
// Return length of key at index. 0 if not exist.
|
||||||
|
uint16_t ctap_key_len(uint8_t index);
|
||||||
|
|
||||||
|
// See error codes in storage.h
|
||||||
|
int8_t ctap_store_key(uint8_t index, uint8_t * key, uint16_t len);
|
||||||
|
int8_t ctap_load_key(uint8_t index, uint8_t * key);
|
||||||
|
uint16_t ctap_key_len(uint8_t index);
|
||||||
|
|
||||||
#define PIN_TOKEN_SIZE 16
|
#define PIN_TOKEN_SIZE 16
|
||||||
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
extern uint8_t PIN_TOKEN[PIN_TOKEN_SIZE];
|
||||||
extern uint8_t KEY_AGREEMENT_PUB[64];
|
extern uint8_t KEY_AGREEMENT_PUB[64];
|
||||||
extern uint8_t PIN_CODE[NEW_PIN_ENC_MAX_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef _DEVICE_H
|
#ifndef _DEVICE_H
|
||||||
#define _DEVICE_H
|
#define _DEVICE_H
|
||||||
|
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
void device_init();
|
void device_init();
|
||||||
|
|
||||||
uint32_t millis();
|
uint32_t millis();
|
||||||
@ -20,6 +22,16 @@ void main_loop_delay();
|
|||||||
|
|
||||||
void heartbeat();
|
void heartbeat();
|
||||||
|
|
||||||
|
void authenticator_read_state(AuthenticatorState * );
|
||||||
|
|
||||||
|
void authenticator_read_backup_state(AuthenticatorState * );
|
||||||
|
|
||||||
|
// Return 1 yes backup is init'd, else 0
|
||||||
|
//void authenticator_initialize()
|
||||||
|
int authenticator_is_backup_initialized();
|
||||||
|
|
||||||
|
void authenticator_write_state(AuthenticatorState *, int backup);
|
||||||
|
|
||||||
|
|
||||||
// Test for user presence
|
// Test for user presence
|
||||||
// Return 1 for user is present, 0 user not present
|
// Return 1 for user is present, 0 user not present
|
||||||
|
@ -32,6 +32,7 @@ struct logtag tagtable[] = {
|
|||||||
{TAG_RED,"[1;31mDEBUG[0m"},
|
{TAG_RED,"[1;31mDEBUG[0m"},
|
||||||
{TAG_TIME,"[1;33mTIME[0m"},
|
{TAG_TIME,"[1;33mTIME[0m"},
|
||||||
{TAG_WALLET,"[1;34mWALLET[0m"},
|
{TAG_WALLET,"[1;34mWALLET[0m"},
|
||||||
|
{TAG_STOR,"[1;35mSTOR[0m"},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ typedef enum
|
|||||||
TAG_HID = (1 << 12),
|
TAG_HID = (1 << 12),
|
||||||
TAG_USB = (1 << 13),
|
TAG_USB = (1 << 13),
|
||||||
TAG_WALLET = (1 << 14),
|
TAG_WALLET = (1 << 14),
|
||||||
|
TAG_STOR = (1 << 15),
|
||||||
|
|
||||||
TAG_FILENO = (1<<31)
|
TAG_FILENO = (1<<31)
|
||||||
} LOG_TAG;
|
} LOG_TAG;
|
||||||
|
@ -28,6 +28,7 @@ int main(int argc, char * argv[])
|
|||||||
/*TAG_MC |*/
|
/*TAG_MC |*/
|
||||||
/*TAG_GA |*/
|
/*TAG_GA |*/
|
||||||
TAG_WALLET |
|
TAG_WALLET |
|
||||||
|
TAG_STOR |
|
||||||
/*TAG_CP |*/
|
/*TAG_CP |*/
|
||||||
// TAG_CTAP|
|
// TAG_CTAP|
|
||||||
// TAG_HID|
|
// TAG_HID|
|
||||||
|
38
fido2/storage.h
Normal file
38
fido2/storage.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef _STORAGE_H
|
||||||
|
#define _STORAGE_H
|
||||||
|
|
||||||
|
#include "ctap.h"
|
||||||
|
|
||||||
|
#define KEY_SPACE_BYTES 128
|
||||||
|
#define MAX_KEYS (KEY_SPACE_BYTES/1)
|
||||||
|
|
||||||
|
#define BACKUP_MARKER 0x5A
|
||||||
|
#define INITIALIZED_MARKER 0xA5
|
||||||
|
|
||||||
|
#define ERR_NO_KEY_SPACE (-1)
|
||||||
|
#define ERR_KEY_SPACE_TAKEN (-2)
|
||||||
|
#define ERR_KEY_SPACE_EMPTY (-2)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
// Pin information
|
||||||
|
uint8_t is_initialized;
|
||||||
|
uint8_t is_pin_set;
|
||||||
|
uint8_t pin_code[NEW_PIN_ENC_MAX_SIZE];
|
||||||
|
uint8_t remaining_tries;
|
||||||
|
|
||||||
|
uint16_t key_lens[MAX_KEYS];
|
||||||
|
uint8_t key_space[KEY_SPACE_BYTES];
|
||||||
|
} AuthenticatorState;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t addr;
|
||||||
|
uint8_t * filename;
|
||||||
|
uint32_t count;
|
||||||
|
} AuthenticatorCounter;
|
||||||
|
|
||||||
|
extern AuthenticatorState STATE;
|
||||||
|
|
||||||
|
#endif
|
133
fido2/wallet.c
133
fido2/wallet.c
@ -5,12 +5,34 @@
|
|||||||
* Author: conor
|
* Author: conor
|
||||||
*/
|
*/
|
||||||
#include "wallet.h"
|
#include "wallet.h"
|
||||||
|
#include "app.h"
|
||||||
#include "ctap.h"
|
#include "ctap.h"
|
||||||
#include "ctap_errors.h"
|
#include "ctap_errors.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
#include "u2f.h"
|
#include "u2f.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "storage.h"
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
#ifdef USING_PC
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MBEDTLS_ECP_DP_NONE = 0,
|
||||||
|
MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */
|
||||||
|
MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */
|
||||||
|
MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */
|
||||||
|
MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */
|
||||||
|
MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */
|
||||||
|
} mbedtls_ecp_group_id;
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
@ -43,9 +65,7 @@ void wallet_init()
|
|||||||
// TODO dont leave this
|
// TODO dont leave this
|
||||||
printf1(TAG_WALLET,"Wallet is ready\n");
|
printf1(TAG_WALLET,"Wallet is ready\n");
|
||||||
|
|
||||||
|
|
||||||
/*ctap_update_pin("1234", 4);*/
|
/*ctap_update_pin("1234", 4);*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * arg2, uint8_t * arg3, int len)
|
int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * arg2, uint8_t * arg3, int len)
|
||||||
@ -58,6 +78,11 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
|||||||
case CP_cmdGetKeyAgreement:
|
case CP_cmdGetKeyAgreement:
|
||||||
printf1(TAG_WALLET,"cmdGetKeyAgreement\n");
|
printf1(TAG_WALLET,"cmdGetKeyAgreement\n");
|
||||||
|
|
||||||
|
if ( ctap_device_locked() )
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
|
u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
|
||||||
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
|
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
|
||||||
|
|
||||||
@ -80,17 +105,22 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
|||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
printf1(TAG_WALLET,"Success. Pin = %s\n",PIN_CODE);
|
printf1(TAG_WALLET,"Success. Pin = %s\n", STATE.pin_code);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CP_cmdChangePin:
|
case CP_cmdChangePin:
|
||||||
printf1(TAG_WALLET,"cmdChangePin\n");
|
printf1(TAG_WALLET,"cmdChangePin\n");
|
||||||
|
|
||||||
if (! ctap_is_pin_set())
|
if (! ctap_is_pin_set() )
|
||||||
{
|
{
|
||||||
return CTAP2_ERR_PIN_NOT_SET;
|
return CTAP2_ERR_PIN_NOT_SET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( ctap_device_locked() )
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
//pinEnc // plat_pubkey // pinHashEnc
|
//pinEnc // plat_pubkey // pinHashEnc
|
||||||
ret = ctap_update_pin_if_verified( arg2, len, arg1, pinAuth, arg3);
|
ret = ctap_update_pin_if_verified( arg2, len, arg1, pinAuth, arg3);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
@ -100,6 +130,11 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
|||||||
case CP_cmdGetPinToken:
|
case CP_cmdGetPinToken:
|
||||||
printf1(TAG_WALLET,"cmdGetPinToken\n");
|
printf1(TAG_WALLET,"cmdGetPinToken\n");
|
||||||
|
|
||||||
|
if ( ctap_device_locked() )
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_OPERATION_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ctap_add_pin_if_verified(pinTokenEnc, arg1, pinAuth); // pubkey, pinHashEnc
|
ret = ctap_add_pin_if_verified(pinTokenEnc, arg1, pinAuth); // pubkey, pinHashEnc
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
return ret;
|
return ret;
|
||||||
@ -132,6 +167,12 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
|||||||
uint8_t * args[5] = {NULL,NULL,NULL,NULL,NULL};
|
uint8_t * args[5] = {NULL,NULL,NULL,NULL,NULL};
|
||||||
uint8_t lens[5];
|
uint8_t lens[5];
|
||||||
|
|
||||||
|
uint8_t key[256];
|
||||||
|
uint8_t shasum[32];
|
||||||
|
uint8_t chksum[4];
|
||||||
|
|
||||||
|
int keysize = sizeof(key);
|
||||||
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(sig); i++)
|
for (i = 0; i < sizeof(sig); i++)
|
||||||
{
|
{
|
||||||
@ -177,7 +218,7 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
|||||||
printf1(TAG_WALLET,"WalletSign\n");
|
printf1(TAG_WALLET,"WalletSign\n");
|
||||||
printf1(TAG_WALLET,"pinAuth:"); dump_hex1(TAG_WALLET, req->pinAuth, 16);
|
printf1(TAG_WALLET,"pinAuth:"); dump_hex1(TAG_WALLET, req->pinAuth, 16);
|
||||||
|
|
||||||
if (args[0] == NULL)
|
if (args[0] == NULL || lens[0] == 0)
|
||||||
{
|
{
|
||||||
ret = CTAP2_ERR_MISSING_PARAMETER;
|
ret = CTAP2_ERR_MISSING_PARAMETER;
|
||||||
printf2(TAG_ERR,"Missing parameter for WalletSign\n");
|
printf2(TAG_ERR,"Missing parameter for WalletSign\n");
|
||||||
@ -208,9 +249,91 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
|||||||
{
|
{
|
||||||
printf1(TAG_WALLET,"Warning: no pin is set. Ignoring pinAuth\n");
|
printf1(TAG_WALLET,"Warning: no pin is set. Ignoring pinAuth\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ret = ctap_load_key(0, key);
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
ret = CTAP2_ERR_NO_CREDENTIALS;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
keysize = ctap_key_len(0);
|
||||||
|
|
||||||
|
crypto_load_external_key(key, keysize);
|
||||||
|
crypto_ecdsa_sign(args[0], lens[0], sig, MBEDTLS_ECP_DP_SECP256R1);
|
||||||
|
|
||||||
|
u2f_response_writeback(sig,64);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WalletRegister:
|
case WalletRegister:
|
||||||
printf1(TAG_WALLET,"WalletRegister\n");
|
printf1(TAG_WALLET,"WalletRegister\n");
|
||||||
|
if (args[0] == NULL)
|
||||||
|
{
|
||||||
|
ret = CTAP2_ERR_MISSING_PARAMETER;
|
||||||
|
printf2(TAG_ERR,"Missing parameter for WalletReg\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (lens[0] < 8 || lens[0] > keysize)
|
||||||
|
{
|
||||||
|
ret = CTAP1_ERR_INVALID_LENGTH;
|
||||||
|
printf2(TAG_ERR,"Invalid length for WalletReg\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (ctap_is_pin_set())
|
||||||
|
{
|
||||||
|
if (check_pinhash(req->pinAuth, msg_buf, reqlen))
|
||||||
|
{
|
||||||
|
printf1(TAG_WALLET,"pinAuth is valid\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_WALLET,"pinAuth is NOT valid\n");
|
||||||
|
ret = CTAP2_ERR_PIN_AUTH_INVALID;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_WALLET,"Warning: no pin is set. Ignoring pinAuth\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
memmove(chksum, args[0] + lens[0] - 4, 4);
|
||||||
|
lens[0] -= 4;
|
||||||
|
|
||||||
|
// perform integrity check
|
||||||
|
printf1(TAG_WALLET,"shasum on [%d]: ",lens[0]); dump_hex1(TAG_WALLET, args[0], lens[0]);
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(args[0], lens[0]);
|
||||||
|
crypto_sha256_final(shasum);
|
||||||
|
crypto_sha256_init();
|
||||||
|
crypto_sha256_update(shasum, 32);
|
||||||
|
crypto_sha256_final(shasum);
|
||||||
|
|
||||||
|
if (memcmp(shasum, chksum, 4) != 0)
|
||||||
|
{
|
||||||
|
ret = CTAP2_ERR_CREDENTIAL_NOT_VALID;
|
||||||
|
printf2(TAG_ERR,"Integrity fail for WalletReg\n");
|
||||||
|
dump_hex1(TAG_ERR, chksum, sizeof(chksum));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
// drop the first byte
|
||||||
|
args[0]++;
|
||||||
|
lens[0]--;
|
||||||
|
|
||||||
|
printf1(TAG_WALLET,"adding key [%d]: ",lens[0]); dump_hex1(TAG_WALLET, args[0], lens[0]);
|
||||||
|
|
||||||
|
ret = ctap_store_key(0, args[0], lens[0]);
|
||||||
|
|
||||||
|
if (ret == ERR_NO_KEY_SPACE || ret == ERR_KEY_SPACE_TAKEN)
|
||||||
|
{
|
||||||
|
ret = CTAP2_ERR_KEY_STORE_FULL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case WalletPin:
|
case WalletPin:
|
||||||
printf1(TAG_WALLET,"WalletPin\n");
|
printf1(TAG_WALLET,"WalletPin\n");
|
||||||
|
2
pc/app.h
2
pc/app.h
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#define USING_DEV_BOARD
|
#define USING_DEV_BOARD
|
||||||
|
|
||||||
|
#define USING_PC
|
||||||
|
|
||||||
#define BRIDGE_TO_WALLET
|
#define BRIDGE_TO_WALLET
|
||||||
|
|
||||||
void printing_init();
|
void printing_init();
|
||||||
|
192
pc/device.c
192
pc/device.c
@ -15,6 +15,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
|
|
||||||
|
void authenticator_initialize();
|
||||||
|
|
||||||
int udp_server()
|
int udp_server()
|
||||||
{
|
{
|
||||||
@ -135,9 +136,13 @@ void usbhid_close()
|
|||||||
udp_close(serverfd);
|
udp_close(serverfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void device_init()
|
void device_init()
|
||||||
{
|
{
|
||||||
usbhid_init();
|
usbhid_init();
|
||||||
|
|
||||||
|
authenticator_initialize();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -206,6 +211,193 @@ int ctap_generate_rng(uint8_t * dst, size_t num)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char * state_file = "authenticator_state.bin";
|
||||||
|
const char * backup_file = "authenticator_state2.bin";
|
||||||
|
|
||||||
|
void authenticator_read_state(AuthenticatorState * state)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
f = fopen(state_file, "rb");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(state, 1, sizeof(AuthenticatorState), f);
|
||||||
|
fclose(f);
|
||||||
|
if(ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_read_backup_state(AuthenticatorState * state )
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
f = fopen(backup_file, "rb");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(state, 1, sizeof(AuthenticatorState), f);
|
||||||
|
fclose(f);
|
||||||
|
if(ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_write_state(AuthenticatorState * state, int backup)
|
||||||
|
{
|
||||||
|
FILE * f;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (! backup)
|
||||||
|
{
|
||||||
|
f = fopen(state_file, "wb+");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
|
||||||
|
fclose(f);
|
||||||
|
if (ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
f = fopen(backup_file, "wb+");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
ret = fwrite(state, 1, sizeof(AuthenticatorState), f);
|
||||||
|
fclose(f);
|
||||||
|
if (ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 1 yes backup is init'd, else 0
|
||||||
|
int authenticator_is_backup_initialized()
|
||||||
|
{
|
||||||
|
uint8_t header[16];
|
||||||
|
AuthenticatorState * state = (AuthenticatorState*) header;
|
||||||
|
FILE * f;
|
||||||
|
int ret;
|
||||||
|
uint8_t * mem;
|
||||||
|
|
||||||
|
printf("state file exists\n");
|
||||||
|
f = fopen(backup_file, "rb");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
printf("Warning, backup file doesn't exist\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(header, 1, sizeof(header), f);
|
||||||
|
fclose(f);
|
||||||
|
if(ret != sizeof(header))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return state->is_initialized == INITIALIZED_MARKER;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return 1 yes backup is init'd, else 0
|
||||||
|
int authenticator_is_initialized()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void authenticator_initialize()
|
||||||
|
{
|
||||||
|
uint8_t header[16];
|
||||||
|
FILE * f;
|
||||||
|
int ret;
|
||||||
|
uint8_t * mem;
|
||||||
|
if (access(state_file, F_OK) != -1)
|
||||||
|
{
|
||||||
|
printf("state file exists\n");
|
||||||
|
f = fopen(state_file, "rb");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = fread(header, 1, sizeof(header), f);
|
||||||
|
fclose(f);
|
||||||
|
if(ret != sizeof(header))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("state file does not exist, creating it\n");
|
||||||
|
f = fopen(state_file, "wb+");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
mem = malloc(sizeof(AuthenticatorState));
|
||||||
|
memset(mem,0xff,sizeof(AuthenticatorState));
|
||||||
|
ret = fwrite(mem, 1, sizeof(AuthenticatorState), f);
|
||||||
|
free(mem);
|
||||||
|
fclose(f);
|
||||||
|
if (ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
f = fopen(backup_file, "wb+");
|
||||||
|
if (f== NULL)
|
||||||
|
{
|
||||||
|
perror("fopen");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
mem = malloc(sizeof(AuthenticatorState));
|
||||||
|
memset(mem,0xff,sizeof(AuthenticatorState));
|
||||||
|
ret = fwrite(mem, 1, sizeof(AuthenticatorState), f);
|
||||||
|
free(mem);
|
||||||
|
fclose(f);
|
||||||
|
if (ret != sizeof(AuthenticatorState))
|
||||||
|
{
|
||||||
|
perror("fwrite");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,8 +36,6 @@ class Packet(object):
|
|||||||
def FromWireFormat(pkt_size,data):
|
def FromWireFormat(pkt_size,data):
|
||||||
return Packet(data)
|
return Packet(data)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Tester():
|
class Tester():
|
||||||
def __init__(self,):
|
def __init__(self,):
|
||||||
self.origin = 'https://examplo.org'
|
self.origin = 'https://examplo.org'
|
||||||
|
141
web/js/wallet.js
141
web/js/wallet.js
@ -1,5 +1,8 @@
|
|||||||
DEVELOPMENT = 1;
|
DEVELOPMENT = 1;
|
||||||
|
|
||||||
|
var to_b58 = function(B){var A="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";var d=[],s="",i,j,c,n;for(i in B){j=0,c=B[i];s+=c||s.length^i?"":1;while(j in d||c){n=d[j];n=n?n*256+c:c;c=n/58|0;d[j]=n%58;j++}}while(j--)s+=A[d[j]];return s};
|
||||||
|
var from_b58 = function(S){var A="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";var d=[],b=[],i,j,c,n;for(i in S){j=0,c=A.indexOf(S[i]);if(c<0)throw new Error('Invald b58 character');c||b.length^i?i:b.push(0);while(j in d||c){n=d[j];n=n?n*58+c:c;c=n>>8;d[j]=n%256;j++}}while(j--)b.push(d[j]);return new Uint8Array(b)};
|
||||||
|
|
||||||
function hex(byteArray, join) {
|
function hex(byteArray, join) {
|
||||||
if (join === undefined) join = ' ';
|
if (join === undefined) join = ' ';
|
||||||
return Array.from(byteArray, function(byte) {
|
return Array.from(byteArray, function(byte) {
|
||||||
@ -67,6 +70,10 @@ function hex2array(string)
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function array2hex(buffer) {
|
||||||
|
return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
|
||||||
|
}
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
|
// https://stackoverflow.com/questions/18729405/how-to-convert-utf8-string-to-byte-array
|
||||||
function toUTF8Array(str) {
|
function toUTF8Array(str) {
|
||||||
var utf8 = [];
|
var utf8 = [];
|
||||||
@ -356,13 +363,32 @@ function signRequestFormat(sigAlg,pinToken,challenge,keyid) {
|
|||||||
var cmd = CMD.sign;
|
var cmd = CMD.sign;
|
||||||
var p1 = sigAlg;
|
var p1 = sigAlg;
|
||||||
var p2 = 0;
|
var p2 = 0;
|
||||||
|
|
||||||
|
if (typeof(challenge) == 'string')
|
||||||
|
{
|
||||||
|
challenge = websafe2array(challenge);
|
||||||
|
}
|
||||||
|
|
||||||
var args = [challenge];
|
var args = [challenge];
|
||||||
if (keyid) args.push(keyid)
|
if (keyid) args.push(keyid)
|
||||||
|
|
||||||
var pinAuth = computePinAuth(pinToken,cmd,p1,p2,args);
|
var pinAuth = computePinAuth(pinToken,cmd,p1,p2,args);
|
||||||
console.log(hex(pinAuth));
|
|
||||||
var req = formatRequest(cmd,p1,p2,pinAuth,args);
|
var req = formatRequest(cmd,p1,p2,pinAuth,args);
|
||||||
console.log('',req);
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @wifkey is wif key in base58 format string
|
||||||
|
function registerRequestFormat(wifkey, pinToken) {
|
||||||
|
|
||||||
|
var cmd = CMD.register;
|
||||||
|
var p1 = 0;
|
||||||
|
var p2 = 0;
|
||||||
|
var keyarr = from_b58(wifkey);
|
||||||
|
var args = [keyarr];
|
||||||
|
|
||||||
|
var pinAuth = computePinAuth(pinToken,cmd,p1,p2,args);
|
||||||
|
var req = formatRequest(cmd,p1,p2,pinAuth,args);
|
||||||
|
|
||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
@ -396,7 +422,6 @@ var get_shared_secret_ = function(func) {
|
|||||||
send_msg(req, function(resp){
|
send_msg(req, function(resp){
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
console.log('getKeyAgreement response:', resp);
|
|
||||||
|
|
||||||
var devicePubkeyHex = '04'+hex(resp.data,'');
|
var devicePubkeyHex = '04'+hex(resp.data,'');
|
||||||
var devicePubkey = self.ecp256.keyFromPublic(devicePubkeyHex,'hex');
|
var devicePubkey = self.ecp256.keyFromPublic(devicePubkeyHex,'hex');
|
||||||
@ -424,7 +449,6 @@ var authenticate_ = function(pin, func){
|
|||||||
hash = sha256.create();
|
hash = sha256.create();
|
||||||
hash.update(toUTF8Array(pin));
|
hash.update(toUTF8Array(pin));
|
||||||
pinHash = hash.array().slice(0,16);
|
pinHash = hash.array().slice(0,16);
|
||||||
console.log('pinHash:', hex(pinHash));
|
|
||||||
|
|
||||||
var iv = new Uint8Array(16);
|
var iv = new Uint8Array(16);
|
||||||
iv.fill(0);
|
iv.fill(0);
|
||||||
@ -432,7 +456,6 @@ var authenticate_ = function(pin, func){
|
|||||||
var aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
var aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
||||||
pinHashEnc = aesCbc.encrypt(pinHash);
|
pinHashEnc = aesCbc.encrypt(pinHash);
|
||||||
|
|
||||||
console.log('pinenc:', hex(pinHashEnc));
|
|
||||||
|
|
||||||
var ourPubkey = this.platform_keypair.getPublic(undefined, 'hex');
|
var ourPubkey = this.platform_keypair.getPublic(undefined, 'hex');
|
||||||
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
||||||
@ -440,12 +463,10 @@ var authenticate_ = function(pin, func){
|
|||||||
|
|
||||||
var req = pinRequestFormat(PIN.getPinToken, pinHashEnc, ourPubkeyBytes);
|
var req = pinRequestFormat(PIN.getPinToken, pinHashEnc, ourPubkeyBytes);
|
||||||
|
|
||||||
console.log('pinTokenReq',req);
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
send_msg(req, function(resp){
|
send_msg(req, function(resp){
|
||||||
console.log('getPinToken:', resp);
|
|
||||||
var aesCbc = new aesjs.ModeOfOperation.cbc(self.shared_secret, iv);
|
var aesCbc = new aesjs.ModeOfOperation.cbc(self.shared_secret, iv);
|
||||||
var pinTokenEnc = resp.data;
|
var pinTokenEnc = resp.data;
|
||||||
var pinToken = aesCbc.decrypt(pinTokenEnc);
|
var pinToken = aesCbc.decrypt(pinTokenEnc);
|
||||||
@ -491,8 +512,6 @@ var set_pin_ = function(pin, func, failAuth){
|
|||||||
var pinBytesPadded = pin2bytes(pin);
|
var pinBytesPadded = pin2bytes(pin);
|
||||||
var encLen = pinBytesPadded.length;
|
var encLen = pinBytesPadded.length;
|
||||||
|
|
||||||
console.log('encrypted len: ',encLen);
|
|
||||||
|
|
||||||
var iv = new Uint8Array(16);
|
var iv = new Uint8Array(16);
|
||||||
iv.fill(0);
|
iv.fill(0);
|
||||||
|
|
||||||
@ -539,7 +558,6 @@ var change_pin_ = function(curpin, newpin, func, failAuth){
|
|||||||
var pinBytesPadded = pin2bytes(newpin);
|
var pinBytesPadded = pin2bytes(newpin);
|
||||||
var encLen = pinBytesPadded.length;
|
var encLen = pinBytesPadded.length;
|
||||||
|
|
||||||
console.log('encrypted len: ',encLen);
|
|
||||||
|
|
||||||
var iv = new Uint8Array(16);
|
var iv = new Uint8Array(16);
|
||||||
iv.fill(0);
|
iv.fill(0);
|
||||||
@ -595,6 +613,21 @@ var sign_ = function(obj, func){
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var register_ = function(wifkey, func){
|
||||||
|
|
||||||
|
if (!wifkey)
|
||||||
|
throw new Error("No key provided");
|
||||||
|
|
||||||
|
|
||||||
|
var req = registerRequestFormat(wifkey,this.pinToken);
|
||||||
|
|
||||||
|
send_msg(req, function(resp){
|
||||||
|
if (func) func(resp);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function WalletDevice() {
|
function WalletDevice() {
|
||||||
var self = this;
|
var self = this;
|
||||||
this.shared_secret = null;
|
this.shared_secret = null;
|
||||||
@ -623,6 +656,39 @@ function WalletDevice() {
|
|||||||
this.change_pin = change_pin_;
|
this.change_pin = change_pin_;
|
||||||
|
|
||||||
this.get_retries = get_retries_;
|
this.get_retries = get_retries_;
|
||||||
|
|
||||||
|
this.register = register_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @key input private key in hex string format
|
||||||
|
function key2wif(key)
|
||||||
|
{
|
||||||
|
//2
|
||||||
|
key = '0x80' + key;
|
||||||
|
|
||||||
|
bin = hex2array(key);
|
||||||
|
|
||||||
|
//3
|
||||||
|
var hash = sha256.create();
|
||||||
|
hash.update(bin);
|
||||||
|
bin = hash.array();
|
||||||
|
|
||||||
|
//4
|
||||||
|
hash = sha256.create();
|
||||||
|
hash.update(bin);
|
||||||
|
bin = hash.array();
|
||||||
|
|
||||||
|
// 5
|
||||||
|
var chksum = bin.slice(0,4);
|
||||||
|
|
||||||
|
// 6
|
||||||
|
key = key + array2hex(chksum);
|
||||||
|
|
||||||
|
// 7
|
||||||
|
key = hex2array(key);
|
||||||
|
key = to_b58(key);
|
||||||
|
|
||||||
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -637,14 +703,18 @@ function run_tests() {
|
|||||||
|
|
||||||
dev.is_pin_set(function(bool){
|
dev.is_pin_set(function(bool){
|
||||||
if (bool) {
|
if (bool) {
|
||||||
console.log('Pin is set. Changing it again..');
|
console.log('Pin is set. ');
|
||||||
dev.change_pin(pin,pin2,function(succ){
|
//dev.change_pin(pin,pin2,function(succ){
|
||||||
console.log('Pin set to ' + pin2,succ);
|
//console.log('Pin set to ' + pin2,succ);
|
||||||
|
|
||||||
dev.get_retries(function(num){
|
//dev.get_retries(function(num){
|
||||||
console.log("Have "+num+" attempts to get pin right");
|
//console.log("Have "+num+" attempts to get pin right");
|
||||||
});
|
//});
|
||||||
|
|
||||||
|
//});
|
||||||
|
dev.authenticate(pin, function(){
|
||||||
|
|
||||||
|
t2();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -657,6 +727,45 @@ function run_tests() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function t2 ()
|
||||||
|
{
|
||||||
|
var ec = new EC('p256');
|
||||||
|
var key = ec.genKeyPair();
|
||||||
|
|
||||||
|
var priv = key.getPrivate('hex');
|
||||||
|
|
||||||
|
// convert to wif
|
||||||
|
priv = key2wif(priv);
|
||||||
|
|
||||||
|
var chal = 'ogfhriodghdro;igh';
|
||||||
|
|
||||||
|
var hash = sha256.create();
|
||||||
|
hash.update(chal);
|
||||||
|
chal = hash.array();
|
||||||
|
|
||||||
|
|
||||||
|
dev.register(priv, function(resp){
|
||||||
|
console.log('register response', resp);
|
||||||
|
dev.sign({challenge: chal}, function(resp){
|
||||||
|
|
||||||
|
var r = resp.data.slice(0,32);
|
||||||
|
var s = resp.data.slice(32,64);
|
||||||
|
|
||||||
|
r = array2hex(r);
|
||||||
|
s = array2hex(s);
|
||||||
|
|
||||||
|
var sig = {r: r, s: s};
|
||||||
|
|
||||||
|
console.log('sign response', resp);
|
||||||
|
|
||||||
|
var ver = key.verify(chal, sig);
|
||||||
|
|
||||||
|
console.log("verify: ",ver);
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user