Merged r3719:3749 from trunk

git-svn-id: https://www.opensc-project.org/svnp/opensc/branches/martin/0.12@3750 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
martin 2009-10-03 07:48:28 +00:00
parent 9a95a40e81
commit 9da39d8462
16 changed files with 1534 additions and 21 deletions

View File

@ -40,7 +40,7 @@ libopensc_la_SOURCES = \
card-oberthur.c card-belpic.c card-atrust-acos.c card-entersafe.c \
card-incrypto34.c card-piv.c card-muscle.c card-acos5.c \
card-asepcos.c card-akis.c card-gemsafeV1.c card-rutoken.c \
card-rtecp.c card-westcos.c \
card-rtecp.c card-westcos.c card-myeid.c \
\
pkcs15-openpgp.c pkcs15-infocamere.c pkcs15-starcert.c \
pkcs15-tcos.c pkcs15-esteid.c pkcs15-postecert.c pkcs15-gemsafeGPK.c \

View File

@ -29,7 +29,7 @@ OBJECTS = \
card-oberthur.obj card-belpic.obj card-atrust-acos.obj card-entersafe.obj \
card-incrypto34.obj card-piv.obj card-muscle.obj card-acos5.obj \
card-asepcos.obj card-akis.obj card-gemsafeV1.obj card-rutoken.obj \
card-rtecp.obj \
card-rtecp.obj card-myeid.obj \
\
p15emu-westcos.obj \
pkcs15-openpgp.obj pkcs15-infocamere.obj pkcs15-starcert.obj \

View File

