예제 #1
0
/*
 * @brief Use PUT DATA to import a private EC key.
 *
 * Format of transmitted data:
 *  0xE0 - Private class, constructed encoding, number one.
 *  0x81 - prime
 *  0x82 - coefficient A
 *  0x83 - coefficient B
 *  0x84 - base point G
 *  0x85 - order
 *  0x87 - cofactor
 *  0x88 - private D (private key)
 *
 * @param card
 * @param ec   The EC private key to import.
 *
 * @return SC_ERROR_INVALID_ARGUMENTS: Curve parameters or private component is missing.
 *         other errors:               Transmit errors / errors returned by card.
 *                                     ASN1 errors.
 */
static int
isoApplet_put_data_prkey_ec(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args)
{
	sc_apdu_t apdu;
	u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE];
	int r;
	u8 *p;
	size_t tags_len;

	LOG_FUNC_CALLED(card->ctx);

	if(!args->privkey.ec.privateD.value
	        || !args->privkey.ec.params.prime.value
	        || !args->privkey.ec.params.coefficientA.value
	        || !args->privkey.ec.params.coefficientB.value
	        || !args->privkey.ec.params.basePointG.value
	        || !args->privkey.ec.params.order.value
	        || !args->privkey.ec.params.coFactor.value
	  )
	{
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "Missing information about EC private key.");
	}

	/* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */
	tags_len = 0;
	r = sc_asn1_put_tag(0x81, NULL, args->privkey.ec.params.prime.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x82, NULL, args->privkey.ec.params.coefficientA.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x83, NULL, args->privkey.ec.params.coefficientB.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x84, NULL, args->privkey.ec.params.basePointG.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x85, NULL, args->privkey.ec.params.order.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x87, NULL, args->privkey.ec.params.coFactor.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x88, NULL, args->privkey.ec.privateD.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;

	/* Write the outer tag and length information. */
	p = sbuf;
	r = sc_asn1_put_tag(0xE0, NULL, tags_len, p, sizeof(sbuf), &p);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");

	/* Write inner tags. */
	r = isoApplet_put_ec_params(card, &args->privkey.ec.params, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
	{
		sc_log(card->ctx, "Error composing EC params.");
		goto out;
	}
	r = sc_asn1_put_tag(0x88, args->privkey.ec.privateD.value, args->privkey.ec.privateD.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;

	/* Send to card. */
	sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF);
	apdu.lc = p - sbuf;
	apdu.datalen = p - sbuf;
	apdu.data = sbuf;
	r = sc_transmit_apdu(card, &apdu);
	if(r < 0)
	{
		sc_log(card->ctx, "APDU transmit failed");
		goto out;
	}

	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	if(apdu.sw1 == 0x6D && apdu.sw2 == 0x00)
	{
		sc_log(card->ctx, "The applet returned that the PUT DATA instruction byte is not supported. "
		       "If you are using an older applet version and are trying to import keys, please update your applet first.");
	}
	else if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81)
	{
		sc_log(card->ctx, "Key import not supported by the card with that particular key type. "
		       "Your card may not support the specified algorithm used by the applet / specified by you. "
		       "In most cases, this happens when trying to import EC keys not supported by your java card. "
		       "In this case, look for supported field lengths and whether FP and/or F2M are supported. "
		       "If you tried to import a private RSA key, check the key length.");
	}
	else if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00)
	{
		sc_log(card->ctx, "Key import not allowed by the applet's security policy. "
		       "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet,"
		       " rebuild and reinstall the applet.");
	}
	if(r < 0)
	{
		sc_log(card->ctx, "Card returned error");
		goto out;
	}

	r = SC_SUCCESS;
out:
	sc_mem_clear(sbuf, sizeof(sbuf));
	LOG_FUNC_RETURN(card->ctx, r);
}
예제 #2
0
static int
sc_oberthur_read_file(struct sc_pkcs15_card *p15card, const char *in_path,
		unsigned char **out, size_t *out_len,
		int verify_pin)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_card *card = p15card->card;
	struct sc_file *file = NULL;
	struct sc_path path;
	size_t sz;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (!in_path || !out || !out_len)
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file");

	sc_log(ctx, "read file '%s'; verify_pin:%i", in_path, verify_pin);

	*out = NULL;
	*out_len = 0;

	sc_format_path(in_path, &path);
	rv = sc_select_file(card, &path, &file);
	LOG_TEST_RET(ctx, rv, "Cannot select oberthur file to read");

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)
		sz = file->size;
	else
		sz = (file->record_length + 2) * file->record_count;

	*out = calloc(sz, 1);
	if (*out == NULL)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot read oberthur file");

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)   {
		rv = sc_read_binary(card, 0, *out, sz, 0);
	}
	else	{
		int rec;
		int offs = 0;
		int rec_len = file->record_length;

		for (rec = 1; ; rec++)   {
			rv = sc_read_record(card, rec, *out + offs + 2, rec_len, SC_RECORD_BY_REC_NR);
			if (rv == SC_ERROR_RECORD_NOT_FOUND)   {
				rv = 0;
				break;
			}
			else if (rv < 0)   {
				break;
			}

			rec_len = rv;

			*(*out + offs) = 'R';
			*(*out + offs + 1) = rv;

			offs += rv + 2;
		}

		sz = offs;
	}

	sc_log(ctx, "read oberthur file result %i", rv);
	if (verify_pin && rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)   {
		struct sc_pkcs15_object *objs[0x10], *pin_obj = NULL;
		const struct sc_acl_entry *acl = sc_file_get_acl_entry(file, SC_AC_OP_READ);
		int ii;

		rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 0x10);
		LOG_TEST_RET(ctx, rv, "Cannot read oberthur file: get AUTH objects error");

		for (ii=0; ii<rv; ii++)   {
			struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) objs[ii]->data;
			sc_log(ctx, "compare PIN/ACL refs:%i/%i, method:%i/%i",
					auth_info->attrs.pin.reference, acl->key_ref, auth_info->auth_method, acl->method);
			if (auth_info->attrs.pin.reference == (int)acl->key_ref && auth_info->auth_method == (unsigned)acl->method)   {
				pin_obj = objs[ii];
				break;
			}
		}

		if (!pin_obj || !pin_obj->content.value)    {
			rv = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
		}
		else    {
			rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin_obj->content.value, pin_obj->content.len);
			if (!rv)
				rv = sc_oberthur_read_file(p15card, in_path, out, out_len, 0);
		}
	};

	sc_file_free(file);

	if (rv < 0)   {
		free(*out);
		*out = NULL;
		*out_len = 0;
	}

	*out_len = sz;

	LOG_FUNC_RETURN(ctx, rv);
}
예제 #3
0
/* Public key info:
 * 	flags:2,
 * 	CN(len:2,value:<variable length>),
 * 	ID(len:2,value:(SHA1 value)),
 * 	StartDate(Ascii:8)
 * 	EndDate(Ascii:8)
 * 	??(0x00:2)
 */
static int
sc_pkcs15emu_oberthur_add_pubkey(struct sc_pkcs15_card *p15card,
		unsigned int file_id, unsigned int size)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_pubkey_info key_info;
	struct sc_pkcs15_object key_obj;
	char ch_tmp[0x100];
	unsigned char *info_blob;
	size_t len, info_len, offs;
	unsigned flags;
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "public key(file-id:%04X,size:%X)", file_id, size);

	memset(&key_info, 0, sizeof(key_info));
	memset(&key_obj, 0, sizeof(key_obj));

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100);
	rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add public key: read oberthur file error");

	/* Flags */
	offs = 2;
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'tag'");
	flags = *(info_blob + 0) * 0x100 + *(info_blob + 1);
	key_info.usage = sc_oberthur_decode_usage(flags);
	if (flags & OBERTHUR_ATTR_MODIFIABLE)
		key_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
	sc_log(ctx, "Public key key-usage:%04X", key_info.usage);

	/* Label */
	if (offs + 2 > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'Label'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len)   {
		if (len > sizeof(key_obj.label) - 1)
			len = sizeof(key_obj.label) - 1;
		memcpy(key_obj.label, info_blob + offs + 2, len);
	}
	offs += 2 + len;

	/* ID */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'ID'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (!len || len > sizeof(key_info.id.value))
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalie 'ID' length");
	memcpy(key_info.id.value, info_blob + offs + 2, len);
	key_info.id.len = len;

	/* Ignore Start/End dates */

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id);
	sc_format_path(ch_tmp, &key_info.path);

	key_info.native = 1;
	key_info.key_reference = file_id & 0xFF;
	key_info.modulus_length = size;

	rv = sc_pkcs15emu_add_rsa_pubkey(p15card, &key_obj, &key_info);

	LOG_FUNC_RETURN(ctx, rv);
}
예제 #4
0
/**
 * Ask for user consent.
 *
 * Check for user consent configuration,
 * Invoke proper gui app and check result
 *
 * @param card pointer to sc_card structure
 * @param title Text to appear in the window header
 * @param text Message to show to the user
 * @return SC_SUCCESS on user consent OK , else error code
 */
