struct json_object *tlv_to_json(const struct tlv *tlv) { struct json_object *result = NULL; char *hex = NULL; void *enc = NULL; size_t enc_sz = 0; int rc = TLV_RC_OK; rc = tlv_encode(tlv, NULL, &enc_sz); if (rc != TLV_RC_OK) goto done; enc = malloc(enc_sz); if (!enc) goto done; rc = tlv_encode(tlv, enc, &enc_sz); if (rc != TLV_RC_OK) goto done; hex = malloc(enc_sz * 2 + 1); if (!hex) goto done; result = json_object_new_string(libtlv_bin_to_hex(enc, enc_sz, hex)); done: if (hex) free(hex); if (enc) free(enc); return result; }
void test_tlv_append (void) { const uint8_t a[] = { 0xde, 0xad, 0xbe, 0xef }; const uint8_t b[] = { 0x42 }; uint8_t ndef_ab_ref[] = { 0x03, 0x04, 0xde, 0xad, 0xbe, 0xef, 0x03, 0x01, 0x42, 0xfe }; uint8_t *ndef_a = tlv_encode (3, a, 4, NULL); uint8_t *ndef_b = tlv_encode (3, b, 1, NULL); ndef_a = tlv_append (ndef_a, ndef_b); cut_assert_equal_memory (ndef_ab_ref, sizeof (ndef_ab_ref), ndef_a, sizeof (ndef_ab_ref), cut_message ("Wrong appended data")); free (ndef_a); free (ndef_b); }
void test_tlv_rfu (void) { uint8_t *data = malloc (0xffff); cut_assert_not_null (data, cut_message ("Out of memory")); uint8_t *res = tlv_encode (7, data, 0xffff, NULL); cut_assert_null (res, cut_message ("Size reserved for future use")); free (data); }
void test_tlv_encode_short (void) { uint8_t *res; size_t osize; res = tlv_encode (3, shortdata, sizeof (shortdata), &osize); cut_assert_equal_int (sizeof (eshortdata), osize, cut_message ("Wrong encoded message length.")); cut_assert_equal_int (3, res[0], cut_message ("Wrong type")); cut_assert_equal_int (sizeof (shortdata), res[1], cut_message ("Wrong value length")); cut_assert_equal_memory (eshortdata, sizeof (eshortdata), res, osize, cut_message ("Wrong encoded value")); free (res); }
void test_tlv_encode_long (void) { uint8_t *res; size_t osize; res = tlv_encode (7, longdata, sizeof (longdata), &osize); cut_assert_equal_int (sizeof (elongdata), osize, cut_message ("Wrong encoded message length.")); cut_assert_equal_int (7, res[0], cut_message ("Wrong type")); cut_assert_equal_int (0xff, res[1], cut_message ("Wrong value length")); cut_assert_equal_int (0x02, res[2], cut_message ("Wrong value length")); cut_assert_equal_int (0x94, res[3], cut_message ("Wrong value length")); cut_assert_equal_memory (elongdata, sizeof (elongdata), res, osize, cut_message ("Wrong encoded value")); free (res); }
int main(int argc, char *argv[]) { MYSQL *conn; MYSQL_RES *result; MYSQL_ROW row; int retval; conn = mysql_init(NULL); retval = mysql_real_connect(conn, def_host_name, def_user_name, def_password, def_db_name, def_port_num, def_socket_name, def_client_flag); if(!retval) { printf("Error connecting to database: %s\n", mysql_error(conn)); return -1; } printf("Connection successful\n"); int error = 0; nfc_device_t *device = NULL; MifareTag *tags = NULL; Mad mad; MifareClassicKey transport_key = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; char ndef_input[15] = {'\0'}; char ID[9] = {'\0'}; double balance = 0; printf("\nID: "); scanf("%s", ID); while (getchar() != '\n') continue; printf("\nBalance: "); scanf("%lf", &balance); while (getchar() != '\n') continue; ID[0] = toupper(ID[0]); ID[1] = toupper(ID[1]); char balance_char[6] = {'\0'}; snprintf(balance_char, 6, "%.2f", balance); //ensure balance always with 4 digit, 4.00 => 04.00 char final_balance[6] = {'\0'}; if(strlen(balance_char) != 5) { strcat(final_balance, "0"); strcat(final_balance, balance_char); } else { strcpy(final_balance, balance_char); } strcat(ndef_input, ID); strcat(ndef_input, final_balance); int i = 0; if (ndef_input == NULL) { printf("Write default message.\n"); for(i=0; i < sizeof(ndef_default_msg); i++) { ndef_msg[i] = (uint8_t)ndef_default_msg[i]; } ndef_msg_len = sizeof(ndef_default_msg); } else { for(i=0; i < strlen(ndef_input); i++) { ndef_msg[i] = (uint8_t)ndef_input[i]; } ndef_msg_len = strlen(ndef_input); } printf ("NDEF message is %zu bytes long.\n", ndef_msg_len); struct mifare_classic_key_and_type *card_write_keys; if (!(card_write_keys = malloc (40 * sizeof (*card_write_keys)))) { err (EXIT_FAILURE, "malloc"); } nfc_device_desc_t devices[8]; size_t device_count; nfc_list_devices (devices, 8, &device_count); if (!device_count) errx (EXIT_FAILURE, "No NFC device found."); for (size_t d = 0; d < device_count; d++) { device = nfc_connect (&(devices[d])); if (!device) { warnx ("nfc_connect() failed."); error = EXIT_FAILURE; continue; } tags = freefare_get_tags (device); if (!tags) { nfc_disconnect (device); errx (EXIT_FAILURE, "Error listing MIFARE classic tag."); } for (int i = 0; (!error) && tags[i]; i++) { switch (freefare_get_tag_type (tags[i])) { case CLASSIC_1K: case CLASSIC_4K: break; default: continue; } char *tag_uid = freefare_get_tag_uid (tags[i]); char buffer[BUFSIZ]; printf ("Found %s with UID %s.\n", freefare_get_tag_friendly_name (tags[i]), tag_uid); bool write_ndef = true; for (int n = 0; n < 40; n++) { memcpy(card_write_keys[n].key, transport_key, sizeof (transport_key)); card_write_keys[n].type = MFC_KEY_A; } if (write_ndef) { switch (freefare_get_tag_type (tags[i])) { case CLASSIC_4K: if (!search_sector_key (tags[i], 0x10, &(card_write_keys[0x10].key), &(card_write_keys[0x10].type))) { error = 1; goto error; } /* fallthrough */ case CLASSIC_1K: if (!search_sector_key (tags[i], 0x00, &(card_write_keys[0x00].key), &(card_write_keys[0x00].type))) { error = 1; goto error; } break; default: /* Keep compiler quiet */ break; } if (!error) { /* Ensure the auth key is always a B one. If not, change it! */ switch (freefare_get_tag_type (tags[i])) { case CLASSIC_4K: if (card_write_keys[0x10].type != MFC_KEY_B) { if( 0 != fix_mad_trailer_block (device, tags[i], 0x10, card_write_keys[0x10].key, card_write_keys[0x10].type)) { error = 1; goto error; } memcpy (&(card_write_keys[0x10].key), &default_keyb, sizeof (MifareClassicKey)); card_write_keys[0x10].type = MFC_KEY_B; } /* fallthrough */ case CLASSIC_1K: if (card_write_keys[0x00].type != MFC_KEY_B) { if( 0 != fix_mad_trailer_block (device, tags[i], 0x00, card_write_keys[0x00].key, card_write_keys[0x00].type)) { error = 1; goto error; } memcpy (&(card_write_keys[0x00].key), &default_keyb, sizeof (MifareClassicKey)); card_write_keys[0x00].type = MFC_KEY_B; } break; default: /* Keep compiler quiet */ break; } } size_t encoded_size; uint8_t *tlv_data = tlv_encode (3, ndef_msg, ndef_msg_len, &encoded_size); /* * At his point, we should have collected all information needed to * succeed. */ // If the card already has a MAD, load it. if ((mad = mad_read (tags[i]))) { // If our application already exists, erase it. MifareClassicSectorNumber *sectors, *p; sectors = p = mifare_application_find (mad, mad_nfcforum_aid); if (sectors) { while (*p) { if (mifare_classic_authenticate (tags[i], mifare_classic_sector_last_block(*p), default_keyb, MFC_KEY_B) < 0) { nfc_perror (device, "mifare_classic_authenticate"); error = 1; goto error; } if (mifare_classic_format_sector (tags[i], *p) < 0) { nfc_perror (device, "mifare_classic_format_sector"); error = 1; goto error; } p++; } } free (sectors); mifare_application_free (mad, mad_nfcforum_aid); } else { // Create a MAD and mark unaccessible sectors in the card if (!(mad = mad_new ((freefare_get_tag_type (tags[i]) == CLASSIC_4K) ? 2 : 1))) { perror ("mad_new"); error = 1; goto error; } MifareClassicSectorNumber max_s; switch (freefare_get_tag_type (tags[i])) { case CLASSIC_1K: max_s = 15; break; case CLASSIC_4K: max_s = 39; break; default: /* Keep compiler quiet */ break; } // Mark unusable sectors as so for (size_t s = max_s; s; s--) { if (s == 0x10) continue; if (!search_sector_key (tags[i], s, &(card_write_keys[s].key), &(card_write_keys[s].type))) { mad_set_aid (mad, s, mad_defect_aid); } else if ((memcmp (card_write_keys[s].key, transport_key, sizeof (transport_key)) != 0) && (card_write_keys[s].type != MFC_KEY_A)) { // Revert to transport configuration if (mifare_classic_format_sector (tags[i], s) < 0) { nfc_perror (device, "mifare_classic_format_sector"); error = 1; goto error; } } } } MifareClassicSectorNumber *sectors = mifare_application_alloc (mad, mad_nfcforum_aid, encoded_size); if (!sectors) { nfc_perror (device, "mifare_application_alloc"); error = EXIT_FAILURE; goto error; } if (mad_write (tags[i], mad, card_write_keys[0x00].key, card_write_keys[0x10].key) < 0) { nfc_perror (device, "mad_write"); error = EXIT_FAILURE; goto error; } int s = 0; while (sectors[s]) { MifareClassicBlockNumber block = mifare_classic_sector_last_block (sectors[s]); MifareClassicBlock block_data; mifare_classic_trailer_block (&block_data, mifare_classic_nfcforum_public_key_a, 0x0, 0x0, 0x0, 0x6, 0x40, default_keyb); if (mifare_classic_authenticate (tags[i], block, card_write_keys[sectors[s]].key, card_write_keys[sectors[s]].type) < 0) { nfc_perror (device, "mifare_classic_authenticate"); error = EXIT_FAILURE; goto error; } if (mifare_classic_write (tags[i], block, block_data) < 0) { nfc_perror (device, "mifare_classic_write"); error = EXIT_FAILURE; goto error; } s++; } if ((ssize_t) encoded_size != mifare_application_write (tags[i], mad, mad_nfcforum_aid, tlv_data, encoded_size, default_keyb, MCAB_WRITE_KEYB)) { nfc_perror (device, "mifare_application_write"); error = EXIT_FAILURE; goto error; } //create new student record in database char sql_stmnt[57] = {'\0'}; int n = 0; //filter tag_uid ulong uid_length = strlen(tag_uid); char uid_esc[(2 * uid_length)+1]; mysql_real_escape_string(conn, uid_esc, tag_uid, uid_length); //filter ID ulong id_length = strlen(ID); char id_esc[(2 * id_length)+1]; mysql_real_escape_string(conn, id_esc, ID, id_length); n = snprintf(sql_stmnt, 57, "INSERT INTO student VALUES('%s', '%s', %.1f)", uid_esc, id_esc, balance); retval = mysql_real_query(conn, sql_stmnt, n); if(retval) { printf("Inserting data from DB Failed\n"); return -1; } printf("Insert to DB successful\n"); free (sectors); free (tlv_data); free (mad); } error: free (tag_uid); } //should at the line 412, but the compiler keep on complaining //jump into scope of identifier with variably modified type //no idea why that happens, goto is always call inside any {} to outside error: //even at 412, still not outside enough freefare_free_tags (tags); nfc_disconnect (device); } free (card_write_keys); mysql_free_result(result); mysql_close(conn); exit (error); }
static struct emu_df *read_df(FILE *f, struct sc *sc, const unsigned char *name, size_t name_len) { struct emu_df *df; int i, j; struct tlvdb *s; unsigned short sw; size_t outlen; unsigned char *outbuf; struct tlv pdol_data_tlv; size_t pdol_data_len; unsigned char *pdol_data; outbuf = sc_command(sc, 0x00, 0xa4, 0x04, 0x00, name_len, name, &sw, &outlen); if (sw != 0x9000) return NULL; s = tlvdb_parse(outbuf, outlen); if (!s) return NULL; df = emu_df_new(); pdol_data_tlv.tag = 0x83; pdol_data_tlv.value = dol_process(tlvdb_get(s, 0x9f38, NULL), s, &pdol_data_tlv.len); pdol_data = tlv_encode(&pdol_data_tlv, &pdol_data_len); if (!pdol_data) return NULL; free((unsigned char *)pdol_data_tlv.value); tlvdb_free(s); emu_df_append(df, emu_property_new("name", emu_value_new_buf(name, name_len))); emu_df_append(df, emu_property_new("fci", emu_value_new_buf(outbuf, outlen))); free(outbuf); outbuf = sc_command(sc, 0x80, 0xa8, 0x00, 0x00, pdol_data_len, pdol_data, &sw, &outlen); free(pdol_data); if (sw == 0x9000) { emu_df_append(df, emu_property_new("gpo", emu_value_new_buf(outbuf, outlen))); free(outbuf); } for (i = 1; i < 31; i++) { int last = 0; struct emu_value *value = NULL; char buf[7]; snprintf(buf, sizeof(buf), "sfi%d", i); for (j = 1; j < 256; j++) { outbuf = sc_command(sc, 0x00, 0xb2, j, (i << 3) | 4, 0, NULL, &sw, &outlen); if (sw == 0x6985) continue; else if (sw != 0x9000) break; for (; last < j - 1; last++) value = emu_value_append(value, ""); value = emu_value_append_buf(value, outbuf, outlen); last ++; free(outbuf); } if (value) emu_df_append(df, emu_property_new(buf, value)); } for (i = 0; card_data[i]; i++) { char buf[10]; tlv_tag_t tag = card_data[i]; outbuf = sc_command(sc, 0x80, 0xca, tag >> 8, tag & 0xff, 0, NULL, &sw, &outlen); if (sw != 0x9000) continue; snprintf(buf, sizeof(buf), "data%x", tag); emu_df_append(df, emu_property_new(buf, emu_value_new_buf(outbuf, outlen))); free(outbuf); } return df; }
int main(void) { int i; struct sc *sc; sc = scard_init(NULL); if (!sc) { printf("Cannot init scard\n"); return 1; } scard_connect(sc, 0); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } struct tlvdb *s; struct tlvdb *t; for (i = 0, s = NULL; apps[i].name_len != 0; i++) { s = emv_select(sc, apps[i].name, apps[i].name_len); if (s) break; } if (!s) return 1; size_t pdol_data_len; unsigned char *pdol_data = dol_process(tlvdb_get(s, 0x9f38, NULL), s, &pdol_data_len); struct tlv pdol_data_tlv = { .tag = 0x83, .len = pdol_data_len, .value = pdol_data }; size_t pdol_data_tlv_data_len; unsigned char *pdol_data_tlv_data = tlv_encode(&pdol_data_tlv, &pdol_data_tlv_data_len); free(pdol_data); if (!pdol_data_tlv_data) return 1; t = emv_gpo(sc, pdol_data_tlv_data, pdol_data_tlv_data_len); free(pdol_data_tlv_data); if (!t) return 1; tlvdb_add(s, t); unsigned char *sda_data = NULL; size_t sda_len = 0; bool ok = emv_read_records(sc, s, &sda_data, &sda_len); if (!ok) return 1; free(sda_data); /* Generate AC asking for AAC */ size_t crm_data_len; unsigned char *crm_data = dol_process(tlvdb_get(s, 0x8c, NULL), s, &crm_data_len); t = emv_generate_ac(sc, 0x00, crm_data, crm_data_len); free(crm_data); tlvdb_add(s, t); tlvdb_add(s, emv_get_data(sc, 0x9f36)); tlvdb_add(s, emv_get_data(sc, 0x9f13)); tlvdb_add(s, emv_get_data(sc, 0x9f17)); tlvdb_add(s, emv_get_data(sc, 0x9f4f)); tlvdb_visit(s, print_cb, NULL); const struct tlv *logent_tlv = tlvdb_get(s, 0x9f4d, NULL); const struct tlv *logent_dol = tlvdb_get(s, 0x9f4f, NULL); if (logent_tlv && logent_tlv->len == 2 && logent_dol) { for (i = 1; i <= logent_tlv->value[1]; i++) { unsigned short sw; size_t log_len; unsigned char *log = emv_read_record(sc, logent_tlv->value[0], i, &sw, &log_len); if (!log) continue; if (sw == 0x9000) { printf("Log #%d\n", i); struct tlvdb *log_db = dol_parse(logent_dol, log, log_len); tlvdb_visit(log_db, print_cb, NULL); tlvdb_free(log_db); } free(log); } } tlvdb_free(s); scard_disconnect(sc); if (scard_is_error(sc)) { printf("%s\n", scard_error(sc)); return 1; } scard_shutdown(sc); return 0; }