@ -169,7 +169,6 @@ static int entersafe_cipher_apdu(sc_card_t *card, sc_apdu_t *apdu,
u8 *buff, size_t buffsize)
{
EVP_CIPHER_CTX ctx;
int i,r;
u8 iv[8]={0};
SC_FUNC_CALLED(card->ctx, 1);
@ -223,7 +222,7 @@ static int entersafe_mac_apdu(sc_card_t *card, sc_apdu_t *apdu,
{
int r;
u8 iv[8];
u8 *tmp=0,*tmp_rounded;
u8 *tmp=0,*tmp_rounded=NULL;
size_t tmpsize=0,tmpsize_rounded=0,outl=0;
EVP_CIPHER_CTX ctx;
@ -430,8 +429,6 @@ static int entersafe_process_fci(struct sc_card *card, struct sc_file *file,
const u8 *buf, size_t buflen)
{
int r;
const u8 *tag = NULL, *p = buf;
size_t taglen, len = buflen;
assert(file);
SC_FUNC_CALLED(card->ctx, 1);
@ -493,7 +490,7 @@ static int entersafe_select_aid(sc_card_t *card,
const sc_path_t *in_path,
sc_file_t **file_out)
{
int r;
int r = 0;
if (card->cache_valid
&& card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
@ -772,7 +769,6 @@ static int entersafe_create_file(sc_card_t *card, sc_file_t *file)
SC_FUNC_CALLED(card->ctx, 1);
if (file->type == SC_FILE_TYPE_WORKING_EF) {
int r;
sc_entersafe_create_data data;
memset(&data,0,sizeof(data));
@ -1127,7 +1123,6 @@ static int entersafe_write_rsa_key_factor(sc_card_t *card,
{
int r;
sc_apdu_t apdu;
u8 sbuff[SC_MAX_APDU_BUFFER_SIZE];
SC_FUNC_CALLED(card->ctx, 1);
@ -1148,6 +1143,8 @@ static int entersafe_write_rsa_key_factor(sc_card_t *card,
}
{/* Write 'x'; */
u8 sbuff[SC_MAX_APDU_BUFFER_SIZE];
sc_format_apdu(card,&apdu,SC_APDU_CASE_3_SHORT,0x46,factor,0x00);
memcpy(sbuff,data.data,data.len);
@ -1378,6 +1375,7 @@ static int entersafe_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
SC_FUNC_RETURN(card->ctx,4,SC_SUCCESS);
}
#if 0
static int entersafe_preinstall_rsa_1024(sc_card_t *card,u8 key_id)
{
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
@ -1440,6 +1438,7 @@ static int entersafe_preinstall_rsa_1024(sc_card_t *card,u8 key_id)
SC_FUNC_RETURN(card->ctx,4,SC_SUCCESS);
}
#endif
static int entersafe_preinstall_rsa_2048(sc_card_t *card,u8 key_id)
{
@ -1591,6 +1590,7 @@ static int entersafe_preinstall_keys(sc_card_t *card,int (*install_rsa)(sc_card_
SC_FUNC_RETURN(card->ctx,4,SC_SUCCESS);
}
#if 0
static int entersafe_card_ctl_1024(sc_card_t *card, unsigned long cmd, void *ptr)
{
sc_entersafe_create_data * tmp = (sc_entersafe_create_data *)ptr;
@ -1621,6 +1621,7 @@ static int entersafe_card_ctl_1024(sc_card_t *card, unsigned long cmd, void *ptr
return SC_ERROR_NOT_SUPPORTED;
}
}
#endif
static int entersafe_card_ctl_2048(sc_card_t *card, unsigned long cmd, void *ptr)
{

981
src/libopensc/card-myeid.c Normal file
View File

@ -0,0 +1,981 @@
/*
* card-myeid.c
*
* Copyright (C) 2008-2009 Aventra Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "internal.h"
#include "asn1.h"
#include "types.h"
#include "cardctl.h"
#include <string.h>
#include <stdlib.h>
static enum LOAD_KEY {
LOAD_KEY_MODULUS = 0x80,
LOAD_KEY_PUBLIC_EXPONENT = 0x81,
LOAD_KEY_PRIME_P = 0x83,
LOAD_KEY_PRIME_Q = 0x84,
LOAD_KEY_DP1 = 0x85,
LOAD_KEY_DQ1 = 0x86,
LOAD_KEY_INVQ = 0x87
};
static struct sc_card_operations myeid_ops;
static struct sc_card_driver myeid_drv = {
"MyEID cards with PKCS#15 applet",
"myeid",
&myeid_ops
};
static const char *myeid_atrs[] = {
"3B:F5:18:00:FF:81:31:FE:45:4D:79:45:49:44:65",
"3B:F5:18:00:00:81:31:FE:45:4D:79:45:49:44:9A",
NULL
};
static int myeid_finish(struct sc_card *card)
{
return 0;
}
static int myeid_match_card(struct sc_card *card)
{
int i, match = -1;
for (i = 0; myeid_atrs[i] != NULL; i++)
{
u8 defatr[SC_MAX_ATR_SIZE];
size_t len = sizeof(defatr);
const char *atrp = myeid_atrs[i];
if (sc_hex_to_bin(atrp, defatr, &len)) continue;
if (len != card->atr_len)
continue;
if (memcmp(card->atr, defatr, len) != 0)
continue;
match = i;
break;
}
if (match == -1)
return 0;
return 1;
}
static int myeid_init(struct sc_card *card)
{
unsigned long flags =0;
flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
_sc_card_add_rsa_alg(card, 1024, flags, 0);
_sc_card_add_rsa_alg(card, 2048, flags, 0);
/* State that we have an RNG */
card->caps |= SC_CARD_CAP_RNG;
return 0;
}
static const struct sc_card_operations *iso_ops = NULL;
static int acl_to_byte(const struct sc_acl_entry *e)
{
switch (e->method) {
case SC_AC_NONE:
return 0x00;
case SC_AC_CHV:
case SC_AC_TERM:
case SC_AC_AUT:
if (e->key_ref == SC_AC_KEY_REF_NONE)
return -1;
if (e->key_ref < 1 || e->key_ref > 14)
return -1;
return e->key_ref;
case SC_AC_NEVER:
return 0x0F;
}
return 0x00;
}
static void add_acl_entry(struct sc_file *file, int op, u8 byte)
{
unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
switch (byte)
{
case 0:
method = SC_AC_NONE;
break;
case 15:
method = SC_AC_NEVER;
break;
default:
method = SC_AC_CHV;
key_ref = byte;
break;
}
sc_file_add_acl_entry(file, op, method, key_ref);
}
static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
{
int i;
const int df_ops[4] =
{ SC_AC_OP_CREATE, SC_AC_OP_CREATE, SC_AC_OP_DELETE, -1 };
const int ef_ops[4] =
{ SC_AC_OP_READ, SC_AC_OP_UPDATE, SC_AC_OP_DELETE, -1 };
const int key_ops[4] =
{ SC_AC_OP_CRYPTO, SC_AC_OP_UPDATE, SC_AC_OP_DELETE, SC_AC_OP_CRYPTO };
const int *ops;
if (len < 2)
return;
switch (file->type) {
case SC_FILE_TYPE_WORKING_EF:
ops = ef_ops;
break;
case SC_FILE_TYPE_INTERNAL_EF:
ops = key_ops;
break;
case SC_FILE_TYPE_DF:
ops = df_ops;
break;
default:
ops = key_ops;
break;
}
for (i = 0; i < 4; i++)
{
if (ops[i] == -1)
continue;
if ((i & 1) == 0)
add_acl_entry(file, ops[i], (u8)(buf[i / 2] >> 4));
else
add_acl_entry(file, ops[i], (u8)(buf[i / 2] & 0x0F));
}
}
static int myeid_select_file(struct sc_card *card, const struct sc_path *in_path,
struct sc_file **file)
{
int r;
r = iso_ops->select_file(card, in_path, file);
if (r)
return r;
if (file != NULL) {
parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
}
return 0;
}
static int myeid_read_binary(struct sc_card *card, unsigned int idx,
u8 * buf, size_t count, unsigned long flags)
{
return iso_ops->read_binary(card, idx, buf, count, flags);
}
static int myeid_list_files(struct sc_card *card, u8 *buf, size_t buflen)
{
struct sc_apdu apdu;
int r,i;
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0xA1);
apdu.resp = buf;
apdu.resplen = buflen;
apdu.le = buflen > 256 ? 256 : buflen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.resplen == 0)
return sc_check_sw(card, apdu.sw1, apdu.sw2);
return apdu.resplen;
}
static int myeid_process_fci(struct sc_card *card, struct sc_file *file,
const u8 *buf, size_t buflen)
{
size_t taglen = 0;
const u8 *tag = NULL;
int r ;
r = iso_ops->process_fci(card, file, buf, buflen);
if (r < 0)
return r;
if(file->type == SC_FILE_EF_UNKNOWN)
{
tag = sc_asn1_find_tag(NULL, buf, buflen, 0x82, &taglen);
if (tag != NULL && taglen > 0 && *tag == 17)
{
file->type = SC_FILE_TYPE_INTERNAL_EF;
}
}
return 0;
}
static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
u8 *out, size_t *outlen)
{
u8 buf[40];
int i;
/* PrivateKey
* 0E0000019 6217 81020400 820111 83024B01 8603000000 85028000 8A0100 RESULT 6984
* 6217 81020400 820111 83024B01 8603000000 85021000 8A0100 */
memset(buf,0x0,sizeof(buf));
buf[0] = 0x62;
buf[1] = 0x17;
/* File size */
buf[2] = (SC_FILE_TYPE_WORKING_EF == file->type ?0x80:0x81);
buf[3] = 0x02;
buf[4] = (file->size >> 8) & 0xFF;
buf[5] = file->size & 0xFF;
/* File Description tag */
buf[6] = 0x82;
buf[7] = 0x01;
buf[8] = 0x01;
/* File Identifier tag */
buf[9] = 0x83;
buf[10] = 0x02;
buf[11] = (file->id >> 8) & 0xFF;
buf[12] = file->id & 0xFF;
/* Security Attributes Tag */
buf[13] = 0x86;
buf[14] = 0x03;
buf[15] = 0x0;
buf[16] = 0x0;
buf[17] = 0x0;
if (file->sec_attr_len == 3 && file->sec_attr)
{
buf[15] = file->sec_attr[0];
buf[16] = file->sec_attr[1];
buf[17] = file->sec_attr[2];
}
/* Proprietary Information */
buf[18] = 0x85;
buf[19] = 0x02;
/* AC right to clear default 0 */
buf[20] = (SC_FILE_TYPE_INTERNAL_EF == file->type ?0x0:0x80);
buf[21] = 0x0;
/* Life Cycle Status tag */
buf[22] = 0x8A;
buf[23] = 0x01;
buf[24] = 0x0; /* RFU */
switch (file->type)
{
case SC_FILE_TYPE_WORKING_EF:
break;
case SC_FILE_TYPE_INTERNAL_EF:
buf[8] = 0x11;
break;
case SC_FILE_TYPE_DF:
buf[8] = 0x38;
if(file->namelen > 0 && file->namelen <= 16)
{
buf[25] = 0x84;
buf[26] = (u8)file->namelen;
for(i=0;i < (int)file->namelen;i++)
{
buf[i + 26] = file->name[i];
}
buf[1] = 0x19 + file->namelen + 2;
}
break;
default:
sc_debug(card->ctx, "Unknown file type\n");
return SC_ERROR_INVALID_ARGUMENTS;
}
*outlen = buf[1]+2;
memcpy(out, buf, *outlen);
return 0;
}
static int myeid_create_file(struct sc_card *card, struct sc_file *file)
{
sc_apdu_t apdu;
u8 sbuf[32];
size_t buflen;
int r;
r = encode_file_structure(card, file, sbuf, &buflen);
if (r)
return r;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
apdu.data = sbuf;
apdu.datalen = buflen;
apdu.lc = buflen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x6A && apdu.sw2 == 0x89)
return SC_ERROR_FILE_ALREADY_EXISTS;
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "Card returned error");
return 0;
}
/* no record oriented file services */
static int myeid_read_record_unsupp(struct sc_card *card, unsigned int rec_nr,
u8 *buf, size_t count, unsigned long flags)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int myeid_wrupd_record_unsupp(struct sc_card *card, unsigned int rec_nr,
const u8 *buf, size_t count, unsigned long flags)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int myeid_append_record_unsupp(struct sc_card *card, const u8 *buf,
size_t count, unsigned long flags)
{
return SC_ERROR_NOT_SUPPORTED;
}
static int myeid_write_binary(struct sc_card *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
return iso_ops->write_binary(card, idx, buf, count, flags);
}
static int myeid_update_binary(struct sc_card *card, unsigned int idx,
const u8 *buf, size_t count, unsigned long flags)
{
return iso_ops->update_binary(card, idx, buf, count, flags);
}
static int myeid_delete_file(struct sc_card *card, const struct sc_path *path)
{
int r;
struct sc_apdu apdu;
SC_FUNC_CALLED(card->ctx, 1);
if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2)
{
sc_debug(card->ctx, "File type has to be SC_PATH_TYPE_FILE_ID\n");
SC_FUNC_RETURN(card->ctx, 1, SC_ERROR_INVALID_ARGUMENTS);
}
r = sc_select_file(card, path, NULL);
SC_TEST_RET(card->ctx, r, "Unable to select file to be deleted");
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
apdu.cla = 0xA0;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_check_sw(card, apdu.sw1, apdu.sw2);
}
static int myeid_set_security_env2(sc_card_t *card, const sc_security_env_t *env,
int se_num)
{
sc_apdu_t apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 *p;
int r, locked = 0;
assert(card != NULL && env != NULL);
if (env->flags & SC_SEC_ENV_KEY_REF_ASYMMETRIC)
{
sc_debug(card->ctx, "asymmetric keyref not supported.\n");
return SC_ERROR_NOT_SUPPORTED;
}
if (se_num > 0)
{
sc_debug(card->ctx, "restore security environment not supported.\n");
return SC_ERROR_NOT_SUPPORTED;
}
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0, 0);
switch (env->operation)
{
case SC_SEC_OPERATION_DECIPHER:
apdu.p1 = 0x41;
apdu.p2 = 0xB8;
break;
case SC_SEC_OPERATION_SIGN:
apdu.p1 = 0x41;
apdu.p2 = 0xB6;
break;
default:
return SC_ERROR_INVALID_ARGUMENTS;
}
apdu.le = 0;
p = sbuf;
if (env->flags & SC_SEC_ENV_ALG_REF_PRESENT)
{
*p++ = 0x80; /* algorithm reference */
*p++ = 0x01;
*p++ = env->algorithm_ref & 0xFF;
}
if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
{
*p++ = 0x81;
*p++ = 2;
memcpy(p, env->file_ref.value, 2);
p += 2;
}
if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
{
*p++ = 0x84;
*p++ = 1;
*p++ = 0;
}
r = p - sbuf;
apdu.lc = r;
apdu.datalen = r;
apdu.data = sbuf;
apdu.resplen = 0;
if (se_num > 0) {
r = sc_lock(card);
SC_TEST_RET(card->ctx, r, "sc_lock() failed");
locked = 1;
}
if (apdu.datalen != 0)
{
r = sc_transmit_apdu(card, &apdu);
if (r)
{
sc_perror(card->ctx, r, "APDU transmit failed");
goto err;
}
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if (r)
{
sc_perror(card->ctx, r, "Card returned error");
goto err;
}
}
if (se_num <= 0)
return 0;
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
r = sc_transmit_apdu(card, &apdu);
sc_unlock(card);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
return sc_check_sw(card, apdu.sw1, apdu.sw2);
err:
if (locked)
sc_unlock(card);
return r;
}
static int myeid_set_security_env(struct sc_card *card,
const struct sc_security_env *env, int se_num)
{
if (env->flags & SC_SEC_ENV_ALG_PRESENT)
{
sc_security_env_t tmp;
tmp = *env;
tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
if (tmp.algorithm != SC_ALGORITHM_RSA)
{
sc_debug(card->ctx, "Only RSA algorithm supported.\n");
return SC_ERROR_NOT_SUPPORTED;
}
tmp.algorithm_ref = 0x00;
/* potential FIXME: return an error, if an unsupported
* pad or hash was requested, although this shouldn't happen */
if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
tmp.algorithm_ref = 0x02;
if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
tmp.algorithm_ref |= 0x10;
return myeid_set_security_env2(card, &tmp, se_num);
}
return myeid_set_security_env2(card, env, se_num);
}
static int myeid_compute_signature(struct sc_card *card, const u8 * data,
size_t datalen, u8 * out, size_t outlen)
{
int r;
struct sc_apdu apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
assert(card != NULL && data != NULL && out != NULL);
if (datalen > 256)
SC_FUNC_RETURN(card->ctx, 4, SC_ERROR_INVALID_ARGUMENTS);
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x9E Resp: Digital Signature
* P2: 0x9A Cmd: Input for Digital Signature */
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E, 0x9A);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 256;
if (datalen == 256)
{
apdu.p2 = data[0];
memcpy(sbuf, data+1, datalen-1);
apdu.lc = datalen - 1;
apdu.datalen = datalen - 1;
}
else
{
memcpy(sbuf, data, datalen);
apdu.lc = datalen;
apdu.datalen = datalen;
}
apdu.data = sbuf;
apdu.sensitive = 1;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
{
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, 4, len);
}
SC_FUNC_RETURN(card->ctx, 4, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int myeid_decipher(struct sc_card *card, const u8 * crgram,
size_t crgram_len, u8 * out, size_t outlen)
{
int r;
struct sc_apdu apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
assert(card != NULL && crgram != NULL && out != NULL);
SC_FUNC_CALLED(card->ctx, 2);
if (crgram_len > 256)
SC_FUNC_RETURN(card->ctx, 2, SC_ERROR_INVALID_ARGUMENTS);
/* INS: 0x2A PERFORM SECURITY OPERATION
* P1: 0x80 Resp: Plain value
* P2: 0x86 Cmd: Padding indicator byte followed by cryptogram */
sc_format_apdu(card, &apdu,
(crgram_len < 256) ? SC_APDU_CASE_4_SHORT : SC_APDU_CASE_3_SHORT,
0x2A, 0x80, 0x86);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = crgram_len;
apdu.sensitive = 1;
if (crgram_len == 256)
{ apdu.le = 0;
/* padding indicator byte, 0x81 = first half of 2048 bit cryptogram */
sbuf[0] = 0x81;
memcpy(sbuf + 1, crgram, crgram_len / 2);
apdu.lc = crgram_len / 2 + 1;
}
else
{
sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
memcpy(sbuf + 1, crgram, crgram_len);
apdu.lc = crgram_len + 1;
}
apdu.datalen = apdu.lc; apdu.data = sbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
{
if (crgram_len == 256)
{
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
0x2A, 0x80, 0x86);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = crgram_len;
apdu.sensitive = 1;
/* padding indicator byte,
* 0x82 = Second half of 2048 bit cryptogram */
sbuf[0] = 0x82;
memcpy(sbuf + 1, crgram + crgram_len / 2, crgram_len / 2);
apdu.lc = crgram_len / 2 + 1;
apdu.datalen = apdu.lc;
apdu.data = sbuf;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
{
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, 2, len);
}
}
else
{
int len = apdu.resplen > outlen ? outlen : apdu.resplen;
memcpy(out, apdu.resp, len);
SC_FUNC_RETURN(card->ctx, 2, len);
}
}
SC_FUNC_RETURN(card->ctx, 2, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
/* Write internal data, e.g. add default pin-records to pin */
static int myeid_putdata(struct sc_card *card, struct sc_cardctl_myeid_data_obj* data_obj)
{
int r;
struct sc_apdu apdu;
SC_FUNC_CALLED(card->ctx, 1);
memset(&apdu, 0, sizeof(apdu));
apdu.cse = SC_APDU_CASE_3_SHORT;
apdu.cla = 0x00;
apdu.ins = 0xDA;
apdu.p1 = data_obj->P1;
apdu.p2 = data_obj->P2;
apdu.lc = data_obj->DataLen;
apdu.datalen = data_obj->DataLen;
apdu.data = data_obj->Data;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "PUT_DATA returned error");
SC_FUNC_RETURN(card->ctx, 1, r);
}
/* Read internal data, e.g. get RSA public key */
static int myeid_getdata(struct sc_card *card, struct sc_cardctl_myeid_data_obj* data_obj)
{
int r;
struct sc_apdu apdu;
SC_FUNC_CALLED(card->ctx, 1);
memset(&apdu, 0, sizeof(apdu));
apdu.cse = SC_APDU_CASE_2_SHORT;
apdu.cla = 0x00;
apdu.ins = 0xCA; /* GET DATA */
apdu.p1 = data_obj->P1;
apdu.p2 = data_obj->P2;
apdu.lc = 0;
apdu.datalen = 0;
apdu.data = data_obj->Data;
apdu.le = 256;
apdu.resp = data_obj->Data;
apdu.resplen = data_obj->DataLen;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "GET_DATA returned error");
if (apdu.resplen > data_obj->DataLen)
r = SC_ERROR_WRONG_LENGTH;
else
data_obj->DataLen = apdu.resplen;
SC_FUNC_RETURN(card->ctx, 1, r);
}
static int myeid_loadkey(sc_card_t *card, int mode, u8* value, int value_len)
{
sc_apdu_t apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int r, len;
len = 0;
if(value_len == 0 || value == NULL)
return 0;
if(value != NULL &&
value[0] != 0x0 &&
mode != LOAD_KEY_PUBLIC_EXPONENT)
sbuf[len++] = 0x0;
SC_FUNC_CALLED(card->ctx, 1);
if(mode == LOAD_KEY_MODULUS && value_len >= 256)
{
r=0;
if((value_len % 2) > 0 && value[0] == 0x00)
{
value_len--;
memmove(value, value + 1, value_len);
}
mode = 0x88;
len = 128;
memcpy(sbuf,value, 128);
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xDA, 0x01, mode);
apdu.cla = 0x00;
apdu.data = sbuf;
apdu.datalen = len;
apdu.lc = len;
r = sc_transmit_apdu(card, &apdu);
if(r < 0)
return r;
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
if(r < 0)
return r;
mode = 0x89;
len = value_len - 128;
memset(&sbuf, 0, SC_MAX_APDU_BUFFER_SIZE);
memcpy(sbuf,value + 128, value_len - 128);
}
else
{
memcpy(sbuf + len, value, value_len);
len += value_len;
}
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xDA, 0x01, mode);
apdu.cla = 0x00;
apdu.data = sbuf;
apdu.datalen = len;
apdu.lc = len;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_FUNC_RETURN(card->ctx, 1, r);
}
/* Generate or store a key */
static int myeid_generate_store_key(struct sc_card *card,
struct sc_cardctl_myeid_gen_store_key_info *data)
{
struct sc_apdu apdu;
u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
int r,len;
/* Setup key-generation paramters */
if (data->op_type == OP_TYPE_GENERATE)
{
len = 0;
sbuf[len++] = 0x30;
sbuf[len++] = 0x05;
sbuf[len++] = 0x81;
sbuf[len++] = data->pubexp_len;
memcpy(sbuf + len, data->pubexp, data->pubexp_len);
len += data->pubexp_len;
memset(&apdu, 0, sizeof(apdu));
sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46, 0x00, 0x00);
apdu.cla = 0x00;
apdu.data = sbuf;
apdu.datalen = len;
apdu.lc = len;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "GENERATE_KEY returned error");
SC_FUNC_RETURN(card->ctx, 1, r);
}
else
{
if((r=myeid_loadkey(card, LOAD_KEY_PRIME_P,
data->primep, data->primep_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_PRIME_Q,
data->primeq, data->primeq_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_DP1,
data->dp1, data->dp1_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_DQ1,
data->dq1, data->dq1_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_INVQ,
data->invq, data->invq_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_MODULUS,
data->mod, data->mod_len)) >= 0 &&
(r=myeid_loadkey(card, LOAD_KEY_PUBLIC_EXPONENT,
data->pubexp, data->pubexp_len)) >= 0)
return r;
}
return r;
}
static int myeid_activate_card(struct sc_card *card)
{
int r;
u8 sbuf[] ="\xA0\x00\x00\x00\x63\x50\x4B\x43\x53\x2D\x31\x35";
sc_apdu_t apdu;
sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x44, 0x04, 0x00);
apdu.cla = 0x00;
apdu.data = sbuf;
apdu.datalen = 0x0C;
apdu.lc = 0x0C;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
SC_TEST_RET(card->ctx, r, "ACTIVATE_APPLET returned error");
SC_FUNC_RETURN(card->ctx, 1, r);
}
static int myeid_get_serialnr(sc_card_t *card, sc_serial_number_t *serial)
{
int r;
sc_apdu_t apdu;
u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0x01, 0xA0);
apdu.resp = rbuf;
apdu.resplen = sizeof(rbuf);
apdu.le = 256;
r = sc_transmit_apdu(card, &apdu);
SC_TEST_RET(card->ctx, r, "APDU transmit failed");
if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
return SC_ERROR_INTERNAL;
if (apdu.resplen != 20)
{
sc_debug(card->ctx, "unexpected response to GET DATA serial number\n");
return SC_ERROR_INTERNAL;
}
/* cache serial number */
memcpy(card->serialnr.value, &rbuf[10], 8);
card->serialnr.len = 8;
/* copy and return serial number */
memcpy(serial, &card->serialnr, sizeof(*serial));
return SC_SUCCESS;
}
static int myeid_card_ctl(struct sc_card *card, unsigned long cmd, void *ptr)
{
switch(cmd) {
case SC_CARDCTL_MYEID_PUTDATA:
return myeid_putdata(card,
(struct sc_cardctl_myeid_data_obj*) ptr);
case SC_CARDCTL_MYEID_GETDATA:
return myeid_getdata(card,
(struct sc_cardctl_myeid_data_obj*) ptr);
case SC_CARDCTL_MYEID_GENERATE_KEY:
return myeid_generate_store_key(card,
(struct sc_cardctl_myeid_gen_store_key_info *) ptr);
case SC_CARDCTL_MYEID_ACTIVATE_CARD:
return myeid_activate_card(card);
case SC_CARDCTL_GET_SERIALNR:
return myeid_get_serialnr(card, (sc_serial_number_t *)ptr);
}
return SC_ERROR_NOT_SUPPORTED;
}
/* "The PINs are "global" in a PKCS#15 sense, meaning that they remain valid
* until card reset! Selecting another applet doesn't invalidate the PINs,
* you need to reset the card." - javacard@zurich.ibm.com, when asked about
* how to invalidate logged in pins.
*/
static int myeid_logout(struct sc_card *card)
{
return 0; /* Can't */
}
static struct sc_card_driver * sc_get_driver(void)
{
struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
myeid_ops = *iso_drv->ops;
myeid_ops.match_card = myeid_match_card;
myeid_ops.init = myeid_init;
myeid_ops.finish = myeid_finish;
if (iso_ops == NULL)
iso_ops = iso_drv->ops;
myeid_ops.read_binary = myeid_read_binary;
myeid_ops.read_record = myeid_read_record_unsupp;
myeid_ops.write_record = myeid_wrupd_record_unsupp;
myeid_ops.append_record = myeid_append_record_unsupp;
myeid_ops.update_record = myeid_wrupd_record_unsupp;
myeid_ops.write_binary = myeid_write_binary;
myeid_ops.update_binary = myeid_update_binary;
myeid_ops.select_file = myeid_select_file;
myeid_ops.create_file = myeid_create_file;
myeid_ops.delete_file = myeid_delete_file;
myeid_ops.list_files = myeid_list_files;
myeid_ops.set_security_env = myeid_set_security_env;
myeid_ops.compute_signature = myeid_compute_signature;
myeid_ops.decipher = myeid_decipher;
myeid_ops.logout = myeid_logout;
myeid_ops.process_fci = myeid_process_fci;
myeid_ops.card_ctl = myeid_card_ctl;
return &myeid_drv;
}
struct sc_card_driver * sc_get_myeid_driver(void)
{
return sc_get_driver();
}

