/* * Create an empty security environment */ static int incrypto34_create_sec_env(struct sc_profile *profile, struct sc_card *card, unsigned int se_id, unsigned int key_id) { struct sc_cardctl_incrypto34_obj_info args; struct tlv tlv; unsigned char buffer[64]; tlv_init(&tlv, buffer, sizeof(buffer)); tlv_next(&tlv, 0x83); tlv_add(&tlv, se_id); tlv_next(&tlv, 0x86); tlv_add(&tlv, 0); tlv_add(&tlv, 0); tlv_next(&tlv, 0x8f); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); args.data = buffer; args.len = tlv_len(&tlv); return sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_SECI, &args); }
/* * Create an empty security environment */ static int cardos_create_sec_env(struct sc_profile *profile, sc_card_t *card, unsigned int se_id, unsigned int key_id) { struct sc_cardctl_cardos_obj_info args; struct tlv tlv; unsigned char buffer[64]; int r; tlv_init(&tlv, buffer, sizeof(buffer)); tlv_next(&tlv, 0x83); tlv_add(&tlv, se_id); tlv_next(&tlv, 0x86); tlv_add(&tlv, 0); tlv_add(&tlv, 0); tlv_next(&tlv, 0x8f); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); tlv_add(&tlv, key_id); args.data = buffer; args.len = tlv_len(&tlv); /* ensure we are in the correct lifecycle */ r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) return r; return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_SECI, &args); }
int cli_extract_all(dz_t *dz, int name_mod) { int status = -1; tlv_t tlv; off_t off; if (tlv_init(&tlv) == -1) { LOGERROR("tlv_init"); return -1; } while ((off = dz_next_tlv(dz, &tlv)) != EOD) { const char *type_str; int type, len; if (off == -1) { goto DESTROY; } type = tlv_get_type(&tlv); if (type == TLV_PAD1 || type == TLV_PADN) { continue; } if (type == TLV_LONGH) { if (cli_extract_ltlv(dz, &tlv, off, name_mod) != 0) { LOGERROR("cli_extract_ltlv failed"); goto DESTROY; } dz_set_offset(dz, off + ltlv_get_total_length(&tlv)); } else if (cli_extract_tlv(dz, off, name_mod) != 0) { LOGERROR("cli_extract_tlv failed"); goto DESTROY; } } /* No error occurred */ status = 0; DESTROY: if (tlv_destroy(&tlv) != 0) { LOGERROR("tlv_destroy failed"); status = -1; } return status; }
static struct tlv_attr * tlv_add(struct tlv_buf *buf, struct tlv_attr *pos, int id, int payload) { int offset = attr_to_offset(buf, pos); int required = (offset - TLV_COOKIE + sizeof(struct tlv_attr) + payload) - buf->buflen; struct tlv_attr *attr; if (required > 0) { tlv_buf_grow(buf, required); attr = offset_to_attr(buf, offset); } else { attr = pos; } tlv_init(attr, id, payload + sizeof(struct tlv_attr)); tlv_fill_pad(attr); return attr; }
static int cardos_store_key_component(sc_card_t *card, int algorithm, unsigned int key_id, unsigned int pin_id, unsigned int num, const u8 *data, size_t len, int last, int use_prefix) { struct sc_cardctl_cardos_obj_info args; struct tlv tlv; unsigned char buffer[256]; #ifdef SET_SM_BYTES unsigned int n; #endif int r; /* Initialize the TLV encoder */ tlv_init(&tlv, buffer, sizeof(buffer)); /* Object address */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x20|num); /* PSO, n-th component */ tlv_add(&tlv, key_id); /* Object parameters */ tlv_next(&tlv, 0x85); tlv_add(&tlv, CARDOS_KEY_OPTIONS|(last? 0x00 : 0x20)); tlv_add(&tlv, CARDOS_KEY_FLAGS); tlv_add(&tlv, algorithm); tlv_add(&tlv, 0x00); tlv_add(&tlv, 0xFF); /* use count */ tlv_add(&tlv, 0xFF); /* DEK (whatever this is) */ tlv_add(&tlv, 0x00); tlv_add(&tlv, 0x00); /* AC bytes */ tlv_next(&tlv, 0x86); tlv_add(&tlv, pin_id); /* AC USE */ tlv_add(&tlv, pin_id); /* AC CHANGE */ tlv_add(&tlv, pin_id); /* UNKNOWN */ tlv_add(&tlv, 0); /* rfu */ tlv_add(&tlv, 0); /* rfu */ tlv_add(&tlv, 0); /* rfu */ #if 0 tlv_add(&tlv, pin_id); /* AC GENKEY */ #else tlv_add(&tlv, 0); #endif #ifdef SET_SM_BYTES /* it shouldn't be necessary to set the default value */ /* SM bytes */ tlv_next(&tlv, 0x8B); for (n = 0; n < 16; n++) tlv_add(&tlv, 0xFF); #endif /* key component */ tlv_next(&tlv, 0x8f); if (use_prefix != 0) { tlv_add(&tlv, len+1); tlv_add(&tlv, 0); } while (len--) tlv_add(&tlv, *data++); args.data = buffer; args.len = tlv_len(&tlv); /* ensure we are in the correct lifecycle */ r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) return r; return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args); }
/* * Store a PIN or PUK */ static int cardos_store_pin(sc_profile_t *profile, sc_card_t *card, sc_pkcs15_pin_info_t *pin_info, int puk_id, const u8 *pin, size_t pin_len) { struct sc_cardctl_cardos_obj_info args; unsigned char buffer[256]; unsigned char pinpadded[256]; struct tlv tlv; unsigned int attempts, minlen, maxlen; int r; /* We need to do padding because pkcs15-lib.c does it. * Would be nice to have a flag in the profile that says * "no padding required". */ maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded)); if (pin_len > maxlen) { sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "invalid pin length: %u (max %u)\n", pin_len, maxlen); return SC_ERROR_INVALID_ARGUMENTS; } memcpy(pinpadded, pin, pin_len); while (pin_len < maxlen) pinpadded[pin_len++] = profile->pin_pad_char; pin = pinpadded; attempts = pin_info->tries_left; minlen = pin_info->min_length; tlv_init(&tlv, buffer, sizeof(buffer)); /* object address: class, id */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */ tlv_add(&tlv, pin_info->reference); /* parameters */ tlv_next(&tlv, 0x85); tlv_add(&tlv, 0x02); /* options byte */ tlv_add(&tlv, attempts & 0xf); /* flags byte */ tlv_add(&tlv, CARDOS_ALGO_PIN); /* algorithm = pin-test */ tlv_add(&tlv, attempts & 0xf); /* errcount = attempts */ /* usecount: not documented, but seems to work like this: * - value of 0xff means pin can be presented any number * of times * - anything less: max # of times before BS object is blocked. */ tlv_add(&tlv, 0xff); /* DEK: not documented, no idea what it means */ tlv_add(&tlv, 0xff); /* ARA counter: number of times the test object can be used before * another verification is required (~ user consent) * (0x00 unlimited usage) */ tlv_add(&tlv, 0x00); tlv_add(&tlv, minlen); /* minlen */ /* AC conditions */ tlv_next(&tlv, 0x86); tlv_add(&tlv, 0x00); /* use: always */ tlv_add(&tlv, pin_info->reference); /* change: PIN */ tlv_add(&tlv, puk_id); /* unblock: PUK */ /* data: PIN */ tlv_next(&tlv, 0x8f); while (pin_len--) tlv_add(&tlv, *pin++); args.data = buffer; args.len = tlv_len(&tlv); /* ensure we are in the correct lifecycle */ r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN); if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) return r; return sc_card_ctl(card, SC_CARDCTL_CARDOS_PUT_DATA_OCI, &args); }
static void hncp_ok(void) { hncp o = create_hncp(); int t = 123000; int i; /* Pushing in a new subscriber should result in us being called. */ smock_is_empty(); smock_push_bool("node_callback", true); hncp_subscribe(o, &dummy_subscriber_1); hncp_subscribe(o, &dummy_subscriber_2); hncp_subscribe(o, &dummy_subscriber_3); hncp_subscribe(o, &dummy_subscriber_4); smock_is_empty(); one_join(true); smock_push_int("schedule", 0); hncp_if_set_enabled(o, dummy_ifname, true); smock_is_empty(); /* Ok. We're cooking with gas. */ smock_push_int("time", t); smock_push_int("random", 0); smock_push_int("schedule", HNCP_TRICKLE_IMIN / 2); hncp_run(o); smock_is_empty(); t += HNCP_TRICKLE_IMIN / 2 - 1; smock_push_int("time", t); smock_push_int("schedule", 1); hncp_run(o); smock_is_empty(); t += 1; /* Ok. we get timestamp -> woah, need to do something. */ smock_push_int("time", t); /* Should send stuff on an interface. */ smock_push("sendto_ifname", dummy_ifname); smock_push("sendto_dst", &o->multicast_address); smock_push_int("sendto_return", 1); /* And schedule next one (=end of interval). */ smock_push_int("schedule", HNCP_TRICKLE_IMIN / 2); hncp_run(o); smock_is_empty(); /* overshoot what we were asked for.. shouldn't be a problem. */ t += HNCP_TRICKLE_IMIN; smock_push_int("time", t); /* should be queueing next send, and now we go for 'max' value. */ smock_push_int("random", 999); smock_push_int("schedule", 2 * HNCP_TRICKLE_IMIN * (1000 + 999) / 2000); hncp_run(o); smock_is_empty(); /* run the clock until we hit HNCP_TRICKLE_IMAX/2 delay; or we run * out of iterations. */ check_timing = false; check_send = false; check_random = false; want_send = 0; for (i = 0 ; i < 100 ; i++) { current_hnetd_time = t; want_schedule = 0; hncp_run(o); if (want_schedule >= (HNCP_TRICKLE_IMAX / 2)) { sput_fail_unless(want_schedule <= HNCP_TRICKLE_IMAX, "reasonable timeout"); break; } t += want_schedule; current_hnetd_time += want_schedule; } sput_fail_unless(want_send <= i / 2, "few sends"); sput_fail_unless(i < 100, "did not encounter big enough delta"); /* then, run for few more iterations, making sure we don't hit too long ones. */ want_send = 0; for (i = 0 ; i < 10 ; i++) { current_hnetd_time = t; want_schedule = 0; hncp_run(o); sput_fail_unless(want_schedule <= HNCP_TRICKLE_IMAX, "reasonable timeout"); t += want_schedule; current_hnetd_time += want_schedule; } sput_fail_unless(want_send > 0 && want_send <= i / 2, "few sends"); check_timing = true; check_send = true; check_random = true; /* Ok, Trickle was in a stable state 'long' time. Make sure the * state resets once we push something new in. */ struct tlv_attr ta; L_NOTICE("add tlv a"); #define TLV_ID_A 123 #define TLV_ID_B 125 #define TLV_ID_C 127 #define TLV_ID_D 124 tlv_init(&ta, TLV_ID_A, 4); smock_push_int("schedule", 0); smock_push_int("local_tlv_callback", TLV_ID_A); hncp_add_tlv(o, &ta); smock_is_empty(); L_NOTICE("add tlv b"); tlv_init(&ta, TLV_ID_B, 4); /* should NOT cause extra schedule! */ smock_push_int("local_tlv_callback", TLV_ID_B); hncp_add_tlv(o, &ta); smock_is_empty(); L_NOTICE("running."); printf("last run starting\n"); smock_push_int("time", t); smock_push_int("random", 0); smock_push_int("schedule", 0); /* Should get notification about two added TLVs. */ smock_push_int("tlv_callback", TLV_ID_A); smock_push_int("tlv_callback", TLV_ID_B); smock_push_bool("republish_callback", true); hncp_run(o); smock_is_empty(); /* Adding / removing last entry have special handling. So let's * test both by adding and removing tlv c (which > a, b). */ /* Our interest in timing has waned by now though, so we disable * those checks. */ check_timing = false; check_random = false; /* So, let's add one more TLV. Make sure we get notification about it. */ L_NOTICE("add tlv c"); tlv_init(&ta, TLV_ID_C, 4); smock_push_int("local_tlv_callback", TLV_ID_C); hncp_add_tlv(o, &ta); smock_is_empty(); smock_push_int("tlv_callback", TLV_ID_C); smock_push_bool("republish_callback", true); hncp_run(o); smock_is_empty(); /* Remove it. */ L_NOTICE("remove tlv c"); smock_push_int("local_tlv_callback", -TLV_ID_C); hncp_remove_tlv(o, &ta); smock_is_empty(); smock_push_int("tlv_callback", -TLV_ID_C); smock_push_bool("republish_callback", true); hncp_run(o); smock_is_empty(); /* Add TLV D in the middle. */ L_NOTICE("add tlv d"); tlv_init(&ta, TLV_ID_D, 4); smock_push_int("local_tlv_callback", TLV_ID_D); hncp_add_tlv(o, &ta); smock_is_empty(); smock_push_int("tlv_callback", TLV_ID_D); smock_push_bool("republish_callback", true); hncp_run(o); smock_is_empty(); /* Unsubscribing should result in callbacks too. */ L_NOTICE("unsubscribe"); smock_push_int("local_tlv_callback", -TLV_ID_A); smock_push_int("local_tlv_callback", -TLV_ID_D); smock_push_int("local_tlv_callback", -TLV_ID_B); smock_push_int("tlv_callback", -TLV_ID_A); smock_push_int("tlv_callback", -TLV_ID_D); smock_push_int("tlv_callback", -TLV_ID_B); smock_push_bool("node_callback", false); hncp_unsubscribe(o, &dummy_subscriber_1); hncp_unsubscribe(o, &dummy_subscriber_2); hncp_unsubscribe(o, &dummy_subscriber_3); hncp_unsubscribe(o, &dummy_subscriber_4); smock_is_empty(); /* Re-enable checks */ check_timing = true; check_random = true; /* no unregisters at end, as we first kill io, and then flush * structures (socket kill should take care of it in any case). */ destroy_hncp(o); }
int cmd_extract(int argc , char **argv, char *dz_path) { dz_t dz; tlv_t tlv; long off; int fd; size_t real_size; char *data; char *path; if (argc != 2) { fprintf(stderr, "cmd extract : <offset> <path> <dazibao>\n"); return DZ_ARGS_ERROR; } /* If the offset doesn't start with a character between '0' and '9', it * must be wrong. */ if (argv[0][0] < 48 || argv[0][0] > 57) { fprintf(stderr, "Usage:\n extract <offset> <file> <dazibao>\n"); return DZ_ARGS_ERROR; } off = str2dec_positive(argv[0]); if (off < DAZIBAO_HEADER_SIZE) { fprintf(stderr, "wrong offset\n"); return DZ_OFFSET_ERROR; } if (dz_open(&dz, dz_path, O_RDWR) < 0) { fprintf(stderr, "Error while opening the dazibao\n"); return -1; } if (dz_check_tlv_at(&dz, off, -1,NULL) <= 0) { fprintf(stderr, "no such TLV\n"); dz_close(&dz); return DZ_OFFSET_ERROR; } if (tlv_init(&tlv) < 0) { printf("error to init tlv\n"); dz_close(&dz); return -1; } if (choose_tlv_extract(&dz,&tlv,off) < 0) { printf("error to init tlv\n"); tlv_destroy(&tlv); dz_close(&dz); return -1; } if (dz_close(&dz) < 0) { fprintf(stderr, "Error while closing the dazibao\n"); tlv_destroy(&tlv); return -1; } if (tlv_get_type(&tlv) == TLV_COMPOUND) { real_size = (size_t)tlv_get_length(&tlv) + DAZIBAO_HEADER_SIZE; } else { real_size = (size_t)tlv_get_length(&tlv); } path = argv[1]; fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0644); if (fd == -1) { tlv_destroy(&tlv); ERROR("open", -1); } if (ftruncate(fd, real_size) < 0) { fprintf(stderr, "Error while ftruncate path"); close(fd); return -1; } data = (char*)mmap(NULL, real_size, PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { fprintf(stderr, "Error while mmap "); close(fd); tlv_destroy(&tlv); return -1; } if (tlv_get_type(&tlv) == TLV_COMPOUND) { data[0] = MAGIC_NUMBER; memset(data + 1, 0, DAZIBAO_HEADER_SIZE - 1); real_size = real_size - DAZIBAO_HEADER_SIZE; memcpy(data + DAZIBAO_HEADER_SIZE, tlv_get_value_ptr(&tlv), real_size); } else { memcpy(data , tlv_get_value_ptr(&tlv), real_size); } tlv_destroy(&tlv); close(fd); return 0; }
int action_add(int argc, char **argv, int f_co, int f_dz, int f_d, int f_in, char *type, char *daz) { dz_t daz_buf; unsigned int buff_size_co = 0; tlv_t tlv = NULL; tlv_t buff_co = NULL; tlv_t buff_d = NULL; int i,j = 0; if (dz_open(&daz_buf, daz, O_RDWR) < 0) { fprintf(stderr, "failed open the dazibao\n"); return -1; } f_d = (f_d == -1 ? argc : f_d); f_co = (f_co == -1 ? argc : f_co); for (i = 0; i < argc; i++) { int tlv_size = 0; /* inizialized tlv */ if (tlv_init(&tlv) < 0) { printf("error to init tlv\n"); return -1; } /* different possibility to create a standard tlv*/ if (i == f_in) { tlv_size = tlv_create_input(&tlv, &type[j]); j++; } else if (i == f_dz) { tlv_size = dz2tlv(argv[i], &tlv); } else { tlv_size = tlv_create_path(argv[i], &tlv, &type[j]); j++; } /* if not tlv as create error */ if (tlv_size < 0) { printf("error to create tlv with path %s\n", argv[i]); return -1; } /* other option who use tlv created */ if ( i >= f_co ) { /* if tlv to insert to compound it type dated*/ if ((i >= f_d) && (f_d > f_co)) { if (tlv_init(&buff_d) < 0) { printf("error to init tlv compound"); return -1; } tlv_size = tlv_create_date(&buff_d, &tlv, tlv_size); if (tlv_size < 0) { printf("error to create tlv dated" "%s\n", argv[i]); return -1; } tlv_destroy(&tlv); tlv = buff_d; buff_d = NULL; } unsigned int size_realloc = TLV_SIZEOF_HEADER; if ((f_co == i) && (tlv_init(&buff_co) < 0)) { printf("error to init tlv compound\n"); return -1; } size_realloc += buff_size_co + tlv_size; buff_co = (tlv_t) safe_realloc(buff_co, sizeof(*buff_co) * size_realloc); if (buff_co == NULL) { ERROR("realloc", -1); } memcpy(buff_co + buff_size_co, tlv, tlv_size); buff_size_co += tlv_size; tlv_destroy(&tlv); /*when all tlv is insert, create tlv compound*/ if (i == argc -1) { if (tlv_init(&tlv) < 0) { printf(" error to init tlv"); return -1; } tlv_size = tlv_create_compound(&tlv, &buff_co, buff_size_co); if (tlv_size < 0) { printf(" error to create compound" " %s\n", argv[i]); return -1; } tlv_destroy(&buff_co); } else { continue; } } if ((i >= f_d) && (f_d <= f_co)) { if (tlv_init(&buff_d) < 0) { printf(" error to init tlv dated\n"); return -1; } tlv_size = tlv_create_date(&buff_d, &tlv, tlv_size); if (tlv_size < 0) { printf(" error to create tlv dated" "%s\n", argv[i]); return -1; } tlv_destroy(&tlv); tlv = buff_d; buff_d = NULL; } if (tlv_size > 0) { if (dz_add_tlv(&daz_buf, &tlv) == -1) { fprintf(stderr, "failed adding the tlv\n"); tlv_destroy(&tlv); return -1; } tlv_destroy(&tlv); } } if (dz_close(&daz_buf) < 0) { fprintf(stderr, "failed closing the dazibao\n"); return -1; } return 0; }
static int incrypto34_store_key_component(struct sc_card *card, int algorithm, unsigned int key_id, unsigned int pin_id, unsigned int num, const u8 *data, size_t len, int last) { int r; struct sc_cardctl_incrypto34_obj_info args; struct tlv tlv; unsigned char buffer[256]; unsigned int n; /* Initialize the TLV encoder */ tlv_init(&tlv, buffer, sizeof(buffer)); /* Object address */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x20|num); /* PSO, n-th component */ tlv_add(&tlv, key_id); /* Object parameters */ tlv_next(&tlv, 0x85); tlv_add(&tlv, INCRYPTO34_KEY_OPTIONS|(last? 0x00 : 0x20)); tlv_add(&tlv, INCRYPTO34_KEY_FLAGS); tlv_add(&tlv, algorithm); tlv_add(&tlv, 0x0F); /* Error Counter*/ tlv_add(&tlv, 0xFF); /* use count */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0x00); /* RFU */ tlv_add(&tlv, 0x00); /* RFU */ /* AC bytes */ tlv_next(&tlv, 0x86); tlv_add(&tlv, pin_id); /* AC USE */ tlv_add(&tlv, pin_id); /* AC CHANGE */ tlv_add(&tlv, 0xFF); /* AC_UNBLOCK */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0); /* AC_GENKEY */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0xFF); /* RFU */ tlv_add(&tlv, 0xFF); /* RFU */ /* SM bytes */ tlv_next(&tlv, 0x8B); for (n = 0; n < 16; n++) tlv_add(&tlv, 0xFF); /* key component */ tlv_next(&tlv, 0x8f); tlv_add(&tlv, len+1); tlv_add(&tlv, 0); while (len--) tlv_add(&tlv, *data++); args.data = buffer; args.len = tlv_len(&tlv); r = sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_OCI, &args); return r; }
/* * Store a PIN or PUK */ static int incrypto34_store_pin(sc_profile_t *profile, sc_card_t *card, sc_pkcs15_auth_info_t *auth_info, int puk_id, const u8 *pin, size_t pin_len) { struct sc_cardctl_incrypto34_obj_info args; unsigned char buffer[256]; unsigned char pinpadded[16]; struct tlv tlv; unsigned int attempts, minlen, maxlen; if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN) return SC_ERROR_OBJECT_NOT_VALID; /* We need to do padding because pkcs15-lib.c does it. * Would be nice to have a flag in the profile that says * "no padding required". */ maxlen = MIN(profile->pin_maxlen, sizeof(pinpadded)); if (pin_len > maxlen) pin_len = maxlen; memcpy(pinpadded, pin, pin_len); while (pin_len < maxlen) pinpadded[pin_len++] = profile->pin_pad_char; pin = pinpadded; attempts = auth_info->tries_left; minlen = auth_info->attrs.pin.min_length; tlv_init(&tlv, buffer, sizeof(buffer)); /* object address: class, id */ tlv_next(&tlv, 0x83); tlv_add(&tlv, 0x00); /* class byte: usage TEST, k=0 */ tlv_add(&tlv, auth_info->attrs.pin.reference); /* parameters */ tlv_next(&tlv, 0x85); tlv_add(&tlv, 0x02); /* options byte */ tlv_add(&tlv, attempts & 0xf); /* flags byte */ tlv_add(&tlv, INCRYPTO34_ALGO_PIN); /* algorithm = pin-test */ tlv_add(&tlv, attempts & 0xf); /* errcount = attempts */ /* usecount: not documented, but seems to work like this: * - value of 0xff means pin can be presented any number * of times * - anything less: max # of times before BS object is blocked. */ tlv_add(&tlv, 0xff); /* DEK: RFU */ tlv_add(&tlv, 0x00); /* ARA counter: the number of times the PIN can be used before the he must be verified again (0 or ff for unlimited usage) */ tlv_add(&tlv, 0x00); tlv_add(&tlv, minlen); /* minlen */ /* AC conditions */ tlv_next(&tlv, 0x86); tlv_add(&tlv, 0x00); /* use: always */ tlv_add(&tlv, auth_info->attrs.pin.reference); /* change: PIN */ tlv_add(&tlv, puk_id); /* unblock: PUK */ tlv_add(&tlv, 0xFF); /*RFU*/ tlv_add(&tlv, 0xFF); /*RFU*/ tlv_add(&tlv, 0xFF); /*RFU*/ tlv_add(&tlv, 0xFF); /*unused on pins*/ tlv_add(&tlv, 0xFF); /*RFU*/ tlv_add(&tlv, 0xFF); /*RFU*/ tlv_add(&tlv, 0xFF); /*RFU*/ /* data: PIN */ tlv_next(&tlv, 0x8f); while (pin_len--) tlv_add(&tlv, *pin++); args.data = buffer; args.len = tlv_len(&tlv); return sc_card_ctl(card, SC_CARDCTL_INCRYPTO34_PUT_DATA_OCI, &args); }
int cli_print_dz(dz_t *dz, int indent, int lvl, int debug) { int status = -1; tlv_t tlv; off_t off; if (tlv_init(&tlv) == -1) { LOGERROR("tlv_init"); return -1; } while ((off = dz_next_tlv(dz, &tlv)) != EOD) { const char *type_str; if (off == -1) { LOGERROR("dz_next_tlv failed"); goto DESTROY; } int type = tlv_get_type(&tlv); if ((type == TLV_PAD1 || type == TLV_PADN) && !debug) { continue; } if (type == TLV_LONGH) { dz_set_offset(dz, off); off_t next = cli_print_ltlv( dz, &tlv, indent, lvl, debug); if (next == -1) { LOGERROR("cli_print_ltlv failed"); goto DESTROY; } dz_set_offset(dz, off + next); continue; } for (int i = 0; i <= indent; i++) { printf("--"); } int len = tlv_get_length(&tlv); type_str = tlv_type2str(type); printf(" @[%10li]: %8s (%d bytes)\n", (unsigned long)off, (type_str ? type_str : "unknown"), len); if ((type != TLV_DATED && type != TLV_COMPOUND) || lvl == 0) { continue; } dz_t cmpnd = { -1, 0, (off + TLV_SIZEOF_HEADER + len), (off + TLV_SIZEOF_HEADER + (type == TLV_DATED ? TLV_SIZEOF_DATE : 0)), -1, dz->data}; if (cli_print_dz(&cmpnd, indent + 1, lvl - 1, debug)) { goto DESTROY; } } /* If no error occurred */ status = 0; DESTROY: if (tlv_destroy(&tlv) != 0) { LOGERROR("tlv_destroy failed"); status = -1; } return status; }
int cli_extract_tlv(dz_t *dz, off_t offset, int name_mod) { tlv_t tlv; int status = -1; int out_fd; int type; if (tlv_init(&tlv) != 0) { LOGERROR("Failed initializing TLV."); goto OUT; } switch (dz_tlv_at(dz, &tlv, offset)) { case -1: case EOD: LOGERROR("dz_tlv_at %d failed.", (int)offset); goto DESTROY; }; type = tlv_get_type(&tlv); switch (type) { case TLV_DATED: case TLV_COMPOUND: { int len = tlv_get_length(&tlv); dz_t cmpnd = { -1, 0, (offset + TLV_SIZEOF_HEADER + len), (offset + TLV_SIZEOF_HEADER + (type == TLV_DATED ? TLV_SIZEOF_DATE : 0)), -1, dz->data}; if (cli_extract_all(&cmpnd, offset + name_mod) != 0) { goto DESTROY; } break; }; case TLV_LONGH: if (cli_extract_ltlv(dz, &tlv, offset, name_mod) != 0) { LOGERROR("cli_extract_ltlv failed"); goto DESTROY; } break; default: if (dz_read_tlv(dz, &tlv, offset) != 0) { LOGERROR("dz_read_tlv failed"); goto DESTROY; } if (cli_write_file(tlv_get_value_ptr(&tlv), tlv_get_length(&tlv), offset + name_mod, type) == -1) { LOGERROR("Printing in file failed."); goto DESTROY; } }; /* If no error occurred */ status = 0; DESTROY: if (tlv_destroy(&tlv) != 0) { LOGERROR("tlv_destroy failed"); status = -1; } OUT: return status; }
int cli_add(int argc, char **argv) { int status = -1; dz_t dz; tlv_t tlv; char date = 0; char *type = NULL; char *file; char **inputs; int nb_inputs = 0; /* Parsing arguments. */ struct s_option opt[] = { {"--date", ARG_TYPE_FLAG, (void *)&date}, {"--type", ARG_TYPE_STRING, (void *)&type}, }; struct s_args args = {&nb_inputs, &inputs, opt}; if (jparse_args(argc, argv, &args, sizeof(opt)/sizeof(*opt)) == -1) { LOGERROR("jparse_args failed."); goto OUT; } if (nb_inputs < 2) { LOGERROR("Missing parameters (see manual)."); goto OUT; } file = inputs[--nb_inputs]; if (dz_open(&dz, file, O_RDWR) != 0) { LOGERROR("Failed opening %s.", file); goto OUT; } if (tlv_init(&tlv) == -1) { LOGERROR("tlv_init failed."); goto CLOSE; } if (cli_mk_tlv(&tlv, nb_inputs, inputs, type, date) == -1) { LOGERROR("cli_mk_tlv failed."); goto DESTROY; } if (dz_add_tlv(&dz, &tlv) != 0) { LOGERROR("Failed adding TLV."); goto DESTROY; } /* If no error occurred */ status = 0; DESTROY: if (tlv_destroy(&tlv) != 0) { LOGERROR("tlv_destroy failed"); status = -1; } CLOSE: if (dz_close(&dz) == -1) { LOGERROR("Failed closing dazibao."); status = -1; } OUT: return status; }