예제 #1
0
파일: apdu.c 프로젝트: entersafe/OpenSC
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);
}
예제 #2
0
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);
}
예제 #3
0
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);
}
예제 #4
0
파일: apdu.c 프로젝트: NWilson/OpenSC
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);
}
예제 #5
0
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
}
예제 #6
0
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
}
예제 #7
0
파일: card.c 프로젝트: AktivCo/OpenSC
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);
}
예제 #8
0
파일: card-jpki.c 프로젝트: jpki/OpenSC
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);
}
예제 #9
0
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;
}
예제 #10
0
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
}
예제 #11
0
파일: iasecc-sm.c 프로젝트: fbezdeka/OpenSC
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
}
예제 #12
0
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;
}
예제 #13
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);
}
예제 #14
0
파일: card.c 프로젝트: AktivCo/OpenSC
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;
}
예제 #15
0
/* 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);
}
예제 #16
0
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);
}
예제 #17
0
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;
}
예제 #18
0
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;
}
예제 #19
0
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;
}
예제 #20
0
파일: pkcs15-rtecp.c 프로젝트: DDvO/OpenSC
/*
 * 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);
}
예제 #21
0
파일: apdu.c 프로젝트: NWilson/OpenSC
/** 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;
}
예제 #22
0
파일: apdu.c 프로젝트: NWilson/OpenSC
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;
}
예제 #23
0
파일: apdu.c 프로젝트: NWilson/OpenSC
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;
}
예제 #24
0
파일: apdu.c 프로젝트: NWilson/OpenSC
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);
}
예제 #25
0
파일: apdu.c 프로젝트: NWilson/OpenSC
/** 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;
}
예제 #26
0
파일: iso7816.c 프로젝트: uDude/OpenSC
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);
		}
	}
예제 #27
0
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);
}
예제 #28
0
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;
}
예제 #29
0
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;
}
예제 #30
0
/*
 * 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);
}