View File

@ -639,6 +639,7 @@ static int rtecp_card_ctl(sc_card_t *card, unsigned long request, void *data)
apdu.resp = buf;
apdu.resplen = sizeof(buf);
apdu.le = sizeof(buf) - 2;
serial->len = sizeof(serial->value);
break;
case SC_CARDCTL_RTECP_GENERATE_KEY:
if (!genkey_data)

View File

@ -188,6 +188,14 @@ enum {
SC_CARDCTL_WESTCOS_SET_DEFAULT_KEY,
SC_CARDCTL_WESTCOS_LOAD_DATA,
/*
* MyEID specific calls
*/
SC_CARDCTL_MYEID_BASE = _CTL_PREFIX('M', 'Y', 'E'),
SC_CARDCTL_MYEID_PUTDATA,
SC_CARDCTL_MYEID_GETDATA,
SC_CARDCTL_MYEID_GENERATE_KEY,
SC_CARDCTL_MYEID_ACTIVATE_CARD,
};
enum {
@ -690,6 +698,35 @@ typedef struct sc_rtecp_genkey_data {
size_t modulus_len;
} sc_rtecp_genkey_data_t;
/*
* MyEID stuff
*/
struct sc_cardctl_myeid_data_obj {
int P1;
int P2;
u8 * Data;
size_t DataLen;
int LengthMax;
};
struct sc_cardctl_myeid_gen_store_key_info {
int op_type;
unsigned int mod_len;
unsigned char *mod;
unsigned int pubexp_len;
unsigned char *pubexp;
unsigned int primep_len;
unsigned char *primep;
unsigned int primeq_len;
unsigned char *primeq;
unsigned int dp1_len;
unsigned char *dp1;
unsigned int dq1_len;
unsigned char *dq1;
unsigned int invq_len;
unsigned char *invq;
};
#ifdef __cplusplus
}
#endif

