diff --git a/fido2/ctap.c b/fido2/ctap.c index 3ccb9cbf..0fee1c88 100644 --- a/fido2/ctap.c +++ b/fido2/ctap.c @@ -1354,6 +1354,45 @@ 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; + } + if (ctap_is_pin_set() == 1) + { + ret = verify_pin_auth(SH.pinAuth, SH.clientDataHash); + check_retr(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_cred_metadata(CborEncoder * encoder) { CborEncoder map; @@ -2226,6 +2265,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: case CTAP_CBOR_CRED_MGMT: case CTAP_CBOR_CRED_MGMT_PRE: if (ctap_device_locked()) @@ -2309,6 +2349,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; case CTAP_CBOR_CRED_MGMT: case CTAP_CBOR_CRED_MGMT_PRE: printf1(TAG_CTAP,"CTAP_CBOR_CRED_MGMT_PRE\n"); diff --git a/fido2/ctap.h b/fido2/ctap.h index db98c27b..4f148b38 100644 --- a/fido2/ctap.h +++ b/fido2/ctap.h @@ -19,6 +19,7 @@ #define CTAP_CBOR_CRED_MGMT 0x0A #define CTAP_VENDOR_FIRST 0x40 #define CTAP_CBOR_CRED_MGMT_PRE 0x41 +#define CTAP_SOLO_SIGN 0x50 #define CTAP_VENDOR_LAST 0xBF #define MC_clientDataHash 0x01 @@ -39,6 +40,9 @@ #define GA_pinAuth 0x06 #define GA_pinProtocol 0x07 +#define SH_clientDataHash 0x01 +#define SH_credential 0x02 +#define SH_pinAuth 0x03 #define CM_cmd 0x01 #define CM_cmdMetadata 0x01 #define CM_cmdRPBegin 0x02 @@ -319,6 +323,13 @@ typedef struct } CTAP_getAssertion; +typedef struct +{ + uint8_t pinAuth[16]; + uint8_t clientDataHash[CLIENT_DATA_HASH_SIZE]; + CTAP_credentialDescriptor cred; +} CTAP_signHash; + typedef struct { int cmd; diff --git a/fido2/ctap_parse.c b/fido2/ctap_parse.c index a6e53f24..86dc56fd 100644 --- a/fido2/ctap_parse.c +++ b/fido2/ctap_parse.c @@ -1007,6 +1007,73 @@ 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: + printf1(TAG_SH, "SH_credential\n"); + ret = parse_credential_descriptor(&map, &SH->cred); + check_ret(ret); + break; + case SH_pinAuth: + printf1(TAG_SH, "SH_pinAuth\n"); + ret = parse_fixed_byte_string(&map, SH->pinAuth, 16); + check_retr(ret); + break; + } + ret = cbor_value_advance(&map); + check_ret(ret); + } + return 0; +} + static uint8_t parse_cred_mgmt_subcommandparams(CborValue * val, CTAP_credMgmt * CM) { size_t map_length; diff --git a/fido2/ctap_parse.h b/fido2/ctap_parse.h index e0be8071..da6dbc2c 100644 --- a/fido2/ctap_parse.h +++ b/fido2/ctap_parse.h @@ -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_cred_mgmt(CTAP_credMgmt * CM, 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); diff --git a/fido2/log.c b/fido2/log.c index bb9a41ad..3a151f28 100644 --- a/fido2/log.c +++ b/fido2/log.c @@ -52,6 +52,7 @@ struct logtag tagtable[] = { {TAG_NFC_APDU, "NAPDU"}, {TAG_CCID, "CCID"}, {TAG_CM, "CRED_MGMT"}, + {TAG_SH, "SH"}, }; diff --git a/fido2/log.h b/fido2/log.h index d415255f..4ac78dc2 100644 --- a/fido2/log.h +++ b/fido2/log.h @@ -49,6 +49,7 @@ typedef enum TAG_NFC_APDU = (1 << 20), TAG_CCID = (1 << 21), TAG_CM = (1 << 22), + TAG_SH = (1 << 23), TAG_NO_TAG = (1UL << 30), TAG_FILENO = (1UL << 31)