int sc_ask_user_consent(struct sc_card * card, const char *title, const char *message)
{
#ifdef __APPLE__
	CFOptionFlags result;  /* result code from the message box */
	/* convert the strings from char* to CFStringRef */
	CFStringRef header_ref; /* to store title */
	CFStringRef message_ref; /* to store message */
#endif
#ifdef linux
	pid_t pid;
	FILE *fin=NULL;
	FILE *fout=NULL;	/* to handle pipes as streams */
	struct stat st_file;	/* to verify that executable exists */
	int srv_send[2];	/* to send data from server to client */
	int srv_recv[2];	/* to receive data from client to server */
	char outbuf[1024];	/* to compose and send messages */	
	char buf[1024];		/* to store client responses */
	int n = 0;		/* to iterate on to-be-sent messages */
#endif
	int res = SC_ERROR_INTERNAL;	/* by default error :-( */
	char *msg = NULL;	/* to makr errors */

	if ((card == NULL) || (card->ctx == NULL))
		return SC_ERROR_INVALID_ARGUMENTS;
	LOG_FUNC_CALLED(card->ctx);

	if ((title==NULL) || (message==NULL)) 
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (GET_DNIE_UI_CTX(card).user_consent_enabled == 0) {
		sc_log(card->ctx,
		       "User Consent is disabled in configuration file");
		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
	}
#ifdef _WIN32
	/* in Windows, do not use pinentry, but MessageBox system call */
	res = MessageBox (
		NULL,
		TEXT(message),
		TEXT(title),
		MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2 | MB_APPLMODAL
		);
	if ( res == IDOK ) 
		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
	LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
#elif __APPLE__
	/* Also in Mac OSX use native functions */

	/* convert the strings from char* to CFStringRef */
	header_ref = CFStringCreateWithCString( NULL, title, strlen(title) );
	message_ref = CFStringCreateWithCString( NULL,message, strlen(message) );

	/* Displlay user notification alert */
	CFUserNotificationDisplayAlert(
		0, /* no timeout */
		kCFUserNotificationNoteAlertLevel,  /* Alert level */
		NULL,	/* IconURL, use default, you can change */
			/* it depending message_type flags */
		NULL,	/* SoundURL (not used) */ 
		NULL,	/* localization of strings */
		header_ref,	/* header. Cannot be null */
		message_ref,	/* message text */
		CFSTR("Cancel"), /* default ( "OK" if null) button text */ 
		CFSTR("OK"), /* second button title */
                NULL, /* third button title, null--> no other button */
		&result /* response flags */
	);

	/* Clean up the strings */
	CFRelease( header_ref );
        CFRelease( message_ref );
	/* Return 0 only if "OK" is selected */
	if( result == kCFUserNotificationAlternateResponse )
		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
	LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_ALLOWED);
#elif linux
	/* check that user_consent_app exists. TODO: check if executable */
	res = stat(GET_DNIE_UI_CTX(card).user_consent_app, &st_file);
	if (res != 0) {
		sc_log(card->ctx, "Invalid pinentry application: %s\n",
		       GET_DNIE_UI_CTX(card).user_consent_app);
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
	}

	/* just a simple bidirectional pipe+fork+exec implementation */
	/* In a pipe, xx[0] is for reading, xx[1] is for writing */
	if (pipe(srv_send) < 0) {
		msg = "pipe(srv_send)";
		goto do_error;
	}
	if (pipe(srv_recv) < 0) {
		msg = "pipe(srv_recv)";
		goto do_error;
	}
	pid = fork();
	switch (pid) {
	case -1:		/* error  */
		msg = "fork()";
		goto do_error;
	case 0:		/* child  */
		/* make our pipes, our new stdin & stderr, closing older ones */
		dup2(srv_send[0], STDIN_FILENO);	/* map srv send for input */
		dup2(srv_recv[1], STDOUT_FILENO);	/* map srv_recv for output */
		/* once dup2'd pipes are no longer needed on client; so close */
		close(srv_send[0]);
		close(srv_send[1]);
		close(srv_recv[0]);
		close(srv_recv[1]);
		/* call exec() with proper user_consent_app from configuration */
		/* if ok should never return */
		execlp(GET_DNIE_UI_CTX(card).user_consent_app, GET_DNIE_UI_CTX(card).user_consent_app, (char *)NULL);
		res = SC_ERROR_INTERNAL;
		msg = "execlp() error";	/* exec() failed */
		goto do_error;
	default:		/* parent */
		/* Close the pipe ends that the child uses to read from / write to 
		 * so when we close the others, an EOF will be transmitted properly.
		 */
		close(srv_send[0]);
		close(srv_recv[1]);
		/* use iostreams to take care on newlines and text based data */
		fin = fdopen(srv_recv[0], "r");
		if (fin == NULL) {
			msg = "fdopen(in)";
			goto do_error;
		}
		fout = fdopen(srv_send[1], "w");
		if (fout == NULL) {
			msg = "fdopen(out)";
			goto do_error;
		}
		/* read and ignore first line */
		fflush(stdin);
		for (n = 0; n<4; n++) {
			char *pt;
			memset(outbuf, 0, sizeof(outbuf));
			if (n==0) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[0],title);
			else if (n==1) snprintf(outbuf,1023,"%s %s\n",user_consent_msgs[1],message);
			else snprintf(outbuf,1023,"%s\n",user_consent_msgs[n]);
			/* send message */
			fputs(outbuf, fout);
			fflush(fout);
			/* get response */
			memset(buf, 0, sizeof(buf));
			pt=fgets(buf, sizeof(buf) - 1, fin);
			if (pt==NULL) {
				res = SC_ERROR_INTERNAL;
				msg = "fgets() Unexpected IOError/EOF";
				goto do_error;
			}
			if (strstr(buf, "OK") == NULL) {
				res = SC_ERROR_NOT_ALLOWED;
				msg = "fail/cancel";
				goto do_error;
			}
		}
	}			/* switch */
	/* arriving here means signature has been accepted by user */
	res = SC_SUCCESS;
	msg = NULL;
do_error:
	/* close out channel to force client receive EOF and also die */
	if (fout != NULL) fclose(fout);
	if (fin != NULL) fclose(fin);
