diff --git a/lib/asn1/FrameProtocol.c b/lib/asn1/FrameProtocol.c index 593dde0..a282074 100644 --- a/lib/asn1/FrameProtocol.c +++ b/lib/asn1/FrameProtocol.c @@ -17,9 +17,9 @@ static const asn_INTEGER_enum_map_t asn_MAP_FrameProtocol_value2enum_1[] = { { 4, 6, "iclass" } }; static const unsigned int asn_MAP_FrameProtocol_enum2value_1[] = { - 0, /* none(0) */ 2, /* iclass(4) */ - 1 /* nfc(2) */ + 1, /* nfc(2) */ + 0 /* none(0) */ }; static const asn_INTEGER_specifics_t asn_SPC_FrameProtocol_specs_1 = { asn_MAP_FrameProtocol_value2enum_1, /* "tag" => N; sorted by tag */ @@ -47,3 +47,4 @@ asn_TYPE_descriptor_t asn_DEF_FrameProtocol = { 0, 0, /* Defined elsewhere */ &asn_SPC_FrameProtocol_specs_1 /* Additional specs */ }; + diff --git a/lib/asn1/SamCommand.c b/lib/asn1/SamCommand.c index 3036e24..c72630a 100644 --- a/lib/asn1/SamCommand.c +++ b/lib/asn1/SamCommand.c @@ -8,15 +8,6 @@ #include "SamCommand.h" asn_TYPE_member_t asn_MBR_SamCommand_1[] = { - { ATF_NOFLAGS, 0, offsetof(struct SamCommand, choice.requestPacs), - (ASN_TAG_CLASS_CONTEXT | (1 << 2)), - -1, /* IMPLICIT tag at current level */ - &asn_DEF_RequestPacs, - 0, - { 0, 0, 0 }, - 0, 0, /* No default value */ - "requestPacs" - }, { ATF_NOFLAGS, 0, offsetof(struct SamCommand, choice.version), (ASN_TAG_CLASS_CONTEXT | (2 << 2)), -1, /* IMPLICIT tag at current level */ @@ -82,14 +73,13 @@ asn_TYPE_member_t asn_MBR_SamCommand_1[] = { }, }; static const asn_TYPE_tag2member_t asn_MAP_SamCommand_tag2el_1[] = { - { (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 0, 0, 0 }, /* requestPacs */ - { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 1, 0, 0 }, /* version */ - { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 2, 0, 0 }, /* cardDetected */ - { (ASN_TAG_CLASS_CONTEXT | (20 << 2)), 3, 0, 0 }, /* processSNMPMessage */ - { (ASN_TAG_CLASS_CONTEXT | (22 << 2)), 4, 0, 0 }, /* serialNumber */ - { (ASN_TAG_CLASS_CONTEXT | (26 << 2)), 7, 0, 0 }, /* processConfigCard */ - { (ASN_TAG_CLASS_CONTEXT | (30 << 2)), 6, 0, 0 }, /* requestPacs2 */ - { (ASN_TAG_CLASS_CONTEXT | (43 << 2)), 5, 0, 0 } /* getItemKCV */ + { (ASN_TAG_CLASS_CONTEXT | (2 << 2)), 0, 0, 0 }, /* version */ + { (ASN_TAG_CLASS_CONTEXT | (13 << 2)), 1, 0, 0 }, /* cardDetected */ + { (ASN_TAG_CLASS_CONTEXT | (20 << 2)), 2, 0, 0 }, /* processSNMPMessage */ + { (ASN_TAG_CLASS_CONTEXT | (22 << 2)), 3, 0, 0 }, /* serialNumber */ + { (ASN_TAG_CLASS_CONTEXT | (26 << 2)), 6, 0, 0 }, /* processConfigCard */ + { (ASN_TAG_CLASS_CONTEXT | (30 << 2)), 5, 0, 0 }, /* requestPacs2 */ + { (ASN_TAG_CLASS_CONTEXT | (43 << 2)), 4, 0, 0 } /* getItemKCV */ }; asn_CHOICE_specifics_t asn_SPC_SamCommand_specs_1 = { sizeof(struct SamCommand), @@ -97,7 +87,7 @@ asn_CHOICE_specifics_t asn_SPC_SamCommand_specs_1 = { offsetof(struct SamCommand, present), sizeof(((struct SamCommand *)0)->present), asn_MAP_SamCommand_tag2el_1, - 8, /* Count of tags in the map */ + 7, /* Count of tags in the map */ 0, 0, -1 /* Extensions start */ }; @@ -111,7 +101,7 @@ asn_TYPE_descriptor_t asn_DEF_SamCommand = { 0, /* No tags (count) */ { 0, 0, CHOICE_constraint }, asn_MBR_SamCommand_1, - 8, /* Elements count */ + 7, /* Elements count */ &asn_SPC_SamCommand_specs_1 /* Additional specs */ }; diff --git a/lib/asn1/SamCommand.h b/lib/asn1/SamCommand.h index 0329cfb..8dee7a3 100644 --- a/lib/asn1/SamCommand.h +++ b/lib/asn1/SamCommand.h @@ -12,11 +12,11 @@ #include /* Including external dependencies */ -#include "RequestPacs.h" #include #include "CardDetected.h" #include #include "NoArguments.h" +#include "RequestPacs.h" #include #ifdef __cplusplus @@ -26,7 +26,6 @@ extern "C" { /* Dependencies */ typedef enum SamCommand_PR { SamCommand_PR_NOTHING, /* No components present */ - SamCommand_PR_requestPacs, SamCommand_PR_version, SamCommand_PR_cardDetected, SamCommand_PR_processSNMPMessage, @@ -40,7 +39,6 @@ typedef enum SamCommand_PR { typedef struct SamCommand { SamCommand_PR present; union SamCommand_u { - RequestPacs_t requestPacs; NULL_t version; CardDetected_t cardDetected; OCTET_STRING_t processSNMPMessage; @@ -57,7 +55,7 @@ typedef struct SamCommand { /* Implementation */ extern asn_TYPE_descriptor_t asn_DEF_SamCommand; extern asn_CHOICE_specifics_t asn_SPC_SamCommand_specs_1; -extern asn_TYPE_member_t asn_MBR_SamCommand_1[8]; +extern asn_TYPE_member_t asn_MBR_SamCommand_1[7]; #ifdef __cplusplus } diff --git a/sam_api.c b/sam_api.c index ee93001..cd8fcb1 100644 --- a/sam_api.c +++ b/sam_api.c @@ -180,10 +180,8 @@ static void seader_sam_set_state( static SeaderSamIntent seader_sam_card_intent(const Seader* seader) { if(seader->credential->type == SeaderCredentialTypeConfig) { return SeaderSamIntentConfig; - } else if(seader->is_debug_enabled) { - return SeaderSamIntentReadPacs2; } else { - return SeaderSamIntentReadPacs; + return SeaderSamIntentReadPacs2; } } @@ -500,24 +498,6 @@ void seader_send_response( seader_send_payload(seader, &payload, from, to, replyTo); } -void seader_send_request_pacs(Seader* seader) { - RequestPacs_t requestPacs = {0}; - requestPacs.contentElementTag = ContentElementTag_implicitFormatPhysicalAccessBits; - - SamCommand_t samCommand = {0}; - samCommand.present = SamCommand_PR_requestPacs; - seader_sam_set_state( - seader, SeaderSamStateConversation, SeaderSamIntentReadPacs, samCommand.present); - samCommand.choice.requestPacs = requestPacs; - - Payload_t payload = {0}; - payload.present = Payload_PR_samCommand; - payload.choice.samCommand = samCommand; - - seader_send_payload( - seader, &payload, ExternalApplicationA, SAMInterface, ExternalApplicationA); -} - void seader_send_request_pacs2(Seader* seader) { OCTET_STRING_t oid = { .buf = (uint8_t*)seader_oid, @@ -607,83 +587,86 @@ void seader_send_no_card_detected(Seader* seader) { ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_CardDetails, &cardDetails); } -bool seader_unpack_pacs(Seader* seader, uint8_t* buf, size_t size) { - SeaderCredential* seader_credential = seader->credential; - PAC_t pac = {0}; - PAC_t* pac_p = &pac; - bool rtn = false; - - asn_dec_rval_t rval = asn_decode(0, ATS_DER, &asn_DEF_PAC, (void**)&pac_p, buf, size); - - if(rval.code == RC_OK) { -#ifdef ASN1_DEBUG - char pacDebug[384] = {0}; - (&asn_DEF_PAC) - ->op->print_struct(&asn_DEF_PAC, &pac, 1, seader_print_struct_callback, pacDebug); - if(strlen(pacDebug) > 0) { - FURI_LOG_D(TAG, "Received pac: %s", pacDebug); - } -#endif - - if(seader_credential->sio[0] == 0x30) { - seader_log_hex_data(TAG, "SIO", seader_credential->sio, seader_credential->sio_len); - -#ifdef ASN1_DEBUG - SIO_t sio = {0}; - SIO_t* sio_p = &sio; - rval = asn_decode( - 0, - ATS_DER, - &asn_DEF_SIO, - (void**)&sio_p, - seader_credential->sio, - seader_credential->sio_len); - - if(rval.code == RC_OK) { - FURI_LOG_D(TAG, "Decoded SIO"); - char sioDebug[384] = {0}; - (&asn_DEF_SIO) - ->op->print_struct( - &asn_DEF_SIO, &sio, 1, seader_print_struct_callback, sioDebug); - if(strlen(sioDebug) > 0) { - FURI_LOG_D(TAG, "SIO: %s", sioDebug); - } - } else { - FURI_LOG_W(TAG, "Failed to decode SIO %d consumed", rval.consumed); - } - - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SIO, &sio); -#endif - } - - if(pac.size <= sizeof(seader_credential->credential)) { - // TODO: make credential into a 12 byte array - seader_credential->bit_length = pac.size * 8 - pac.bits_unused; - uint64_t credential_val = 0; - memcpy(&credential_val, pac.buf, pac.size); - credential_val = __builtin_bswap64(credential_val); - // After bswap64, the bits are left-aligned in the 64-bit word - // We need to shift them right by (64 - bit_length) to get the value - seader_credential->credential = credential_val >> (64 - seader_credential->bit_length); - - FURI_LOG_D( - TAG, - "credential (%d) %016llx", - seader_credential->bit_length, - seader_credential->credential); - - rtn = true; - } else { - // PACS too big (probably bad data) - seader_abort_active_read(seader); - } - } else { - FURI_LOG_W(TAG, "Failed to decode PAC %d consumed, size %d", rval.consumed, size); - seader_abort_active_read(seader); +static bool seader_store_pacs_bits( + SeaderCredential* credential, + const uint8_t* payload, + size_t payload_size, + uint8_t unused_bits) { + if(!credential || !payload || payload_size == 0 || payload_size > sizeof(credential->credential) || + unused_bits > 7) { + return false; } - ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_PAC, &pac); - return rtn; + const uint8_t bit_length = payload_size * 8 - unused_bits; + if(bit_length == 0) { + return false; + } + + uint64_t credential_val = 0; + memcpy(&credential_val, payload, payload_size); + credential_val = __builtin_bswap64(credential_val); + + credential->bit_length = bit_length; + credential->credential = credential_val >> (64 - bit_length); + return true; +} + +static bool seader_unpack_pacs2_bits(Seader* seader, const OCTET_STRING_t* pacs_bits) { + SeaderCredential* seader_credential = seader->credential; + if(!pacs_bits || !pacs_bits->buf || pacs_bits->size < 2) { + FURI_LOG_W(TAG, "Malformed pacs2 bits"); + return false; + } + + seader_log_hex_data(TAG, "PACS2 bits", pacs_bits->buf, pacs_bits->size); + + if(seader_credential->sio[0] == 0x30) { + seader_log_hex_data(TAG, "SIO", seader_credential->sio, seader_credential->sio_len); +#ifdef ASN1_DEBUG + asn_dec_rval_t rval; + SIO_t sio = {0}; + SIO_t* sio_p = &sio; + rval = asn_decode( + 0, + ATS_DER, + &asn_DEF_SIO, + (void**)&sio_p, + seader_credential->sio, + seader_credential->sio_len); + + if(rval.code == RC_OK) { + FURI_LOG_D(TAG, "Decoded SIO"); + char sioDebug[384] = {0}; + (&asn_DEF_SIO)->op->print_struct( + &asn_DEF_SIO, &sio, 1, seader_print_struct_callback, sioDebug); + if(strlen(sioDebug) > 0) { + FURI_LOG_D(TAG, "SIO: %s", sioDebug); + } + } else { + FURI_LOG_W(TAG, "Failed to decode SIO %d consumed", rval.consumed); + } + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_SIO, &sio); +#endif + } + + const uint8_t unused_bits = pacs_bits->buf[0]; + const uint8_t* payload = pacs_bits->buf + 1; + const size_t payload_size = pacs_bits->size - 1; + FURI_LOG_D(TAG, "PACS2 unused_bits=%u payload_size=%zu", unused_bits, payload_size); + + if(!seader_store_pacs_bits(seader_credential, payload, payload_size, unused_bits)) { + FURI_LOG_W(TAG, "Failed to store PACS2 bits"); + return false; + } + + FURI_LOG_D( + TAG, + "credential (%d) %016llx", + seader_credential->bit_length, + seader_credential->credential); + + return true; } // 800201298106683d052026b6820101 @@ -839,7 +822,6 @@ static void seader_abort_active_read(Seader* seader) { } bool seader_parse_sam_response2(Seader* seader, SamResponse2_t* samResponse) { - uint8_t buffer[10]; switch(samResponse->present) { case SamResponse2_PR_pacs: FURI_LOG_I(TAG, "samResponse2 SamResponse2_PR_pacs"); @@ -857,14 +839,13 @@ bool seader_parse_sam_response2(Seader* seader, SamResponse2_t* samResponse) { Pacs2_t pacs2 = samResponse->choice.pacs; OCTET_STRING_t* pacs = pacs2.bits; - buffer[0] = 0x03; - buffer[1] = pacs->size & 0xFF; - memcpy(buffer + 2, pacs->buf, pacs->size); - if(seader_unpack_pacs(seader, buffer, pacs->size + 2)) { + if(seader_unpack_pacs2_bits(seader, pacs)) { view_dispatcher_send_custom_event( seader->view_dispatcher, SeaderCustomEventPollerSuccess); seader_sam_set_state( seader, SeaderSamStateIdle, SeaderSamIntentNone, SamCommand_PR_NOTHING); + } else { + seader_abort_active_read(seader); } break; case SamResponse2_PR_NOTHING: @@ -886,15 +867,7 @@ bool seader_parse_sam_response(Seader* seader, SamResponse_t* samResponse) { switch(seader->sam_state) { case SeaderSamStateConversation: case SeaderSamStateFinishing: - if(seader->sam_intent == SeaderSamIntentReadPacs) { - FURI_LOG_I(TAG, "samResponse read PACS"); - if(seader_unpack_pacs(seader, samResponse->buf, samResponse->size)) { - view_dispatcher_send_custom_event( - seader->view_dispatcher, SeaderCustomEventPollerSuccess); - seader_sam_set_state( - seader, SeaderSamStateIdle, SeaderSamIntentNone, SamCommand_PR_NOTHING); - } - } else if(seader->sam_intent == SeaderSamIntentConfig) { + if(seader->sam_intent == SeaderSamIntentConfig) { FURI_LOG_I(TAG, "samResponse config"); seader_worker->stage = SeaderPollerEventTypeFail; seader_sam_set_state( @@ -921,8 +894,6 @@ bool seader_parse_sam_response(Seader* seader, SamResponse_t* samResponse) { seader_send_process_config_card(seader); } else if(seader->sam_intent == SeaderSamIntentReadPacs2) { seader_send_request_pacs2(seader); - } else if(seader->sam_intent == SeaderSamIntentReadPacs) { - seader_send_request_pacs(seader); } else { FURI_LOG_W(TAG, "Unexpected detect intent=%d", seader->sam_intent); seader_abort_active_read(seader); @@ -1379,8 +1350,7 @@ void seader_parse_nfc_off(Seader* seader) { seader_send_response(seader, &response, ExternalApplicationA, SAMInterface, 0); if(seader->sam_state == SeaderSamStateConversation && - (seader->sam_intent == SeaderSamIntentReadPacs || - seader->sam_intent == SeaderSamIntentReadPacs2 || + (seader->sam_intent == SeaderSamIntentReadPacs2 || seader->sam_intent == SeaderSamIntentConfig)) { seader_sam_set_state( seader, SeaderSamStateFinishing, seader->sam_intent, seader->samCommand); diff --git a/seader.asn1 b/seader.asn1 index 67b85d8..472761c 100644 --- a/seader.asn1 +++ b/seader.asn1 @@ -22,7 +22,6 @@ ErrorResponse ::= SEQUENCE { } SamCommand ::= CHOICE { - requestPacs [1] RequestPacs, version [2] NULL, cardDetected [13] CardDetected, processSNMPMessage [20] OCTET STRING, diff --git a/seader_i.h b/seader_i.h index de5f92b..535e8b6 100644 --- a/seader_i.h +++ b/seader_i.h @@ -110,7 +110,6 @@ typedef enum { typedef enum { SeaderSamIntentNone, - SeaderSamIntentReadPacs, SeaderSamIntentReadPacs2, SeaderSamIntentConfig, SeaderSamIntentMaintenance,