Skip to content

Commit

Permalink
PoC: Add vendor command for signing an arbitrary SHA256 hash
Browse files Browse the repository at this point in the history
This patch adds new CTAP2 vendor command with command value 0x50. The
command arguments are credentialId and user specified SHA256 hash. It
returns a DER encoded signature of the given hash, using the key
which corresponds to the specified credentialId.

Example request:
{1: <sha256_hash>, 2: {"id": <credential_id>, "type": "public-key"}}

Example response:
{1: <der_signature>}

Issue: #395
  • Loading branch information
Radoslav Gerganov committed Mar 19, 2020
1 parent ec7a6fd commit 5180a5a
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 0 deletions.
41 changes: 41 additions & 0 deletions fido2/ctap.c
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,40 @@ uint8_t ctap_get_next_assertion(CborEncoder * encoder)
return 0;
}

uint8_t ctap_sign_hash(CborEncoder * encoder, uint8_t * request, int length)
{
CTAP_signHash SH;
CborEncoder map;
uint8_t sigbuf[64];
uint8_t sigder[72];

int ret = ctap_parse_sign_hash(&SH, request, length);
if (ret != 0)
{
printf2(TAG_ERR,"error, ctap_parse_sign_hash failed\n");
return ret;
}
ret = ctap2_user_presence_test(CTAP2_UP_DELAY_MS);
check_retr(ret);
ret = cbor_encoder_create_map(encoder, &map, 1);
check_ret(ret);

unsigned int cred_size = get_credential_id_size(&SH.cred);
crypto_ecc256_load_key((uint8_t*)&SH.cred.credential.id, cred_size, NULL, 0);
crypto_ecc256_sign(SH.clientDataHash, CLIENT_DATA_HASH_SIZE, sigbuf);
int sigder_sz = ctap_encode_der_sig(sigbuf,sigder);
printf1(TAG_SH,"der sig [%d]: ", sigder_sz); dump_hex1(TAG_SH, sigder, sigder_sz);

ret = cbor_encode_int(&map, 1);
check_ret(ret);
ret = cbor_encode_byte_string(&map, sigder, sigder_sz);
check_ret(ret);

ret = cbor_encoder_close_container(encoder, &map);
check_ret(ret);
return 0;
}

uint8_t ctap_get_assertion(CborEncoder * encoder, uint8_t * request, int length)
{
CTAP_getAssertion GA;
Expand Down Expand Up @@ -1641,6 +1675,7 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
{
case CTAP_MAKE_CREDENTIAL:
case CTAP_GET_ASSERTION:
case CTAP_SOLO_SIGN:
if (ctap_device_locked())
{
status = CTAP2_ERR_PIN_BLOCKED;
Expand Down Expand Up @@ -1722,6 +1757,12 @@ uint8_t ctap_request(uint8_t * pkt_raw, int length, CTAP_RESPONSE * resp)
status = CTAP2_ERR_NOT_ALLOWED;
}
break;
case CTAP_SOLO_SIGN:
printf1(TAG_CTAP,"CTAP_SOLO_SIGN\n");
status = ctap_sign_hash(&encoder, pkt_raw, length);
resp->length = cbor_encoder_get_buffer_size(&encoder, buf);
dump_hex1(TAG_DUMP, buf, resp->length);
break;
default:
status = CTAP1_ERR_INVALID_COMMAND;
printf2(TAG_ERR,"error, invalid cmd: 0x%02x\n", cmd);
Expand Down
11 changes: 11 additions & 0 deletions fido2/ctap.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#define CTAP_RESET 0x07
#define GET_NEXT_ASSERTION 0x08
#define CTAP_VENDOR_FIRST 0x40
#define CTAP_SOLO_SIGN 0x50
#define CTAP_VENDOR_LAST 0xBF

#define MC_clientDataHash 0x01
Expand All @@ -37,6 +38,9 @@
#define GA_pinAuth 0x06
#define GA_pinProtocol 0x07

#define SH_clientDataHash 0x01
#define SH_credential 0x02

#define CP_pinProtocol 0x01
#define CP_subCommand 0x02
#define CP_cmdGetRetries 0x01
Expand Down Expand Up @@ -285,6 +289,13 @@ typedef struct

} CTAP_getAssertion;

typedef struct
{
uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE];
CTAP_credentialDescriptor cred;
} CTAP_signHash;