#else
#error "Don't know how to handle user consent in this (rare) Operating System"
#endif
	if (msg != NULL)
		sc_log(card->ctx, "%s", msg);
	LOG_FUNC_RETURN(card->ctx, res);
}
예제 #5
0
파일: dir.c 프로젝트: AktivCo/OpenSC
static int
parse_dir_record(sc_card_t *card, u8 ** buf, size_t *buflen, int rec_nr)
{
	struct sc_context *ctx = card->ctx;
	struct sc_asn1_entry asn1_dirrecord[5], asn1_dir[2];
	scconf_block *conf_block = NULL;
	sc_app_info_t *app = NULL;
	struct sc_aid aid;
	u8 label[128], path[128], ddo[128];
	size_t label_len = sizeof(label) - 1, path_len = sizeof(path), ddo_len = sizeof(ddo);
	int r;

	LOG_FUNC_CALLED(ctx);
	aid.len = sizeof(aid.value);

	memset(label, 0, sizeof(label));
	sc_copy_asn1_entry(c_asn1_dirrecord, asn1_dirrecord);
	sc_copy_asn1_entry(c_asn1_dir, asn1_dir);
	sc_format_asn1_entry(asn1_dir + 0, asn1_dirrecord, NULL, 0);
	sc_format_asn1_entry(asn1_dirrecord + 0, aid.value, &aid.len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 1, label, &label_len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 2, path, &path_len, 0);
	sc_format_asn1_entry(asn1_dirrecord + 3, ddo, &ddo_len, 0);

	r = sc_asn1_decode(ctx, asn1_dir, *buf, *buflen, (const u8 **) buf, buflen);
	if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
		LOG_FUNC_RETURN(ctx, r);
	LOG_TEST_RET(ctx, r, "EF(DIR) parsing failed");

	conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1);
	if (conf_block)   {
		scconf_block **blocks = NULL;
		char aid_str[SC_MAX_AID_STRING_SIZE];
		int ignore_app = 0;

		sc_bin_to_hex(aid.value, aid.len, aid_str, sizeof(aid_str), 0);
		blocks = scconf_find_blocks(card->ctx->conf, conf_block, "application", aid_str);
		if (blocks)   {
			ignore_app = (blocks[0] && scconf_get_str(blocks[0], "disable", 0));
                        free(blocks);
		 }

		if (ignore_app)   {
			sc_log(ctx, "Application '%s' ignored", aid_str);
			LOG_FUNC_RETURN(ctx, SC_SUCCESS);
		}
	}

	app = calloc(1, sizeof(struct sc_app_info));
	if (app == NULL)
		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);

	memcpy(&app->aid, &aid, sizeof(struct sc_aid));

	if (asn1_dirrecord[1].flags & SC_ASN1_PRESENT)
		app->label = strdup((char *) label);
	else
		app->label = NULL;

	if (asn1_dirrecord[2].flags & SC_ASN1_PRESENT && path_len > 0) {
		/* application path present: ignore AID */
		if (path_len > SC_MAX_PATH_SIZE) {
			free(app);
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_ASN1_OBJECT, "Application path is too long.");
		}
		memcpy(app->path.value, path, path_len);
		app->path.len = path_len;
		app->path.type = SC_PATH_TYPE_PATH;
	}
	else {
		/* application path not present: use AID as application path */
		memcpy(app->path.value, aid.value, aid.len);
		app->path.len = aid.len;
		app->path.type = SC_PATH_TYPE_DF_NAME;
	}

	if (asn1_dirrecord[3].flags & SC_ASN1_PRESENT) {
		app->ddo.value = malloc(ddo_len);
		if (app->ddo.value == NULL) {
			free(app);
			LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate DDO value");
		}
		memcpy(app->ddo.value, ddo, ddo_len);
		app->ddo.len = ddo_len;
	} else {
		app->ddo.value = NULL;
		app->ddo.len = 0;
	}

	app->rec_nr = rec_nr;
	card->app[card->app_count] = app;
	card->app_count++;

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
예제 #6
0
파일: apdu.c 프로젝트: pawmas/opensc
LIBOPENSC_API 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 > 0 ? card->max_send_size : 255;

		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;
}
예제 #7
0
파일: iasecc-sm.c 프로젝트: fbezdeka/OpenSC
int
iasecc_sm_initialize(struct sc_card *card, unsigned se_num, unsigned cmd)
{
	struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
	struct sm_info *sm_info = &card->sm_ctx.info;
	struct sm_cwa_session *cwa_session = &sm_info->session.cwa;
	struct sc_remote_data rdata;
	int rv;

	LOG_FUNC_CALLED(ctx);

	strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section));
	sm_info->cmd = cmd;
	sm_info->serialnr = card->serialnr;
	sm_info->card_type = card->type;
	sm_info->sm_type = SM_TYPE_CWA14890;

	rv = iasecc_sm_se_mutual_authentication(card, se_num);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() MUTUAL AUTHENTICATION failed");

	rv = iasecc_sm_get_challenge(card, cwa_session->card_challenge, SM_SMALL_CHALLENGE_LEN);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() GET CHALLENGE failed");

	sc_remote_data_init(&rdata);

	rv = sm_save_sc_context(card, sm_info);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() cannot save current context");

	if (!card->sm_ctx.module.ops.initialize)
		LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "iasecc_sm_initialize() no SM module");
	rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() INITIALIZE failed");


	if (rdata.length == 1)   {
		rdata.data->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER;
		rdata.data->apdu.flags &= ~SC_APDU_FLAGS_NO_GET_RESP;
	}
	else   {
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "TODO: SM init with more then one APDU");
	}

	cwa_session->mdata_len = sizeof(cwa_session->mdata);
	rv = iasecc_sm_transmit_apdus (card, &rdata, cwa_session->mdata, &cwa_session->mdata_len);
	if (rv == SC_ERROR_PIN_CODE_INCORRECT)
		sc_log(ctx, "SM initialization failed, %i tries left", (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_initialize() transmit APDUs failed");

	rdata.free(&rdata);

	sc_log(ctx, "MA data(len:%"SC_FORMAT_LEN_SIZE_T"u) '%s'",
	       cwa_session->mdata_len,
	       sc_dump_hex(cwa_session->mdata, cwa_session->mdata_len));
	if (cwa_session->mdata_len != 0x48)
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "iasecc_sm_initialize() invalid MUTUAL AUTHENTICATE result data");

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
#else
	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of Secure-Messaging");
	return SC_ERROR_NOT_SUPPORTED;
#endif
}
예제 #8
0
/* Finish initialization. After this ACL is in affect */
static int myeid_finalize_card(sc_card_t *card) {
	LOG_FUNC_CALLED(card->ctx);
	LOG_FUNC_RETURN(card->ctx, sc_card_ctl(card, SC_CARDCTL_MYEID_ACTIVATE_CARD, NULL));
}
예제 #9
0
파일: iasecc-sdo.c 프로젝트: pawmas/opensc
static int
iasecc_sdo_parse_data(struct sc_card *card, unsigned char *data, struct iasecc_sdo *sdo)
{
	struct sc_context *ctx = card->ctx;
	struct iasecc_extended_tlv tlv;
	int tlv_size, rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "iasecc_sdo_parse_data() class %X; ref %X", sdo->sdo_class, sdo->sdo_ref);

	tlv_size = iasecc_parse_get_tlv(card, data, &tlv);
	LOG_TEST_RET(ctx, tlv_size, "parse error: get TLV");

	sc_log(ctx, "iasecc_sdo_parse_data() tlv.tag 0x%X", tlv.tag);
	if (tlv.tag == IASECC_DOCP_TAG)   {
		sc_log(ctx, "iasecc_sdo_parse_data() parse IASECC_DOCP_TAG: 0x%X; size %i", tlv.tag, tlv.size);
		rv = iasecc_parse_docp(card, tlv.value, tlv.size, sdo);
		sc_log(ctx, "iasecc_sdo_parse_data() parsed IASECC_DOCP_TAG rv %i", rv);
		free(tlv.value);
		LOG_TEST_RET(ctx, rv, "parse error: cannot parse DOCP");
	}
	else if (tlv.tag == IASECC_DOCP_TAG_NON_REPUDATION)   {
		sdo->docp.non_repudiation = tlv;
	}
	else if (tlv.tag == IASECC_DOCP_TAG_USAGE_REMAINING)   {
		sdo->docp.usage_remaining = tlv;
	}
	else if (tlv.tag == IASECC_DOCP_TAG_TRIES_MAXIMUM)   {
		sdo->docp.tries_maximum = tlv;
	}
	else if (tlv.tag == IASECC_DOCP_TAG_TRIES_REMAINING)   {
		sdo->docp.tries_remaining = tlv;
	}
	else if (tlv.tag == IASECC_SDO_CHV_TAG)   {
		if (sdo->sdo_class != IASECC_SDO_CLASS_CHV)
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: IASECC_SDO_CHV_TAG tag in non User CHV SDO");

		rv = iasecc_parse_chv(card, tlv.value, tlv.size, &sdo->data.chv);
		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO CHV data");

		free(tlv.value);
	}
	else if (tlv.tag == IASECC_SDO_PUBKEY_TAG)   {
		if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PUBLIC)
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PUBLIC_KEY tag in non PUBLIC_KEY SDO");

		rv = iasecc_parse_pubkey(card, tlv.value, tlv.size, &sdo->data.pub_key);
		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PUBLIC KEY data");

		free(tlv.value);
	}
	else if (tlv.tag == IASECC_SDO_PRVKEY_TAG)   {
		if (sdo->sdo_class != IASECC_SDO_CLASS_RSA_PRIVATE)
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_PRIVATE_KEY tag in non PRIVATE_KEY SDO");

		rv = iasecc_parse_prvkey(card, tlv.value, tlv.size, &sdo->data.prv_key);
		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO PRIVATE KEY data");

		free(tlv.value);
	}
	else if (tlv.tag == IASECC_SDO_KEYSET_TAG)   {
		if (sdo->sdo_class != IASECC_SDO_CLASS_KEYSET)
			LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "parse error: SDO_KEYSET tag in non KEYSET SDO");

		rv = iasecc_parse_keyset(card, tlv.value, tlv.size, &sdo->data.keyset);
		LOG_TEST_RET(ctx, rv, "parse error: cannot parse SDO KEYSET data");

		free(tlv.value);
	}
	else   {
		sc_log(ctx, "iasecc_sdo_parse_data() non supported tag 0x%X", tlv.tag);
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
	}

	return tlv_size;
}
예제 #10
0
/*
 * Get 'Initialize Applet' data
 * 	using the ACLs defined in card profile.
 */
static int
myeid_get_init_applet_data(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
		unsigned char *data, size_t data_len) {
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_file *tmp_file = NULL;
	const struct sc_acl_entry *entry = NULL;
	int r;

	LOG_FUNC_CALLED(ctx);

	if (data_len < 8)
		LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "Cannot get init applet data");

	*(data + 0) = 0xFF;
	*(data + 1) = 0xFF;

	/* MF acls */
	sc_file_dup(&tmp_file, profile->mf_info->file);
	if (tmp_file == NULL)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate MF file");
	r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
	LOG_TEST_RET(ctx, r, "MF fixup failed");

	/* AC 'Create DF' and 'Create EF' */
	*(data + 2) = 0x00; /* 'NONE' */
	entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE);
	if (entry->method == SC_AC_CHV)
		*(data + 2) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx'. */
	else if (entry->method == SC_AC_NEVER)
		*(data + 2) = 0xFF; /* 'NEVER'. */

	/* AC 'INITIALISE APPLET'. */
	*(data + 3) = 0x0F; /* 'NONE' */
#ifndef KEEP_AC_NONE_FOR_INIT_APPLET
	entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE);
	if (entry->method == SC_AC_CHV)
		*(data + 3) = (entry->key_ref << 4) | 0xF;
	else if (entry->method == SC_AC_NEVER)
		*(data + 3) = 0xFF;
#endif
	*(data + 4) = 0xFF;

	sc_file_free(tmp_file);
	tmp_file = NULL;

	/* Application DF (5015) acls */
	sc_file_dup(&tmp_file, profile->df_info->file);
	if (tmp_file == NULL)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot duplicate Application DF file");
	r = sc_pkcs15init_fixup_file(profile, p15card, tmp_file);
	LOG_TEST_RET(ctx, r, "Application DF fixup failed");

	/* AC 'Create DF' and 'Create EF' */
	*(data + 5) = 0x00; /* 'NONE' */
	entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_CREATE);
	if (entry->method == SC_AC_CHV)
		*(data + 5) = entry->key_ref | (entry->key_ref << 4); /* 'CHVx' */
	else if (entry->method == SC_AC_NEVER)
		*(data + 5) = 0xFF; /* 'NEVER'. */

	/* AC 'Self delete' */
	*(data + 6) = 0x0F; /* 'NONE' */
	entry = sc_file_get_acl_entry(tmp_file, SC_AC_OP_DELETE);
	if (entry->method == SC_AC_CHV)
		*(data + 6) = (entry->key_ref << 4) | 0xF; /* 'CHVx' */
	else if (entry->method == SC_AC_NEVER)
		*(data + 6) = 0xFF; /* 'NEVER'. */
	*(data + 7) = 0xFF;
	sc_file_free(tmp_file);

	LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}
예제 #11
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:
			if (sc_card_find_ec_alg(p15card->card, keybits) == NULL)
				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
			if(key_info->field_length != 0)
				keybits = key_info->field_length;
			else 
				key_info->field_length = keybits;
				
			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");

			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);
}
예제 #12
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:
			if (sc_card_find_ec_alg(p15card->card, keybits) == NULL)
				LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Unsupported EC key size");
			if(key_info->field_length != 0)
				keybits = key_info->field_length;
			else 
				key_info->field_length = keybits;
				
			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);
}
예제 #13
0
/* For Myeid, all objects are files that can be deleted in any order */
static int
myeid_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
		struct sc_pkcs15_object *object, const struct sc_path *path) {
	LOG_FUNC_CALLED(p15card->card->ctx);
	return sc_pkcs15init_delete_by_path(profile, p15card, path);
}
예제 #14
0
/*
 * @brief Import a private key.
 */
