/* * Object deletion. */ static int cardos_delete_object(sc_profile_t *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const struct sc_path *path) { int r = SC_SUCCESS, stored_in_ef = 0, algorithm = 0; size_t keybits; sc_file_t *file = NULL; struct sc_pkcs15_prkey_info *key_info; struct sc_pkcs15_prkey_rsa key_obj; struct sc_context *ctx = p15card->card->ctx; uint8_t abignum[256]; LOG_FUNC_CALLED(ctx); /* * If we are deleting a private key, overwrite it so it can't be used. */ if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_PRKEY) { key_info = obj->data; keybits = key_info->modulus_length & ~7UL; init_key_object(&key_obj, abignum, keybits >> 3); r = cardos_key_algorithm(key_info->usage, keybits, &algorithm); LOG_TEST_RET(ctx, r, "cardos_key_algorithm failed"); r = sc_select_file(p15card->card, &key_info->path, &file); LOG_TEST_RET(ctx, r, "Failed to store key: cannot select parent DF"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); sc_file_free(file); LOG_TEST_RET(ctx, r, "Failed to store key: UPDATE authentication failed"); r = cardos_put_key(profile, p15card, algorithm, key_info, &key_obj); LOG_TEST_RET(ctx, r, "cardos_put_key failed"); }
/* * Certificates with a related private key are stored in the fid range CE00 - CEFF. The * second byte in the fid matches the key id. * Certificates without a related private key (e.g. CA certificates) are stored in the fid range * CA00 - CAFF. The second byte is a free selected id. */ static int sc_hsm_emu_store_cert(struct sc_pkcs15_card *p15card, struct sc_profile *profile, struct sc_pkcs15_object *object, struct sc_pkcs15_der *data) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) object->data; struct sc_pkcs15_object *prkey; sc_path_t path; u8 id[2]; int r; r = sc_pkcs15_find_object_by_id(p15card, SC_PKCS15_TYPE_PRKEY, &cert_info->id , &prkey); if (r == SC_ERROR_OBJECT_NOT_FOUND) { r = sc_hsm_determine_free_id(p15card, CA_CERTIFICATE_PREFIX); LOG_TEST_RET(p15card->card->ctx, r, "Out of identifier to store certificate description"); id[0] = CA_CERTIFICATE_PREFIX; id[1] = r; } else { LOG_TEST_RET(p15card->card->ctx, r, "Error locating matching private key"); id[0] = EE_CERTIFICATE_PREFIX; id[1] = ((struct sc_pkcs15_prkey_info *)prkey->data)->key_reference; } sc_path_set(&path, SC_PATH_TYPE_FILE_ID, id, 2, 0, -1); cert_info->path = path; r = sc_hsm_update_ef(p15card, id[0], id[1], 1, data->value, data->len); return r; }
int sm_authentic_get_apdus(struct sc_context *ctx, struct sm_info *sm_info, unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata, int release_sm) { int rv = 0; LOG_FUNC_CALLED(ctx); if (!sm_info) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM get APDUs: rdata:%p, init_len:%i", rdata, init_len); sc_log(ctx, "SM get APDUs: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len)); if (init_data) { rv = sm_gp_external_authentication(ctx, sm_info, init_data, init_len, rdata, sm_oberthur_diversify_keyset); LOG_TEST_RET(ctx, rv, "SM get APDUs: cannot authenticate card"); } switch (sm_info->cmd) { case SM_CMD_APDU_TRANSMIT: rv = sm_authentic_encode_apdu(ctx, sm_info); LOG_TEST_RET(ctx, rv, "SM get APDUs: cannot encode APDU"); break; case SM_CMD_INITIALIZE: break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported SM command"); } LOG_FUNC_RETURN(ctx, rv); }
int sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_data_info *info, struct sc_pkcs15_data **data_object_out) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_data *data_object; struct sc_pkcs15_der der; int r; LOG_FUNC_CALLED(ctx); if (!info || !data_object_out) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); if (!info->data.value) { r = sc_pkcs15_read_file(p15card, &info->path, &info->data.value, &info->data.len); LOG_TEST_RET(ctx, r, "Cannot get DATA object data"); } sc_der_copy(&der, &info->data); data_object = calloc(sizeof(struct sc_pkcs15_data), 1); if (!data_object && !der.value) LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate memory for data object"); data_object->data = der.value; data_object->data_len = der.len; *data_object_out = data_object; LOG_FUNC_RETURN(ctx,SC_SUCCESS); }
/* * SELECT an applet on the smartcard. (Not in the emulated filesystem.) * The response will be written to resp. * * @param[in] card * @param[in] aid The applet ID. * @param[in] aid_len The legth of aid. * @param[out] resp The response of the applet upon selection. * @param[in,out] resp_len In: The buffer size of resp. Out: The length of the response. * * @return SC_SUCCESS: The applet is present and could be selected. * any other: Transmit failure or the card returned an error. * The card will return an error when the applet is * not present. */ static int isoApplet_select_applet(sc_card_t *card, const u8 *aid, const size_t aid_len, u8 *resp, size_t *resp_len) { int rv; sc_context_t *ctx = card->ctx; sc_apdu_t apdu; LOG_FUNC_CALLED(card->ctx); if(aid_len > SC_MAX_APDU_BUFFER_SIZE) LOG_FUNC_RETURN(card->ctx, SC_ERROR_BUFFER_TOO_SMALL); sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xa4, 0x04, 0x00); apdu.lc = aid_len; apdu.data = aid; apdu.datalen = aid_len; apdu.resp = resp; apdu.resplen = *resp_len; apdu.le = 0; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "APDU transmit faiure."); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rv, "Card returned error"); *resp_len = apdu.resplen; LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2], u8 *efbin, size_t *len) { sc_path_t path; int r; sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, 0); /* look this up with our AID */ path.aid = sc_hsm_aid; /* we don't have a pre-known size of the file */ path.count = -1; if (!p15card->opts.use_file_cache || SC_SUCCESS != sc_pkcs15_read_cached_file(p15card, &path, &efbin, len)) { /* avoid re-selection of SC-HSM */ path.aid.len = 0; r = sc_select_file(p15card->card, &path, NULL); LOG_TEST_RET(p15card->card->ctx, r, "Could not select EF"); r = sc_read_binary(p15card->card, 0, efbin, *len, 0); LOG_TEST_RET(p15card->card->ctx, r, "Could not read EF"); *len = r; if (p15card->opts.use_file_cache) { /* save this with our AID */ path.aid = sc_hsm_aid; sc_pkcs15_cache_file(p15card, &path, efbin, *len); } } return SC_SUCCESS; }
static int sm_gp_encrypt_command_data(struct sc_context *ctx, unsigned char *session_key, const unsigned char *in, size_t in_len, unsigned char **out, size_t *out_len) { unsigned char *data = NULL; int rv, len; if (!out || !out_len) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "SM GP encrypt command data error"); sc_debug(ctx, SC_LOG_DEBUG_SM, "SM GP encrypt command data(len:%"SC_FORMAT_LEN_SIZE_T"u,%p)", in_len, in); if (in==NULL || in_len==0) { *out = NULL; *out_len = 0; LOG_FUNC_RETURN(ctx, SC_SUCCESS); } len = in_len + 8; len -= (len%8); data = calloc(1, len); if (!data) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); *data = in_len; memcpy(data + 1, in, in_len); rv = sm_encrypt_des_cbc3(ctx, session_key, data, in_len + 1, out, out_len, 1); free(data); LOG_TEST_RET(ctx, rv, "SM GP encrypt command data: encryption error"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int iasecc_sm_sdo_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_update *update) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_sdo_update() SE#%i, SDO(class:0x%X,ref:%i)", se_num, update->sdo_class, update->sdo_ref); rv = iasecc_sm_initialize(card, se_num, SM_CMD_SDO_UPDATE); LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM INITIALIZE failed"); sc_log(ctx, "current DF '%s'", sc_print_path(&sm_info->current_path_df)); sm_info->cmd_data = update; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM 'SDO UPDATE' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_sdo_update() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
int iasecc_sm_pin_reset(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_pin_reset() SE#%i, PIN(ref:%i,len:%i)", se_num, data->pin_reference, data->pin2.len); rv = iasecc_sm_initialize(card, se_num, SM_CMD_PIN_RESET); LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM INITIALIZE failed"); sm_info->cmd_data = data; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM 'PIN RESET' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_reset() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int iasecc_parse_chv(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_chv *chv) { struct sc_context *ctx = card->ctx; size_t offs = 0; int rv; LOG_FUNC_CALLED(ctx); while(offs < data_len) { struct iasecc_extended_tlv tlv; rv = iasecc_parse_get_tlv(card, data + offs, &tlv); LOG_TEST_RET(ctx, rv, "iasecc_parse_chv() get and parse TLV error"); sc_log(ctx, "iasecc_parse_chv() get and parse TLV returned %i; tag %X; size %i", rv, tlv.tag, tlv.size); if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MAX) chv->size_max = tlv; else if (tlv.tag == IASECC_SDO_CHV_TAG_SIZE_MIN) chv->size_min = tlv; else if (tlv.tag == IASECC_SDO_CHV_TAG_VALUE) chv->value = tlv; else LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non CHV SDO tag"); offs += rv; } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int iasecc_sm_pin_verify(struct sc_card *card, unsigned se_num, struct sc_pin_cmd_data *data, int *tries_left) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_pin_verify() SE#%i, PIN(ref:%i,len:%i)", se_num, data->pin_reference, data->pin1.len); rv = iasecc_sm_initialize(card, se_num, SM_CMD_PIN_VERIFY); LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM INITIALIZE failed"); sm_info->cmd_data = data; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); if (rv && rdata.length && tries_left) if (rdata.data->apdu.sw1 == 0x63 && (rdata.data->apdu.sw2 & 0xF0) == 0xC0) *tries_left = rdata.data->apdu.sw2 & 0x0F; LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM 'PIN VERIFY' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_pin_verify() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int iso7816_update_binary(struct sc_card *card, unsigned int idx, const u8 *buf, size_t count, unsigned long flags) { struct sc_apdu apdu; int r; if (idx > 0x7fff) { sc_log(card->ctx, "invalid EF offset: 0x%X > 0x7FFF", idx); return SC_ERROR_OFFSET_TOO_LARGE; } sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xD6, (idx >> 8) & 0x7F, idx & 0xFF); apdu.lc = count; apdu.datalen = count; apdu.data = buf; fixup_transceive_length(card, &apdu); r = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, r, "APDU transmit failed"); r = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, r, "Card returned error"); LOG_FUNC_RETURN(card->ctx, count); }
/** Sends a single APDU to the card reader and calls GET RESPONSE to get the return data if necessary. * @param card sc_card_t object for the smartcard * @param apdu APDU to be sent * @return SC_SUCCESS on success and an error value otherwise */ static int sc_transmit(sc_card_t *card, sc_apdu_t *apdu) { struct sc_context *ctx = card->ctx; size_t olen = apdu->resplen; int r; LOG_FUNC_CALLED(ctx); r = sc_single_transmit(card, apdu); LOG_TEST_RET(ctx, r, "transmit APDU failed"); /* ok, the APDU was successfully transmitted. Now we have two special cases: * 1. the card returned 0x6Cxx: in this case APDU will be re-trasmitted with Le set to SW2 * (possible only if response buffer size is larger than new Le = SW2) */ if (apdu->sw1 == 0x6C && (apdu->flags & SC_APDU_FLAGS_NO_RETRY_WL) == 0) r = sc_set_le_and_transmit(card, apdu, olen); LOG_TEST_RET(ctx, r, "cannot re-transmit APDU "); /* 2. the card returned 0x61xx: more data can be read from the card * using the GET RESPONSE command (mostly used in the T0 protocol). * Unless the SC_APDU_FLAGS_NO_GET_RESP is set we try to read as * much data as possible using GET RESPONSE. */ if (apdu->sw1 == 0x61 && (apdu->flags & SC_APDU_FLAGS_NO_GET_RESP) == 0) r = sc_get_response(card, apdu, olen); LOG_TEST_RET(ctx, r, "cannot get all data with 'GET RESPONSE'"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
static int sc_awp_parse_df(struct sc_pkcs15_card *p15card, struct sc_pkcs15_df *df) { struct sc_context *ctx = p15card->card->ctx; unsigned char *buf = NULL; size_t buf_len; int rv; LOG_FUNC_CALLED(ctx); if (df->type != SC_PKCS15_PRKDF && df->type != SC_PKCS15_DODF) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); if (df->enumerated) LOG_FUNC_RETURN(ctx, SC_SUCCESS); rv = sc_oberthur_read_file(p15card, AWP_OBJECTS_LIST_PRV, &buf, &buf_len, 1); LOG_TEST_RET(ctx, rv, "Parse DF: read pribate objects info failed"); rv = sc_oberthur_parse_privateinfo(p15card, buf, buf_len, 0); if (buf) free(buf); if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) LOG_FUNC_RETURN(ctx, SC_SUCCESS); LOG_TEST_RET(ctx, rv, "Parse DF: private info parse error"); df->enumerated = 1; LOG_FUNC_RETURN(ctx, rv); }
static int esteid_get_pin_remaining_tries(sc_card_t *card, int pin_reference) { unsigned char get_pin_info[] = {0x4D, 0x08, 0x70, 0x06, 0xBF, 0x81, 0xFF, 0x02, 0xA0, 0x80}; struct sc_apdu apdu; unsigned char apdu_resp[SC_MAX_APDU_RESP_SIZE]; LOG_FUNC_CALLED(card->ctx); // We don't get the file information here, so we need to be ugly if (pin_reference == PIN1_REF || pin_reference == PUK_REF) { LOG_TEST_RET(card->ctx, esteid_select(card, 0x00, 0x3F, 0x00), "Cannot select MF"); } else if (pin_reference == PIN2_REF) { LOG_TEST_RET(card->ctx, esteid_select_file(card, &adf2, NULL), "Cannot select QSCD AID"); } else { LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); } get_pin_info[6] = pin_reference & 0x0F; // mask out local/global sc_format_apdu_ex(card, &apdu, 0xCB, 0x3F, 0xFF, get_pin_info, sizeof(get_pin_info), apdu_resp, sizeof(apdu_resp)); SC_TRANSMIT_TEST_RET(card, apdu, "GET DATA(pin info) failed"); if (apdu.resplen < 32) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL); } // XXX: sc_asn1_find_tag with the following payload (to get to tag 0x9B): // https://lapo.it/asn1js/#cB6_gQEaoBiaAQObAQOhEIwG8wAAc0MAnAbzAABzQwA return (int)apdu_resp[13]; }
/** * Initialize * * Read keyset from the OpenSC configuration file, * get and return the APDU(s) to initialize SM session. */ int initialize(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *out) { int rv = SC_ERROR_NOT_SUPPORTED; LOG_FUNC_CALLED(ctx); if (!sm_info) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "Current AID: %s", sc_dump_hex(sm_info->current_aid.value, sm_info->current_aid.len)); switch (sm_info->sm_type) { case SM_TYPE_GP_SCP01: rv = sm_gp_config_get_keyset(ctx, sm_info); LOG_TEST_RET(ctx, rv, "SM gp configuration error"); rv = sm_gp_initialize(ctx, sm_info, out); LOG_TEST_RET(ctx, rv, "SM gp initializing error"); break; case SM_TYPE_CWA14890: rv = sm_cwa_config_get_keyset(ctx, sm_info); LOG_TEST_RET(ctx, rv, "SM iasecc configuration error"); rv = sm_cwa_initialize(ctx, sm_info, out); LOG_TEST_RET(ctx, rv, "SM iasecc initializing error"); break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported SM type"); }; LOG_FUNC_RETURN(ctx, rv); }
/** * Get APDU(s) * * Get securized APDU(s) corresponding * to the asked command. */ int get_apdus(struct sc_context *ctx, struct sm_info *sm_info, unsigned char *init_data, size_t init_len, struct sc_remote_data *out) { int rv = SC_ERROR_NOT_SUPPORTED; LOG_FUNC_CALLED(ctx); if (!sm_info) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM get APDUs: out:%p", out); sc_log(ctx, "SM get APDUs: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len)); if (sm_info->card_type == SC_CARD_TYPE_OBERTHUR_AUTHENTIC_3_2) { rv = sm_authentic_get_apdus(ctx, sm_info, init_data, init_len, out, 1); LOG_TEST_RET(ctx, rv, "SM get APDUs: failed for AuthentIC"); } else if (sm_info->card_type/10*10 == SC_CARD_TYPE_IASECC_BASE) { rv = sm_iasecc_get_apdus(ctx, sm_info, init_data, init_len, out, 1); LOG_TEST_RET(ctx, rv, "SM get APDUs: failed for IAS/ECC"); } else { LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "SM get APDUs: unsupported card type"); } LOG_FUNC_RETURN(ctx, rv); }
static int iasecc_sm_transmit_apdus(struct sc_card *card, struct sc_remote_data *rdata, unsigned char *out, size_t *out_len) { struct sc_context *ctx = card->ctx; struct sc_remote_apdu *rapdu = rdata->data; int rv = SC_SUCCESS, offs = 0; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_transmit_apdus() rdata-length %i", rdata->length); while (rapdu) { sc_log(ctx, "iasecc_sm_transmit_apdus() rAPDU flags 0x%lX", rapdu->apdu.flags); rv = sc_transmit_apdu(card, &rapdu->apdu); LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() failed to execute r-APDU"); rv = sc_check_sw(card, rapdu->apdu.sw1, rapdu->apdu.sw2); if (rv < 0 && !(rapdu->flags & SC_REMOTE_APDU_FLAG_NOT_FATAL)) LOG_TEST_RET(ctx, rv, "iasecc_sm_transmit_apdus() fatal error %i"); if (out && out_len && (rapdu->flags & SC_REMOTE_APDU_FLAG_RETURN_ANSWER)) { int len = rapdu->apdu.resplen > (*out_len - offs) ? (*out_len - offs) : rapdu->apdu.resplen; memcpy(out + offs, rapdu->apdu.resp, len); offs += len; /* TODO: decode and gather data answers */ } rapdu = rapdu->next; } if (out_len) *out_len = offs; LOG_FUNC_RETURN(ctx, rv); }
static int iasecc_parse_docp(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo *sdo) { struct sc_context *ctx = card->ctx; size_t offs = 0; int rv; LOG_FUNC_CALLED(ctx); while(offs < data_len) { struct iasecc_extended_tlv tlv; rv = iasecc_parse_get_tlv(card, data + offs, &tlv); LOG_TEST_RET(ctx, rv, "iasecc_parse_get_tlv() get and parse TLV error"); sc_log(ctx, "iasecc_parse_docp() parse_get_tlv retuned %i; tag %X; size %i", rv, tlv.tag, tlv.size); if (tlv.tag == IASECC_DOCP_TAG_ACLS) { int _rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo); free(tlv.value); LOG_TEST_RET(ctx, _rv, "parse error: cannot parse DOCP"); } else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACT) { sdo->docp.acls_contact = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_ACLS_CONTACTLESS) { sdo->docp.acls_contactless = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_SIZE) { sdo->docp.size = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_NAME) { sdo->docp.name = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_ISSUER_DATA) { sdo->docp.issuer_data = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDATION) { sdo->docp.non_repudiation = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING) { sdo->docp.usage_remaining = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM) { sdo->docp.tries_maximum = tlv; } else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING) { sdo->docp.tries_remaining = tlv; } else { LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "iasecc_parse_get_tlv() parse error: non DOCP tag"); } offs += rv; } rv = iasecc_parse_acls(card, &sdo->docp, 0); LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
static int iasecc_parse_keyset(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_keyset *keyset) { struct sc_context *ctx = card->ctx; size_t offs = 0; int rv; LOG_FUNC_CALLED(ctx); while(offs < data_len) { struct iasecc_extended_tlv tlv; rv = iasecc_parse_get_tlv(card, data + offs, &tlv); LOG_TEST_RET(ctx, rv, "iasecc_parse_keyset() get and parse TLV error"); sc_log(ctx, "iasecc_parse_prvkey() get and parse TLV returned %i; tag %X; size %i", rv, tlv.tag, tlv.size); if (tlv.tag == IASECC_SDO_KEYSET_TAG_COMPULSORY) keyset->compulsory = tlv; else LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non KeySet SDO tag"); offs += rv; } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int iasecc_sm_create_file(struct sc_card *card, unsigned se_num, unsigned char *fcp, size_t fcp_len) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; struct iasecc_sm_cmd_create_file cmd_data; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "iasecc_sm_create_file() SE#%i, fcp(%i) '%s'", se_num, fcp_len, sc_dump_hex(fcp, fcp_len)); rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_CREATE); LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM INITIALIZE failed"); cmd_data.data = fcp; cmd_data.size = fcp_len; sm_info->cmd_data = &cmd_data; sc_remote_data_init(&rdata); rv= iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM 'UPDATE BINARY' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_create_file() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int ias_compute_signature(sc_card_t *card, const u8 *data, size_t data_len, u8 *out, size_t outlen) { sc_apdu_t apdu; size_t len; /* ** XXX: Ensure sufficient space exists for the card's response ** as the caller's buffer size may not be sufficient */ u8 rbuf[SC_MAX_APDU_BUFFER_SIZE]; sc_context_t *ctx = card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (data_len > 64) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "error: input data too long: %lu bytes\n", data_len); return SC_ERROR_INVALID_ARGUMENTS; } sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x88, 0x02, 0x00); apdu.data = (u8 *) data; apdu.lc = data_len; apdu.datalen = data_len; apdu.resp = rbuf; apdu.resplen = sizeof(rbuf); apdu.le = 256; LOG_TEST_RET(card->ctx, sc_transmit_apdu(card, &apdu), "APDU transmit failed"); LOG_TEST_RET(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2), "INTERNAL AUTHENTICATE failed"); len = apdu.resplen > outlen ? outlen : apdu.resplen; memcpy(out, apdu.resp, len); LOG_FUNC_RETURN(card->ctx, apdu.resplen); }
int iasecc_sm_delete_file(struct sc_card *card, unsigned se_num, unsigned int file_id) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM delete file: SE#:%X, file-id:%X", se_num, file_id); rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_DELETE); LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM INITIALIZE failed"); sm_info->cmd_data = (void *)file_id; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM 'FILE DELETE' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_delete_file() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
/* * Add a unrelated certificate object and description in PKCS#15 format to the framework */ static int sc_pkcs15emu_sc_hsm_add_cd(sc_pkcs15_card_t * p15card, u8 id) { sc_card_t *card = p15card->card; sc_pkcs15_cert_info_t *cert_info; sc_pkcs15_object_t obj; u8 fid[2]; u8 efbin[512]; const u8 *ptr; size_t len; int r; fid[0] = CD_PREFIX; fid[1] = id; /* Try to select a related EF containing the PKCS#15 description of the data */ len = sizeof efbin; r = read_file(p15card, fid, efbin, &len); LOG_TEST_RET(card->ctx, r, "Could not read EF.DCOD"); ptr = efbin; memset(&obj, 0, sizeof(obj)); r = sc_pkcs15_decode_cdf_entry(p15card, &obj, &ptr, &len); LOG_TEST_RET(card->ctx, r, "Could not decode EF.CD"); cert_info = (sc_pkcs15_cert_info_t *)obj.data; r = sc_pkcs15emu_add_x509_cert(p15card, &obj, cert_info); LOG_TEST_RET(card->ctx, r, "Could not add data object to framework"); return SC_SUCCESS; }
/* * Erase the card. */ static int myeid_erase_card(struct sc_profile *profile, struct sc_pkcs15_card *p15card) { struct sc_context *ctx = p15card->card->ctx; struct sc_cardctl_myeid_data_obj data_obj; struct sc_file *mf = NULL; unsigned char data[8]; int r; LOG_FUNC_CALLED(ctx); r = myeid_get_init_applet_data(profile, p15card, data, sizeof (data)); LOG_TEST_RET(ctx, r, "Get init applet date error"); /* Select parent DF and verify PINs/key as necessary */ r = sc_select_file(p15card->card, sc_get_mf_path(), &mf); LOG_TEST_RET(ctx, r, "Cannot select MF"); /* ACLs are not actives if file is not in the operational state */ if (mf->status == SC_FILE_STATUS_ACTIVATED) r = sc_pkcs15init_authenticate(profile, p15card, mf, SC_AC_OP_DELETE); LOG_TEST_RET(ctx, r, "'DELETE' authentication failed on MF"); data_obj.P1 = 0x01; data_obj.P2 = 0xE0; data_obj.Data = data; data_obj.DataLen = sizeof (data); r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj); LOG_FUNC_RETURN(p15card->card->ctx, r); }
static int jpki_compute_signature(sc_card_t * card, const u8 * data, size_t datalen, u8 * out, size_t outlen) { int rc; sc_apdu_t apdu; unsigned char resp[SC_MAX_APDU_BUFFER_SIZE]; LOG_FUNC_CALLED(card->ctx); sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x00, 0x80); apdu.cla = 0x80; apdu.data = data; apdu.datalen = datalen; apdu.lc = datalen; apdu.resp = resp; apdu.resplen = sizeof(resp); apdu.le = 0; rc = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(card->ctx, rc, "APDU transmit failed"); rc = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(card->ctx, rc, "SW Check failed"); if (apdu.resplen > outlen) { LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY); } memcpy(out, resp, apdu.resplen); LOG_FUNC_RETURN(card->ctx, apdu.resplen); }
static int sc_set_le_and_transmit(struct sc_card *card, struct sc_apdu *apdu, size_t olen) { struct sc_context *ctx = card->ctx; size_t nlen = apdu->sw2 ? (size_t)apdu->sw2 : 256; int rv; LOG_FUNC_CALLED(ctx); /* we cannot re-transmit the APDU with the demanded Le value * as the buffer is too small => error */ if (olen < nlen) LOG_TEST_RET(ctx, SC_ERROR_WRONG_LENGTH, "wrong length: required length exceeds resplen"); /* don't try again if it doesn't work this time */ apdu->flags |= SC_APDU_FLAGS_NO_GET_RESP; /* set the new expected length */ apdu->resplen = olen; apdu->le = nlen; /* Belpic V1 applets have a problem: if the card sends a 6C XX (only XX bytes available), * and we resend the command too soon (i.e. the reader is too fast), the card doesn't respond. * So we build in a delay. */ if (card->type == SC_CARD_TYPE_BELPIC_EID) msleep(40); /* re-transmit the APDU with new Le length */ rv = sc_single_transmit(card, apdu); LOG_TEST_RET(ctx, rv, "cannot re-transmit APDU"); LOG_FUNC_RETURN(ctx, rv); }
int iasecc_sm_rsa_update(struct sc_card *card, unsigned se_num, struct iasecc_sdo_rsa_update *udata) { struct sc_context *ctx = card->ctx; #ifdef ENABLE_SM struct sm_info *sm_info = &card->sm_ctx.info; struct sc_remote_data rdata; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM update RSA: SE#: 0x%X, SDO(class:0x%X:ref:%X)", se_num, udata->sdo_prv_key->sdo_class, udata->sdo_prv_key->sdo_ref); rv = iasecc_sm_initialize(card, se_num, SM_CMD_RSA_UPDATE); LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM initialize failed"); sm_info->cmd_data = udata; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM cmd failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_rsa_update() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, rv); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
static int sm_iasecc_get_apdu_delete_file(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { unsigned int file_id = (unsigned int)sm_info->cmd_data; struct sc_remote_apdu *rapdu = NULL; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM get 'DELETE FILE' APDU: file-id %04X", file_id); if (!file_id) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); if (!rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'DELETE FILE' APDUs: cannot allocate remote APDU"); rapdu->apdu.cse = SC_APDU_CASE_1; rapdu->apdu.cla = 0x00; rapdu->apdu.ins = 0xE4; rapdu->apdu.p1 = 0x00; rapdu->apdu.p2 = 0x00; /** 99 02 SW 8E 08 MAC **/ rapdu->apdu.le = 0x0E; rv = sm_cwa_securize_apdu(ctx, sm_info, rapdu); LOG_TEST_RET(ctx, rv, "SM get 'DELETE FILE' APDUs: securize APDU error"); rapdu->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER; LOG_FUNC_RETURN(ctx, rv); }
/* * Store a private key */ static int myeid_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object) { struct sc_context *ctx = p15card->card->ctx; struct sc_card *card = p15card->card; struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *) object->data; struct sc_file *file = NULL; int keybits = key_info->modulus_length, r; LOG_FUNC_CALLED(card->ctx); /* Check that the card supports the requested modulus length */ switch (object->type) { case SC_PKCS15_TYPE_PRKEY_RSA: if (sc_card_find_rsa_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported RSA key size"); break; case SC_PKCS15_TYPE_PRKEY_EC: if (sc_card_find_ec_alg(p15card->card, keybits) == NULL) LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size"); break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); break; } sc_log(ctx, "create MyEID private key ID:%s", sc_pkcs15_print_id(&key_info->id)); /* Get the private key file */ r = myeid_new_file(profile, card, object->type, key_info->key_reference, &file); LOG_TEST_RET(ctx, r, "Cannot get new MyEID private key file"); sc_log(ctx, "Key file size %d", keybits); file->size = keybits; if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) file->ef_structure = SC_CARDCTL_MYEID_KEY_RSA; else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) file->ef_structure = SC_CARDCTL_MYEID_KEY_EC; memcpy(&key_info->path.value, &file->path.value, file->path.len); key_info->key_reference = file->path.value[file->path.len - 1] & 0xFF; sc_log(ctx, "Path of MyEID private key file to create %s", sc_print_path(&file->path)); /* Now create the key file */ r = sc_pkcs15init_create_file(profile, p15card, file); sc_file_free(file); LOG_TEST_RET(ctx, r, "Cannot create MyEID private key file"); LOG_FUNC_RETURN(ctx, r); }