solo/fido2/wallet.c
2018-07-08 22:36:16 -04:00

208 lines
5.5 KiB
C

/*
* wallet.c
*
* Created on: Jul 7, 2018
* Author: conor
*/
#include "wallet.h"
#include "ctap.h"
#include "ctap_errors.h"
#include "crypto.h"
#include "u2f.h"
#include "log.h"
#include "util.h"
typedef enum
{
WalletSign = 0x10,
WalletRegister = 0x11,
WalletPin = 0x12,
} WalletOperation;
// return 1 if hash is valid, 0 otherwise
int check_pinhash(uint8_t * pinAuth, uint8_t * msg, uint8_t len)
{
uint8_t hmac[32];
crypto_sha256_hmac_init(PIN_TOKEN, PIN_TOKEN_SIZE, hmac);
crypto_sha256_update(msg, 4);
crypto_sha256_update(msg+ 4 + 16, len - 4 - 16);
crypto_sha256_hmac_final(PIN_TOKEN, PIN_TOKEN_SIZE, hmac);
printf1(TAG_WALLET, "recalc pinhash:"); dump_hex1(TAG_WALLET, hmac,32);
return (memcmp(pinAuth, hmac, 16) == 0);
}
/*int16_t wallet_sign(uint8_t alg, uint8_t * chal, uint8_t len, uint8_t * kh, uint8_t kl)*/
/*{*/
/*crypto_sha256_hmac_init(uint8_t * key, uint32_t klen, uint8_t * hmac);*/
/*}*/
void wallet_init()
{
// TODO dont leave this
printf1(TAG_WALLET,"Wallet is ready\n");
ctap_update_pin("1234", 4);
}
int8_t wallet_pin(uint8_t subcmd, uint8_t * pinAuth, uint8_t * arg1, uint8_t * arg2)
{
uint8_t pinTokenEnc[PIN_TOKEN_SIZE];
int ret;
switch(subcmd)
{
case CP_cmdGetKeyAgreement:
printf1(TAG_WALLET,"cmdGetKeyAgreement\n");
u2f_response_writeback(KEY_AGREEMENT_PUB,sizeof(KEY_AGREEMENT_PUB));
printf1(TAG_WALLET,"pubkey: "); dump_hex1(TAG_WALLET,KEY_AGREEMENT_PUB,64);
break;
case CP_cmdGetRetries:
printf1(TAG_WALLET,"cmdGetRetries\n");
return CTAP2_ERR_UNSUPPORTED_OPTION;
break;
case CP_cmdSetPin:
printf1(TAG_WALLET,"cmdSetPin\n");
return CTAP2_ERR_UNSUPPORTED_OPTION;
break;
case CP_cmdChangePin:
printf1(TAG_WALLET,"cmdChangePin\n");
return CTAP2_ERR_UNSUPPORTED_OPTION;
break;
case CP_cmdGetPinToken:
printf1(TAG_WALLET,"cmdGetPinToken\n");
ret = ctap_add_pin_if_verified(pinTokenEnc, arg1, pinAuth); // pubkey, pinHashEnc
if (ret != 0)
return ret;
printf1(TAG_WALLET,"pinToken: "); dump_hex1(TAG_WALLET, PIN_TOKEN, 16);
u2f_response_writeback(pinTokenEnc, PIN_TOKEN_SIZE);
break;
default:
printf2(TAG_ERR,"Error, invalid client pin subcommand\n");
return CTAP2_ERR_INVALID_OPTION;
}
return 0;
}
int16_t bridge_u2f_to_wallet(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
{
static uint8_t msg_buf[WALLET_MAX_BUFFER];
int reqlen = klen;
int i;
int8_t ret = 0;
uint32_t count;
uint8_t up = 1;
uint8_t sig[200];
uint8_t * args[5] = {NULL,NULL,NULL,NULL,NULL};
uint8_t lens[5];
for (i = 0; i < sizeof(sig); i++)
{
sig[i] = i;
}
wallet_request * req = (wallet_request *) msg_buf;
uint8_t * payload = req->payload;
memmove(msg_buf, keyh, klen);
printf1(TAG_WALLET, "u2f2wallet [%d]: ",reqlen); dump_hex1(TAG_WALLET, msg_buf,reqlen);
count = ctap_atomic_count(0);
u2f_response_writeback(&up,1);
u2f_response_writeback((uint8_t *)&count,4);
u2f_response_writeback((uint8_t *)&ret,1);
int offset = 0;
for (i = 0; i < MIN(5,req->numArgs); i++)
{
if (offset > MAX_PAYLOAD_SIZE)
{
ret = CTAP1_ERR_INVALID_LENGTH;
goto cleanup;
}
lens[i] = *(payload + offset);
offset++;
args[i] = payload + offset;
offset += lens[i];
}
if (offset > MAX_PAYLOAD_SIZE)
{
ret = CTAP1_ERR_INVALID_LENGTH;
printf2(TAG_ERR,"Wallet operation lengths too big\n");
goto cleanup;
}
switch(req->operation)
{
case WalletSign:
printf1(TAG_WALLET,"WalletSign\n");
printf1(TAG_WALLET,"pinAuth:"); dump_hex1(TAG_WALLET, req->pinAuth, 16);
if (args[0] == NULL)
{
ret = CTAP2_ERR_MISSING_PARAMETER;
printf2(TAG_ERR,"Missing parameter for WalletSign\n");
goto cleanup;
}
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 (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;
}
break;
case WalletRegister:
printf1(TAG_WALLET,"WalletRegister\n");
break;
case WalletPin:
printf1(TAG_WALLET,"WalletPin\n");
ret = wallet_pin(req->p1, req->pinAuth, args[0], args[1]);
break;
default:
printf2(TAG_ERR,"Invalid wallet command: %x\n",req->operation);
ret = CTAP1_ERR_INVALID_COMMAND;
break;
}
cleanup:
if (ret != 0)
{
u2f_reset_response();
u2f_response_writeback(&up,1);
u2f_response_writeback((uint8_t *)&count,4);
memset(sig,0,sizeof(sig));
sig[0] = ret;
u2f_response_writeback(sig,72);
}
else
{
/*u2f_response_writeback(sig,sizeof(sig));*/
}
return U2F_SW_NO_ERROR;
}