static int
isoApplet_ctl_import_key(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args)
{
	int r;
	sc_apdu_t apdu;
	u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
	u8 *p;

	LOG_FUNC_CALLED(card->ctx);

	/*
	 * Private keys are not stored in the filesystem.
	 * ISO 7816-8 - section C.2	 describes:
	 * "Usage of the PUT DATA command for private key import"
	 * The applet uses this PUT DATA to import private keys, if private key import is allowed.
	 *
	 * The first step is to perform a MANAGE SECURITY ENVIRONMENT as it would be done
	 * with on-card key generation. The second step is PUT DATA (instead of
	 * GENERATE ASYMMETRIC KEYPAIR).
	 */

	/* MANAGE SECURITY ENVIRONMENT (SET). Set the algorithm and key references. */
	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0x00);

	p = sbuf;
	*p++ = 0x80; /* algorithm reference */
	*p++ = 0x01;
	*p++ = args->algorithm_ref;

	*p++ = 0x84; /* Private key reference */
	*p++ = 0x01;
	*p++ = args->priv_key_ref;

	r = p - sbuf;
	p = NULL;

	apdu.lc = r;
	apdu.datalen = r;
	apdu.data = sbuf;

	r = sc_transmit_apdu(card, &apdu);
	LOG_TEST_RET(card->ctx, r, "%s: APDU transmit failed");

	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	LOG_TEST_RET(card->ctx, r, "Card returned error");


	/* PUT DATA */
	switch(args->algorithm_ref)
	{

	case SC_ISOAPPLET_ALG_REF_RSA_GEN_2048:
		r = isoApplet_put_data_prkey_rsa(card, args);
		LOG_TEST_RET(card->ctx, r, "Error in PUT DATA.");
		break;

	case SC_ISOAPPLET_ALG_REF_EC_GEN:
		r = isoApplet_put_data_prkey_ec(card, args);
		LOG_TEST_RET(card->ctx, r, "Error in PUT DATA.");
		break;

	default:
		LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Uknown algorithm refernce.");
	}

	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
예제 #15
0
static int sc_pkcs15emu_pteid_init(sc_pkcs15_card_t * p15card)
{
	u8 buf[1024];
	sc_pkcs15_df_t *df;
	sc_pkcs15_object_t *p15_obj;
	sc_path_t path;
	struct sc_file *file = NULL;
	size_t len;
	int rv;
	int i;

	sc_context_t *ctx = p15card->card->ctx;
	LOG_FUNC_CALLED(ctx);

	/* Check for correct card atr */
	if (pteid_detect_card(p15card->card) != SC_SUCCESS)
		return SC_ERROR_WRONG_CARD;

	sc_log(p15card->card->ctx, "Selecting application DF");
	sc_format_path("4F00", &path);
	rv = sc_select_file(p15card->card, &path, &file);
	if (rv != SC_SUCCESS || !file)
		return SC_ERROR_INTERNAL;
	/* set the application DF */
	if (p15card->file_app)
		free(p15card->file_app);
	p15card->file_app = file;

	/* Load TokenInfo */
	len = sizeof(buf);
	rv = dump_ef(p15card->card, "4F005032", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	memset(p15card->tokeninfo, 0, sizeof(*p15card->tokeninfo));
	rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo,
				       buf, len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	p15card->tokeninfo->flags |= SC_PKCS15_TOKEN_PRN_GENERATION
				  | SC_PKCS15_TOKEN_EID_COMPLIANT
				  | SC_PKCS15_TOKEN_READONLY;

	/* Load ODF */
	len = sizeof(buf);
	rv = dump_ef(p15card->card, "4F005031", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	rv = parse_odf(buf, len, p15card);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	/* Decode EF.PrKDF, EF.PuKDF, EF.CDF and EF.AODF */
	for (df = p15card->df_list; df != NULL; df = df->next) {
		if (df->type == SC_PKCS15_PRKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PrKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_PUKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PuKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_CDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.CDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_AODF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.AODF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
	}

	p15_obj = p15card->obj_list;
	while (p15_obj != NULL) {
		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PRKDF) ) {
			struct sc_pkcs15_prkey_info *prkey_info = (sc_pkcs15_prkey_info_t *) p15_obj->data;
			prkey_info->access_flags = SC_PKCS15_PRKEY_ACCESS_SENSITIVE
					| SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
					| SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
					| SC_PKCS15_PRKEY_ACCESS_LOCAL;
			p15_obj->flags = SC_PKCS15_CO_FLAG_PRIVATE;
		}


		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_AODF) ) {
			static const char *pteid_pin_names[3] = {
			    "Auth PIN",
			    "Sign PIN",
			    "Address PIN"
			};

			struct sc_pin_cmd_data pin_cmd_data;
			struct sc_pkcs15_auth_info *pin_info = (sc_pkcs15_auth_info_t *) p15_obj->data;

			strlcpy(p15_obj->label, pteid_pin_names[pin_info->auth_id.value[0]-1], sizeof(p15_obj->label));

			pin_info->attrs.pin.flags |= SC_PKCS15_PIN_FLAG_NEEDS_PADDING;
			pin_info->tries_left = -1;
			pin_info->max_tries = 3;
			pin_info->auth_method = SC_AC_CHV;

			memset(&pin_cmd_data, 0, sizeof(pin_cmd_data));
			pin_cmd_data.cmd = SC_PIN_CMD_GET_INFO;
			pin_cmd_data.pin_type = pin_info->attrs.pin.type;
			pin_cmd_data.pin_reference = pin_info->attrs.pin.reference;
			rv = sc_pin_cmd(p15card->card, &pin_cmd_data, NULL);
			if (rv == SC_SUCCESS) {
				pin_info->tries_left = pin_cmd_data.pin1.tries_left;
				pin_info->logged_in = pin_cmd_data.pin1.logged_in;
			}
		}
		/* Remove found public keys as cannot be read_binary()'d */
		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) {
			sc_pkcs15_object_t *puk = p15_obj;
			p15_obj = p15_obj->next;
			sc_pkcs15_remove_object(p15card, puk);
			sc_pkcs15_free_object(puk);
		} else {
			p15_obj = p15_obj->next;
		}
	}

	/* Add data objects */
	for (i = 0; i < 5; i++) {
		static const char *object_labels[5] = {
			"Trace",
			"Citizen Data",
			"Citizen Address Data",
			"SOd",
			"Citizen Notepad",
		};
		static const char *object_authids[5] = {NULL, NULL, "3", NULL, NULL};
		static const char *object_paths[5] = {
			"3f000003",
			"3f005f00ef02",
			"3f005f00ef05",
			"3f005f00ef06",
			"3f005f00ef07",
		};
		static const int object_flags[5] = {
			0,
			0,
			SC_PKCS15_CO_FLAG_PRIVATE,
			0,
			0,
		};
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object obj_obj;

		memset(&obj_info, 0, sizeof(obj_info));
		memset(&obj_obj, 0, sizeof(obj_obj));

		sc_format_path(object_paths[i], &obj_info.path);
		strlcpy(obj_info.app_label, object_labels[i], SC_PKCS15_MAX_LABEL_SIZE);
		if (object_authids[i] != NULL)
			sc_pkcs15_format_id(object_authids[i], &obj_obj.auth_id);
		strlcpy(obj_obj.label, object_labels[i], SC_PKCS15_MAX_LABEL_SIZE);
		obj_obj.flags = object_flags[i];

		rv = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, &obj_obj, &obj_info);
		if (rv != SC_SUCCESS){
			sc_log(ctx, "Object add failed: %d", rv);
			break;
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
예제 #16
0
파일: iasecc-sdo.c 프로젝트: pawmas/opensc
LIBOPENSC_API int
iasecc_sdo_convert_acl(struct sc_card *card, struct iasecc_sdo *sdo,
		unsigned char op, unsigned *out_method, unsigned *out_ref)
{
	struct sc_context *ctx = card->ctx;
	struct acl_op {
		unsigned char op;
		unsigned char mask;
	} ops[] = {
		{SC_AC_OP_PSO_COMPUTE_SIGNATURE,IASECC_ACL_PSO_SIGNATURE},
		{SC_AC_OP_INTERNAL_AUTHENTICATE,IASECC_ACL_INTERNAL_AUTHENTICATE},
		{SC_AC_OP_PSO_DECRYPT,	IASECC_ACL_PSO_DECIPHER},
		{SC_AC_OP_GENERATE,	IASECC_ACL_GENERATE_KEY},
		{SC_AC_OP_UPDATE,	IASECC_ACL_PUT_DATA},
		{SC_AC_OP_READ,		IASECC_ACL_GET_DATA},
		{0x00, 0x00}
	};
	unsigned char mask = 0x80, op_mask;
	int ii;

	LOG_FUNC_CALLED(ctx);

	for (ii=0; ops[ii].mask; ii++)   {
		if (op == ops[ii].op)   {
			op_mask = ops[ii].mask;
			break;
		}
	}
	if (ops[ii].mask == 0)
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	sc_log(ctx, "OP:%i, mask:0x%X", op, ops[ii].mask);
	sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS));
	sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size));

	if (!sdo->docp.amb && sdo->docp.acls_contact.size)   {
		int rv = iasecc_parse_acls(card, &sdo->docp, 0);
		LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP");
	}

	*out_method = SC_AC_NEVER;
	*out_ref = SC_AC_NEVER;

	for (ii=0; ii<7; ii++)   {
		mask >>= 1;
		if (sdo->docp.amb & mask)   {
			if (op_mask == mask)   {
				unsigned char scb = sdo->docp.scbs[ii];
				sc_log(ctx, "ii:%i, scb:0x%X", ii, scb);

				*out_ref = scb & 0x0F;
				if (scb == 0)
					*out_method = SC_AC_NONE;
				else if (scb == 0xFF)
					*out_method = SC_AC_NEVER;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH)
					*out_method = SC_AC_SEN;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_EXT_AUTH)
					*out_method = SC_AC_AUT;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_SM)
					*out_method = SC_AC_PRO;
				else
					*out_method = SC_AC_SCB, *out_ref = scb;

				break;
			}
		}
	}

	sc_log(ctx, "returns method %X; ref %X", *out_method, *out_ref);
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
예제 #17
0
파일: apdu.c 프로젝트: pawmas/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);
}
예제 #18
0
int
sm_gp_external_authentication(struct sc_context *ctx, struct sm_info *sm_info,
		unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata,
		int (*diversify_keyset)(struct sc_context *ctx,
				struct sm_info *sm_info,
				unsigned char *idata, size_t idata_len))
{
	struct sc_remote_apdu *new_rapdu = NULL;
	struct sc_apdu *apdu = NULL;
	unsigned char host_cryptogram[8], raw_apdu[SC_MAX_APDU_BUFFER_SIZE];
	struct sm_gp_session *gp_session = &sm_info->session.gp;
	DES_cblock mac;
	int rv, offs = 0;

	LOG_FUNC_CALLED(ctx);
	if (!sm_info || !init_data || !rdata || !rdata->alloc)
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (init_len != 0x1C)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "SM GP authentication: invalid auth data length");

	rv = sm_gp_parse_init_data(ctx, gp_session, init_data, init_len);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: 'INIT DATA' parse error");

	if (diversify_keyset)   {
		rv = (*diversify_keyset)(ctx, sm_info, init_data, init_len);
		LOG_TEST_RET(ctx, rv, "SM GP authentication: keyset diversification error");
	}

	rv = sm_gp_init_session(ctx, gp_session, init_data + 20, 8);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: init session error");

	rv = sm_gp_get_cryptogram(gp_session->session_enc,
			gp_session->card_challenge, gp_session->host_challenge,
			host_cryptogram, sizeof(host_cryptogram));
	LOG_TEST_RET(ctx, rv, "SM GP authentication: get host cryptogram error");

	sc_log(ctx, "SM GP authentication: host_cryptogram:%s", sc_dump_hex(host_cryptogram, 8));

	rv = rdata->alloc(rdata, &new_rapdu);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: cannot allocate remote APDU");
	apdu = &new_rapdu->apdu;

	offs = 0;
	apdu->cse = SC_APDU_CASE_3_SHORT;
	apdu->cla = raw_apdu[offs++] = 0x84;
	apdu->ins = raw_apdu[offs++] = 0x82;
	apdu->p1  = raw_apdu[offs++] = gp_session->params.level;
	apdu->p2  = raw_apdu[offs++] = 0;
	apdu->lc  = raw_apdu[offs++] = 0x10;
	apdu->datalen = 0x10;

	memcpy(raw_apdu + offs, host_cryptogram, 8);
	offs += 8;
	rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, raw_apdu, offs, &mac);
	LOG_TEST_RET(ctx, rv, "SM GP authentication: get MAC error");

	memcpy(new_rapdu->sbuf, host_cryptogram, 8);
	memcpy(new_rapdu->sbuf + 8, mac, 8);
	memcpy(gp_session->mac_icv, mac, 8);

	LOG_FUNC_RETURN(ctx, 1);
}
예제 #19
0
파일: iasecc-sm.c 프로젝트: fbezdeka/OpenSC
int
iasecc_sm_external_authentication(struct sc_card *card, unsigned skey_ref, int *tries_left)
{
	struct sc_context *ctx = card->ctx;
#ifdef ENABLE_SM
	struct sm_info *sm_info = &card->sm_ctx.info;
	struct sm_cwa_session *cwa_session = &sm_info->session.cwa;
	struct sc_remote_data rdata;
	struct sc_apdu apdu;
	unsigned char sbuf[0x100];
	int rv, offs;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "iasecc_sm_external_authentication(): SKey ref %i", skey_ref);

	if (card->sm_ctx.sm_mode == SM_MODE_NONE)
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot do 'External Authentication' without SM activated ");

	strlcpy(sm_info->config_section, card->sm_ctx.config_section, sizeof(sm_info->config_section));
	sm_info->cmd = SM_CMD_EXTERNAL_AUTH;
	sm_info->serialnr = card->serialnr;
	sm_info->card_type = card->type;
	sm_info->sm_type = SM_TYPE_CWA14890;
	cwa_session->params.crt_at.usage = IASECC_UQB_AT_EXTERNAL_AUTHENTICATION;
	cwa_session->params.crt_at.algo = IASECC_ALGORITHM_ROLE_AUTH;
	cwa_session->params.crt_at.refs[0] = skey_ref;

	offs = 0;
	sbuf[offs++] = IASECC_CRT_TAG_ALGO;
	sbuf[offs++] = 0x01;
	sbuf[offs++] = IASECC_ALGORITHM_ROLE_AUTH;
	sbuf[offs++] = IASECC_CRT_TAG_REFERENCE;
	sbuf[offs++] = 0x01;
	sbuf[offs++] = skey_ref;

	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x81, 0xA4);
	apdu.data = sbuf;
	apdu.datalen = offs;
	apdu.lc = offs;

	rv = sc_transmit_apdu(card, &apdu);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): APDU transmit failed");
	rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
	LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error");

	rv = sc_get_challenge(card, cwa_session->card_challenge, sizeof(cwa_session->card_challenge));
	LOG_TEST_RET(ctx, rv, "iasecc_sm_external_authentication(): set SE error");

	sc_remote_data_init(&rdata);

	if (!card->sm_ctx.module.ops.initialize)
		LOG_TEST_RET(ctx, SC_ERROR_SM_NOT_INITIALIZED, "No SM module");
	rv = card->sm_ctx.module.ops.initialize(ctx, sm_info, &rdata);
	LOG_TEST_RET(ctx, rv, "SM: INITIALIZE failed");

	sc_log(ctx, "sm_iasecc_external_authentication(): rdata length %i\n", rdata.length);

	rv = iasecc_sm_transmit_apdus (card, &rdata, NULL, 0);
	if (rv == SC_ERROR_PIN_CODE_INCORRECT && tries_left)
		*tries_left = (rdata.data + rdata.length - 1)->apdu.sw2 & 0x0F;
	LOG_TEST_RET(ctx, rv, "sm_iasecc_external_authentication(): execute failed");

	LOG_FUNC_RETURN(ctx, rv);