typedef struct
{
int pinProtocol;
Expand Down
60 changes: 60 additions & 0 deletions fido2/ctap_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -999,6 +999,66 @@ uint8_t parse_allow_list(CTAP_getAssertion * GA, CborValue * it)
return 0;
}

uint8_t ctap_parse_sign_hash(CTAP_signHash * SH, uint8_t * request, int length)
{
int key;
size_t i, map_length;
CborParser parser;
CborValue it,map;

memset(SH, 0, sizeof(CTAP_signHash));
int ret = cbor_parser_init(request, length, CborValidateCanonicalFormat, &parser, &it);
check_ret(ret);

CborType type = cbor_value_get_type(&it);
if (type != CborMapType)
{
printf2(TAG_ERR,"Error, expecting cbor map\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}

ret = cbor_value_enter_container(&it,&map);
check_ret(ret);

ret = cbor_value_get_map_length(&it, &map_length);
check_ret(ret);

printf1(TAG_SH, "SH map has %d elements\n", map_length);

for (i = 0; i < map_length; i++)
{
type = cbor_value_get_type(&map);
if (type != CborIntegerType)
{
printf2(TAG_ERR,"Error, expecting int for map key\n");
return CTAP2_ERR_INVALID_CBOR_TYPE;
}
ret = cbor_value_get_int_checked(&map, &key);
check_ret(ret);

ret = cbor_value_advance(&map);
check_ret(ret);

switch(key)
{
case SH_clientDataHash:
printf1(TAG_SH, "SH_clientHash\n");

ret = parse_fixed_byte_string(&map, SH->clientDataHash, CLIENT_DATA_HASH_SIZE);
check_retr(ret);

printf1(TAG_SH," "); dump_hex1(TAG_SH, SH->clientDataHash, CLIENT_DATA_HASH_SIZE);
break;
case SH_credential:
ret = parse_credential_descriptor(&map, &SH->cred);
check_ret(ret);
break;
}
ret = cbor_value_advance(&map);
check_ret(ret);
}
return 0;
}

uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length)
{
Expand Down
1 change: 1 addition & 0 deletions fido2/ctap_parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ uint8_t parse_cose_key(CborValue * it, COSE_key * cose);

uint8_t ctap_parse_make_credential(CTAP_makeCredential * MC, CborEncoder * encoder, uint8_t * request, int length);
uint8_t ctap_parse_get_assertion(CTAP_getAssertion * GA, uint8_t * request, int length);
uint8_t ctap_parse_sign_hash(CTAP_signHash * SH, uint8_t * request, int length);
uint8_t ctap_parse_client_pin(CTAP_clientPin * CP, uint8_t * request, int length);
uint8_t parse_credential_descriptor(CborValue * arr, CTAP_credentialDescriptor * cred);

Expand Down
1 change: 1 addition & 0 deletions fido2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ struct logtag tagtable[] = {
{TAG_NFC,"NFC"},
{TAG_NFC_APDU, "NAPDU"},
{TAG_CCID, "CCID"},
{TAG_SH, "SH"},
};


Expand Down
1 change: 1 addition & 0 deletions fido2/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ typedef enum
TAG_NFC = (1 << 19),
TAG_NFC_APDU = (1 << 20),
TAG_CCID = (1 << 21),
TAG_SH = (1 << 22),

TAG_NO_TAG = (1UL << 30),
TAG_FILENO = (1UL << 31)
Expand Down

0 comments on commit 5180a5a

Please sign in to comment.