View File

@ -146,6 +146,10 @@ enum {
SC_CARD_TYPE_ENTERSAFE_BASE = 19000,
SC_CARD_TYPE_ENTERSAFE_3K,
SC_CARD_TYPE_ENTERSAFE_FTCOS_PK_01C,
/* MyEID cards */
SC_CARD_TYPE_MYEID_BASE = 20000,
SC_CARD_TYPE_MYEID_GENERIC,
};
extern sc_card_driver_t *sc_get_default_driver(void);
@ -175,6 +179,7 @@ extern sc_card_driver_t *sc_get_entersafe_driver(void);
extern sc_card_driver_t *sc_get_rutoken_driver(void);
extern sc_card_driver_t *sc_get_rtecp_driver(void);
extern sc_card_driver_t *sc_get_westcos_driver(void);
extern sc_card_driver_t *sc_get_myeid_driver(void);
#ifdef __cplusplus
}

View File

@ -85,6 +85,7 @@ static const struct _sc_driver_entry internal_card_drivers[] = {
{ "rutoken", (void *(*)(void)) sc_get_rutoken_driver },
{ "rutoken_ecp",(void *(*)(void)) sc_get_rtecp_driver },
{ "westcos", (void *(*)(void)) sc_get_westcos_driver },
{ "myeid", (void *(*)(void)) sc_get_myeid_driver },
/* emv is not really implemented */
{ "emv", (void *(*)(void)) sc_get_emv_driver },
/* The default driver should be last, as it handles all the

View File

@ -25,7 +25,8 @@ dist_pkgdata_DATA = \
asepcos.profile \
entersafe.profile \
rutoken_ecp.profile \
westcos.profile
westcos.profile \
myeid.profile
AM_CPPFLAGS = -DSC_PKCS15_PROFILE_DIRECTORY=\"$(pkgdatadir)\"
AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(LTLIB_CFLAGS)
@ -38,7 +39,7 @@ libpkcs15init_la_SOURCES = \
pkcs15-cardos.c pkcs15-jcop.c pkcs15-starcos.c \
pkcs15-oberthur.c pkcs15-setcos.c pkcs15-incrypto34.c \
pkcs15-muscle.c pkcs15-asepcos.c pkcs15-rutoken.c \
pkcs15-entersafe.c pkcs15-rtecp.c \
pkcs15-entersafe.c pkcs15-rtecp.c pkcs15-myeid.c \
pkcs15init.exports
if WIN32
libpkcs15init_la_SOURCES += versioninfo.rc

View File

@ -11,6 +11,7 @@ OBJECTS = pkcs15-lib.obj profile.obj keycache.obj \
pkcs15-oberthur.obj pkcs15-setcos.obj pkcs15-incrypto34.obj \
pkcs15-muscle.obj pkcs15-asepcos.obj pkcs15-rutoken.obj \
pkcs15-entersafe.obj pkcs15-rtecp.obj pkcs15-westcos.obj \
pkcs15-myeid.obj \
versioninfo.res
all: install-headers $(TARGET)

View File

@ -264,6 +264,10 @@ sc_keycache_set_pin_name(const sc_path_t *path, int ref, int name)
s = new_entry(path, SC_AC_CHV, ref);
if (s == NULL)
return SC_ERROR_OUT_OF_MEMORY;
s->len = sc_keycache_get_key(path, SC_AC_CHV, -1, s->value, MAX_SECRET);
if(s->len < 0)
return SC_ERROR_OBJECT_NOT_FOUND;
}
/* Set the pin name */

View File

@ -0,0 +1,53 @@
#
# PKCS15 r/w profile for MyEID cards
#
cardinfo {
max-pin-length = 8;
pin-encoding = ascii-numeric;
pin-pad-char = 0x00;
}
# Define reasonable limits for PINs and PUK
# Note that we do not set a file path or reference
# here; that is done dynamically.
PIN user-pin {
attempts = 3;
}
PIN user-puk {
attempts = 10;
}
# Additional filesystem info.
# This is added to the file system info specified in the
# main profile.
filesystem {
DF MF {
DF PKCS15-AppDF {
EF template-private-key {
type = internal-ef;
file-id = 4B01; # This is the base FileID
size = 266; # 266 is enough for 1024-bit keys
ACL = *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
}
EF template-public-key {
file-id = 5501;
ACL = *=NEVER, READ=NONE, UPDATE=$PIN;
}
EF template-certificate {
file-id = 4301;
ACL = *=NEVER, READ=NONE, UPDATE=$PIN;
}
EF template-extractable-key {
file-id = 7000;
ACL = *=NEVER, READ=$PIN, UPDATE=$PIN;
}
}
}
}
# Define an SO pin
# This PIN is not used yet.
#PIN sopin {
# file = sopinfile;
# reference = 0;
#}

View File

@ -405,6 +405,7 @@ extern struct sc_pkcs15init_operations *sc_pkcs15init_get_rutoken_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_entersafe_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_rtecp_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_westcos_ops(void);
extern struct sc_pkcs15init_operations *sc_pkcs15init_get_myeid_ops(void);
#ifdef __cplusplus
}