#else
	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "built without support of SM and External Authentication");
	return SC_ERROR_NOT_SUPPORTED;
#endif
}
예제 #20
0
int
sm_gp_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info,
		char *init_data, struct sc_apdu *apdu)
{
	unsigned char  buff[SC_MAX_APDU_BUFFER_SIZE + 24];
	unsigned char *apdu_data = NULL;
	struct sm_gp_session *gp_session = &sm_info->session.gp;
	unsigned gp_level = sm_info->session.gp.params.level;
	unsigned gp_index = sm_info->session.gp.params.index;
	DES_cblock mac;
	unsigned char *encrypted = NULL;
	size_t encrypted_len = 0;
	int rv;

	LOG_FUNC_CALLED(ctx);

	apdu_data = (unsigned char *)apdu->data;
	sc_log(ctx, "SM GP securize APDU(cse:%X,cla:%X,ins:%X,data(len:%i,%p),lc:%i,GP level:%X,GP index:%X",
				apdu->cse, apdu->cla, apdu->ins, apdu->datalen, apdu->data,
				apdu->lc, gp_level, gp_index);

	if (gp_level == 0 || (apdu->cla & 0x04))
		return 0;

	if (gp_level == SM_GP_SECURITY_MAC)   {
		if (apdu->datalen + 8 > SC_MAX_APDU_BUFFER_SIZE)
			LOG_TEST_RET(ctx, SC_ERROR_WRONG_LENGTH, "SM GP securize APDU: too much data");
	}
	else if (gp_level == SM_GP_SECURITY_ENC)   {
		if (!gp_session->session_enc)
			LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_SESSION_KEY, "SM GP securize APDU: no ENC session key found");

		if (sm_gp_encrypt_command_data(ctx, gp_session->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len))
			LOG_TEST_RET(ctx, SC_ERROR_SM_ENCRYPT_FAILED, "SM GP securize APDU: data encryption error");

		if (encrypted_len + 8 > SC_MAX_APDU_BUFFER_SIZE)
			LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "SM GP securize APDU: not enough place for encrypted data");

		sc_log(ctx, "SM GP securize APDU: encrypted length %i", encrypted_len);
	}
	else   {
		LOG_TEST_RET(ctx, SC_ERROR_SM_INVALID_LEVEL, "SM GP securize APDU: invalid SM level");
	}

	buff[0] = apdu->cla | 0x04;
	buff[1] = apdu->ins;
	buff[2] = apdu->p1;
	buff[3] = apdu->p2;
	buff[4] = apdu->lc + 8;

	memcpy(buff + 5, apdu_data, apdu->datalen);

	rv = sm_gp_get_mac(gp_session->session_mac, &gp_session->mac_icv, buff, 5 + apdu->datalen, &mac);
	LOG_TEST_RET(ctx, rv, "SM GP securize APDU: get MAC error");

	if (gp_level == SM_GP_SECURITY_MAC)   {
		memcpy(apdu_data + apdu->datalen, mac, 8);

		apdu->cla |= 0x04;
		apdu->datalen += 8;
		apdu->lc = apdu->datalen;

		if (apdu->cse==SC_APDU_CASE_2_SHORT)
			apdu->cse = SC_APDU_CASE_4_SHORT;
	}
	else if (gp_level == SM_GP_SECURITY_ENC)   {
		memcpy(apdu_data + encrypted_len, mac, 8);
		if (encrypted_len)
			memcpy(apdu_data, encrypted, encrypted_len);

		apdu->cla |= 0x04;
		apdu->datalen = encrypted_len + 8;
		apdu->lc = encrypted_len + 8;

		if (apdu->cse == SC_APDU_CASE_2_SHORT)
			apdu->cse = SC_APDU_CASE_4_SHORT;

		if (apdu->cse == SC_APDU_CASE_1)
			apdu->cse = SC_APDU_CASE_3_SHORT;

		free(encrypted);
	}

	memcpy(sm_info->session.gp.mac_icv, mac, 8);

	LOG_FUNC_RETURN(ctx, rv);
}
/*
 * Initialize PKCS#15 emulation with user PIN, private keys, certificate and data objects
 *
 */
