mirror of
https://github.com/polhenarejos/pico-fido.git
synced 2024-09-20 03:10:10 +00:00
Added support to Nitrokey's nitropy tool.
Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
parent
07729f807b
commit
24224b78dd
@ -1 +1 @@
|
||||
Subproject commit 46e7d3a181fab92fb8e394ed9b579b2b2f6a54a0
|
||||
Subproject commit 2700e3ae7a6bd6a43b8bdf39f243df8e8c52e7bf
|
@ -464,12 +464,12 @@ int cbor_make_credential(const uint8_t *data, size_t len) {
|
||||
CBOR_CHECK(cbor_encode_uint(&mapEncoder, 0x03));
|
||||
|
||||
CBOR_CHECK(cbor_encoder_create_map(&mapEncoder, &mapEncoder2,
|
||||
self_attestation == false ? 3 : 2));
|
||||
self_attestation == false || is_nitrokey ? 3 : 2));
|
||||
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "alg"));
|
||||
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation ? -alg : -FIDO2_ALG_ES256));
|
||||
CBOR_CHECK(cbor_encode_negative_int(&mapEncoder2, self_attestation || is_nitrokey ? -alg : -FIDO2_ALG_ES256));
|
||||
CBOR_CHECK(cbor_encode_text_stringz(&mapEncoder2, "sig"));
|
||||
CBOR_CHECK(cbor_encode_byte_string(&mapEncoder2, sig, olen));
|
||||
if (self_attestation == false) {
|
||||
if (self_attestation == false || is_nitrokey) {
|
||||
CborEncoder arrEncoder;
|
||||
file_t *ef_cert = NULL;
|
||||
if (enterpriseAttestation == 2) {
|
||||
|
@ -46,6 +46,8 @@ file_t file_entries[] = {
|
||||
{ .fid = EF_LARGEBLOB, .parent = 0, .name = NULL,
|
||||
.type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH, .data = NULL,
|
||||
.ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } }, // Large Blob
|
||||
{ .fid = EF_OTP_PIN, .parent = 0, .name = NULL, .type = FILE_TYPE_INTERNAL_EF | FILE_DATA_FLASH,
|
||||
.data = NULL, .ef_structure = FILE_EF_TRANSPARENT, .acl = { 0xff } },
|
||||
{ .fid = 0x0000, .parent = 0xff, .name = NULL, .type = FILE_TYPE_UNKNOWN, .data = NULL,
|
||||
.ef_structure = 0, .acl = { 0 } } //end
|
||||
};
|
||||
|
@ -36,6 +36,7 @@
|
||||
#define EF_OATH_CODE 0xBAFF
|
||||
#define EF_OTP_SLOT1 0xBB00
|
||||
#define EF_OTP_SLOT2 0xBB01
|
||||
#define EF_OTP_PIN 0x10A0 // Nitrokey OTP PIN
|
||||
|
||||
extern file_t *ef_keydev;
|
||||
extern file_t *ef_certdev;
|
||||
|
138
src/fido/oath.c
138
src/fido/oath.c
@ -22,9 +22,11 @@
|
||||
#include "random.h"
|
||||
#include "version.h"
|
||||
#include "asn1.h"
|
||||
#include "crypto_utils.h"
|
||||
|
||||
#define MAX_OATH_CRED 255
|
||||
#define CHALLENGE_LEN 8
|
||||
#define MAX_OTP_COUNTER 3
|
||||
|
||||
#define TAG_NAME 0x71
|
||||
#define TAG_NAME_LIST 0x72
|
||||
@ -38,6 +40,9 @@
|
||||
#define TAG_IMF 0x7a
|
||||
#define TAG_ALGO 0x7b
|
||||
#define TAG_TOUCH_RESPONSE 0x7c
|
||||
#define TAG_PASSWORD 0x80
|
||||
#define TAG_NEW_PASSWORD 0x81
|
||||
#define TAG_PIN_COUNTER 0x82
|
||||
|
||||
#define ALG_HMAC_SHA1 0x01
|
||||
#define ALG_HMAC_SHA256 0x02
|
||||
@ -88,6 +93,16 @@ app_t *oath_select(app_t *a, const uint8_t *aid, uint8_t aid_len) {
|
||||
memcpy(res_APDU + res_APDU_size, challenge, sizeof(challenge));
|
||||
res_APDU_size += sizeof(challenge);
|
||||
}
|
||||
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
|
||||
if (file_has_data(ef_otp_pin)) {
|
||||
const uint8_t *pin_data = file_get_data(ef_otp_pin);
|
||||
res_APDU[res_APDU_size++] = TAG_PIN_COUNTER;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = *pin_data;
|
||||
}
|
||||
res_APDU[res_APDU_size++] = TAG_ALGO;
|
||||
res_APDU[res_APDU_size++] = 1;
|
||||
res_APDU[res_APDU_size++] = ALG_HMAC_SHA1;
|
||||
apdu.ne = res_APDU_size;
|
||||
return a;
|
||||
}
|
||||
@ -252,6 +267,8 @@ int cmd_reset() {
|
||||
}
|
||||
}
|
||||
delete_file(search_dynamic_file(EF_OATH_CODE));
|
||||
flash_clear_file(search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF));
|
||||
low_flash_available();
|
||||
validated = true;
|
||||
return SW_OK();
|
||||
}
|
||||
@ -479,6 +496,119 @@ int cmd_send_remaining() {
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_set_otp_pin() {
|
||||
size_t pw_len = 0;
|
||||
uint8_t *pw = NULL, hsh[33] = { 0 };
|
||||
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
|
||||
if (file_has_data(ef_otp_pin)) {
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
hsh[0] = MAX_OTP_COUNTER;
|
||||
double_hash_pin(pw, pw_len, hsh + 1);
|
||||
flash_write_data_to_file(ef_otp_pin, hsh, sizeof(hsh));
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_change_otp_pin() {
|
||||
size_t pw_len = 0, new_pw_len = 0;
|
||||
uint8_t *pw = NULL, *new_pw = NULL, hsh[33] = { 0 };
|
||||
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
|
||||
if (!file_has_data(ef_otp_pin)) {
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
double_hash_pin(pw, pw_len, hsh + 1);
|
||||
if (memcmp(file_get_data(ef_otp_pin) + 1, hsh + 1, 32) != 0) {
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NEW_PASSWORD, &new_pw_len, &new_pw) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
hsh[0] = MAX_OTP_COUNTER;
|
||||
double_hash_pin(new_pw, new_pw_len, hsh + 1);
|
||||
flash_write_data_to_file(ef_otp_pin, hsh, sizeof(hsh));
|
||||
low_flash_available();
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_verify_otp_pin() {
|
||||
size_t pw_len = 0;
|
||||
uint8_t *pw = NULL, hsh[33] = { 0 }, data_hsh[33];
|
||||
file_t *ef_otp_pin = search_by_fid(EF_OTP_PIN, NULL, SPECIFY_EF);
|
||||
if (!file_has_data(ef_otp_pin)) {
|
||||
return SW_CONDITIONS_NOT_SATISFIED();
|
||||
}
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_PASSWORD, &pw_len, &pw) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
double_hash_pin(pw, pw_len, hsh + 1);
|
||||
memcpy(data_hsh, file_get_data(ef_otp_pin), sizeof(data_hsh));
|
||||
if (data_hsh[0] == 0 || memcmp(data_hsh + 1, hsh + 1, 32) != 0) {
|
||||
if (data_hsh[0] > 0) {
|
||||
data_hsh[0] -= 1;
|
||||
}
|
||||
flash_write_data_to_file(ef_otp_pin, data_hsh, sizeof(data_hsh));
|
||||
low_flash_available();
|
||||
validated = false;
|
||||
return SW_SECURITY_STATUS_NOT_SATISFIED();
|
||||
}
|
||||
data_hsh[0] = MAX_OTP_COUNTER;
|
||||
flash_write_data_to_file(ef_otp_pin, data_hsh, sizeof(data_hsh));
|
||||
low_flash_available();
|
||||
validated = true;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
int cmd_verify_hotp() {
|
||||
size_t key_len = 0, chal_len = 0, name_len = 0, code_len = 0;
|
||||
uint8_t *key = NULL, *chal = NULL, *name = NULL, *code = NULL;
|
||||
uint32_t code_int = 0;
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_NAME, &name_len, &name) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
file_t *ef = find_oath_cred(name, name_len);
|
||||
if (file_has_data(ef) == false) {
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_KEY, &key_len, &key) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
|
||||
if ((key[0] & OATH_TYPE_MASK) != OATH_TYPE_HOTP) {
|
||||
return SW_DATA_INVALID();
|
||||
}
|
||||
if (asn1_find_tag(file_get_data(ef), file_get_size(ef), TAG_IMF, &chal_len,
|
||||
&chal) == false) {
|
||||
return SW_INCORRECT_PARAMS();
|
||||
}
|
||||
if (asn1_find_tag(apdu.data, apdu.nc, TAG_RESPONSE, &code_len, &code) == true) {
|
||||
code_int = (code[0] << 24) | (code[1] << 16) | (code[2] << 8) | code[3];
|
||||
}
|
||||
|
||||
int ret = calculate_oath(0x01, key, key_len, chal, chal_len);
|
||||
if (ret != CCID_OK) {
|
||||
return SW_EXEC_ERROR();
|
||||
}
|
||||
uint32_t res_int = (res_APDU[2] << 24) | (res_APDU[3] << 16) | (res_APDU[4] << 8) | res_APDU[5];
|
||||
if (res_APDU[1] == 6) {
|
||||
res_int %= (uint32_t)1e6;
|
||||
}
|
||||
else {
|
||||
res_int %= (uint32_t)1e8;
|
||||
}
|
||||
if (res_int != code_int) {
|
||||
return SW_WRONG_DATA();
|
||||
}
|
||||
res_APDU_size = apdu.ne = 0;
|
||||
return SW_OK();
|
||||
}
|
||||
|
||||
#define INS_PUT 0x01
|
||||
#define INS_DELETE 0x02
|
||||
#define INS_SET_CODE 0x03
|
||||
@ -488,6 +618,10 @@ int cmd_send_remaining() {
|
||||
#define INS_VALIDATE 0xa3
|
||||
#define INS_CALC_ALL 0xa4
|
||||
#define INS_SEND_REMAINING 0xa5
|
||||
#define INS_VERIFY_CODE 0xb1
|
||||
#define INS_VERIFY_PIN 0xb2
|
||||
#define INS_CHANGE_PIN 0xb3
|
||||
#define INS_SET_PIN 0xb4
|
||||
|
||||
static const cmd_t cmds[] = {
|
||||
{ INS_PUT, cmd_put },
|
||||
@ -499,6 +633,10 @@ static const cmd_t cmds[] = {
|
||||
{ INS_CALCULATE, cmd_calculate },
|
||||
{ INS_CALC_ALL, cmd_calculate_all },
|
||||
{ INS_SEND_REMAINING, cmd_send_remaining },
|
||||
{ INS_SET_PIN, cmd_set_otp_pin },
|
||||
{ INS_CHANGE_PIN, cmd_change_otp_pin },
|
||||
{ INS_VERIFY_PIN, cmd_verify_otp_pin },
|
||||
{ INS_VERIFY_CODE, cmd_verify_hotp },
|
||||
{ 0x00, 0x0 }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user