View File

@ -166,6 +166,7 @@ static struct profile_operations {
{ "entersafe",(void*) sc_pkcs15init_get_entersafe_ops },
{ "rutoken_ecp", (void *) sc_pkcs15init_get_rtecp_ops },
{ "westcos", (void *) sc_pkcs15init_get_westcos_ops },
{ "myeid", (void *) sc_pkcs15init_get_myeid_ops },
{ NULL, NULL },
};

View File

@ -0,0 +1,426 @@
/*
* MyEID specific operations for PKCS15 initialization
*
* Copyright (C) 2008-2009 Aventra Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <opensc/opensc.h>
#include <opensc/cardctl.h>
#include <opensc/log.h>
#include "pkcs15-init.h"
#include "keycache.h"
#include "profile.h"
#define MYEID_MAX_PINS 5
unsigned char MYEID_DEFAULT_PUBKEY[] = {0x01, 0x00, 0x01};
#define MYEID_DEFAULT_PUBKEY_LEN sizeof(MYEID_DEFAULT_PUBKEY)
static int myeid_generate_store_key( sc_profile_t *, sc_card_t *,
unsigned int, unsigned int, sc_pkcs15_pubkey_t *,
sc_pkcs15_prkey_t *, sc_pkcs15_prkey_info_t *);
static int myeid_create_pin_internal(sc_profile_t *, sc_card_t *,
int, sc_pkcs15_pin_info_t *, const u8 *, size_t,
const u8 *, size_t);
static int myeid_puk_retries(sc_profile_t *, int);
/*
* Erase the card.
*/
static int myeid_erase_card(sc_profile_t *profile, sc_card_t *card)
{
struct sc_cardctl_myeid_data_obj data_obj;
sc_pkcs15_pin_info_t pin_info;
u8 data[8];
int r;
/* Just delete the entire MF */
/* The SO pin has pin reference 1 -- not that it matters much
* because pkcs15-init will ask to enter all pins, even if we
* did a --so-pin on the command line. */
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info);
sc_keycache_set_pin_name(NULL, pin_info.reference, SC_PKCS15INIT_SO_PIN);
/* Select parent DF and verify PINs/key as necessary */
r = sc_pkcs15init_authenticate(profile, card, profile->mf_info->file, SC_AC_OP_DELETE);
if (r < 0)
return r == SC_ERROR_FILE_NOT_FOUND ? 0 : r;
data[0]= 0xFF;
data[1]= 0xFF;
data[2]= 0x33;
data[3]= 0x3F;
data[4]= 0xFF;
data[5]= 0x33;
data[6]= 0x3F;
data[7]= 0xFF;
data_obj.P1 = 0x01;
data_obj.P2 = 0xE0;
data_obj.Data = data;
data_obj.DataLen = 0x08;
r = sc_card_ctl(card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
return r;
}
/*
* Select the PIN reference
*/
static int myeid_select_pin_reference(sc_profile_t *profile, sc_card_t *card,
sc_pkcs15_pin_info_t *pin_info)
{
sc_pkcs15_pin_info_t pin_info_prof;
pin_info_prof.reference = 1; /* Default SO PIN ref. */
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info_prof);
/* For the SO pin, we take the first available pin reference = 1 */
if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
pin_info->reference = pin_info_prof.reference;
/* sc_pkcs15init_create_pin() starts checking if 0 is an acceptable
* pin reference, which isn't for the myeid cards. And since the
* value 1 has been assigned to the SO pin, we'll jump to 2. */
else if (pin_info->reference == 0)
pin_info->reference = pin_info_prof.reference + 1;
return 0;
}
/*
* Create a new PIN
*/
static int myeid_create_pin(sc_profile_t *profile, sc_card_t *card,
sc_file_t *df, sc_pkcs15_object_t *pin_obj,
const u8 *pin, size_t pin_len,
const u8 *puk, size_t puk_len)
{
return myeid_create_pin_internal(profile, card,
0, (sc_pkcs15_pin_info_t *) pin_obj->data,
pin, pin_len,
puk, puk_len);
}
/*
* Setup file struct & path: get correct template from the profile, construct full path
* num = number of objects of this type already on the card
*/
static int myeid_new_file(sc_profile_t *profile, sc_card_t *card,
unsigned int type, unsigned int num,
sc_file_t **out)
{
sc_file_t *file;
sc_path_t *p;
char name[64], *tag;
int r;
if (type == SC_PKCS15_TYPE_PRKEY_RSA)
tag = "private-key";
else if (type == SC_PKCS15_TYPE_PUBKEY_RSA)
tag = "public-key";
else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_CERT)
tag = "certificate";
else if ((type & SC_PKCS15_TYPE_CLASS_MASK) == SC_PKCS15_TYPE_DATA_OBJECT)
tag = "data";
else
{
sc_debug(card->ctx, "Unsupported file type");
return SC_ERROR_INVALID_ARGUMENTS;
}
/* Get template from profile */
snprintf(name, sizeof(name), "template-%s", tag);
if (sc_profile_get_file(profile, name, &file) < 0)
{
sc_debug(card->ctx, "Profile doesn't define %s", name);
return SC_ERROR_NOT_SUPPORTED;
}
/* Auto-increment FID for next object */
file->id += num;
p = &file->path;
*p = profile->df_info->file->path;
p->value[p->len++] = (u8) (file->id / 256);
p->value[p->len++] = (u8) (file->id % 256);
/* Increment FID until there's no file with such path */
r = sc_select_file(card, p, NULL);
while(r == 0)
{
file->id++;
p->value[p->len - 2] = (u8) (file->id / 256);
p->value[p->len - 1] = (u8) (file->id % 256);
r = sc_select_file(card, p, NULL);
}
*out = file;
return 0;
}
static int myeid_encode_private_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
size_t *keysize, int key_ref)
{
return 0;
}
static int myeid_encode_public_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey_rsa *rsa, u8 *key,
size_t *keysize, int key_ref)
{
return 0;
}
/*
* Generate RSA key
*/
static int myeid_generate_key(sc_profile_t *profile, sc_card_t *card,
unsigned int index, /* keyref: 0 for 1st key, ... */
unsigned int keybits,
sc_pkcs15_pubkey_t *pubkey,
struct sc_pkcs15_prkey_info *info)
{
return myeid_generate_store_key(profile, card, index, keybits,
pubkey, NULL, info);
}
/*
* Store RSA key
*/
static int myeid_new_key(sc_profile_t *profile, sc_card_t *card,
struct sc_pkcs15_prkey *key, unsigned int index,
struct sc_pkcs15_prkey_info *info)
{
return myeid_generate_store_key(profile, card, index,
key->u.rsa.modulus.len * 8, NULL, key, info);
}
/*
* Common code for generating or storing a private key.
* If pubkey == NULL and prkey != NULL, we have to store a private key
* In the oposite case, we have to generate a private key
*/
static int myeid_generate_store_key(sc_profile_t *profile, sc_card_t *card,
unsigned int index, /* keynumber: 0 for 1st priv key, ... */
unsigned int keybits,
sc_pkcs15_pubkey_t *pubkey,
sc_pkcs15_prkey_t *prkey,
sc_pkcs15_prkey_info_t *info)
{
struct sc_cardctl_myeid_gen_store_key_info args;
struct sc_cardctl_myeid_data_obj data_obj;
unsigned char raw_pubkey[256];
int r;
unsigned int mod_len;
sc_file_t *prkf = NULL;
/* Parameter check */
if ( (keybits < 1024) || (keybits > 2048) || (keybits & 0X7)) {
sc_debug(card->ctx,
"Unsupported key size [%u]: 1024-2048 bit + 8-multiple\n", keybits);
return SC_ERROR_INVALID_ARGUMENTS;
}
/* Get the private key file */
r = myeid_new_file(profile, card, SC_PKCS15_TYPE_PRKEY_RSA, index, &prkf);
if (r < 0)
goto done;
/* Take enough room for a 1024 bit key */
if (prkf->size < 1024)
prkf->size = 1024;
/* Now create the key file */
r = sc_pkcs15init_create_file(profile, card, prkf);
if (r < 0)
goto done;
/* Fill in data structure */
memset(&args, 0, sizeof(args));
args.mod_len = keybits;
if (prkey == NULL)
{
args.op_type = OP_TYPE_GENERATE;
args.pubexp_len = MYEID_DEFAULT_PUBKEY_LEN;
args.pubexp = MYEID_DEFAULT_PUBKEY;
}
else
{
args.op_type = OP_TYPE_STORE;
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.mod_len = prkey->u.rsa.modulus.len;
args.mod = prkey->u.rsa.modulus.data;
}
/* Authenticate */
r = sc_pkcs15init_authenticate(profile, card, prkf, SC_AC_OP_UPDATE);
if (r < 0)
goto done;
/* Generate/store rsa key */
r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_KEY, &args);
if (r < 0)
goto done;
info->key_reference = 0;
info->path = prkf->path;
done:
if (prkf)
sc_file_free(prkf);
return r;
}
/*
* Create a new PIN
*/
static int myeid_create_pin_internal(sc_profile_t *profile, sc_card_t *card,
int ignore_ac, sc_pkcs15_pin_info_t *pin_info,
const u8 *pin, size_t pin_len,
const u8 *puk, size_t puk_len)
{
u8 data[19];
int so_pin_ref;
int r;
struct sc_cardctl_myeid_data_obj data_obj;
sc_file_t *pinfile = NULL;
if (pin_info->reference >= MYEID_MAX_PINS)
return SC_ERROR_INVALID_ARGUMENTS;
if (pin == NULL || puk == NULL || pin_len < 4 || puk_len < 4)
return SC_ERROR_INVALID_PIN_LENGTH;
/* Verify required access rights if needed (i.e. if the
* pin file isn't in the CREATE life cycle state). */
if (!ignore_ac)
{
/* Re-ink the SO pin to the MF because there is the pin file */
so_pin_ref = sc_keycache_find_named_pin(&profile->df_info->file->path,
SC_PKCS15INIT_SO_PIN);
if (so_pin_ref >= 0)
sc_keycache_set_pin_name(&profile->mf_info->file->path,
so_pin_ref, SC_PKCS15INIT_SO_PIN);
r = sc_profile_get_file(profile, "pinfile", &pinfile);
if (r >= 0)
r = sc_pkcs15init_authenticate(profile, card, pinfile, SC_AC_OP_UPDATE);
sc_file_free(pinfile);
if (r < 0)
return r;
}
/* Make command to add a pin-record */
data_obj.P1 = 01;
data_obj.P2 = pin_info->reference; /* myeid pin number */
memcpy(&data[0], (u8 *)pin, pin_len); /* copy pin*/
memcpy(&data[8], (u8 *)puk, puk_len); /* copy puk */
/* Optional PIN locking
* data[17] = pin_info->tries_left & 0x0F;
* data[18] = myeid_puk_retries(profile, pin_info->reference) & 0x0F;
*/
data[17] = 0x00;
data[18] = 0x00;
data[19] = 0x00;
data_obj.Data = data;
data_obj.DataLen = 0x10;
r = sc_card_ctl(card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
return r;
}
static int myeid_puk_retries(sc_profile_t *profile, int pin_ref)
{
sc_pkcs15_pin_info_t pin_info;
pin_info.reference = 1; /* Default SO PIN ref. */
sc_profile_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &pin_info);
/* If pin_ref is the SO PIN, get the SO PUK info, otherwise the User PUK info */
sc_profile_get_pin_info(profile,
pin_ref == pin_info.reference ?
SC_PKCS15INIT_SO_PUK : SC_PKCS15INIT_USER_PUK,
&pin_info);
if ((pin_info.tries_left < 0) || (pin_info.tries_left > 15))
return 3; /* Little extra safety */
return pin_info.tries_left;
}
/* For Myeid, all objects are files that can be deleted in any order */
static int myeid_delete_object(struct sc_profile *profile,
struct sc_card *card, unsigned int type,
const void *data, const sc_path_t *path)
{
return sc_pkcs15init_delete_by_path(profile, card, path);
}
static struct sc_pkcs15init_operations sc_pkcs15init_myeid_operations = {
myeid_erase_card,
NULL, /* init_card */
NULL, /* create_dir */
NULL, /* create_domain */
myeid_select_pin_reference,
myeid_create_pin,
NULL, /* select_key_reference */
NULL, /* create_key */
NULL, /* store_key */
NULL, /* generate_key */
myeid_encode_private_key,
myeid_encode_public_key,
NULL, /* finalize_card */
NULL,
NULL, /* style api */
myeid_new_key,
myeid_new_file,
myeid_generate_key,
myeid_delete_object
};
struct sc_pkcs15init_operations *sc_pkcs15init_get_myeid_ops(void)
{
return &sc_pkcs15init_myeid_operations;
}