static int sc_pkcs15emu_sc_hsm_init (sc_pkcs15_card_t * p15card)
{
    sc_card_t *card = p15card->card;
    sc_file_t *file = NULL;
    sc_path_t path;
    u8 filelist[MAX_EXT_APDU_LENGTH];
    int filelistlength;
    int r, i;
    sc_cvc_t devcert;
    struct sc_app_info *appinfo;
    struct sc_pkcs15_auth_info pin_info;
    struct sc_pkcs15_object pin_obj;
    u8 efbin[512];
    u8 *ptr;
    size_t len;

    LOG_FUNC_CALLED(card->ctx);

    appinfo = calloc(1, sizeof(struct sc_app_info));

    if (appinfo == NULL) {
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
    }

    appinfo->aid = sc_hsm_aid;

    appinfo->ddo.aid = sc_hsm_aid;
    p15card->app = appinfo;

    sc_path_set(&path, SC_PATH_TYPE_DF_NAME, sc_hsm_aid.value, sc_hsm_aid.len, 0, 0);
    r = sc_select_file(card, &path, &file);
    LOG_TEST_RET(card->ctx, r, "Could not select SmartCard-HSM application");

    p15card->card->version.hw_major = 24;	/* JCOP 2.4.1r3 */
    p15card->card->version.hw_minor = 13;
    p15card->card->version.fw_major = file->prop_attr[file->prop_attr_len - 2];
    p15card->card->version.fw_minor = file->prop_attr[file->prop_attr_len - 1];

    sc_file_free(file);

    /* Read device certificate to determine serial number */
    sc_path_set(&path, SC_PATH_TYPE_FILE_ID, (u8 *) "\x2F\x02", 2, 0, 0);
    r = sc_select_file(card, &path, &file);
    LOG_TEST_RET(card->ctx, r, "Could not select EF.C_DevAut");
    sc_file_free(file);

    r = sc_read_binary(p15card->card, 0, efbin, sizeof(efbin), 0);
    LOG_TEST_RET(card->ctx, r, "Could not read EF.C_DevAut");

    ptr = efbin;
    len = r;

    memset(&devcert, 0 ,sizeof(devcert));
    r = sc_pkcs15emu_sc_hsm_decode_cvc(p15card, (const u8 **)&ptr, &len, &devcert);
    LOG_TEST_RET(card->ctx, r, "Could not decode EF.C_DevAut");

    sc_pkcs15emu_sc_hsm_read_tokeninfo(p15card);

    if (p15card->tokeninfo->label == NULL) {
        p15card->tokeninfo->label = strdup("SmartCard-HSM");
        if (p15card->tokeninfo->label == NULL)
            LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
    }

    if ((p15card->tokeninfo->manufacturer_id != NULL) && !strcmp("(unknown)", p15card->tokeninfo->manufacturer_id)) {
        free(p15card->tokeninfo->manufacturer_id);
        p15card->tokeninfo->manufacturer_id = NULL;
    }

    if (p15card->tokeninfo->manufacturer_id == NULL) {
        p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de");
        if (p15card->tokeninfo->manufacturer_id == NULL)
            LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
    }

    appinfo->label = strdup(p15card->tokeninfo->label);
    if (appinfo->label == NULL)
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);

    len = strlen(devcert.chr);		/* Strip last 5 digit sequence number from CHR */
    assert(len >= 8);
    len -= 5;

    p15card->tokeninfo->serial_number = calloc(len + 1, 1);
    if (p15card->tokeninfo->serial_number == NULL)
        LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);

    memcpy(p15card->tokeninfo->serial_number, devcert.chr, len);
    *(p15card->tokeninfo->serial_number + len) = 0;

    sc_hsm_set_serialnr(card, p15card->tokeninfo->serial_number);

    sc_pkcs15emu_sc_hsm_free_cvc(&devcert);

    memset(&pin_info, 0, sizeof(pin_info));
    memset(&pin_obj, 0, sizeof(pin_obj));

    pin_info.auth_id.len = 1;
    pin_info.auth_id.value[0] = 1;
    pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
    pin_info.attrs.pin.reference = 0x81;
    pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_EXCHANGE_REF_DATA;
    pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
    pin_info.attrs.pin.min_length = 6;
    pin_info.attrs.pin.stored_length = 0;
    pin_info.attrs.pin.max_length = 15;
    pin_info.attrs.pin.pad_char = '\0';
    pin_info.tries_left = 3;
    pin_info.max_tries = 3;

    strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label));
    pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE|SC_PKCS15_CO_FLAG_MODIFIABLE;

    r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
    if (r < 0)
        LOG_FUNC_RETURN(card->ctx, r);


    memset(&pin_info, 0, sizeof(pin_info));
    memset(&pin_obj, 0, sizeof(pin_obj));

    pin_info.auth_id.len = 1;
    pin_info.auth_id.value[0] = 2;
    pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
    pin_info.attrs.pin.reference = 0x88;
    pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_LOCAL|SC_PKCS15_PIN_FLAG_CHANGE_DISABLED|SC_PKCS15_PIN_FLAG_INITIALIZED|SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED|SC_PKCS15_PIN_FLAG_SO_PIN;
    pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_BCD;
    pin_info.attrs.pin.min_length = 16;
    pin_info.attrs.pin.stored_length = 0;
    pin_info.attrs.pin.max_length = 16;
    pin_info.attrs.pin.pad_char = '\0';
    pin_info.tries_left = 3;
    pin_info.max_tries = 3;

    strlcpy(pin_obj.label, "SOPIN", sizeof(pin_obj.label));
    pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;

    r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
    if (r < 0)
        LOG_FUNC_RETURN(card->ctx, r);


    filelistlength = sc_list_files(card, filelist, sizeof(filelist));
    LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier");

    for (i = 0; i < filelistlength; i += 2) {
        switch(filelist[i]) {
        case KEY_PREFIX:
            r = sc_pkcs15emu_sc_hsm_add_prkd(p15card, filelist[i + 1]);
            break;
        case DCOD_PREFIX:
            r = sc_pkcs15emu_sc_hsm_add_dcod(p15card, filelist[i + 1]);
            break;
        case CD_PREFIX:
            r = sc_pkcs15emu_sc_hsm_add_cd(p15card, filelist[i + 1]);
            break;
        }
        if (r != SC_SUCCESS) {
            sc_log(card->ctx, "Error %d adding elements to framework", r);
        }
    }

    LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
예제 #22
0
int
sm_gp_decode_card_answer(struct sc_context *ctx, struct sc_remote_data *rdata, unsigned char *out, size_t out_len)
{
#if 0
	struct sc_asn1_entry asn1_authentic_card_response[4], asn1_card_response[2];
	struct sc_hash *hash = NULL;
	unsigned char *hex = NULL;
	size_t hex_len;
	int rv, offs;
	unsigned char card_data[SC_MAX_APDU_BUFFER_SIZE];
	size_t card_data_len = sizeof(card_data), len_left = 0;

	LOG_FUNC_CALLED(ctx);

	if (!out || !out_len)
		LOG_FUNC_RETURN(ctx, 0);
	if (strstr(str_data, "DATA="))   {
		rv = sc_hash_parse(ctx, str_data, strlen(str_data), &hash);
		LOG_TEST_RET(ctx, rv, "SM GP decode card answer: parse input data error");

		str_data = sc_hash_get(hash, "DATA");
	}

	if (!strlen(str_data))
		LOG_FUNC_RETURN(ctx, 0);

	hex_len = strlen(str_data) / 2;
	hex = calloc(1, hex_len);
	if (!hex)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "SM GP decode card answer: hex allocate error");

	sc_log(ctx, "SM GP decode card answer: hex length %i", hex_len);
	rv = sc_hex_to_bin(str_data, hex, &hex_len);
	LOG_TEST_RET(ctx, rv, "SM GP decode card answer: data 'HEX to BIN' conversion error");
	sc_log(ctx, "SM GP decode card answer: hex length %i", hex_len);

	if (hash)
		sc_hash_free(hash);

	for (offs = 0, len_left = hex_len; len_left; )   {
		int num, status;

		sc_copy_asn1_entry(c_asn1_authentic_card_response, asn1_authentic_card_response);
		sc_copy_asn1_entry(c_asn1_card_response, asn1_card_response);
		sc_format_asn1_entry(asn1_authentic_card_response + 0, &num, NULL, 0);
		sc_format_asn1_entry(asn1_authentic_card_response + 1, &status, NULL, 0);
		card_data_len = sizeof(card_data);
		sc_format_asn1_entry(asn1_authentic_card_response + 2, &card_data, &card_data_len, 0);
		sc_format_asn1_entry(asn1_card_response + 0, asn1_authentic_card_response, NULL, 0);

		rv = sc_asn1_decode(ctx, asn1_card_response, hex + hex_len - len_left, len_left, NULL, &len_left);
		if (rv) {
			sc_log(ctx, "SM GP decode card answer: ASN.1 parse error: %s", sc_strerror(rv));
			return rv;
		}
		if (status != 0x9000)
			continue;

		if (asn1_authentic_card_response[2].flags & SC_ASN1_PRESENT)   {
			sc_log(ctx, "SM GP decode card answer: card_data_len %i", card_data_len);
			if (out_len < offs + card_data_len)
				LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "SM GP decode card answer: buffer too small");

			memcpy(out + offs, card_data, card_data_len);
			offs += card_data_len;
		}

		sc_log(ctx, "SM GP decode card answer: offs:%i,left:%i", offs, len_left);
	}

	free(hex);
	LOG_FUNC_RETURN(ctx, offs);
#else
	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
