static int sc_single_sm_transmit(struct sc_card *card, struct sc_apdu *apdu) { struct sc_context *ctx = card->ctx; struct sc_apdu *sm_apdu = NULL; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM_MODE:%X", card->sm_ctx.sm_mode); if (!card->sm_ctx.ops.get_sm_apdu || !card->sm_ctx.ops.free_sm_apdu) LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); /* get SM encoded APDU */ rv = card->sm_ctx.ops.get_sm_apdu(card, apdu, &sm_apdu); if (rv == SC_ERROR_SM_NOT_APPLIED) { /* SM wrap of this APDU is ignored by card driver. * Send plain APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, apdu); LOG_FUNC_RETURN(ctx, rv); } LOG_TEST_RET(ctx, rv, "get SM APDU error"); /* check if SM APDU is still valid */ rv = sc_check_apdu(card, sm_apdu); if (rv < 0) { card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); LOG_TEST_RET(ctx, rv, "cannot validate SM encoded APDU"); } /* send APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, sm_apdu); LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); /* decode SM answer and free temporary SM related data */ rv = card->sm_ctx.ops.free_sm_apdu(card, apdu, &sm_apdu); LOG_FUNC_RETURN(ctx, rv); }
static int sm_iasecc_get_apdu_verify_pin(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { struct sc_pin_cmd_data *pin_data = (struct sc_pin_cmd_data *)sm_info->cmd_data; struct sc_remote_apdu *rapdu = NULL; int rv; LOG_FUNC_CALLED(ctx); if (!pin_data || !rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM get 'VERIFY PIN' APDU: ", pin_data->pin_reference); rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'VERIFY PIN' APDUs: cannot allocate remote APDU"); rapdu->apdu.cse = SC_APDU_CASE_3_SHORT; rapdu->apdu.cla = 0x00; rapdu->apdu.ins = 0x20; rapdu->apdu.p1 = 0x00; rapdu->apdu.p2 = pin_data->pin_reference & ~IASECC_OBJECT_REF_GLOBAL; if (pin_data->pin1.len > SM_MAX_DATA_SIZE) LOG_TEST_RET(ctx, rv, "SM get 'VERIFY PIN' APDU: invelid PIN size"); memcpy((unsigned char *)rapdu->apdu.data, pin_data->pin1.data, pin_data->pin1.len); rapdu->apdu.datalen = pin_data->pin1.len; rapdu->apdu.lc = pin_data->pin1.len; /** 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 'VERIFY PIN' APDUs: securize APDU error"); rapdu->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER; LOG_FUNC_RETURN(ctx, rv); }
static int iasecc_sm_get_challenge(struct sc_card *card, unsigned char *out, size_t len) { struct sc_context *ctx = card->ctx; struct sc_apdu apdu; unsigned char rbuf[SC_MAX_APDU_BUFFER_SIZE]; int rv; sc_log(ctx, "SM get challenge: length %i",len); sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x84, 0, 0); apdu.le = len; apdu.resplen = len; apdu.resp = rbuf; rv = sc_transmit_apdu(card, &apdu); LOG_TEST_RET(ctx, rv, "APDU transmit failed"); rv = sc_check_sw(card, apdu.sw1, apdu.sw2); LOG_TEST_RET(ctx, rv, "Command failed"); memcpy(out, rbuf, apdu.resplen); LOG_FUNC_RETURN(ctx, apdu.resplen); }
static int sc_single_transmit(struct sc_card *card, struct sc_apdu *apdu) { struct sc_context *ctx = card->ctx; int rv; LOG_FUNC_CALLED(ctx); if (card->reader->ops->transmit == NULL) LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "cannot transmit APDU"); sc_log(ctx, "CLA:%X, INS:%X, P1:%X, P2:%X, data(%i) %p", apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen, apdu->data); #ifdef ENABLE_SM if (card->sm_ctx.sm_mode == SM_MODE_TRANSMIT) return sc_sm_single_transmit(card, apdu); #endif /* send APDU to the reader driver */ rv = card->reader->ops->transmit(card->reader, apdu); LOG_TEST_RET(ctx, rv, "unable to transmit APDU"); LOG_FUNC_RETURN(ctx, rv); }
CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* the signature to be verified */ CK_ULONG ulSignatureLen) { /* count of bytes of signature */ #ifndef ENABLE_OPENSSL return CKR_FUNCTION_NOT_SUPPORTED; #else CK_RV rv; struct sc_pkcs11_session *session; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; rv = get_session(hSession, &session); if (rv == CKR_OK) rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen); sc_log(context, "C_VerifyFinal() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; #endif }
CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pPart, /* plaintext data (digest) to compare */ CK_ULONG ulPartLen) { /* length of data (digest) in bytes */ #ifndef ENABLE_OPENSSL return CKR_FUNCTION_NOT_SUPPORTED; #else CK_RV rv; struct sc_pkcs11_session *session; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; rv = get_session(hSession, &session); if (rv == CKR_OK) rv = sc_pkcs11_verif_update(session, pPart, ulPartLen); sc_log(context, "C_VerifyUpdate() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; #endif }
static void sc_card_free(sc_card_t *card) { sc_free_apps(card); sc_free_ef_atr(card); sc_file_free(card->ef_dir); free(card->ops); if (card->algorithms != NULL) { int i; for (i=0; i<card->algorithm_count; i++) { struct sc_algorithm_info *info = (card->algorithms + i); if (info->algorithm == SC_ALGORITHM_EC) { struct sc_ec_parameters ep = info->u._ec.params; free(ep.named_curve); free(ep.der.value); } } free(card->algorithms); card->algorithms = NULL; card->algorithm_count = 0; } sc_file_free(card->cache.current_ef); sc_file_free(card->cache.current_df); if (card->mutex != NULL) { int r = sc_mutex_destroy(card->ctx, card->mutex); if (r != SC_SUCCESS) sc_log(card->ctx, "unable to destroy mutex"); } sc_mem_clear(card, sizeof(*card)); free(card); }
static int jpki_set_security_env(sc_card_t * card, const sc_security_env_t * env, int se_num) { int rc; sc_path_t path; LOG_FUNC_CALLED(card->ctx); sc_log(card->ctx, "flags=%08lx op=%d alg=%d algf=%08x algr=%08x kr0=%02x, krfl=%"SC_FORMAT_LEN_SIZE_T"u", env->flags, env->operation, env->algorithm, env->algorithm_flags, env->algorithm_ref, env->key_ref[0], env->key_ref_len); switch (env->operation) { case SC_SEC_OPERATION_SIGN: break; default: LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } switch (env->key_ref[0]) { case 1: sc_format_path(JPKI_AUTH_KEY, &path); break; case 2: sc_format_path(JPKI_SIGN_KEY, &path); break; default: LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED); } path.type = SC_PATH_TYPE_FILE_ID; rc = sc_select_file(card, &path, NULL); LOG_TEST_RET(card->ctx, rc, "select key failed"); LOG_FUNC_RETURN(card->ctx, SC_SUCCESS); }
CK_RV C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ CK_BYTE_PTR pSignature, /* receives the signature */ CK_ULONG_PTR pulSignatureLen) /* receives byte count of signature */ { struct sc_pkcs11_session *session; CK_ULONG length; CK_RV rv; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; rv = get_session(hSession, &session); if (rv != CKR_OK) goto out; /* According to the pkcs11 specs, we must not do any calls that * change our crypto state if the caller is just asking for the * signature buffer size, or if the result would be * CKR_BUFFER_TOO_SMALL. */ if ((rv = sc_pkcs11_sign_size(session, &length)) != CKR_OK) goto out; if (pSignature == NULL || length > *pulSignatureLen) { *pulSignatureLen = length; rv = pSignature ? CKR_BUFFER_TOO_SMALL : CKR_OK; } else { rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); } out: sc_log(context, "C_SignFinal() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; }
int iasecc_sm_update_binary(struct sc_card *card, unsigned se_num, size_t offs, const unsigned char *buff, size_t count) { 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_update_binary cmd_data; int rv; LOG_FUNC_CALLED(ctx); sc_log(ctx, "SM update binary: acl:%X, offs:%i, count:%i", se_num, offs, count); rv = iasecc_sm_initialize(card, se_num, SM_CMD_FILE_UPDATE); LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM INITIALIZE failed"); cmd_data.offs = offs; cmd_data.count = count; cmd_data.data = buff; sm_info->cmd_data = &cmd_data; sc_remote_data_init(&rdata); rv = iasecc_sm_cmd(card, &rdata); LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM 'UPDATE BINARY' failed"); rv = sm_release (card, &rdata, NULL, 0); LOG_TEST_RET(ctx, rv, "iasecc_sm_update_binary() SM release failed"); rdata.free(&rdata); LOG_FUNC_RETURN(ctx, count); #else LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging"); return SC_ERROR_NOT_SUPPORTED; #endif }
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(%"SC_FORMAT_LEN_SIZE_T"u) '%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 ctapi_connect(sc_reader_t *reader) { struct ctapi_private_data *priv = GET_PRIV_DATA(reader); char rv; u8 cmd[9], rbuf[256], sad, dad; unsigned short lr; int r; if (reader->ctx->flags & SC_CTX_FLAG_TERMINATE) return SC_ERROR_NOT_ALLOWED; cmd[0] = CTBCS_CLA; cmd[1] = CTBCS_INS_REQUEST; cmd[2] = CTBCS_P1_INTERFACE1; cmd[3] = CTBCS_P2_REQUEST_GET_ATR; cmd[4] = 0x00; dad = 1; sad = 2; lr = 256; rv = priv->funcs.CT_data(priv->ctn, &dad, &sad, 5, cmd, &lr, rbuf); if (rv || rbuf[lr-2] != 0x90) { sc_log(reader->ctx, "Error activating card: %d", rv); return SC_ERROR_TRANSMIT_FAILED; } if (lr < 2) SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL); lr -= 2; if (lr > SC_MAX_ATR_SIZE) return SC_ERROR_INTERNAL; reader->atr.len = lr; memcpy(reader->atr.value, rbuf, lr); r = _sc_parse_atr(reader); return 0; }
static int iasecc_parse_pubkey(struct sc_card *card, unsigned char *data, size_t data_len, struct iasecc_sdo_pubkey *pubkey) { 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_pubkey() get and parse TLV error"); sc_log(ctx, "iasecc_parse_pubkey() get and parse TLV returned %i; tag %X; size %"SC_FORMAT_LEN_SIZE_T"u", rv, tlv.tag, tlv.size); if (tlv.tag == IASECC_SDO_PUBKEY_TAG_N) pubkey->n = tlv; else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_E) pubkey->e = tlv; else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHR) pubkey->chr = tlv; else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_CHA) pubkey->cha = tlv; else if (tlv.tag == IASECC_SDO_PUBKEY_TAG_COMPULSORY) pubkey->compulsory = tlv; else LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "parse error: non PubKey SDO tag"); offs += rv; } LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
int sc_reset(sc_card_t *card, int do_cold_reset) { int r, r2; if (card == NULL) return SC_ERROR_INVALID_ARGUMENTS; if (card->reader->ops->reset == NULL) return SC_ERROR_NOT_SUPPORTED; r = sc_mutex_lock(card->ctx, card->mutex); if (r != SC_SUCCESS) return r; r = card->reader->ops->reset(card->reader, do_cold_reset); sc_invalidate_cache(card); r2 = sc_mutex_unlock(card->ctx, card->mutex); if (r2 != SC_SUCCESS) { sc_log(card->ctx, "unable to release lock"); r = r != SC_SUCCESS ? r : r2; } return r; }
/* TODO: reduce name of functions */ static int sm_iasecc_get_apdu_create_file(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata) { struct iasecc_sm_cmd_create_file *cmd_data = (struct iasecc_sm_cmd_create_file *)sm_info->cmd_data; struct sc_remote_apdu *rapdu = NULL; int rv = 0; LOG_FUNC_CALLED(ctx); if (!cmd_data || !cmd_data->data || !rdata || !rdata->alloc) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM get 'CREATE FILE' APDU: FCP(%i) %s", cmd_data->size, sc_dump_hex(cmd_data->data,cmd_data->size)); rv = rdata->alloc(rdata, &rapdu); LOG_TEST_RET(ctx, rv, "SM get 'UPDATE BINARY' APDUs: cannot allocate remote APDU"); rapdu->apdu.cse = SC_APDU_CASE_3_SHORT; rapdu->apdu.cla = 0x00; rapdu->apdu.ins = 0xE0; rapdu->apdu.p1 = 0x00; rapdu->apdu.p2 = 0x00; memcpy((unsigned char *)rapdu->apdu.data, cmd_data->data, cmd_data->size); rapdu->apdu.datalen = cmd_data->size; rapdu->apdu.lc = cmd_data->size; /** 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 'UPDATE BINARY' APDUs: securize APDU error"); rapdu->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER; LOG_FUNC_RETURN(ctx, rv); }
static int sm_gp_init_session(struct sc_context *ctx, struct sm_gp_session *gp_session, unsigned char *adata, size_t adata_len) { struct sm_gp_keyset *gp_keyset = &gp_session->gp_keyset; unsigned char cksum[8]; int rv; LOG_FUNC_CALLED(ctx); if (!adata || adata_len < 8) LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); sc_log(ctx, "SM GP init session: auth.data %s", sc_dump_hex(adata, 8)); gp_session->session_enc = sc_gp_get_session_key(ctx, gp_session, gp_keyset->enc); gp_session->session_mac = sc_gp_get_session_key(ctx, gp_session, gp_keyset->mac); gp_session->session_kek = sc_gp_get_session_key(ctx, gp_session, gp_keyset->kek); if (!gp_session->session_enc || !gp_session->session_mac || !gp_session->session_kek) LOG_TEST_RET(ctx, SC_ERROR_SM_NO_SESSION_KEYS, "SM GP init session: get session keys error"); memcpy(gp_session->session_kek, gp_keyset->kek, 16); sc_log(ctx, "SM GP init session: session ENC: %s", sc_dump_hex(gp_session->session_enc, 16)); sc_log(ctx, "SM GP init session: session MAC: %s", sc_dump_hex(gp_session->session_mac, 16)); sc_log(ctx, "SM GP init session: session KEK: %s", sc_dump_hex(gp_session->session_kek, 16)); memset(cksum, 0, sizeof(cksum)); rv = sm_gp_get_cryptogram(gp_session->session_enc, gp_session->host_challenge, gp_session->card_challenge, cksum, sizeof(cksum)); LOG_TEST_RET(ctx, rv, "SM GP init session: cannot get cryptogram"); sc_log(ctx, "SM GP init session: cryptogram: %s", sc_dump_hex(cksum, 8)); if (memcmp(cksum, adata, adata_len)) LOG_FUNC_RETURN(ctx, SC_ERROR_SM_AUTHENTICATION_FAILED); sc_log(ctx, "SM GP init session: card authenticated"); LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
CK_RV C_GetSlotList(CK_BBOOL tokenPresent, /* only slots with token present */ CK_SLOT_ID_PTR pSlotList, /* receives the array of slot IDs */ CK_ULONG_PTR pulCount) /* receives the number of slots */ { CK_SLOT_ID_PTR found = NULL; unsigned int i; CK_ULONG numMatches; sc_pkcs11_slot_t *slot; sc_reader_t *prev_reader = NULL; CK_RV rv; if (pulCount == NULL_PTR) return CKR_ARGUMENTS_BAD; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; sc_log(context, "C_GetSlotList(token=%d, %s)", tokenPresent, (pSlotList==NULL_PTR && sc_pkcs11_conf.plug_and_play)? "plug-n-play":"refresh"); /* Slot list can only change in v2.20 */ if (pSlotList == NULL_PTR && sc_pkcs11_conf.plug_and_play) { /* Trick NSS into updating the slot list by changing the hotplug slot ID */ sc_pkcs11_slot_t *hotplug_slot = list_get_at(&virtual_slots, 0); hotplug_slot->id--; sc_ctx_detect_readers(context); } card_detect_all(); found = calloc(list_size(&virtual_slots), sizeof(CK_SLOT_ID)); if (found == NULL) { rv = CKR_HOST_MEMORY; goto out; } prev_reader = NULL; numMatches = 0; for (i=0; i<list_size(&virtual_slots); i++) { slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i); /* the list of available slots contains: * - if present, virtual hotplug slot; * - any slot with token; * - without token(s), one empty slot per reader; */ if ((!tokenPresent && !slot->reader) || (!tokenPresent && slot->reader != prev_reader) || (slot->slot_info.flags & CKF_TOKEN_PRESENT)) found[numMatches++] = slot->id; prev_reader = slot->reader; } if (pSlotList == NULL_PTR) { sc_log(context, "was only a size inquiry (%d)\n", numMatches); *pulCount = numMatches; rv = CKR_OK; goto out; } if (*pulCount < numMatches) { sc_log(context, "buffer was too small (needed %d)\n", numMatches); *pulCount = numMatches; rv = CKR_BUFFER_TOO_SMALL; goto out; } memcpy(pSlotList, found, numMatches * sizeof(CK_SLOT_ID)); *pulCount = numMatches; rv = CKR_OK; sc_log(context, "returned %d slots\n", numMatches); out: if (found != NULL) { free (found); found = NULL; } sc_pkcs11_unlock(); return rv; }
CK_RV C_Initialize(CK_VOID_PTR pInitArgs) { CK_RV rv; #if !defined(_WIN32) pid_t current_pid = getpid(); #endif int rc; unsigned int i; sc_context_param_t ctx_opts; #if !defined(_WIN32) /* Handle fork() exception */ if (current_pid != initialized_pid) { if (context) context->flags |= SC_CTX_FLAG_TERMINATE; C_Finalize(NULL_PTR); } initialized_pid = current_pid; in_finalize = 0; #endif if (context != NULL) { sc_log(context, "C_Initialize(): Cryptoki already initialized\n"); return CKR_CRYPTOKI_ALREADY_INITIALIZED; } rv = sc_pkcs11_init_lock((CK_C_INITIALIZE_ARGS_PTR) pInitArgs); if (rv != CKR_OK) goto out; /* set context options */ memset(&ctx_opts, 0, sizeof(sc_context_param_t)); ctx_opts.ver = 0; ctx_opts.app_name = MODULE_APP_NAME; ctx_opts.thread_ctx = &sc_thread_ctx; rc = sc_context_create(&context, &ctx_opts); if (rc != SC_SUCCESS) { rv = CKR_GENERAL_ERROR; goto out; } /* Load configuration */ load_pkcs11_parameters(&sc_pkcs11_conf, context); /* List of sessions */ list_init(&sessions); list_attributes_seeker(&sessions, session_list_seeker); /* List of slots */ list_init(&virtual_slots); list_attributes_seeker(&virtual_slots, slot_list_seeker); /* Create a slot for a future "PnP" stuff. */ if (sc_pkcs11_conf.plug_and_play) { create_slot(NULL); } /* Create slots for readers found on initialization, only if in 2.11 mode */ if (!sc_pkcs11_conf.plug_and_play) { for (i=0; i<sc_ctx_get_reader_count(context); i++) { initialize_reader(sc_ctx_get_reader(context, i)); } } out: if (context != NULL) sc_log(context, "C_Initialize() = %s", lookup_enum ( RV_T, rv )); if (rv != CKR_OK) { if (context != NULL) { sc_release_context(context); context = NULL; } /* Release and destroy the mutex */ sc_pkcs11_free_lock(); } return rv; }
int sc_pkcs15_decode_cdf_entry(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *obj, const u8 ** buf, size_t *buflen) { sc_context_t *ctx = p15card->card->ctx; struct sc_pkcs15_cert_info info; struct sc_asn1_entry asn1_cred_ident[3], asn1_com_cert_attr[4], asn1_x509_cert_attr[2], asn1_type_cert_attr[2], asn1_cert[2], asn1_x509_cert_value_choice[3]; struct sc_asn1_pkcs15_object cert_obj = { obj, asn1_com_cert_attr, NULL, asn1_type_cert_attr }; sc_pkcs15_der_t *der = &info.value; u8 id_value[128]; int id_type; size_t id_value_len = sizeof(id_value); int r; sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); sc_copy_asn1_entry(c_asn1_com_cert_attr, asn1_com_cert_attr); sc_copy_asn1_entry(c_asn1_x509_cert_attr, asn1_x509_cert_attr); sc_copy_asn1_entry(c_asn1_x509_cert_value_choice, asn1_x509_cert_value_choice); sc_copy_asn1_entry(c_asn1_type_cert_attr, asn1_type_cert_attr); sc_copy_asn1_entry(c_asn1_cert, asn1_cert); sc_format_asn1_entry(asn1_cred_ident + 0, &id_type, NULL, 0); sc_format_asn1_entry(asn1_cred_ident + 1, &id_value, &id_value_len, 0); sc_format_asn1_entry(asn1_com_cert_attr + 0, &info.id, NULL, 0); sc_format_asn1_entry(asn1_com_cert_attr + 1, &info.authority, NULL, 0); sc_format_asn1_entry(asn1_com_cert_attr + 2, asn1_cred_ident, NULL, 0); sc_format_asn1_entry(asn1_x509_cert_attr + 0, asn1_x509_cert_value_choice, NULL, 0); sc_format_asn1_entry(asn1_x509_cert_value_choice + 0, &info.path, NULL, 0); sc_format_asn1_entry(asn1_x509_cert_value_choice + 1, &der->value, &der->len, 0); sc_format_asn1_entry(asn1_type_cert_attr + 0, asn1_x509_cert_attr, NULL, 0); sc_format_asn1_entry(asn1_cert + 0, &cert_obj, NULL, 0); /* Fill in defaults */ memset(&info, 0, sizeof(info)); info.authority = 0; r = sc_asn1_decode(ctx, asn1_cert, *buf, *buflen, buf, buflen); /* In case of error, trash the cert value (direct coding) */ if (r < 0 && der->value) free(der->value); if (r == SC_ERROR_ASN1_END_OF_CONTENTS) return r; LOG_TEST_RET(ctx, r, "ASN.1 decoding failed"); if (!p15card->app || !p15card->app->ddo.aid.len) { r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path); LOG_TEST_RET(ctx, r, "Cannot make absolute path"); } else { info.path.aid = p15card->app->ddo.aid; } sc_log(ctx, "Certificate path '%s'", sc_print_path(&info.path)); obj->type = SC_PKCS15_TYPE_CERT_X509; obj->data = malloc(sizeof(info)); if (obj->data == NULL) LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY); memcpy(obj->data, &info, sizeof(info)); return 0; }
/* * Create an empty key object */ static int rtecp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj) { sc_context_t *ctx; /* RSA_PRkey/ Adds Miller- * RSA_PUBkey Rabin tests Attempts Reserve */ const unsigned char prkey_prop[] = { 0x23, 0, 0, 0xAA, 0, 0 }; const unsigned char pbkey_prop[] = { 0x33, 0, 0, 0xAA, 0, 0 }; /* GOSTR3410_PRkey/ * GOSTR3410_PUBkey paramset Attempts Reserve */ unsigned char prgkey_prop[] = { 0x03, '?', 0, 0xAA, 0, 0 }; unsigned char pbgkey_prop[] = { 0x13, '?', 0, 0xAA, 0, 0 }; /* AccessMode - Update Use - - - Delete */ unsigned char prkey_sec[15] = { 0x46, 0, '?', '?', 0, 0, 0, '?' }; unsigned char pbkey_sec[15] = { 0x46, 0, '?', 0, 0, 0, 0, '?' }; unsigned char auth_id, paramset; sc_pkcs15_prkey_info_t *key_info; sc_file_t *file; int r; if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !obj || !obj->data) return SC_ERROR_INVALID_ARGUMENTS; ctx = p15card->card->ctx; SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA && obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410) return SC_ERROR_NOT_SUPPORTED; if (obj->auth_id.len != 1) return SC_ERROR_INVALID_ARGUMENTS; auth_id = obj->auth_id.value[0]; key_info = (sc_pkcs15_prkey_info_t *)obj->data; assert(key_info); if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA && key_info->modulus_length % 128 != 0) || (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410 && key_info->modulus_length != SC_PKCS15_GOSTR3410_KEYSIZE)) { sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %u\n", key_info->modulus_length); return SC_ERROR_INVALID_ARGUMENTS; } if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) { if (key_info->params.len < sizeof(int)) return SC_ERROR_INVALID_ARGUMENTS; if (((int*)key_info->params.data)[0] < 1 || ((int*)key_info->params.data)[0] > 3) return SC_ERROR_INVALID_ARGUMENTS; paramset = ((unsigned int*)key_info->params.data)[0] & 0x03; assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1); assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1); prgkey_prop[1] = 0x10 + (paramset << 4); pbgkey_prop[1] = prgkey_prop[1]; } r = sc_profile_get_file(profile, "PKCS15-AppDF", &file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Get PKCS15-AppDF info failed"); r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, auth_id); if (r == SC_SUCCESS) r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE); assert(file); sc_file_free(file); SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Authenticate failed"); file = sc_file_new(); if (!file) SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY); file->id = key_info->key_reference; r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2); /* private key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 5 + 8; else file->size = key_info->modulus_length / 8; if (r == SC_SUCCESS) { assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7); prkey_sec[2] = auth_id; prkey_sec[3] = auth_id; prkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop)); else r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create private key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } /* public key file */ if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) file->size = key_info->modulus_length / 8 / 2 * 3; else file->size = key_info->modulus_length / 8 * 2; if (r == SC_SUCCESS) { assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7); pbkey_sec[2] = auth_id; pbkey_sec[7] = auth_id; r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec)); } if (r == SC_SUCCESS) { if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA) r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop)); else r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop)); } if (r == SC_SUCCESS) { sc_log(ctx, "create public key file id:%04i", file->id); r = sc_create_file(p15card->card, file); } assert(file); sc_file_free(file); SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r); }
/** Encodes a APDU as an octet string * @param ctx sc_context_t object (used for logging) * @param apdu APDU to be encoded as an octet string * @param proto protocol version to be used * @param out output buffer of size outlen. * @param outlen size of hte output buffer * @return SC_SUCCESS on success and an error code otherwise */ static int sc_apdu2bytes(sc_context_t *ctx, const sc_apdu_t *apdu, unsigned int proto, u8 *out, size_t outlen) { u8 *p = out; size_t len = sc_apdu_get_length(apdu, proto); if (out == NULL || outlen < len) return SC_ERROR_INVALID_ARGUMENTS; /* CLA, INS, P1 and P2 */ *p++ = apdu->cla; *p++ = apdu->ins; *p++ = apdu->p1; *p++ = apdu->p2; /* case depend part */ switch (apdu->cse) { case SC_APDU_CASE_1: /* T0 needs an additional 0x00 byte */ if (proto == SC_PROTO_T0) *p = (u8)0x00; break; case SC_APDU_CASE_2_SHORT: *p = (u8)apdu->le; break; case SC_APDU_CASE_2_EXT: if (proto == SC_PROTO_T0) /* T0 extended APDUs look just like short APDUs */ *p = (u8)apdu->le; else { /* in case of T1 always use 3 bytes for length */ *p++ = (u8)0x00; *p++ = (u8)(apdu->le >> 8); *p = (u8)apdu->le; } break; case SC_APDU_CASE_3_SHORT: *p++ = (u8)apdu->lc; memcpy(p, apdu->data, apdu->lc); break; case SC_APDU_CASE_3_EXT: if (proto == SC_PROTO_T0) { /* in case of T0 the command is transmitted in chunks * < 255 using the ENVELOPE command ... */ if (apdu->lc > 255) { /* ... so if Lc is greater than 255 bytes * an error has occurred on a higher level */ sc_log(ctx, "invalid Lc length for CASE 3 extended APDU (need ENVELOPE)"); return SC_ERROR_INVALID_ARGUMENTS; } } else { /* in case of T1 always use 3 bytes for length */ *p++ = (u8)0x00; *p++ = (u8)(apdu->lc >> 8); *p++ = (u8)apdu->lc; } memcpy(p, apdu->data, apdu->lc); break; case SC_APDU_CASE_4_SHORT: *p++ = (u8)apdu->lc; memcpy(p, apdu->data, apdu->lc); p += apdu->lc; /* in case of T0 no Le byte is added */ if (proto != SC_PROTO_T0) *p = (u8)apdu->le; break; case SC_APDU_CASE_4_EXT: if (proto == SC_PROTO_T0) { /* again a T0 extended case 4 APDU looks just * like a short APDU, the additional data is * transferred using ENVELOPE and GET RESPONSE */ *p++ = (u8)apdu->lc; memcpy(p, apdu->data, apdu->lc); } else { *p++ = (u8)0x00; *p++ = (u8)(apdu->lc >> 8); *p++ = (u8)apdu->lc; memcpy(p, apdu->data, apdu->lc); p += apdu->lc; /* only 2 bytes are use to specify the length of the * expected data */ *p++ = (u8)(apdu->le >> 8); *p = (u8)apdu->le; } break; } return SC_SUCCESS; }
int sc_bytes2apdu(sc_context_t *ctx, const u8 *buf, size_t len, sc_apdu_t *apdu) { const unsigned char *p; size_t len0; if (!buf || !apdu) return SC_ERROR_INVALID_ARGUMENTS; len0 = len; if (len < 4) { sc_log(ctx, "APDU too short (must be at least 4 bytes)"); return SC_ERROR_INVALID_DATA; } memset(apdu, 0, sizeof *apdu); p = buf; apdu->cla = *p++; apdu->ins = *p++; apdu->p1 = *p++; apdu->p2 = *p++; len -= 4; if (!len) { apdu->cse = SC_APDU_CASE_1; sc_log(ctx, "CASE_1 APDU: %lu bytes:\tins=%02x p1=%02x p2=%02x lc=%04x le=%04x", (unsigned long) len0, apdu->ins, apdu->p1, apdu->p2, apdu->lc, apdu->le); return SC_SUCCESS; } if (*p == 0 && len >= 3) { /* ...must be an extended APDU */ p++; if (len == 3) { apdu->le = (*p++)<<8; apdu->le += *p++; if (apdu->le == 0) apdu->le = 0xffff+1; len -= 3; apdu->cse = SC_APDU_CASE_2_EXT; } else { /* len > 3 */ apdu->lc = (*p++)<<8; apdu->lc += *p++; len -= 3; if (len < apdu->lc) { sc_log(ctx, "APDU too short (need %lu more bytes)", (unsigned long) apdu->lc - len); return SC_ERROR_INVALID_DATA; } apdu->data = p; apdu->datalen = apdu->lc; len -= apdu->lc; p += apdu->lc; if (!len) { apdu->cse = SC_APDU_CASE_3_EXT; } else { /* at this point the apdu has a Lc, so Le is on 2 bytes */ if (len < 2) { sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "APDU too short (need 2 more bytes)\n"); return SC_ERROR_INVALID_DATA; } apdu->le = (*p++)<<8; apdu->le += *p++; if (apdu->le == 0) apdu->le = 0xffff+1; len -= 2; apdu->cse = SC_APDU_CASE_4_EXT; } } } else { /* ...must be a short APDU */ if (len == 1) { apdu->le = *p++; if (apdu->le == 0) apdu->le = 0xff+1; len--; apdu->cse = SC_APDU_CASE_2_SHORT; } else { apdu->lc = *p++; len--; if (len < apdu->lc) { sc_log(ctx, "APDU too short (need %lu more bytes)", (unsigned long) apdu->lc - len); return SC_ERROR_INVALID_DATA; } apdu->data = p; apdu->datalen = apdu->lc; len -= apdu->lc; p += apdu->lc; if (!len) { apdu->cse = SC_APDU_CASE_3_SHORT; } else { apdu->le = *p++; if (apdu->le == 0) apdu->le = 0xff+1; len--; apdu->cse = SC_APDU_CASE_4_SHORT; } } } if (len) { sc_log(ctx, "APDU too long (%lu bytes extra)",(unsigned long) len); return SC_ERROR_INVALID_DATA; } sc_log(ctx, "Case %d %s APDU, %lu bytes:\tins=%02x p1=%02x p2=%02x lc=%04x le=%04x", apdu->cse & SC_APDU_SHORT_MASK, (apdu->cse & SC_APDU_EXT) != 0 ? "extended" : "short", (unsigned long) len0, apdu->ins, apdu->p1, apdu->p2, apdu->lc, apdu->le); return SC_SUCCESS; }
int sc_transmit_apdu(sc_card_t *card, sc_apdu_t *apdu) { int r = SC_SUCCESS; if (card == NULL || apdu == NULL) return SC_ERROR_INVALID_ARGUMENTS; LOG_FUNC_CALLED(card->ctx); /* determine the APDU type if necessary, i.e. to use * short or extended APDUs */ sc_detect_apdu_cse(card, apdu); /* basic APDU consistency check */ r = sc_check_apdu(card, apdu); if (r != SC_SUCCESS) return SC_ERROR_INVALID_ARGUMENTS; r = sc_lock(card); /* acquire card lock*/ if (r != SC_SUCCESS) { sc_log(card->ctx, "unable to acquire lock"); return r; } if ((apdu->flags & SC_APDU_FLAGS_CHAINING) != 0) { /* divide et impera: transmit APDU in chunks with Lc <= max_send_size * bytes using command chaining */ size_t len = apdu->datalen; const u8 *buf = apdu->data; size_t max_send_size = card->max_send_size; while (len != 0) { size_t plen; sc_apdu_t tapdu; int last = 0; tapdu = *apdu; /* clear chaining flag */ tapdu.flags &= ~SC_APDU_FLAGS_CHAINING; if (len > max_send_size) { /* adjust APDU case: in case of CASE 4 APDU * the intermediate APDU are of CASE 3 */ if ((tapdu.cse & SC_APDU_SHORT_MASK) == SC_APDU_CASE_4_SHORT) tapdu.cse--; /* XXX: the chunk size must be adjusted when * secure messaging is used */ plen = max_send_size; tapdu.cla |= 0x10; tapdu.le = 0; /* the intermediate APDU don't expect data */ tapdu.lc = 0; tapdu.resplen = 0; tapdu.resp = NULL; } else { plen = len; last = 1; } tapdu.data = buf; tapdu.datalen = tapdu.lc = plen; r = sc_check_apdu(card, &tapdu); if (r != SC_SUCCESS) { sc_log(card->ctx, "inconsistent APDU while chaining"); break; } r = sc_transmit(card, &tapdu); if (r != SC_SUCCESS) break; if (last != 0) { /* in case of the last APDU set the SW1 * and SW2 bytes in the original APDU */ apdu->sw1 = tapdu.sw1; apdu->sw2 = tapdu.sw2; apdu->resplen = tapdu.resplen; } else { /* otherwise check the status bytes */ r = sc_check_sw(card, tapdu.sw1, tapdu.sw2); if (r != SC_SUCCESS) break; } len -= plen; buf += plen; } } else /* transmit single APDU */ r = sc_transmit(card, apdu); /* all done => release lock */ if (sc_unlock(card) != SC_SUCCESS) sc_log(card->ctx, "sc_unlock failed"); return r; }
static int sc_get_response(struct sc_card *card, struct sc_apdu *apdu, size_t olen) { struct sc_context *ctx = card->ctx; size_t le, minlen, buflen; unsigned char *buf; int rv; LOG_FUNC_CALLED(ctx); if (apdu->le == 0) { /* no data is requested => change return value to 0x9000 and ignore the remaining data */ apdu->sw1 = 0x90; apdu->sw2 = 0x00; return SC_SUCCESS; } /* this should _never_ happen */ if (!card->ops->get_response) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "no GET RESPONSE command"); /* call GET RESPONSE until we have read all data requested or until the card retuns 0x9000, * whatever happens first. */ /* if there are already data in response append a new data to the end of the buffer */ buf = apdu->resp + apdu->resplen; /* read as much data as fits in apdu->resp (i.e. min(apdu->resplen, amount of data available)). */ buflen = olen - apdu->resplen; /* 0x6100 means at least 256 more bytes to read */ le = apdu->sw2 != 0 ? (size_t)apdu->sw2 : 256; /* we try to read at least as much as bytes as promised in the response bytes */ minlen = le; do { unsigned char resp[256]; size_t resp_len = le; /* call GET RESPONSE to get more date from the card; * note: GET RESPONSE returns the left amount of data (== SW2) */ memset(resp, 0, sizeof(resp)); rv = card->ops->get_response(card, &resp_len, resp); if (rv < 0) { #ifdef ENABLE_SM if (resp_len) { sc_log(ctx, "SM response data %s", sc_dump_hex(resp, resp_len)); sc_sm_update_apdu_response(card, resp, resp_len, rv, apdu); } #endif LOG_TEST_RET(ctx, rv, "GET RESPONSE error"); } le = resp_len; /* copy as much as will fit in requested buffer */ if (buflen < le) le = buflen; memcpy(buf, resp, le); buf += le; buflen -= le; /* we have all the data the caller requested even if the card has more data */ if (buflen == 0) break; minlen -= le; if (rv != 0) le = minlen = (size_t)rv; else /* if the card has returned 0x9000 but we still expect data ask for more * until we have read enough bytes */ le = minlen; } while (rv != 0 || minlen != 0); /* we've read all data, let's return 0x9000 */ apdu->resplen = buf - apdu->resp; apdu->sw1 = 0x90; apdu->sw2 = 0x00; LOG_FUNC_RETURN(ctx, SC_SUCCESS); }
/** basic consistency check of the sc_apdu_t object * @param ctx sc_context_t object for error messages * @param apdu sc_apdu_t object to check * @return SC_SUCCESS on success and an error code otherwise */ int sc_check_apdu(sc_card_t *card, const sc_apdu_t *apdu) { if ((apdu->cse & ~SC_APDU_SHORT_MASK) == 0) { /* length check for short APDU */ if (apdu->le > 256 || (apdu->lc > 255 && (apdu->flags & SC_APDU_FLAGS_CHAINING) == 0)) goto error; } else if ((apdu->cse & SC_APDU_EXT) != 0) { /* check if the card supports extended APDUs */ if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0) { sc_log(card->ctx, "card doesn't support extended APDUs"); goto error; } /* length check for extended APDU */ if (apdu->le > 65536 || apdu->lc > 65535) goto error; } else { goto error; } switch (apdu->cse & SC_APDU_SHORT_MASK) { case SC_APDU_CASE_1: /* no data is sent or received */ if (apdu->datalen != 0 || apdu->lc != 0 || apdu->le != 0) goto error; break; case SC_APDU_CASE_2_SHORT: /* no data is sent */ if (apdu->datalen != 0 || apdu->lc != 0) goto error; /* data is expected */ if (apdu->resplen == 0 || apdu->resp == NULL) goto error; /* return buffer to small */ if ((apdu->le == 0 && apdu->resplen < SC_MAX_APDU_BUFFER_SIZE-2) || (apdu->resplen < apdu->le)) goto error; break; case SC_APDU_CASE_3_SHORT: /* data is sent */ if (apdu->datalen == 0 || apdu->data == NULL || apdu->lc == 0) goto error; /* no data is expected */ if (apdu->le != 0) goto error; /* inconsistent datalen */ if (apdu->datalen != apdu->lc) goto error; break; case SC_APDU_CASE_4_SHORT: /* data is sent */ if (apdu->datalen == 0 || apdu->data == NULL || apdu->lc == 0) goto error; /* data is expected */ if (apdu->resplen == 0 || apdu->resp == NULL) goto error; /* return buffer to small */ if ((apdu->le == 0 && apdu->resplen < SC_MAX_APDU_BUFFER_SIZE-2) || (apdu->resplen < apdu->le)) goto error; /* inconsistent datalen */ if (apdu->datalen != apdu->lc) goto error; break; default: sc_log(card->ctx, "Invalid APDU case %d", apdu->cse); return SC_ERROR_INVALID_ARGUMENTS; } return SC_SUCCESS; error: sc_log(card->ctx, "Invalid Case %d %s APDU:\n" "cse=%02x cla=%02x ins=%02x p1=%02x p2=%02x lc=%lu le=%lu\n" "resp=%p resplen=%lu data=%p datalen=%lu", apdu->cse & SC_APDU_SHORT_MASK, (apdu->cse & SC_APDU_EXT) != 0 ? "extended" : "short", apdu->cse, apdu->cla, apdu->ins, apdu->p1, apdu->p2, (unsigned long) apdu->lc, (unsigned long) apdu->le, apdu->resp, (unsigned long) apdu->resplen, apdu->data, (unsigned long) apdu->datalen); return SC_ERROR_INVALID_ARGUMENTS; }
static int iso7816_process_fci(struct sc_card *card, struct sc_file *file, const unsigned char *buf, size_t buflen) { struct sc_context *ctx = card->ctx; size_t taglen, len = buflen; int i; const unsigned char *tag = NULL, *p = buf; sc_log(ctx, "processing FCI bytes"); tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen); if (tag != NULL && taglen == 2) { file->id = (tag[0] << 8) | tag[1]; sc_log(ctx, " file identifier: 0x%02X%02X", tag[0], tag[1]); } /* determine the file size */ /* try the tag 0x80 then the tag 0x81 */ file->size = 0; for (i = 0x80; i <= 0x81; i++) { int size = 0; len = buflen; tag = sc_asn1_find_tag(ctx, p, len, i, &taglen); if (tag == NULL) continue; if (taglen == 0) continue; if (sc_asn1_decode_integer(tag, taglen, &size) < 0) continue; if (size <0) continue; file->size = size; sc_log(ctx, " bytes in file: %d", file->size); break; } tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen); if (tag != NULL) { if (taglen > 0) { unsigned char byte = tag[0]; const char *type; file->shareable = byte & 0x40 ? 1 : 0; sc_log(ctx, " shareable: %s", (byte & 0x40) ? "yes" : "no"); file->ef_structure = byte & 0x07; switch ((byte >> 3) & 7) { case 0: type = "working EF"; file->type = SC_FILE_TYPE_WORKING_EF; break; case 1: type = "internal EF"; file->type = SC_FILE_TYPE_INTERNAL_EF; break; case 7: type = "DF"; file->type = SC_FILE_TYPE_DF; break; default: type = "unknown"; break; } sc_log(ctx, " type: %s", type); sc_log(ctx, " EF structure: %d", byte & 0x07); } }
static int myeid_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, struct sc_pkcs15_pubkey *pubkey) { 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_cardctl_myeid_gen_store_key_info args; struct sc_file *file = NULL; int r; size_t keybits = key_info->modulus_length; unsigned char raw_pubkey[256]; LOG_FUNC_CALLED(ctx); if (object->type != SC_PKCS15_TYPE_PRKEY_RSA && object->type != SC_PKCS15_TYPE_PRKEY_EC) LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Generate key failed: only RSA and EC supported"); /* 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: LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "20140202: waiting for cards and specification from Aventra. VTA"); break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported key type"); break; } sc_log(ctx, "Generate key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path)); r = sc_select_file(card, &key_info->path, &file); LOG_TEST_RET(ctx, r, "Cannot generate key: failed to select key file"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_GENERATE); LOG_TEST_RET(ctx, r, "No authorisation to generate private key"); /* Fill in data structure */ memset(&args, 0, sizeof (args)); args.key_len_bits = keybits; args.op_type = OP_TYPE_GENERATE; if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { args.key_type = SC_CARDCTL_MYEID_KEY_RSA; args.pubexp_len = MYEID_DEFAULT_PUBKEY_LEN; args.pubexp = MYEID_DEFAULT_PUBKEY; } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { args.key_type = SC_CARDCTL_MYEID_KEY_EC; } /* Generate RSA key */ r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); /* Keypair generation -> collect public key info */ if (pubkey != NULL) { struct sc_cardctl_myeid_data_obj data_obj; if (object->type == SC_PKCS15_TYPE_PRKEY_RSA) { pubkey->algorithm = SC_ALGORITHM_RSA; pubkey->u.rsa.modulus.len = (keybits + 7) / 8; pubkey->u.rsa.modulus.data = malloc(pubkey->u.rsa.modulus.len); pubkey->u.rsa.exponent.len = MYEID_DEFAULT_PUBKEY_LEN; pubkey->u.rsa.exponent.data = malloc(MYEID_DEFAULT_PUBKEY_LEN); memcpy(pubkey->u.rsa.exponent.data, MYEID_DEFAULT_PUBKEY, MYEID_DEFAULT_PUBKEY_LEN); /* Get public key modulus */ r = sc_select_file(card, &file->path, NULL); LOG_TEST_RET(ctx, r, "Cannot get key modulus: select key file failed"); data_obj.P1 = 0x01; data_obj.P2 = 0x01; data_obj.Data = raw_pubkey; data_obj.DataLen = sizeof (raw_pubkey); r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); LOG_TEST_RET(ctx, r, "Cannot get RSA key modulus: 'MYEID_GETDATA' failed"); if ((data_obj.DataLen * 8) != key_info->modulus_length) LOG_TEST_RET(ctx, SC_ERROR_PKCS15INIT, "Cannot get RSA key modulus: invalid key-size"); memcpy(pubkey->u.rsa.modulus.data, raw_pubkey, pubkey->u.rsa.modulus.len); } else if (object->type == SC_PKCS15_TYPE_PRKEY_EC) { pubkey->algorithm = SC_ALGORITHM_EC; r = sc_select_file(card, &file->path, NULL); LOG_TEST_RET(ctx, r, "Cannot get public key: select key file failed"); data_obj.P1 = 0x01; data_obj.P2 = 0x86; /* Get public EC key (Q) */ data_obj.Data = raw_pubkey; data_obj.DataLen = sizeof (raw_pubkey); r = sc_card_ctl(card, SC_CARDCTL_MYEID_GETDATA, &data_obj); LOG_TEST_RET(ctx, r, "Cannot get EC public key: 'MYEID_GETDATA' failed"); /* * TODO DEE - this looks like a bug... * pubkey->u.ec.ecpointQ.value is just value. "04||X||Y" * pubkey->data.value should be DER OCTET STRING * but * pubkey->data.value looks like TLV with TAG if 0x86 * and single byte length. * Could call sc_pkcs15_encode_pubkey * to set pubkey->data.value */ pubkey->u.ec.ecpointQ.value = malloc(data_obj.DataLen - 2); pubkey->u.ec.ecpointQ.len = data_obj.DataLen - 2; //pubkey->data.value = malloc(data_obj.DataLen); //pubkey->data.len = data_obj.DataLen; pubkey->u.ec.params.field_length = keybits; /* Omit the first 2 bytes (0x86??) */ memcpy(pubkey->u.ec.ecpointQ.value, data_obj.Data + 2, data_obj.DataLen - 2); //memcpy(pubkey->data.value, data_obj.Data, data_obj.DataLen); } } if (file) sc_file_free(file); LOG_FUNC_RETURN(ctx, r); }
CK_RV C_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { struct sc_pkcs11_slot *slot; unsigned int uninit_slotcount; sc_timestamp_t now; CK_RV rv; if (pInfo == NULL_PTR) return CKR_ARGUMENTS_BAD; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; sc_log(context, "C_GetSlotInfo(0x%lx)", slotID); if (sc_pkcs11_conf.plug_and_play) uninit_slotcount = 1; else uninit_slotcount = 0; if (sc_pkcs11_conf.init_sloppy && uninit_slotcount <= list_size(&virtual_slots)) { /* Most likely virtual_slots only contains the hotplug slot and has not * been initialized because the caller has *not* called C_GetSlotList * before C_GetSlotInfo, as required by PKCS#11. Initialize * virtual_slots to make things work and hope the caller knows what * it's doing... */ card_detect_all(); } rv = slot_get_slot(slotID, &slot); sc_log(context, "C_GetSlotInfo() get slot rv %i", rv); if (rv == CKR_OK) { if (slot->reader == NULL) { rv = CKR_TOKEN_NOT_PRESENT; } else { now = get_current_time(); if (now >= slot->slot_state_expires || now == 0) { /* Update slot status */ rv = card_detect(slot->reader); sc_log(context, "C_GetSlotInfo() card detect rv 0x%X", rv); if (rv == CKR_TOKEN_NOT_RECOGNIZED || rv == CKR_OK) slot->slot_info.flags |= CKF_TOKEN_PRESENT; /* Don't ask again within the next second */ slot->slot_state_expires = now + 1000; } } } if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED) rv = CKR_OK; if (rv == CKR_OK) memcpy(pInfo, &slot->slot_info, sizeof(CK_SLOT_INFO)); sc_log(context, "C_GetSlotInfo() flags 0x%X", pInfo->flags); sc_log(context, "C_GetSlotInfo(0x%lx) = %s", slotID, lookup_enum( RV_T, rv)); sc_pkcs11_unlock(); return rv; }
CK_RV C_WaitForSlotEvent(CK_FLAGS flags, /* blocking/nonblocking flag */ CK_SLOT_ID_PTR pSlot, /* location that receives the slot ID */ CK_VOID_PTR pReserved) /* reserved. Should be NULL_PTR */ { sc_reader_t *found; unsigned int mask, events; void *reader_states = NULL; CK_SLOT_ID slot_id; CK_RV rv; int r; if (pReserved != NULL_PTR) return CKR_ARGUMENTS_BAD; sc_log(context, "C_WaitForSlotEvent(block=%d)", !(flags & CKF_DONT_BLOCK)); /* Not all pcsc-lite versions implement consistently used functions as they are */ /* FIXME: add proper checking into build to check correct pcsc-lite version for SCardStatusChange/SCardCancel */ if (!(flags & CKF_DONT_BLOCK)) return CKR_FUNCTION_NOT_SUPPORTED; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; mask = SC_EVENT_CARD_EVENTS; /* Detect and add new slots for added readers v2.20 */ if (sc_pkcs11_conf.plug_and_play) { mask |= SC_EVENT_READER_EVENTS; } rv = slot_find_changed(&slot_id, mask); if ((rv == CKR_OK) || (flags & CKF_DONT_BLOCK)) goto out; again: sc_log(context, "C_WaitForSlotEvent() reader_states:%p", reader_states); sc_pkcs11_unlock(); r = sc_wait_for_event(context, mask, &found, &events, -1, &reader_states); if (sc_pkcs11_conf.plug_and_play && events & SC_EVENT_READER_ATTACHED) { /* NSS/Firefox Triggers a C_GetSlotList(NULL) only if a slot ID is returned that it does not know yet Change the first hotplug slot id on every call to make this happen. */ sc_pkcs11_slot_t *hotplug_slot = list_get_at(&virtual_slots, 0); *pSlot= hotplug_slot->id -1; rv = sc_pkcs11_lock(); if (rv != CKR_OK) return rv; goto out; } /* Was C_Finalize called ? */ if (in_finalize == 1) return CKR_CRYPTOKI_NOT_INITIALIZED; if ((rv = sc_pkcs11_lock()) != CKR_OK) return rv; if (r != SC_SUCCESS) { sc_log(context, "sc_wait_for_event() returned %d\n", r); rv = sc_to_cryptoki_error(r, "C_WaitForSlotEvent"); goto out; } /* If no changed slot was found (maybe an unsupported card * was inserted/removed) then go waiting again */ rv = slot_find_changed(&slot_id, mask); if (rv != CKR_OK) goto again; out: if (pSlot) *pSlot = slot_id; /* Free allocated readers states holder */ if (reader_states) { sc_log(context, "free reader states"); sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states); } sc_log(context, "C_WaitForSlotEvent() = %s", lookup_enum (RV_T, rv)); sc_pkcs11_unlock(); return rv; }
/* * Store a private key */ static int myeid_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *object, struct sc_pkcs15_prkey *prkey) { 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_cardctl_myeid_gen_store_key_info args; struct sc_file *file = NULL; int r, keybits = key_info->modulus_length; LOG_FUNC_CALLED(ctx); 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: LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "20140202: waiting for cards and specification from Aventra. VTA"); break; default: LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Store key failed: Unsupported key type"); break; } sc_log(ctx, "store MyEID key with ID:%s and path:%s", sc_pkcs15_print_id(&key_info->id), sc_print_path(&key_info->path)); r = sc_select_file(card, &key_info->path, &file); LOG_TEST_RET(ctx, r, "Cannot store MyEID key: select key file failed"); r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE); LOG_TEST_RET(ctx, r, "No authorisation to store MyEID private key"); if (file) sc_file_free(file); /* Fill in data structure */ memset(&args, 0, sizeof (args)); args.op_type = OP_TYPE_STORE; if(object->type == SC_PKCS15_TYPE_PRKEY_RSA) { //args.key_len_bits = keybits; args.key_type = SC_CARDCTL_MYEID_KEY_RSA; args.pubexp_len = prkey->u.rsa.exponent.len; args.pubexp = prkey->u.rsa.exponent.data; args.primep_len = prkey->u.rsa.p.len; args.primep = prkey->u.rsa.p.data; args.primeq_len = prkey->u.rsa.q.len; args.primeq = prkey->u.rsa.q.data; args.dp1_len = prkey->u.rsa.dmp1.len; args.dp1 = prkey->u.rsa.dmp1.data; args.dq1_len = prkey->u.rsa.dmq1.len; args.dq1 = prkey->u.rsa.dmq1.data; args.invq_len = prkey->u.rsa.iqmp.len; args.invq = prkey->u.rsa.iqmp.data; args.key_len_bits = prkey->u.rsa.modulus.len; args.mod = prkey->u.rsa.modulus.data; } else { args.key_type = SC_CARDCTL_MYEID_KEY_EC; args.d = prkey->u.ec.privateD.data; args.d_len = prkey->u.ec.privateD.len; args.ecpublic_point = prkey->u.ec.ecpointQ.value; args.ecpublic_point_len = prkey->u.ec.ecpointQ.len; args.key_len_bits = prkey->u.ec.params.field_length; } /* Store RSA key */ r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args); LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed"); LOG_FUNC_RETURN(ctx, r); }