View File

@ -18,7 +18,7 @@ It isn't
It doesn't have
- anything else but data. No locking, no threads etc.
It has heirarchical data blocks, it has lists.
It has heirarchical data blocks, it has lists.
Similar, but different:
- .ini files. scconf is block structured, has lists and arrays
@ -216,8 +216,8 @@ typedef struct _scconf_entry {
* Look for blocks with this key, or check if this
* block has an item with this key. Run the block
* or blocks found against the rest of this entry
* Stop after the first one, unless
* SCCONF_ALL_BLOCKS is set in flags
* Stop after the first one, unless
* SCCONF_ALL_BLOCKS is set in flags
unsigned int type;
* SCCONF_CALLBACK
* parm contains a function ptr of type
@ -226,7 +226,7 @@ typedef struct _scconf_entry {
* scconf_entry* entry,
* int depth);
* run the callback with the block found
*
*
* SCCONF_BLOCK
* param contains a pointer to another entry table
* use the found block against every entry
@ -269,7 +269,7 @@ typedef struct _scconf_entry {
* where a pointer to a copy of list
* can be stored
*
*
*
unsigned int flags;
* SCCONF_PRESENT
* This bit is or'ed in when found
@ -298,8 +298,8 @@ Sub-blocks can be added, and callbacks can be issued.
This is a handy method for adding scconf data from within a program.
typedef struct _scconf_entry {
const char *name;
* key value for blocks and items *
const char *name;
* key value for blocks and items *
unsigned int type;
* SCCONF_CALLBACK
* parm contains a function ptr of type
@ -307,12 +307,12 @@ typedef struct _scconf_entry {
* scconf_block* block,
* scconf_entry* entry,
* int depth);
*
*
* SCCONF_BLOCK
* param contains a pointer to another entry table
* the entry table is added as a block to the
* current block, with name as the key, and
* arg is a list of names
* arg is a list of names
*
* SCCONF_LIST
* SCCONF_BOOLEAN
@ -320,7 +320,7 @@ typedef struct _scconf_entry {
* SCCONF_STRING
* these add key=value pairs to the current
* block. The value is in parm.
*
*
unsigned int flags;
* SCCONF_PRESENT
* This bit is or'ed in when item added