#endif
}
예제 #23
0
파일: dir.c 프로젝트: AktivCo/OpenSC
int sc_enum_apps(sc_card_t *card)
{
	struct sc_context *ctx = card->ctx;
	sc_path_t path;
	int ef_structure;
	size_t file_size, jj;
	int r, ii, idx;

	LOG_FUNC_CALLED(ctx);
	if (card->app_count < 0)
		card->app_count = 0;

	sc_format_path("3F002F00", &path);
	sc_file_free(card->ef_dir);
	card->ef_dir = NULL;
	r = sc_select_file(card, &path, &card->ef_dir);
	LOG_TEST_RET(ctx, r, "Cannot select EF.DIR file");

	if (card->ef_dir->type != SC_FILE_TYPE_WORKING_EF) {
		sc_file_free(card->ef_dir);
		card->ef_dir = NULL;
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_CARD, "EF(DIR) is not a working EF.");
	}

	ef_structure = card->ef_dir->ef_structure;
	if (ef_structure == SC_FILE_EF_TRANSPARENT) {
		u8 *buf = NULL, *p;
		size_t bufsize;

		file_size = card->ef_dir->size;
		if (file_size == 0)
			LOG_FUNC_RETURN(ctx, 0);

		buf = malloc(file_size);
		if (buf == NULL)
			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
		p = buf;
		r = sc_read_binary(card, 0, buf, file_size, 0);
		if (r < 0) {
			free(buf);
			LOG_TEST_RET(ctx, r, "sc_read_binary() failed");
		}
		bufsize = r;
		while (bufsize > 0) {
			if (card->app_count == SC_MAX_CARD_APPS) {
				sc_log(ctx, "Too many applications on card");
				break;
			}
			r = parse_dir_record(card, &p, &bufsize, -1);
			if (r)
				break;
		}
		if (buf)
			free(buf);

	}
	else {	/* record structure */
		unsigned char buf[256], *p;
		unsigned int rec_nr;
		size_t rec_size;

		/* Arbitrary set '16' as maximal number of records to check out:
		 * to avoid endless loop because of some incomplete cards/drivers */
		for (rec_nr = 1; rec_nr < 16; rec_nr++) {
			r = sc_read_record(card, rec_nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
			if (r == SC_ERROR_RECORD_NOT_FOUND)
				break;
			LOG_TEST_RET(ctx, r, "read_record() failed");

			if (card->app_count == SC_MAX_CARD_APPS) {
				sc_log(ctx, "Too many applications on card");
				break;
			}

			rec_size = r;
			p = buf;
			parse_dir_record(card, &p, &rec_size, (int)rec_nr);
		}
	}

	/* Move known PKCS#15 applications to the head of the list */
	for (ii=0, idx=0; ii<card->app_count; ii++)   {
		for (jj=0; jj < sizeof(apps)/sizeof(apps[0]); jj++) {
			if (apps[jj].aid_len != card->app[ii]->aid.len)
				continue;
			if (memcmp(apps[jj].aid, card->app[ii]->aid.value, apps[jj].aid_len))
				continue;
			break;
		}

		if (ii != idx && jj < sizeof(apps)/sizeof(apps[0]))   {
			struct sc_app_info *tmp = card->app[idx];

			card->app[idx] = card->app[ii];
			card->app[ii] = tmp;
			idx++;
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
예제 #24
0
/**
 * Select a file from card, process fci and read data.
 *
 * This is done by mean of iso_select_file() and iso_read_binary()
 *
 * @param card pointer to sc_card data
 * @param path pathfile
 * @param file pointer to resulting file descriptor
 * @param buffer pointer to buffer where to store file contents
 * @param length length of buffer data
 * @return SC_SUCCESS if ok; else error code
 */
int dnie_read_file(sc_card_t * card,
		   const sc_path_t * path,
		   sc_file_t ** file, u8 ** buffer, size_t * length)
{
	u8 *data = NULL;
	char *msg = NULL;
	int res = SC_SUCCESS;
	size_t fsize = 0;	/* file size */
	sc_context_t *ctx = NULL;

	if (!card || !card->ctx)
		return SC_ERROR_INVALID_ARGUMENTS;
	ctx = card->ctx;
	LOG_FUNC_CALLED(card->ctx);
	if (!buffer || !length || !path)	/* check received arguments */
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
	/* select file by mean of iso7816 ops */
	res = card->ops->select_file(card, path, file);
	if (res != SC_SUCCESS || !file || !(*file)) {
		msg = "select_file failed";
		goto dnie_read_file_err;
	}
	/* iso's select file calls if needed process_fci, so arriving here
	 * we have file structure filled.
	 */
	if ((*file)->type == SC_FILE_TYPE_DF) {
		/* just a DF, no need to read_binary() */
		*buffer = NULL;
		*length = 0;
		res = SC_SUCCESS;
		msg = "File is a DF: no need to read_binary()";
		goto dnie_read_file_end;
	}
	fsize = (*file)->size;
	/* reserve enought space to read data from card */
	if (fsize <= 0) {
		res = SC_ERROR_FILE_TOO_SMALL;
		msg = "provided buffer size is too small";
		goto dnie_read_file_err;
	}
	data = calloc(fsize, sizeof(u8));
	if (data == NULL) {
		res = SC_ERROR_OUT_OF_MEMORY;
		msg = "cannot reserve requested buffer size";
		goto dnie_read_file_err;
	}
	/* call sc_read_binary() to retrieve data */
	sc_log(ctx, "read_binary(): expected '%d' bytes", fsize);
	res = sc_read_binary(card, 0, data, fsize, 0L);
	if (res < 0) {		/* read_binary returns number of bytes readed */
		res = SC_ERROR_CARD_CMD_FAILED;
		msg = "read_binary() failed";
		goto dnie_read_file_err;
	}
	*buffer = data;
	*length = res;
	/* arriving here means success */
	res = SC_SUCCESS;
	goto dnie_read_file_end;
 dnie_read_file_err:
	if (data)
		free(data);
	if (file && *file) {
		sc_file_free(*file);
		*file = NULL;
	}
 dnie_read_file_end:
	if (msg)
		sc_log(ctx, msg);
	LOG_FUNC_RETURN(ctx, res);
}
예제 #25
0
static void
sc_awp_clear(struct sc_pkcs15_card *p15card)
{
	LOG_FUNC_CALLED(p15card->card->ctx);
}
예제 #26
0
/**
 * Retrieve SN.IFD (8 bytes left padded with zeroes if required)
 * for the PIN channel DNIe 3.0.
 *
 * In DNIe local SM procedure, just read it from static data and
 * return SC_SUCCESS
 *
 * @param card pointer to card structure
 * @param buf where to store result (8 bytes)
 * @return SC_SUCCESS if ok; else error
 */
static int dnie_get_sn_ifd_pin(sc_card_t * card, u8 ** buf)
{
	LOG_FUNC_CALLED(card->ctx);
	*buf = sn_ifd_pin;
	return SC_SUCCESS;
}
예제 #27
0
static int
sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *p15card,
		unsigned char *buff, size_t len, int postpone_allowed)
{
	struct sc_context *ctx = p15card->card->ctx;
	size_t ii;
	int rv;
	int no_more_private_keys = 0, no_more_private_data = 0;

	LOG_FUNC_CALLED(ctx);

	for (ii=0; ii<len; ii+=5)   {
		unsigned int file_id, size;

		if(*(buff+ii) != 0xFF)
			continue;

		file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2);
		size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4);
		sc_log(ctx, "add private object (file-id:%04X, size:%X)", file_id, size);

		switch (*(buff+ii + 1))   {
		case BASE_ID_PRV_RSA :
			if (no_more_private_keys)
				break;

			rv = sc_pkcs15emu_oberthur_add_prvkey(p15card, file_id, size);
			if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed)   {
				struct sc_path path;

				sc_log(ctx, "postpone adding of the private keys");
				sc_format_path("5011A5A5", &path);
				rv = sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path);
				LOG_TEST_RET(ctx, rv, "Add PrkDF error");
				no_more_private_keys = 1;
			}
			LOG_TEST_RET(ctx, rv, "Cannot parse private key info");
			break;
		case BASE_ID_PRV_DES :
			break;
		case BASE_ID_PRV_DATA :
			sc_log(ctx, "*(buff+ii + 1):%X", *(buff+ii + 1));
			if (no_more_private_data)
				break;

			rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 1);
			if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed)   {
				struct sc_path path;

				sc_log(ctx, "postpone adding of the private data");
				sc_format_path("5011A6A6", &path);
				rv = sc_pkcs15_add_df(p15card, SC_PKCS15_DODF, &path);
				LOG_TEST_RET(ctx, rv, "Add DODF error");
				no_more_private_data = 1;
			}
			LOG_TEST_RET(ctx, rv, "Cannot parse private data info");
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Private object parse error");
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
예제 #28
0
/* Private key info:
 * 	flags:2,
 * 	CN(len:2,value:),
 * 	ID(len:2,value:(SHA1 value)),
 * 	StartDate(Ascii:8)
 * 	EndDate(Ascii:8)
 * 	Subject in ASN.1(len:2,value:)
 * 	modulus(value:)
 *	exponent(length:1, value:3)
 */
static int
sc_pkcs15emu_oberthur_add_prvkey(struct sc_pkcs15_card *p15card,
		unsigned int file_id, unsigned int size)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_prkey_info kinfo;
	struct sc_pkcs15_object kobj;
	struct crypto_container ccont;
	unsigned char *info_blob = NULL;
	size_t info_len = 0;
	unsigned flags;
	size_t offs, len;
	char ch_tmp[0x100];
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "add private key(file-id:%04X,size:%04X)", file_id, size);

	memset(&kinfo, 0, sizeof(kinfo));
	memset(&kobj, 0, sizeof(kobj));
	memset(&ccont, 0, sizeof(ccont));

	rv = sc_oberthur_get_friends (file_id, &ccont);
	LOG_TEST_RET(ctx, rv, "Failed to add private key: get friends error");

	if (ccont.id_cert)   {
		struct sc_pkcs15_object *objs[32];
		int ii;

		sc_log(ctx, "friend certificate %04X", ccont.id_cert);
		rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_CERT_X509, objs, 32);
		LOG_TEST_RET(ctx, rv, "Failed to add private key: get certificates error");

		for (ii=0; ii<rv; ii++) {
			struct sc_pkcs15_cert_info *cert = (struct sc_pkcs15_cert_info *)objs[ii]->data;
			struct sc_path path = cert->path;
			unsigned int id = path.value[path.len - 2] * 0x100 + path.value[path.len - 1];

			if (id == ccont.id_cert)   {
				strlcpy(kobj.label, objs[ii]->label, sizeof(kobj.label));
				break;
			}
		}

		if (ii == rv)
			LOG_TEST_RET(ctx, SC_ERROR_INCONSISTENT_PROFILE, "Failed to add private key: friend not found");
	}

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id | 0x100);
	rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add private key: read oberthur file error");

	if (info_len < 2)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'tag'");
	flags = *(info_blob + 0) * 0x100 + *(info_blob + 1);
	offs = 2;

	/* CN */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'CN'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len && !strlen(kobj.label))   {
		if (len > sizeof(kobj.label) - 1)
			len = sizeof(kobj.label) - 1;
		strncpy(kobj.label, (char *)(info_blob + offs + 2), len);
	}
	offs += 2 + len;

	/* ID */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: no 'ID'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (!len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add private key: zero length ID");
	else if (len > sizeof(kinfo.id.value))
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add private key: invalid ID length");
	memcpy(kinfo.id.value, info_blob + offs + 2, len);
	kinfo.id.len = len;
	offs += 2 + len;

	/* Ignore Start/End dates */
	offs += 16;

	/* Subject encoded in ASN1 */
	if (offs > info_len)
		return SC_ERROR_UNKNOWN_DATA_RECEIVED;
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len)   {
		kinfo.subject.value = malloc(len);
		if (!kinfo.subject.value)
			LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to add private key: memory allocation error");
		kinfo.subject.len = len;
		memcpy(kinfo.subject.value, info_blob + offs + 2, len);
	}

	/* Modulus and exponent are ignored */

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PRV, file_id);
	sc_format_path(ch_tmp, &kinfo.path);
	sc_log(ctx, "Private key info path %s", ch_tmp);

	kinfo.modulus_length	= size;
	kinfo.native		= 1;
	kinfo.key_reference	 = file_id & 0xFF;

	kinfo.usage = sc_oberthur_decode_usage(flags);
	kobj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
	if (flags & OBERTHUR_ATTR_MODIFIABLE)
		kobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;

	kobj.auth_id.len = sizeof(PinDomainID) > sizeof(kobj.auth_id.value)
			? sizeof(kobj.auth_id.value) : sizeof(PinDomainID);
	memcpy(kobj.auth_id.value, PinDomainID, kobj.auth_id.len);

	sc_log(ctx, "Parsed private key(reference:%i,usage:%X,flags:%X)", kinfo.key_reference, kinfo.usage, kobj.flags);

	rv = sc_pkcs15emu_add_rsa_prkey(p15card, &kobj, &kinfo);
	LOG_FUNC_RETURN(ctx, rv);
}
예제 #29
0
/* Certificate info:
 * 	flags:2,
 * 	Label(len:2,value:),
 * 	ID(len:2,value:(SHA1 value)),
 * 	Subject in ASN.1(len:2,value:)
 * 	Issuer in ASN.1(len:2,value:)
 * 	Serial encoded in LV or ASN.1	FIXME
 */
static int
sc_pkcs15emu_oberthur_add_cert(struct sc_pkcs15_card *p15card, unsigned int file_id)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_cert_info cinfo;
	struct sc_pkcs15_object cobj;
	unsigned char *info_blob, *cert_blob;
	size_t info_len, cert_len, len, offs;
	unsigned flags;
	int rv;
	char ch_tmp[0x20];

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "add certificate(file-id:%04X)", file_id);

	memset(&cinfo, 0, sizeof(cinfo));
	memset(&cobj, 0, sizeof(cobj));

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100);
	rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add certificate: read oberthur file error");

	if (info_len < 2)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'tag'");
	flags = *(info_blob + 0) * 0x100 + *(info_blob + 1);
	offs = 2;

	/* Label */
	if (offs + 2 > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'CN'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len)   {
		if (len > sizeof(cobj.label) - 1)
			len = sizeof(cobj.label) - 1;
		memcpy(cobj.label, info_blob + offs + 2, len);
	}
	offs += 2 + len;

	/* ID */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'ID'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len > sizeof(cinfo.id.value))
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add certificate: invalie 'ID' length");
	memcpy(cinfo.id.value, info_blob + offs + 2, len);
	cinfo.id.len = len;

	/* Ignore subject, issuer and serial */

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id);
	sc_format_path(ch_tmp, &cinfo.path);
	rv = sc_oberthur_read_file(p15card, ch_tmp, &cert_blob, &cert_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add certificate: read certificate error");

	cinfo.value.value = cert_blob;
	cinfo.value.len = cert_len;

	rv = sc_oberthur_get_certificate_authority(&cinfo.value, &cinfo.authority);
	LOG_TEST_RET(ctx, rv, "Failed to add certificate: get certificate attributes error");

	if (flags & OBERTHUR_ATTR_MODIFIABLE)
		cobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;

	rv = sc_pkcs15emu_add_x509_cert(p15card, &cobj, &cinfo);

	SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, rv);
}
예제 #30
0
/*
 * @brief Use PUT DATA to import a private RSA key.
 *
 * For simplicity, command chaining has to be used. One chunk (apdu) must contain
 * one RSA field (P, Q, etc.). The first apdu must contain the outer tag (7F48).
 *
 * @param card
 * @param rsa The RSA private key to import.
 *
 * @return SC_ERROR_INVALID_ARGUMENTS: The RSA key does not contain CRT fields.
 *		   other errors:               Transmit errors / errors returned by card.
 */
static int
isoApplet_put_data_prkey_rsa(sc_card_t *card, sc_cardctl_isoApplet_import_key_t *args)
{
	sc_apdu_t apdu;
	u8 sbuf[SC_MAX_EXT_APDU_BUFFER_SIZE];
	u8 *p = NULL;
	int r;
	size_t tags_len;

	LOG_FUNC_CALLED(card->ctx);

	if(!args->privkey.rsa.p.value
	        || !args->privkey.rsa.q.value
	        || !args->privkey.rsa.iqmp.value
	        || !args->privkey.rsa.dmp1.value
	        || !args->privkey.rsa.dmq1.value)
	{
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS, "RSA key is missing information.");
	}

	/* Note: The format is according to ISO 2-byte tag 7F48
	 * "T-L pair to indicate a private key data object" */

	/* Calculate the length of all inner tag-length-value entries, but do not write anything yet. */
	tags_len = 0;
	r = sc_asn1_put_tag(0x92, NULL, args->privkey.rsa.p.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x93, NULL, args->privkey.rsa.q.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x94, NULL, args->privkey.rsa.iqmp.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x95, NULL, args->privkey.rsa.dmp1.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;
	r = sc_asn1_put_tag(0x96, NULL, args->privkey.rsa.dmq1.len, NULL, 0, NULL);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");
	tags_len += r;

	/* Write the outer tag and length information. */
	p = sbuf;
	r = sc_asn1_put_tag(0x7F48, NULL, tags_len, p, sizeof(sbuf), &p);
	LOG_TEST_RET(card->ctx, r, "Error handling TLV.");

	/* Write inner tags. */
	/* p */
	r = sc_asn1_put_tag(0x92, args->privkey.rsa.p.value, args->privkey.rsa.p.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;
	/* q */
	r = sc_asn1_put_tag(0x93, args->privkey.rsa.q.value, args->privkey.rsa.q.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;
	/* 1/q mod p */
	r = sc_asn1_put_tag(0x94, args->privkey.rsa.iqmp.value, args->privkey.rsa.iqmp.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;
	/* d mod (p-1) */
	r = sc_asn1_put_tag(0x95, args->privkey.rsa.dmp1.value, args->privkey.rsa.dmp1.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;
	/* d mod (q-1) */
	r = sc_asn1_put_tag(0x96, args->privkey.rsa.dmq1.value, args->privkey.rsa.dmq1.len, p, sizeof(sbuf) - (p - sbuf), &p);
	if(r < 0)
		goto out;

	/* Send to card, using chaining or extended APDUs. */
	sc_format_apdu(card, &apdu, SC_APDU_CASE_3, 0xDB, 0x3F, 0xFF);
	apdu.data = sbuf;
	apdu.datalen = p - sbuf;
	apdu.lc = p - sbuf;
	if ((card->caps & SC_CARD_CAP_APDU_EXT) == 0)
	{
		/* The lower layers will automatically do chaining */
		apdu.flags |= SC_APDU_FLAGS_CHAINING;
	}
	r = sc_transmit_apdu(card, &apdu);
	if(r < 0)
		goto out;
	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	if(apdu.sw1 == 0x6A && apdu.sw2 == 0x81)
	{
		sc_log(card->ctx, "Key import not supported by the card with that particular key type. "
		       "Your card may not support the specified algorithm used by the applet / specified by you. "
		       "In most cases, this happens when trying to import EC keys not supported by your java card. "
		       "In this case, look for supported field lengths and whether FP and/or F2M are supported. "
		       "If you tried to import a private RSA key, check the key length.");
	}
	if(apdu.sw1 == 0x69 && apdu.sw2 == 0x00)
	{
		sc_log(card->ctx, "Key import not allowed by the applet's security policy. "
		       "If you want to allow key import, set DEF_PRIVATE_KEY_IMPORT_ALLOWED in the IsoApplet,"
		       " rebuild and reinstall the applet.");
	}
	if(r < 0)
		goto out;

	r = SC_SUCCESS;
out:
	sc_mem_clear(sbuf, sizeof(sbuf));
	LOG_FUNC_RETURN(card->ctx, r);
}