- improved file selection on Cryptoflex cards
- fixed an incompatability in PKCS #11 module git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@178 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
d9792242cc
commit
f1582007f6
|
@ -168,85 +168,101 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
static int check_path(struct sc_card *card, const u8 **pathptr, size_t *pathlen,
|
||||||
struct sc_file *file)
|
int need_info)
|
||||||
|
{
|
||||||
|
const u8 *curptr = card->cache.current_path.value;
|
||||||
|
const u8 *ptr = *pathptr;
|
||||||
|
size_t curlen = card->cache.current_path.len;
|
||||||
|
size_t len = *pathlen;
|
||||||
|
|
||||||
|
if (curlen < 2)
|
||||||
|
return 0;
|
||||||
|
if (len < 2)
|
||||||
|
return 0;
|
||||||
|
if (memcmp(ptr, "\x3F\x00", 2) != 0) {
|
||||||
|
/* Skip the MF id */
|
||||||
|
curptr += 2;
|
||||||
|
curlen -= 2;
|
||||||
|
}
|
||||||
|
if (len == curlen && memcmp(ptr, curptr, len) == 0) {
|
||||||
|
if (need_info)
|
||||||
|
return 0;
|
||||||
|
*pathptr = ptr + len;
|
||||||
|
*pathlen = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (curlen < len && memcmp(ptr, curptr, curlen) == 0) {
|
||||||
|
*pathptr = ptr + curlen;
|
||||||
|
*pathlen = len - curlen;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/* FIXME: Build additional logic */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cache_path(struct sc_card *card, const struct sc_path *path)
|
||||||
|
{
|
||||||
|
struct sc_path *curpath = &card->cache.current_path;
|
||||||
|
|
||||||
|
switch (path->type) {
|
||||||
|
case SC_PATH_TYPE_FILE_ID:
|
||||||
|
if (path->value[0] == 0x3F && path->value[1] == 0x00)
|
||||||
|
sc_format_path("3F00", curpath);
|
||||||
|
else {
|
||||||
|
if (curpath->len + 2 > SC_MAX_PATH_SIZE) {
|
||||||
|
curpath->len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(curpath->value + curpath->len, path->value, 2);
|
||||||
|
curpath->len += 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_PATH:
|
||||||
|
curpath->len = 0;
|
||||||
|
if (path->value[0] != 0x3F || path->value[1] != 0)
|
||||||
|
sc_format_path("3F00", curpath);
|
||||||
|
if (curpath->len + path->len > SC_MAX_PATH_SIZE) {
|
||||||
|
curpath->len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(curpath->value + curpath->len, path->value, path->len);
|
||||||
|
curpath->len += path->len;
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_DF_NAME:
|
||||||
|
/* All bets are off */
|
||||||
|
curpath->len = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int select_file_id(struct sc_card *card, const u8 *buf, size_t buflen,
|
||||||
|
u8 p1, struct sc_file *file)
|
||||||
{
|
{
|
||||||
int r, i;
|
int r, i;
|
||||||
struct sc_apdu apdu;
|
struct sc_apdu apdu;
|
||||||
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
|
||||||
const u8 *pathptr = path->value;
|
|
||||||
size_t pathlen = path->len;
|
|
||||||
int locked = 0;
|
|
||||||
|
|
||||||
SC_FUNC_CALLED(card->ctx, 3);
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, p1, 0);
|
||||||
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0);
|
|
||||||
apdu.resp = rbuf;
|
apdu.resp = rbuf;
|
||||||
apdu.resplen = sizeof(rbuf);
|
apdu.resplen = sizeof(rbuf);
|
||||||
apdu.p1 = apdu.p2 = 0;
|
apdu.datalen = buflen;
|
||||||
|
apdu.data = buf;
|
||||||
|
apdu.lc = buflen;
|
||||||
|
|
||||||
switch (path->type) {
|
/* No need to get file information, if file is NULL. */
|
||||||
case SC_PATH_TYPE_PATH:
|
|
||||||
if ((pathlen & 1) != 0) /* not divisible by 2 */
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
|
||||||
struct sc_path tmppath;
|
|
||||||
|
|
||||||
locked = 1;
|
|
||||||
r = sc_lock(card);
|
|
||||||
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
|
||||||
if (memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
|
||||||
sc_format_path("I3F00", &tmppath);
|
|
||||||
r = flex_select_file(card, &tmppath, NULL);
|
|
||||||
if (r)
|
|
||||||
sc_unlock(card);
|
|
||||||
SC_TEST_RET(card->ctx, r, "Unable to select Master File (MF)");
|
|
||||||
}
|
|
||||||
while (pathlen > 2) {
|
|
||||||
memcpy(tmppath.value, pathptr, 2);
|
|
||||||
tmppath.len = 2;
|
|
||||||
r = flex_select_file(card, &tmppath, NULL);
|
|
||||||
if (r)
|
|
||||||
sc_unlock(card);
|
|
||||||
SC_TEST_RET(card->ctx, r, "Unable to select DF");
|
|
||||||
pathptr += 2;
|
|
||||||
pathlen -= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case SC_PATH_TYPE_DF_NAME:
|
|
||||||
apdu.p1 = 0x04;
|
|
||||||
break;
|
|
||||||
case SC_PATH_TYPE_FILE_ID:
|
|
||||||
if ((pathlen & 1) != 0)
|
|
||||||
return SC_ERROR_INVALID_ARGUMENTS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
apdu.datalen = pathlen;
|
|
||||||
apdu.data = pathptr;
|
|
||||||
apdu.lc = pathlen;
|
|
||||||
|
|
||||||
/* No need to get file information, if file is NULL or already
|
|
||||||
* valid. */
|
|
||||||
#if 0
|
|
||||||
if (file == NULL || sc_file_valid(file))
|
|
||||||
#endif
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
apdu.resplen = 0;
|
apdu.resplen = 0;
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
if (locked)
|
|
||||||
sc_unlock(card);
|
|
||||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||||
SC_TEST_RET(card->ctx, r, "Card returned error");
|
SC_TEST_RET(card->ctx, r, "Card returned error");
|
||||||
#if 0
|
|
||||||
if (file == NULL || sc_file_valid(file))
|
|
||||||
#endif
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (apdu.resplen < 14)
|
if (apdu.resplen < 14)
|
||||||
return SC_ERROR_UNKNOWN_REPLY;
|
return SC_ERROR_UNKNOWN_REPLY;
|
||||||
|
|
||||||
if (apdu.resp[0] == 0x6F) {
|
if (apdu.resp[0] == 0x6F) {
|
||||||
error(card->ctx, "unsupported: card returned FCI\n");
|
error(card->ctx, "unsupported: card returned FCI\n");
|
||||||
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
|
return SC_ERROR_UNKNOWN_REPLY; /* FIXME */
|
||||||
|
@ -257,6 +273,61 @@ static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
||||||
file->acl[i] = SC_AC_UNKNOWN;
|
file->acl[i] = SC_AC_UNKNOWN;
|
||||||
|
|
||||||
return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
|
return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int flex_select_file(struct sc_card *card, const struct sc_path *path,
|
||||||
|
struct sc_file *file)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const u8 *pathptr = path->value;
|
||||||
|
size_t pathlen = path->len;
|
||||||
|
int locked = 0, magic_done;
|
||||||
|
u8 p1 = 0;
|
||||||
|
|
||||||
|
SC_FUNC_CALLED(card->ctx, 3);
|
||||||
|
switch (path->type) {
|
||||||
|
case SC_PATH_TYPE_PATH:
|
||||||
|
if ((pathlen & 1) != 0) /* not divisible by 2 */
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
magic_done = check_path(card, &pathptr, &pathlen, file != NULL);
|
||||||
|
if (pathlen == 0)
|
||||||
|
return 0;
|
||||||
|
if (pathlen != 2 || memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
||||||
|
locked = 1;
|
||||||
|
r = sc_lock(card);
|
||||||
|
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
|
||||||
|
if (!magic_done && memcmp(pathptr, "\x3F\x00", 2) != 0) {
|
||||||
|
r = select_file_id(card, "\x3F\x00", 2, 0, NULL);
|
||||||
|
if (r)
|
||||||
|
sc_unlock(card);
|
||||||
|
SC_TEST_RET(card->ctx, r, "Unable to select Master File (MF)");
|
||||||
|
}
|
||||||
|
while (pathlen > 2) {
|
||||||
|
r = select_file_id(card, pathptr, 2, 0, NULL);
|
||||||
|
if (r)
|
||||||
|
sc_unlock(card);
|
||||||
|
SC_TEST_RET(card->ctx, r, "Unable to select DF");
|
||||||
|
pathptr += 2;
|
||||||
|
pathlen -= 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_DF_NAME:
|
||||||
|
p1 = 0x04;
|
||||||
|
break;
|
||||||
|
case SC_PATH_TYPE_FILE_ID:
|
||||||
|
if (pathlen != 2)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r = select_file_id(card, pathptr, pathlen, p1, file);
|
||||||
|
if (locked)
|
||||||
|
sc_unlock(card);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
cache_path(card, path);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flex_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
static int flex_list_files(struct sc_card *card, u8 *buf, size_t buflen)
|
||||||
|
@ -448,7 +519,10 @@ static int flex_create_file(struct sc_card *card, struct sc_file *file)
|
||||||
|
|
||||||
r = sc_transmit_apdu(card, &apdu);
|
r = sc_transmit_apdu(card, &apdu);
|
||||||
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
|
||||||
return sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
r = sc_sw_to_errorcode(card, apdu.sw1, apdu.sw2);
|
||||||
|
SC_TEST_RET(card->ctx, r, "Card returned error");
|
||||||
|
card->cache.current_path.len = 0;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int flex_set_security_env(struct sc_card *card,
|
static int flex_set_security_env(struct sc_card *card,
|
||||||
|
|
|
@ -669,6 +669,20 @@ int sc_select_file(struct sc_card *card,
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(card != NULL && in_path != NULL);
|
assert(card != NULL && in_path != NULL);
|
||||||
|
if (in_path->len > SC_MAX_PATH_SIZE)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
if (in_path->type == SC_PATH_TYPE_PATH) {
|
||||||
|
/* Perform a sanity check */
|
||||||
|
int i;
|
||||||
|
if ((in_path->len & 1) != 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
for (i = 0; i < in_path->len/2; i++) {
|
||||||
|
u8 p1 = in_path->value[2*i],
|
||||||
|
p2 = in_path->value[2*i+1];
|
||||||
|
if ((p1 == 0x3F && p2 == 0x00) && i > 0)
|
||||||
|
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (card->ctx->debug >= 2) {
|
if (card->ctx->debug >= 2) {
|
||||||
char line[128], *linep = line;
|
char line[128], *linep = line;
|
||||||
|
|
||||||
|
@ -680,8 +694,6 @@ int sc_select_file(struct sc_card *card,
|
||||||
strcpy(linep, "\n");
|
strcpy(linep, "\n");
|
||||||
debug(card->ctx, line);
|
debug(card->ctx, line);
|
||||||
}
|
}
|
||||||
if (in_path->len > SC_MAX_PATH_SIZE)
|
|
||||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
|
|
||||||
if (card->ops->select_file == NULL)
|
if (card->ops->select_file == NULL)
|
||||||
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
|
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_NOT_SUPPORTED);
|
||||||
r = card->ops->select_file(card, in_path, file);
|
r = card->ops->select_file(card, in_path, file);
|
||||||
|
|
|
@ -152,7 +152,7 @@ static CK_RV pkcs15_create_tokens(struct sc_pkcs11_card *p11card)
|
||||||
|
|
||||||
debug(context, "Enumerating private keys\n");
|
debug(context, "Enumerating private keys\n");
|
||||||
rv = sc_pkcs15_enum_private_keys(card);
|
rv = sc_pkcs15_enum_private_keys(card);
|
||||||
if (rv < 0)
|
if (rv < 0)
|
||||||
return sc_to_cryptoki_error(rv, reader);
|
return sc_to_cryptoki_error(rv, reader);
|
||||||
|
|
||||||
for (i = 0; i < card->pin_count; i++) {
|
for (i = 0; i < card->pin_count; i++) {
|
||||||
|
@ -484,25 +484,24 @@ CK_RV pkcs15_prkey_sign(struct sc_pkcs11_session *ses, void *obj,
|
||||||
CK_ULONG_PTR pulDataLen)
|
CK_ULONG_PTR pulDataLen)
|
||||||
{
|
{
|
||||||
struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
|
struct pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
|
||||||
int rv, hash;
|
int rv, flags = 0;
|
||||||
|
|
||||||
debug(context, "Initiating signing operation.\n");
|
debug(context, "Initiating signing operation.\n");
|
||||||
|
|
||||||
switch (pMechanism->mechanism) {
|
switch (pMechanism->mechanism) {
|
||||||
case CKM_RSA_PKCS:
|
case CKM_RSA_PKCS:
|
||||||
hash = SC_PKCS15_HASH_NONE;
|
|
||||||
break;
|
break;
|
||||||
case CKM_SHA1_RSA_PKCS:
|
case CKM_SHA1_RSA_PKCS:
|
||||||
hash = SC_PKCS15_HASH_SHA1;
|
flags = SC_PKCS15_HASH_SHA1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return CKR_MECHANISM_INVALID;
|
return CKR_MECHANISM_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(context, "Selected hash %d. Now computing signature.\n", hash);
|
debug(context, "Selected flags %X. Now computing signature.\n", flags);
|
||||||
rv = sc_pkcs15_compute_signature((struct sc_pkcs15_card*) ses->slot->card->fw_data,
|
rv = sc_pkcs15_compute_signature((struct sc_pkcs15_card*) ses->slot->card->fw_data,
|
||||||
prkey->prkey_info,
|
prkey->prkey_info,
|
||||||
hash,
|
flags,
|
||||||
pData,
|
pData,
|
||||||
ulDataLen,
|
ulDataLen,
|
||||||
pSignature,
|
pSignature,
|
||||||
|
|
|
@ -37,7 +37,6 @@ CK_RV C_Initialize(CK_VOID_PTR pReserved)
|
||||||
error(context, "C_Initialize(): Cryptoki already initialized\n");
|
error(context, "C_Initialize(): Cryptoki already initialized\n");
|
||||||
return CKR_CRYPTOKI_ALREADY_INITIALIZED;
|
return CKR_CRYPTOKI_ALREADY_INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = sc_establish_context(&context);
|
rc = sc_establish_context(&context);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return CKR_DEVICE_ERROR;
|
return CKR_DEVICE_ERROR;
|
||||||
|
|
|
@ -266,7 +266,7 @@ int main(int argc, char * const argv[])
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
r = sc_lock(card);
|
r = sc_lock(card);
|
||||||
if (r) {
|
if (r) {
|
||||||
fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r));
|
fprintf(stderr, "Unable to lock card: %s\n", sc_strerror(r));
|
||||||
|
@ -340,7 +340,7 @@ end:
|
||||||
if (p15card)
|
if (p15card)
|
||||||
sc_pkcs15_unbind(p15card);
|
sc_pkcs15_unbind(p15card);
|
||||||
if (card) {
|
if (card) {
|
||||||
#if 0
|
#if 1
|
||||||
sc_unlock(card);
|
sc_unlock(card);
|
||||||
#endif
|
#endif
|
||||||
sc_disconnect_card(card);
|
sc_disconnect_card(card);
|
||||||
|
|
Loading…
Reference in New Issue