- Improved OpenPGP handling; we're now able to sign things
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1625 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
59c38ee7cd
commit
43da7aac4e
|
@ -38,8 +38,6 @@ static struct sc_card_driver pgp_drv = {
|
||||||
&pgp_ops
|
&pgp_ops
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pgp_get_pubkey(sc_card_t *, unsigned int, u8 *, size_t);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The OpenPGP card doesn't have a file system, instead everything
|
* The OpenPGP card doesn't have a file system, instead everything
|
||||||
* is stored in data objects that are accessed through GET/PUT.
|
* is stored in data objects that are accessed through GET/PUT.
|
||||||
|
@ -54,39 +52,59 @@ static int pgp_get_pubkey(sc_card_t *, unsigned int, u8 *, size_t);
|
||||||
struct blob {
|
struct blob {
|
||||||
struct blob * next;
|
struct blob * next;
|
||||||
struct blob * parent;
|
struct blob * parent;
|
||||||
|
struct do_info *info;
|
||||||
|
|
||||||
sc_file_t * file;
|
sc_file_t * file;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
|
int status;
|
||||||
|
|
||||||
unsigned char * data;
|
unsigned char * data;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
struct blob * files;
|
struct blob * files;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct do_info {
|
struct do_info {
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
unsigned int constructed : 1;
|
unsigned int constructed : 1;
|
||||||
|
unsigned int size;
|
||||||
int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t);
|
int (*get_fn)(sc_card_t *, unsigned int, u8 *, size_t);
|
||||||
int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t);
|
int (*put_fn)(sc_card_t *, unsigned int, const u8 *, size_t);
|
||||||
} pgp_objects[] = {
|
};
|
||||||
{ 0x004f, 0, sc_get_data, sc_put_data },
|
|
||||||
{ 0x005e, 1, sc_get_data, sc_put_data },
|
static struct blob * pgp_new_blob(struct blob *, unsigned int, int,
|
||||||
{ 0x0065, 1, sc_get_data, sc_put_data },
|
struct do_info *);
|
||||||
{ 0x006e, 1, sc_get_data, sc_put_data },
|
static int pgp_get_pubkey(sc_card_t *, unsigned int,
|
||||||
{ 0x0073, 1, sc_get_data, sc_put_data },
|
u8 *, size_t);
|
||||||
{ 0x007a, 1, sc_get_data, sc_put_data },
|
static int pgp_get_pubkey_pem(sc_card_t *, unsigned int,
|
||||||
{ 0x5f50, 0, sc_get_data, sc_put_data },
|
u8 *, size_t);
|
||||||
{ 0xb600, 0, pgp_get_pubkey, NULL },
|
|
||||||
{ 0xb800, 0, pgp_get_pubkey, NULL },
|
struct do_info pgp_objects[] = {
|
||||||
{ 0xa400, 0, pgp_get_pubkey, NULL },
|
{ 0x004f, 0, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x005e, 1, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x0065, 1, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x006e, 1, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x0073, 1, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x007a, 1, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0x5f50, 0, 0, sc_get_data, sc_put_data },
|
||||||
|
{ 0xb600, 1, 0, pgp_get_pubkey, NULL },
|
||||||
|
{ 0xb800, 1, 0, pgp_get_pubkey, NULL },
|
||||||
|
{ 0xa400, 1, 0, pgp_get_pubkey, NULL },
|
||||||
|
{ 0xb601, 0, 0, pgp_get_pubkey_pem,NULL },
|
||||||
|
{ 0xb801, 0, 0, pgp_get_pubkey_pem,NULL },
|
||||||
|
{ 0xa401, 0, 0, pgp_get_pubkey_pem,NULL },
|
||||||
|
|
||||||
{ 0 },
|
{ 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data))
|
#define DRVDATA(card) ((struct pgp_priv_data *) ((card)->drv_data))
|
||||||
struct pgp_priv_data {
|
struct pgp_priv_data {
|
||||||
struct blob mf;
|
struct blob mf;
|
||||||
struct blob * current;
|
struct blob * current;
|
||||||
|
|
||||||
|
sc_security_env_t sec_env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pgp_match_card(sc_card_t *card)
|
pgp_match_card(sc_card_t *card)
|
||||||
{
|
{
|
||||||
|
@ -119,6 +137,7 @@ pgp_init(sc_card_t *card)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
sc_path_t aid;
|
sc_path_t aid;
|
||||||
sc_file_t *file = NULL;
|
sc_file_t *file = NULL;
|
||||||
|
struct do_info *info;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
priv = (struct pgp_priv_data *) calloc (1, sizeof *priv);
|
priv = (struct pgp_priv_data *) calloc (1, sizeof *priv);
|
||||||
|
@ -152,6 +171,15 @@ pgp_init(sc_card_t *card)
|
||||||
priv->mf.id = 0x3F00;
|
priv->mf.id = 0x3F00;
|
||||||
|
|
||||||
priv->current = &priv->mf;
|
priv->current = &priv->mf;
|
||||||
|
|
||||||
|
/* Populate MF - add all blobs listed in the pgp_objects
|
||||||
|
* table. */
|
||||||
|
for (info = pgp_objects; info->id > 0; info++) {
|
||||||
|
pgp_new_blob(&priv->mf, info->id,
|
||||||
|
info->constructed? SC_FILE_TYPE_DF
|
||||||
|
: SC_FILE_TYPE_WORKING_EF,
|
||||||
|
info);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,9 +198,23 @@ pgp_finish(sc_card_t *card)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pgp_set_blob(struct blob *blob, const u8 *data, size_t len)
|
||||||
|
{
|
||||||
|
if (blob->data)
|
||||||
|
free(blob->data);
|
||||||
|
blob->len = len;
|
||||||
|
blob->status = 0;
|
||||||
|
blob->data = malloc(len);
|
||||||
|
memcpy(blob->data, data, len);
|
||||||
|
|
||||||
|
blob->file->size = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static struct blob *
|
static struct blob *
|
||||||
pgp_new_blob(struct blob *parent, unsigned int file_id,
|
pgp_new_blob(struct blob *parent, unsigned int file_id,
|
||||||
int file_type, const u8 *data, size_t len)
|
int file_type, struct do_info *info)
|
||||||
{
|
{
|
||||||
sc_file_t *file = sc_file_new();
|
sc_file_t *file = sc_file_new();
|
||||||
struct blob *blob, **p;
|
struct blob *blob, **p;
|
||||||
|
@ -181,13 +223,10 @@ pgp_new_blob(struct blob *parent, unsigned int file_id,
|
||||||
blob->parent = parent;
|
blob->parent = parent;
|
||||||
blob->id = file_id;
|
blob->id = file_id;
|
||||||
blob->file = file;
|
blob->file = file;
|
||||||
blob->len = len;
|
blob->info = info;
|
||||||
blob->data = malloc(len);
|
|
||||||
memcpy(blob->data, data, len);
|
|
||||||
|
|
||||||
file->type = file_type;
|
file->type = file_type;
|
||||||
file->path = parent->file->path;
|
file->path = parent->file->path;
|
||||||
file->size = len;
|
|
||||||
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
file->ef_structure = SC_FILE_EF_TRANSPARENT;
|
||||||
sc_append_file_id(&file->path, file_id);
|
sc_append_file_id(&file->path, file_id);
|
||||||
|
|
||||||
|
@ -198,6 +237,29 @@ pgp_new_blob(struct blob *parent, unsigned int file_id,
|
||||||
return blob;
|
return blob;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pgp_read_blob(sc_card_t *card, struct blob *blob)
|
||||||
|
{
|
||||||
|
unsigned char buffer[256];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (blob->data != NULL)
|
||||||
|
return 0;
|
||||||
|
if (blob->info == NULL)
|
||||||
|
return blob->status;
|
||||||
|
|
||||||
|
card->ctx->suppress_errors++;
|
||||||
|
r = blob->info->get_fn(card, blob->id, buffer, sizeof(buffer));
|
||||||
|
card->ctx->suppress_errors--;
|
||||||
|
|
||||||
|
if (r < 0) {
|
||||||
|
blob->status = r;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pgp_set_blob(blob, buffer, r);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enumerate contents of a data blob.
|
* Enumerate contents of a data blob.
|
||||||
* The OpenPGP card has a funny TLV encoding.
|
* The OpenPGP card has a funny TLV encoding.
|
||||||
|
@ -206,6 +268,13 @@ static int
|
||||||
pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
|
pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
|
||||||
{
|
{
|
||||||
const u8 *in, *end;
|
const u8 *in, *end;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (blob->files != NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if ((r = pgp_read_blob(card, blob)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
in = blob->data;
|
in = blob->data;
|
||||||
end = blob->data + blob->len;
|
end = blob->data + blob->len;
|
||||||
|
@ -246,7 +315,7 @@ pgp_enumerate_blob(sc_card_t *card, struct blob *blob)
|
||||||
if (in + len > end)
|
if (in + len > end)
|
||||||
goto eoc;
|
goto eoc;
|
||||||
|
|
||||||
pgp_new_blob(blob, tag, type, in, len);
|
pgp_set_blob(pgp_new_blob(blob, tag, type, NULL), in, len);
|
||||||
in += len;
|
in += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,60 +329,24 @@ static int
|
||||||
pgp_get_blob(sc_card_t *card, struct blob *blob, unsigned int id,
|
pgp_get_blob(sc_card_t *card, struct blob *blob, unsigned int id,
|
||||||
struct blob **ret)
|
struct blob **ret)
|
||||||
{
|
{
|
||||||
struct pgp_priv_data *priv = DRVDATA(card);
|
|
||||||
struct blob *child;
|
struct blob *child;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
again:
|
if ((r = pgp_enumerate_blob(card, blob)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
for (child = blob->files; child; child = child->next) {
|
for (child = blob->files; child; child = child->next) {
|
||||||
if (child->id == id) {
|
if (child->id == id)
|
||||||
*ret = child;
|
break;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Blob not found. Are we a child of the MF, i.e. do
|
if (child != NULL) {
|
||||||
* we represent a proper data object? If so, try to
|
(void) pgp_read_blob(card, child);
|
||||||
* read the object. If not, try to enumerate the
|
*ret = child;
|
||||||
* contents of blob.
|
|
||||||
*/
|
|
||||||
if (blob->parent == NULL) {
|
|
||||||
/* Try to read contents of data object */
|
|
||||||
unsigned char buffer[256];
|
|
||||||
struct do_info *doi;
|
|
||||||
int type = SC_FILE_TYPE_DF;
|
|
||||||
|
|
||||||
r = SC_ERROR_FILE_NOT_FOUND;
|
|
||||||
for (doi = pgp_objects; doi->id > 0; doi++) {
|
|
||||||
if (doi->id != id)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!doi->constructed)
|
|
||||||
type = SC_FILE_TYPE_WORKING_EF;
|
|
||||||
|
|
||||||
/* If we fail to read an object, we treat it as
|
|
||||||
* if it's there anyway, just empty */
|
|
||||||
card->ctx->suppress_errors++;
|
|
||||||
r = doi->get_fn(card, id, buffer, sizeof(buffer));
|
|
||||||
card->ctx->suppress_errors--;
|
|
||||||
if (r < 0)
|
|
||||||
r = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
|
|
||||||
*ret = pgp_new_blob(&priv->mf, id, type, buffer, r);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If already enumerated, stop now */
|
return SC_ERROR_FILE_NOT_FOUND;
|
||||||
if (blob->files != NULL)
|
|
||||||
return SC_ERROR_FILE_NOT_FOUND;
|
|
||||||
|
|
||||||
if ((r = pgp_enumerate_blob(card, blob)) < 0)
|
|
||||||
return r;
|
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -363,23 +396,11 @@ pgp_list_files(sc_card_t *card, u8 *buf, size_t buflen)
|
||||||
unsigned int k;
|
unsigned int k;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if ((blob = priv->current) == &priv->mf) {
|
blob = priv->current;
|
||||||
struct do_info *doi;
|
|
||||||
|
|
||||||
for (k = 0, doi = pgp_objects; doi->id > 0; doi++) {
|
|
||||||
if (k + 2 > buflen)
|
|
||||||
break;
|
|
||||||
buf[k++] = doi->id >> 8;
|
|
||||||
buf[k++] = doi->id;
|
|
||||||
}
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blob->file->type != SC_FILE_TYPE_DF)
|
if (blob->file->type != SC_FILE_TYPE_DF)
|
||||||
return SC_ERROR_OBJECT_NOT_VALID;
|
return SC_ERROR_OBJECT_NOT_VALID;
|
||||||
|
|
||||||
if (blob->files == NULL
|
if ((r = pgp_enumerate_blob(card, blob)) < 0)
|
||||||
&& (r = pgp_enumerate_blob(card, blob)) < 0)
|
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
for (k = 0, blob = blob->files; blob; blob = blob->next) {
|
for (k = 0, blob = blob->files; blob; blob = blob->next) {
|
||||||
|
@ -398,6 +419,7 @@ pgp_read_binary(sc_card_t *card, unsigned int idx,
|
||||||
{
|
{
|
||||||
struct pgp_priv_data *priv = DRVDATA(card);
|
struct pgp_priv_data *priv = DRVDATA(card);
|
||||||
struct blob *blob;
|
struct blob *blob;
|
||||||
|
int r;
|
||||||
|
|
||||||
if ((blob = priv->current) == NULL)
|
if ((blob = priv->current) == NULL)
|
||||||
return SC_ERROR_FILE_NOT_FOUND;
|
return SC_ERROR_FILE_NOT_FOUND;
|
||||||
|
@ -405,6 +427,9 @@ pgp_read_binary(sc_card_t *card, unsigned int idx,
|
||||||
if (blob->file->type != SC_FILE_TYPE_WORKING_EF)
|
if (blob->file->type != SC_FILE_TYPE_WORKING_EF)
|
||||||
return SC_ERROR_FILE_NOT_FOUND;
|
return SC_ERROR_FILE_NOT_FOUND;
|
||||||
|
|
||||||
|
if ((r = pgp_read_blob(card, blob)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
if (idx > blob->len)
|
if (idx > blob->len)
|
||||||
return SC_ERROR_INCORRECT_PARAMETERS;
|
return SC_ERROR_INCORRECT_PARAMETERS;
|
||||||
|
|
||||||
|
@ -429,6 +454,8 @@ pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
||||||
u8 idbuf[2];
|
u8 idbuf[2];
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
sc_debug(card->ctx, "called, tag=%04x\n", tag);
|
||||||
|
|
||||||
idbuf[0] = tag >> 8;
|
idbuf[0] = tag >> 8;
|
||||||
idbuf[1] = tag;
|
idbuf[1] = tag;
|
||||||
|
|
||||||
|
@ -436,7 +463,7 @@ pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
||||||
apdu.lc = 2;
|
apdu.lc = 2;
|
||||||
apdu.data = idbuf;
|
apdu.data = idbuf;
|
||||||
apdu.datalen = 2;
|
apdu.datalen = 2;
|
||||||
apdu.le = (buf_len > 256)? 256 : 0;
|
apdu.le = (buf_len > 256)? 256 : buf_len;
|
||||||
apdu.resp = buf;
|
apdu.resp = buf;
|
||||||
apdu.resplen = buf_len;
|
apdu.resplen = buf_len;
|
||||||
|
|
||||||
|
@ -448,6 +475,43 @@ pgp_get_pubkey(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
||||||
return apdu.resplen;
|
return apdu.resplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pgp_get_pubkey_pem(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
||||||
|
{
|
||||||
|
struct pgp_priv_data *priv = DRVDATA(card);
|
||||||
|
struct blob *blob, *mod_blob, *exp_blob;
|
||||||
|
sc_pkcs15_pubkey_t pubkey;
|
||||||
|
u8 *data;
|
||||||
|
size_t len;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
sc_debug(card->ctx, "called, tag=%04x\n", tag);
|
||||||
|
|
||||||
|
if ((r = pgp_get_blob(card, &priv->mf, tag & 0xFFFE, &blob)) < 0
|
||||||
|
|| (r = pgp_get_blob(card, blob, 0x7F49, &blob)) < 0
|
||||||
|
|| (r = pgp_get_blob(card, blob, 0x0081, &mod_blob)) < 0
|
||||||
|
|| (r = pgp_get_blob(card, blob, 0x0082, &exp_blob)) < 0
|
||||||
|
|| (r = pgp_read_blob(card, mod_blob)) < 0
|
||||||
|
|| (r = pgp_read_blob(card, exp_blob)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
memset(&pubkey, 0, sizeof(pubkey));
|
||||||
|
pubkey.algorithm = SC_ALGORITHM_RSA;
|
||||||
|
pubkey.u.rsa.modulus.data = mod_blob->data;
|
||||||
|
pubkey.u.rsa.modulus.len = mod_blob->len;
|
||||||
|
pubkey.u.rsa.exponent.data = exp_blob->data;
|
||||||
|
pubkey.u.rsa.exponent.len = exp_blob->len;
|
||||||
|
|
||||||
|
if ((r = sc_pkcs15_encode_pubkey(card->ctx, &pubkey, &data, &len)) < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (len > buf_len)
|
||||||
|
len = buf_len;
|
||||||
|
memcpy(buf, data, len);
|
||||||
|
free(data);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
pgp_get_data(sc_card_t *card, unsigned int tag, u8 *buf, size_t buf_len)
|
||||||
{
|
{
|
||||||
|
@ -487,16 +551,148 @@ pgp_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pgp_set_security_env(sc_card_t *card,
|
pgp_set_security_env(sc_card_t *card,
|
||||||
const struct sc_security_env *env, int se_num)
|
const sc_security_env_t *env, int se_num)
|
||||||
{
|
{
|
||||||
return SC_ERROR_NOT_SUPPORTED;
|
struct pgp_priv_data *priv = DRVDATA(card);
|
||||||
|
|
||||||
|
if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
|
||||||
|
if (env->algorithm != SC_ALGORITHM_RSA)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
}
|
||||||
|
if (!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT)
|
||||||
|
|| env->key_ref_len != 1)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
switch (env->operation) {
|
||||||
|
case SC_SEC_OPERATION_SIGN:
|
||||||
|
if (env->key_ref[0] != 0x00
|
||||||
|
&& env->key_ref[0] != 0x02) {
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Key reference not compatible with "
|
||||||
|
"requested usage\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SC_SEC_OPERATION_DECIPHER:
|
||||||
|
if (env->key_ref[0] != 0x01) {
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Key reference not compatible with "
|
||||||
|
"requested usage\n");
|
||||||
|
return SC_ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->sec_env = *env;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
pgp_compute_signature(sc_card_t *card, const u8 *data,
|
pgp_compute_signature(sc_card_t *card, const u8 *data,
|
||||||
size_t data_len, u8 * out, size_t outlen)
|
size_t data_len, u8 * out, size_t outlen)
|
||||||
{
|
{
|
||||||
return SC_ERROR_NOT_SUPPORTED;
|
struct pgp_priv_data *priv = DRVDATA(card);
|
||||||
|
sc_security_env_t *env = &priv->sec_env;
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (env->operation != SC_SEC_OPERATION_SIGN)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
switch (env->key_ref[0]) {
|
||||||
|
case 0x00: /* signature key */
|
||||||
|
/* PSO SIGNATURE */
|
||||||
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
|
||||||
|
0x2A, 0x9E, 0x9A);
|
||||||
|
break;
|
||||||
|
case 0x02: /* authentication key */
|
||||||
|
/* INTERNAL AUTHENTICATE */
|
||||||
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
|
||||||
|
0x88, 0, 0);
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Invalid key reference (decipher only key)\n");
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Invalid key reference 0x%02x\n",
|
||||||
|
env->key_ref[0]);
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
apdu.lc = data_len;
|
||||||
|
apdu.data = data;
|
||||||
|
apdu.datalen = data_len;
|
||||||
|
apdu.le = 256;
|
||||||
|
apdu.resp = out;
|
||||||
|
apdu.resplen = outlen;
|
||||||
|
|
||||||
|
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, "Card returned error");
|
||||||
|
|
||||||
|
return apdu.resplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
pgp_decipher(sc_card_t *card, const u8 *in, size_t inlen,
|
||||||
|
u8 *out, size_t outlen)
|
||||||
|
{
|
||||||
|
struct pgp_priv_data *priv = DRVDATA(card);
|
||||||
|
sc_security_env_t *env = &priv->sec_env;
|
||||||
|
sc_apdu_t apdu;
|
||||||
|
u8 *temp = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* There's some funny padding indicator that must be
|
||||||
|
* prepended... hmm. */
|
||||||
|
if (1) {
|
||||||
|
if (!(temp = (u8 *) malloc(inlen + 1)))
|
||||||
|
return SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
temp[0] = '\0';
|
||||||
|
memcpy(temp + 1, in, inlen);
|
||||||
|
in = temp;
|
||||||
|
inlen += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->operation != SC_SEC_OPERATION_DECIPHER)
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
|
||||||
|
switch (env->key_ref[0]) {
|
||||||
|
case 0x01: /* Decryption key */
|
||||||
|
/* PSO DECIPHER */
|
||||||
|
sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT,
|
||||||
|
0x2A, 0x80, 0x86);
|
||||||
|
break;
|
||||||
|
case 0x00: /* signature key */
|
||||||
|
case 0x02: /* authentication key */
|
||||||
|
sc_error(card->ctx,
|
||||||
|
"Invalid key reference (signature only key)\n");
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
default:
|
||||||
|
sc_error(card->ctx, "Invalid key reference 0x%02x\n",
|
||||||
|
env->key_ref[0]);
|
||||||
|
return SC_ERROR_INVALID_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
apdu.lc = inlen;
|
||||||
|
apdu.data = in;
|
||||||
|
apdu.datalen = inlen;
|
||||||
|
apdu.le = 256;
|
||||||
|
apdu.resp = out;
|
||||||
|
apdu.resplen = outlen;
|
||||||
|
|
||||||
|
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, "Card returned error");
|
||||||
|
|
||||||
|
return apdu.resplen;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -527,6 +723,7 @@ sc_get_driver(void)
|
||||||
pgp_ops.put_data = pgp_put_data;
|
pgp_ops.put_data = pgp_put_data;
|
||||||
pgp_ops.set_security_env= pgp_set_security_env;
|
pgp_ops.set_security_env= pgp_set_security_env;
|
||||||
pgp_ops.compute_signature= pgp_compute_signature;
|
pgp_ops.compute_signature= pgp_compute_signature;
|
||||||
|
pgp_ops.decipher = pgp_decipher;
|
||||||
pgp_ops.logout = pgp_logout;
|
pgp_ops.logout = pgp_logout;
|
||||||
|
|
||||||
return &pgp_drv;
|
return &pgp_drv;
|
||||||
|
|
|
@ -38,9 +38,9 @@ static char * pgp_key_name[3] = {
|
||||||
"Authentication key"
|
"Authentication key"
|
||||||
};
|
};
|
||||||
static char * pgp_pubkey_path[3] = {
|
static char * pgp_pubkey_path[3] = {
|
||||||
"B600",
|
"B601",
|
||||||
"B800",
|
"B801",
|
||||||
"A400"
|
"A401"
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -88,6 +88,8 @@ sc_pkcs15emu_add_object(sc_pkcs15_card_t *p15card, int type,
|
||||||
|
|
||||||
if (!(p15card->flags & SC_PKCS15_CARD_FLAG_READONLY))
|
if (!(p15card->flags & SC_PKCS15_CARD_FLAG_READONLY))
|
||||||
obj->flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;
|
obj->flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;
|
||||||
|
if (auth_id)
|
||||||
|
obj->auth_id = *auth_id;
|
||||||
|
|
||||||
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
|
switch (type & SC_PKCS15_TYPE_CLASS_MASK) {
|
||||||
case SC_PKCS15_TYPE_AUTH:
|
case SC_PKCS15_TYPE_AUTH:
|
||||||
|
@ -180,7 +182,8 @@ sc_pkcs15emu_add_pubkey(sc_pkcs15_card_t *p15card,
|
||||||
const sc_pkcs15_id_t *id,
|
const sc_pkcs15_id_t *id,
|
||||||
const char *label, int type,
|
const char *label, int type,
|
||||||
unsigned int modulus_length, int usage,
|
unsigned int modulus_length, int usage,
|
||||||
const sc_path_t *path)
|
const sc_path_t *path, int ref,
|
||||||
|
const sc_pkcs15_id_t *auth_id)
|
||||||
{
|
{
|
||||||
sc_pkcs15_pubkey_info_t *info;
|
sc_pkcs15_pubkey_info_t *info;
|
||||||
|
|
||||||
|
@ -189,11 +192,12 @@ sc_pkcs15emu_add_pubkey(sc_pkcs15_card_t *p15card,
|
||||||
info->modulus_length = modulus_length;
|
info->modulus_length = modulus_length;
|
||||||
info->usage = usage;
|
info->usage = usage;
|
||||||
info->access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
|
info->access_flags = SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE;
|
||||||
|
info->key_reference = ref;
|
||||||
|
|
||||||
if (path)
|
if (path)
|
||||||
info->path = *path;
|
info->path = *path;
|
||||||
|
|
||||||
return sc_pkcs15emu_add_object(p15card, type, label, info, NULL);
|
return sc_pkcs15emu_add_object(p15card, type, label, info, auth_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -276,6 +280,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < 3; i++) {
|
for (i = 0; i < 3; i++) {
|
||||||
|
sc_path_t path;
|
||||||
sc_pkcs15_id_t auth_id;
|
sc_pkcs15_id_t auth_id;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
|
@ -287,10 +292,11 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
SC_PKCS15_PIN_FLAG_SO_PIN;
|
SC_PKCS15_PIN_FLAG_SO_PIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc_format_path("3F00", &path);
|
||||||
auth_id.value[0] = i + 1;
|
auth_id.value[0] = i + 1;
|
||||||
auth_id.len = 1;
|
auth_id.len = 1;
|
||||||
sc_pkcs15emu_add_pin(p15card, &auth_id,
|
sc_pkcs15emu_add_pin(p15card, &auth_id,
|
||||||
pgp_pin_name[i], NULL, i+1,
|
pgp_pin_name[i], &path, i+1,
|
||||||
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
|
||||||
0, buffer[1+i], flags, buffer[4+i]);
|
0, buffer[1+i], flags, buffer[4+i]);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +321,7 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
pgp_key_name[i],
|
pgp_key_name[i],
|
||||||
SC_PKCS15_TYPE_PRKEY_RSA,
|
SC_PKCS15_TYPE_PRKEY_RSA,
|
||||||
1024, prkey_usage[i],
|
1024, prkey_usage[i],
|
||||||
NULL, 0,
|
NULL, i,
|
||||||
&auth_id);
|
&auth_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -327,17 +333,19 @@ sc_pkcs15emu_openpgp_init(sc_pkcs15_card_t *p15card)
|
||||||
| SC_PKCS15_PRKEY_USAGE_WRAP,
|
| SC_PKCS15_PRKEY_USAGE_WRAP,
|
||||||
SC_PKCS15_PRKEY_USAGE_VERIFY
|
SC_PKCS15_PRKEY_USAGE_VERIFY
|
||||||
};
|
};
|
||||||
sc_pkcs15_id_t id;
|
sc_pkcs15_id_t id, auth_id;
|
||||||
sc_path_t path;
|
sc_path_t path;
|
||||||
|
|
||||||
id.value[0] = i + 1;
|
id.value[0] = i + 1;
|
||||||
id.len = 1;
|
id.len = 1;
|
||||||
|
auth_id.value[0] = 3;
|
||||||
|
auth_id.len = 1;
|
||||||
sc_format_path(pgp_pubkey_path[i], &path);
|
sc_format_path(pgp_pubkey_path[i], &path);
|
||||||
sc_pkcs15emu_add_pubkey(p15card, &id,
|
sc_pkcs15emu_add_pubkey(p15card, &id,
|
||||||
pgp_key_name[i],
|
pgp_key_name[i],
|
||||||
SC_PKCS15_TYPE_PUBKEY_RSA,
|
SC_PKCS15_TYPE_PUBKEY_RSA,
|
||||||
1024, pubkey_usage[i],
|
1024, pubkey_usage[i],
|
||||||
&path);
|
&path, 0, &auth_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue