complete pin support
This commit is contained in:
parent
50ee579d03
commit
156dc3163a
4
.gitignore
vendored
4
.gitignore
vendored
@ -66,3 +66,7 @@ GNU\ *
|
|||||||
Keil\ *
|
Keil\ *
|
||||||
docs/
|
docs/
|
||||||
efm32/hw
|
efm32/hw
|
||||||
|
|
||||||
|
mbedtls/
|
||||||
|
sl_crypto/
|
||||||
|
tools/python-fido2/*
|
||||||
|
@ -21,7 +21,7 @@ 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;
|
static uint8_t PIN_CODE_SET = 0;
|
||||||
static uint8_t PIN_CODE[NEW_PIN_ENC_MAX_SIZE];
|
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;
|
static uint8_t DEVICE_LOCKOUT = 0;
|
||||||
|
|
||||||
|
@ -249,6 +249,7 @@ void ctap_init();
|
|||||||
void ctap_reset_state();
|
void ctap_reset_state();
|
||||||
|
|
||||||
uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubkey, uint8_t * pinHashEnc);
|
uint8_t ctap_add_pin_if_verified(uint8_t * pinTokenEnc, uint8_t * platform_pubkey, uint8_t * pinHashEnc);
|
||||||
|
uint8_t ctap_update_pin_if_verified(uint8_t * pinEnc, int len, uint8_t * platform_pubkey, uint8_t * pinAuth, uint8_t * pinHashEnc);
|
||||||
|
|
||||||
void ctap_update_pin(uint8_t * pin, int len);
|
void ctap_update_pin(uint8_t * pin, int len);
|
||||||
uint8_t ctap_decrement_pin_attempts();
|
uint8_t ctap_decrement_pin_attempts();
|
||||||
@ -262,6 +263,7 @@ int8_t ctap_device_locked();
|
|||||||
#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
|
||||||
|
@ -44,11 +44,11 @@ void wallet_init()
|
|||||||
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)
|
int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * arg2, uint8_t * arg3, int len)
|
||||||
{
|
{
|
||||||
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
|
||||||
int ret;
|
int ret;
|
||||||
@ -64,15 +64,38 @@ int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * a
|
|||||||
break;
|
break;
|
||||||
case CP_cmdGetRetries:
|
case CP_cmdGetRetries:
|
||||||
printf1(TAG_WALLET,"cmdGetRetries\n");
|
printf1(TAG_WALLET,"cmdGetRetries\n");
|
||||||
return CTAP2_ERR_UNSUPPORTED_OPTION;
|
pinTokenEnc[0] = ctap_leftover_pin_attempts();
|
||||||
|
u2f_response_writeback(pinTokenEnc,1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CP_cmdSetPin:
|
case CP_cmdSetPin:
|
||||||
printf1(TAG_WALLET,"cmdSetPin\n");
|
printf1(TAG_WALLET,"cmdSetPin\n");
|
||||||
return CTAP2_ERR_UNSUPPORTED_OPTION;
|
if (ctap_is_pin_set())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pinEnc // plat_pubkey
|
||||||
|
ret = ctap_update_pin_if_verified( arg2, len, arg1, pinAuth, NULL);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
printf1(TAG_WALLET,"Success. Pin = %s\n",PIN_CODE);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CP_cmdChangePin:
|
case CP_cmdChangePin:
|
||||||
printf1(TAG_WALLET,"cmdChangePin\n");
|
printf1(TAG_WALLET,"cmdChangePin\n");
|
||||||
return CTAP2_ERR_UNSUPPORTED_OPTION;
|
|
||||||
|
if (! ctap_is_pin_set())
|
||||||
|
{
|
||||||
|
return CTAP2_ERR_PIN_NOT_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pinEnc // plat_pubkey // pinHashEnc
|
||||||
|
ret = ctap_update_pin_if_verified( arg2, len, arg1, pinAuth, arg3);
|
||||||
|
if (ret != 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case CP_cmdGetPinToken:
|
case CP_cmdGetPinToken:
|
||||||
printf1(TAG_WALLET,"cmdGetPinToken\n");
|
printf1(TAG_WALLET,"cmdGetPinToken\n");
|
||||||
@ -162,8 +185,14 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf1(TAG_WALLET,"challenge:"); dump_hex1(TAG_WALLET, args[0], lens[0]);
|
printf1(TAG_WALLET,"challenge:"); dump_hex1(TAG_WALLET, args[0], lens[0]);
|
||||||
if (args[1] != NULL) printf1(TAG_WALLET,"keyid:"); dump_hex1(TAG_WALLET, args[1], lens[1]);
|
if (args[1] != NULL && req->numArgs > 1)
|
||||||
|
{
|
||||||
|
printf1(TAG_WALLET,"keyid is specified\n");
|
||||||
|
printf1(TAG_WALLET,"keyid:"); dump_hex1(TAG_WALLET, args[1], lens[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctap_is_pin_set())
|
||||||
|
{
|
||||||
if (check_pinhash(req->pinAuth, msg_buf, reqlen))
|
if (check_pinhash(req->pinAuth, msg_buf, reqlen))
|
||||||
{
|
{
|
||||||
printf1(TAG_WALLET,"pinAuth is valid\n");
|
printf1(TAG_WALLET,"pinAuth is valid\n");
|
||||||
@ -174,13 +203,18 @@ int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, ui
|
|||||||
ret = CTAP2_ERR_PIN_AUTH_INVALID;
|
ret = CTAP2_ERR_PIN_AUTH_INVALID;
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf1(TAG_WALLET,"Warning: no pin is set. Ignoring pinAuth\n");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case WalletRegister:
|
case WalletRegister:
|
||||||
printf1(TAG_WALLET,"WalletRegister\n");
|
printf1(TAG_WALLET,"WalletRegister\n");
|
||||||
break;
|
break;
|
||||||
case WalletPin:
|
case WalletPin:
|
||||||
printf1(TAG_WALLET,"WalletPin\n");
|
printf1(TAG_WALLET,"WalletPin\n");
|
||||||
ret = wallet_pin(req->p1, req->pinAuth, args[0], args[1]);
|
ret = wallet_pin(req->p1, req->pinAuth, args[0], args[1], args[2], lens[0]);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
|
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
|
||||||
|
294
web/js/wallet.js
294
web/js/wallet.js
@ -1,3 +1,5 @@
|
|||||||
|
DEVELOPMENT = 1;
|
||||||
|
|
||||||
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) {
|
||||||
@ -162,7 +164,7 @@ var PIN = {
|
|||||||
getPinToken: 0x05,
|
getPinToken: 0x05,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create the XHR object.
|
// Create XHR object.
|
||||||
function createCORSRequest(method, url) {
|
function createCORSRequest(method, url) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
if ("withCredentials" in xhr) {
|
if ("withCredentials" in xhr) {
|
||||||
@ -222,7 +224,8 @@ function send_msg_http(data, func, timeout) {
|
|||||||
|
|
||||||
xhr.send(req);
|
xhr.send(req);
|
||||||
}
|
}
|
||||||
//run_tests();
|
|
||||||
|
// For real
|
||||||
function send_msg_u2f(data, func, timeout) {
|
function send_msg_u2f(data, func, timeout) {
|
||||||
// Use key handle and signature response as comm channel
|
// Use key handle and signature response as comm channel
|
||||||
var d = new Date();
|
var d = new Date();
|
||||||
@ -253,7 +256,6 @@ function send_msg_u2f(data, func, timeout) {
|
|||||||
},timeout);
|
},timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEVELOPMENT = 1
|
|
||||||
var send_msg;
|
var send_msg;
|
||||||
if (DEVELOPMENT) {
|
if (DEVELOPMENT) {
|
||||||
send_msg = send_msg_http;
|
send_msg = send_msg_http;
|
||||||
@ -304,6 +306,11 @@ function formatRequest(cmd, p1, p2, pinAuth, args) {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Computes sha256 HMAC
|
||||||
|
// @pinToken is key for HMAC
|
||||||
|
// @cmd,p1,p2 each are bytes input to HMAC
|
||||||
|
// @args array of Uint8Arrays input to HMAC
|
||||||
|
// @return first 16 bytes of HMAC
|
||||||
function computePinAuth(pinToken, cmd,p1,p2,args)
|
function computePinAuth(pinToken, cmd,p1,p2,args)
|
||||||
{
|
{
|
||||||
var hmac = sha256.hmac.create(pinToken);
|
var hmac = sha256.hmac.create(pinToken);
|
||||||
@ -322,6 +329,12 @@ function computePinAuth(pinToken, cmd,p1,p2,args)
|
|||||||
return hmac.array().slice(0,16)
|
return hmac.array().slice(0,16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function computePinAuthRaw(pinToken, data)
|
||||||
|
{
|
||||||
|
var hmac = sha256.hmac.create(pinToken);
|
||||||
|
hmac.update(data);
|
||||||
|
return hmac.array().slice(0,16)
|
||||||
|
}
|
||||||
|
|
||||||
// @sigAlg is a number 0-255
|
// @sigAlg is a number 0-255
|
||||||
// @pinAuth token, see pinToken information. Uint8Array
|
// @pinAuth token, see pinToken information. Uint8Array
|
||||||
@ -340,7 +353,7 @@ function signRequestFormat(sigAlg,pinToken,challenge,keyid) {
|
|||||||
// keyID: keyid 0-233
|
// keyID: keyid 0-233
|
||||||
// Note: total size must not exceed 255 bytes
|
// Note: total size must not exceed 255 bytes
|
||||||
|
|
||||||
var cmd = 0x10;
|
var cmd = CMD.sign;
|
||||||
var p1 = sigAlg;
|
var p1 = sigAlg;
|
||||||
var p2 = 0;
|
var p2 = 0;
|
||||||
var args = [challenge];
|
var args = [challenge];
|
||||||
@ -355,17 +368,19 @@ function signRequestFormat(sigAlg,pinToken,challenge,keyid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @subCmd is one of the following in PIN {}
|
// @subCmd is one of the following in PIN {}
|
||||||
function pinRequestFormat(subcmd,pubkey,pinHashEnc) {
|
function pinRequestFormat(subcmd, pinAuth, pubkey, pinEnc, pinHashEnc) {
|
||||||
|
|
||||||
var cmd = 0x12;
|
var cmd = CMD.pin;
|
||||||
var p1 = subcmd;
|
var p1 = subcmd;
|
||||||
var p2 = 0;
|
var p2 = 0;
|
||||||
//var args = [challenge];
|
//var args = [challenge];
|
||||||
//if (keyid) args.push(keyid)
|
//if (keyid) args.push(keyid)
|
||||||
var pinAuth = pinHashEnc || new Uint8Array(16);
|
pinAuth = pinAuth || new Uint8Array(16);
|
||||||
var args = [];
|
var args = [];
|
||||||
|
|
||||||
if (pubkey) args.push(pubkey)
|
if (pubkey) args.push(pubkey);
|
||||||
|
if (pinEnc) args.push(pinEnc);
|
||||||
|
if (pinHashEnc) args.push(pinHashEnc);
|
||||||
|
|
||||||
//var pinAuth = computePinAuth(pinToken,cmd,p1,p2,args);
|
//var pinAuth = computePinAuth(pinToken,cmd,p1,p2,args);
|
||||||
//console.log(hex(pinAuth));
|
//console.log(hex(pinAuth));
|
||||||
@ -374,43 +389,38 @@ function pinRequestFormat(subcmd,pubkey,pinHashEnc) {
|
|||||||
return req;
|
return req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var get_shared_secret_ = function(func) {
|
||||||
|
// Get temporary pubkey from device to compute shared secret
|
||||||
|
|
||||||
function run_tests()
|
|
||||||
{
|
|
||||||
var pin = '1234';
|
|
||||||
var ec256k1 = new EC('secp256k1');
|
|
||||||
var ecp256 = new EC('p256');
|
|
||||||
var sharedSecret = new Uint8Array([1,2,3,4])
|
|
||||||
var pinToken = new Uint8Array([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16])
|
|
||||||
|
|
||||||
var req = pinRequestFormat(PIN.getKeyAgreement);
|
var req = pinRequestFormat(PIN.getKeyAgreement);
|
||||||
|
var self = this;
|
||||||
send_msg(req, function(resp){
|
send_msg(req, function(resp){
|
||||||
|
|
||||||
var i;
|
var i;
|
||||||
console.log('getKeyAgreement response:', resp);
|
console.log('getKeyAgreement response:', resp);
|
||||||
|
|
||||||
var pubkey_hex = '04'+hex(resp.data,'');
|
var devicePubkeyHex = '04'+hex(resp.data,'');
|
||||||
console.log('pubkey:', pubkey_hex);
|
var devicePubkey = self.ecp256.keyFromPublic(devicePubkeyHex,'hex');
|
||||||
|
|
||||||
|
// Generate a new key pair for shared secret
|
||||||
|
var platform_keypair = self.ecp256.genKeyPair();
|
||||||
|
self.platform_keypair = platform_keypair;
|
||||||
|
|
||||||
|
|
||||||
var pubkey = ecp256.keyFromPublic(pubkey_hex,'hex');
|
// shared secret
|
||||||
var keypair = ecp256.genKeyPair();
|
var shared = platform_keypair.derive(devicePubkey.getPublic()).toArray();
|
||||||
var shared = keypair.derive(pubkey.getPublic()).toArray();
|
var hash = sha256.create();
|
||||||
|
|
||||||
hash = sha256.create();
|
|
||||||
hash.update(shared);
|
hash.update(shared);
|
||||||
shared = hash.array();
|
shared = hash.array();
|
||||||
|
|
||||||
var ourPubkey = keypair.getPublic(undefined, 'hex');
|
if (func) func(shared);
|
||||||
|
|
||||||
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
});
|
||||||
|
};
|
||||||
|
|
||||||
console.log('shared-secret:', hex(shared));
|
|
||||||
console.log('our pubkey:', keypair.getPublic(undefined, 'hex'));
|
|
||||||
|
|
||||||
|
var authenticate_ = function(pin, func){
|
||||||
|
if (! this.shared_secret){
|
||||||
|
throw new Error('Device is not connected.');
|
||||||
|
}
|
||||||
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);
|
||||||
@ -419,40 +429,234 @@ function run_tests()
|
|||||||
var iv = new Uint8Array(16);
|
var iv = new Uint8Array(16);
|
||||||
iv.fill(0);
|
iv.fill(0);
|
||||||
|
|
||||||
var aesCbc = new aesjs.ModeOfOperation.cbc(shared, iv);
|
var aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
||||||
pinHashEnc = aesCbc.encrypt(pinHash);
|
pinHashEnc = aesCbc.encrypt(pinHash);
|
||||||
|
|
||||||
console.log('pinenc:', hex(pinHashEnc));
|
console.log('pinenc:', hex(pinHashEnc));
|
||||||
|
|
||||||
var req = pinRequestFormat(PIN.getPinToken, ourPubkeyBytes, pinHashEnc);
|
var ourPubkey = this.platform_keypair.getPublic(undefined, 'hex');
|
||||||
|
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
||||||
|
|
||||||
|
|
||||||
|
var req = pinRequestFormat(PIN.getPinToken, pinHashEnc, ourPubkeyBytes);
|
||||||
|
|
||||||
console.log('pinTokenReq',req);
|
console.log('pinTokenReq',req);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
send_msg(req, function(resp){
|
send_msg(req, function(resp){
|
||||||
console.log('getPinToken:', resp);
|
console.log('getPinToken:', resp);
|
||||||
var aesCbc = new aesjs.ModeOfOperation.cbc(shared, 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);
|
||||||
//var pinToken = string2array('123456789abcdfe0');
|
self.pinToken = pinToken;
|
||||||
|
if (func) func(pinToken);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
console.log('pintoken:', hex(pinToken));
|
function pin2bytes(pin){
|
||||||
|
var pinBytes = toUTF8Array(pin);
|
||||||
|
|
||||||
var sigAlg = 3;
|
var encLen = pinBytes.length + (16-(pinBytes.length % 16));
|
||||||
var challenge = string2array('1234567890 1234567890 1234567890');
|
|
||||||
var keyid = string2array('');
|
|
||||||
|
|
||||||
var req = signRequestFormat(sigAlg,pinToken,challenge,keyid);
|
if (encLen < 64){
|
||||||
|
encLen = 64;
|
||||||
|
}
|
||||||
|
|
||||||
//console.log('req:',req)
|
if (pin.length < 4){
|
||||||
|
throw Error('FIDO2 pin must be at least 4 unicode characters.');
|
||||||
|
}
|
||||||
|
if (encLen > 255){
|
||||||
|
throw Error('FIDO2 pin may not exceed 255 bytes');
|
||||||
|
}
|
||||||
|
if (encLen > 80){
|
||||||
|
throw Error('Recommended to not use pins longer than 80 bytes due to 255 byte max message size.');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var pinBytesPadded = new Uint8Array(encLen);
|
||||||
|
pinBytesPadded.fill(0);
|
||||||
|
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < pinBytes.length; i++){
|
||||||
|
pinBytesPadded[i] = pinBytes[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return pinBytesPadded;
|
||||||
|
}
|
||||||
|
|
||||||
|
var set_pin_ = function(pin, func, failAuth){
|
||||||
|
var subcmd = PIN.setPin;
|
||||||
|
|
||||||
|
var pinBytesPadded = pin2bytes(pin);
|
||||||
|
var encLen = pinBytesPadded.length;
|
||||||
|
|
||||||
|
console.log('encrypted len: ',encLen);
|
||||||
|
|
||||||
|
var iv = new Uint8Array(16);
|
||||||
|
iv.fill(0);
|
||||||
|
|
||||||
|
var aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
||||||
|
pinEnc = aesCbc.encrypt(pinBytesPadded);
|
||||||
|
|
||||||
|
var pinAuth = computePinAuthRaw(this.shared_secret, pinEnc);
|
||||||
|
|
||||||
|
if (failAuth){
|
||||||
|
pinAuth.fill(0xAA);
|
||||||
|
pinEnc.fill(0xAA);
|
||||||
|
}
|
||||||
|
|
||||||
|
var ourPubkey = this.platform_keypair.getPublic(undefined, 'hex');
|
||||||
|
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
||||||
|
|
||||||
|
var req = pinRequestFormat(subcmd, pinAuth, ourPubkeyBytes, pinEnc);
|
||||||
|
|
||||||
send_msg(req, function(resp){
|
send_msg(req, function(resp){
|
||||||
console.assert(resp.status == 'CTAP1_SUCCESS');
|
if (func) func(resp.status);
|
||||||
console.log('Walletsign',resp);
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var is_pin_set_ = function(func)
|
||||||
|
{
|
||||||
|
this.set_pin('12345', function(stat){
|
||||||
|
if (stat == "CTAP2_ERR_NOT_ALLOWED") {
|
||||||
|
func(true);
|
||||||
|
}
|
||||||
|
else if (stat == "CTAP2_ERR_PIN_AUTH_INVALID"){
|
||||||
|
func(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new Error("Device returned expected status: " + stat);
|
||||||
|
}
|
||||||
|
}, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
var change_pin_ = function(curpin, newpin, func, failAuth){
|
||||||
|
var subcmd = PIN.changePin;
|
||||||
|
|
||||||
|
pin2bytes(curpin); // validation only
|
||||||
|
|
||||||
|
var pinBytesPadded = pin2bytes(newpin);
|
||||||
|
var encLen = pinBytesPadded.length;
|
||||||
|
|
||||||
|
console.log('encrypted len: ',encLen);
|
||||||
|
|
||||||
|
var iv = new Uint8Array(16);
|
||||||
|
iv.fill(0);
|
||||||
|
|
||||||
|
var aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
||||||
|
newPinEnc = aesCbc.encrypt(pinBytesPadded);
|
||||||
|
|
||||||
|
var hash = sha256.create();
|
||||||
|
hash.update(toUTF8Array(curpin));
|
||||||
|
curPinHash = hash.array().slice(0,16);
|
||||||
|
|
||||||
|
aesCbc = new aesjs.ModeOfOperation.cbc(this.shared_secret, iv);
|
||||||
|
curPinHashEnc = aesCbc.encrypt(curPinHash);
|
||||||
|
|
||||||
|
var concat = new Uint8Array(newPinEnc.length + curPinHashEnc.length);
|
||||||
|
concat.set(newPinEnc);
|
||||||
|
concat.set(curPinHashEnc, newPinEnc.length);
|
||||||
|
|
||||||
|
var pinAuth = computePinAuthRaw(this.shared_secret, concat);
|
||||||
|
|
||||||
|
var ourPubkey = this.platform_keypair.getPublic(undefined, 'hex');
|
||||||
|
var ourPubkeyBytes = hex2array(ourPubkey.slice(2,ourPubkey.length));
|
||||||
|
|
||||||
|
var req = pinRequestFormat(subcmd, pinAuth, ourPubkeyBytes, newPinEnc, curPinHashEnc);
|
||||||
|
|
||||||
|
send_msg(req, function(resp){
|
||||||
|
if (func) func(resp.status);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var get_retries_ = function(func){
|
||||||
|
var subcmd = PIN.getRetries;
|
||||||
|
|
||||||
|
var req = pinRequestFormat(subcmd);
|
||||||
|
|
||||||
|
send_msg(req, function(resp){
|
||||||
|
if (func) func(resp.data[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var sign_ = function(obj, func){
|
||||||
|
|
||||||
|
if (!obj.challenge)
|
||||||
|
throw new Error("Need something to sign");
|
||||||
|
|
||||||
|
var alg = obj.alg || 3;
|
||||||
|
|
||||||
|
var req = signRequestFormat(alg,this.pinToken,obj.challenge,obj.keyid);
|
||||||
|
|
||||||
|
send_msg(req, function(resp){
|
||||||
|
|
||||||
|
if (func) func(resp);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function WalletDevice() {
|
||||||
|
var self = this;
|
||||||
|
this.shared_secret = null;
|
||||||
|
this.ec256k1 = new EC('secp256k1');
|
||||||
|
this.ecp256 = new EC('p256');
|
||||||
|
|
||||||
|
|
||||||
|
this.init = function(func){
|
||||||
|
this.get_shared_secret(function(shared){
|
||||||
|
self.shared_secret = shared;
|
||||||
|
if (func) func();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.get_shared_secret = get_shared_secret_;
|
||||||
|
|
||||||
|
// getPinToken using set pin
|
||||||
|
this.authenticate = authenticate_;
|
||||||
|
|
||||||
|
this.sign = sign_;
|
||||||
|
|
||||||
|
this.set_pin = set_pin_;
|
||||||
|
|
||||||
|
this.is_pin_set = is_pin_set_;
|
||||||
|
|
||||||
|
this.change_pin = change_pin_;
|
||||||
|
|
||||||
|
this.get_retries = get_retries_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function run_tests() {
|
||||||
|
|
||||||
|
var dev = new WalletDevice();
|
||||||
|
var pin = "Conor's pin 👽 ";;
|
||||||
|
var pin2 = "Conor's pin2 😀";;
|
||||||
|
|
||||||
|
dev.init(function(){
|
||||||
|
console.log('connected.');
|
||||||
|
|
||||||
|
dev.is_pin_set(function(bool){
|
||||||
|
if (bool) {
|
||||||
|
console.log('Pin is set. Changing it again..');
|
||||||
|
dev.change_pin(pin,pin2,function(succ){
|
||||||
|
console.log('Pin set to ' + pin2,succ);
|
||||||
|
|
||||||
|
dev.get_retries(function(num){
|
||||||
|
console.log("Have "+num+" attempts to get pin right");
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.log('Pin is NOT set. Setting it to "' + pin + '"');
|
||||||
|
dev.set_pin(pin, function(succ){
|
||||||
|
console.log(succ);
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user