2002-03-18 10:42:03 +01:00
|
|
|
|
/* card-p15.c - PKCS-15 based card access
|
|
|
|
|
* Copyright (C) 2002 Free Software Foundation, Inc.
|
|
|
|
|
*
|
|
|
|
|
* This file is part of GnuPG.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* GnuPG 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 General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
|
2002-08-09 20:12:01 +02:00
|
|
|
|
#include <opensc/pkcs15.h>
|
2002-03-18 10:42:03 +01:00
|
|
|
|
#include <ksba.h>
|
|
|
|
|
|
|
|
|
|
#include "scdaemon.h"
|
|
|
|
|
#include "card-common.h"
|
|
|
|
|
|
|
|
|
|
|
2002-08-16 12:33:31 +02:00
|
|
|
|
struct p15private_s {
|
|
|
|
|
int n_prkey_rsa_objs;
|
|
|
|
|
struct sc_pkcs15_object *prkey_rsa_objs[32];
|
2002-08-16 16:23:40 +02:00
|
|
|
|
int n_cert_objs;
|
|
|
|
|
struct sc_pkcs15_object *cert_objs[32];
|
2002-08-16 12:33:31 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Allocate private data. */
|
|
|
|
|
static int
|
|
|
|
|
init_private_data (CARD card)
|
|
|
|
|
{
|
|
|
|
|
struct p15private_s *priv;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (card->p15priv)
|
|
|
|
|
return 0; /* already done. */
|
|
|
|
|
|
|
|
|
|
priv = xtrycalloc (1, sizeof *priv);
|
|
|
|
|
if (!priv)
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
|
|
|
|
|
/* OpenSC (0.7.0) is a bit strange in that the get_objects functions
|
|
|
|
|
tries to be a bit too clever and implicitly does an enumeration
|
|
|
|
|
which eventually leads to the fact that every call to this
|
|
|
|
|
fucntion returns one more macthing object. The old code in
|
|
|
|
|
p15_enum_keypairs assume that it would alwyas return the same
|
|
|
|
|
numer of objects and used this to figure out what the last object
|
|
|
|
|
enumerated is. We now do an enum_objects just once and keep it
|
|
|
|
|
in the private data. */
|
|
|
|
|
rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_PRKEY_RSA,
|
|
|
|
|
priv->prkey_rsa_objs,
|
|
|
|
|
DIM (priv->prkey_rsa_objs));
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
{
|
|
|
|
|
log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
|
|
|
|
|
xfree (priv);
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
priv->n_prkey_rsa_objs = rc;
|
2002-08-16 16:23:40 +02:00
|
|
|
|
|
|
|
|
|
/* Read all certificate objects. */
|
|
|
|
|
rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_CERT_X509,
|
|
|
|
|
priv->cert_objs,
|
|
|
|
|
DIM (priv->cert_objs));
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
{
|
|
|
|
|
log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
|
|
|
|
|
xfree (priv);
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
priv->n_cert_objs = rc;
|
|
|
|
|
|
2002-08-16 12:33:31 +02:00
|
|
|
|
card->p15priv = priv;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Release private data used in this module. */
|
|
|
|
|
void
|
|
|
|
|
p15_release_private_data (CARD card)
|
|
|
|
|
{
|
|
|
|
|
if (!card->p15priv)
|
|
|
|
|
return;
|
|
|
|
|
xfree (card->p15priv);
|
|
|
|
|
card->p15priv = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2002-03-18 10:42:03 +01:00
|
|
|
|
/* See card.c for interface description */
|
|
|
|
|
static int
|
|
|
|
|
p15_enum_keypairs (CARD card, int idx,
|
|
|
|
|
unsigned char *keygrip, char **keyid)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
KsbaError krc;
|
2002-08-16 12:33:31 +02:00
|
|
|
|
struct p15private_s *priv;
|
|
|
|
|
struct sc_pkcs15_object *tmpobj;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
int nobjs;
|
|
|
|
|
struct sc_pkcs15_prkey_info *pinfo;
|
|
|
|
|
struct sc_pkcs15_cert_info *certinfo;
|
|
|
|
|
struct sc_pkcs15_cert *certder;
|
|
|
|
|
KsbaCert cert;
|
|
|
|
|
|
2002-08-16 12:33:31 +02:00
|
|
|
|
rc = init_private_data (card);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
priv = card->p15priv;
|
|
|
|
|
nobjs = priv->n_prkey_rsa_objs;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
rc = 0;
|
|
|
|
|
if (idx >= nobjs)
|
|
|
|
|
return -1;
|
2002-08-16 12:33:31 +02:00
|
|
|
|
pinfo = priv->prkey_rsa_objs[idx]->data;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
|
|
|
|
|
/* now we need to read the certificate so that we can calculate the
|
|
|
|
|
keygrip */
|
|
|
|
|
rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &tmpobj);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("certificate for private key %d not found: %s\n",
|
|
|
|
|
idx, sc_strerror (rc));
|
|
|
|
|
/* note, that we return the ID anyway */
|
|
|
|
|
rc = GNUPG_Missing_Certificate;
|
|
|
|
|
goto return_keyid;
|
|
|
|
|
}
|
|
|
|
|
certinfo = tmpobj->data;
|
|
|
|
|
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("failed to read certificate for private key %d: %s\n",
|
|
|
|
|
idx, sc_strerror (rc));
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cert = ksba_cert_new ();
|
|
|
|
|
if (!cert)
|
|
|
|
|
{
|
|
|
|
|
sc_pkcs15_free_certificate (certder);
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
|
|
|
|
|
sc_pkcs15_free_certificate (certder);
|
|
|
|
|
if (krc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to parse the certificate for private key %d: %s\n",
|
|
|
|
|
idx, ksba_strerror (krc));
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
if (card_help_get_keygrip (cert, keygrip))
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to calculate the keygrip of private key %d\n", idx);
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
ksba_cert_release (cert);
|
|
|
|
|
|
|
|
|
|
rc = 0;
|
|
|
|
|
return_keyid:
|
|
|
|
|
if (keyid)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
*keyid = p = xtrymalloc (9+pinfo->id.len*2+1);
|
|
|
|
|
if (!*keyid)
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
p = stpcpy (p, "P15-5015.");
|
|
|
|
|
for (i=0; i < pinfo->id.len; i++, p += 2)
|
|
|
|
|
sprintf (p, "%02X", pinfo->id.value[i]);
|
|
|
|
|
*p = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2002-08-16 16:23:40 +02:00
|
|
|
|
/* See card.c for interface description */
|
|
|
|
|
static int
|
|
|
|
|
p15_enum_certs (CARD card, int idx, char **certid, int *type)
|
|
|
|
|
{
|
|
|
|
|
int rc;
|
|
|
|
|
struct p15private_s *priv;
|
|
|
|
|
struct sc_pkcs15_object *obj;
|
|
|
|
|
struct sc_pkcs15_cert_info *cinfo;
|
|
|
|
|
int nobjs;
|
|
|
|
|
|
|
|
|
|
rc = init_private_data (card);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
priv = card->p15priv;
|
|
|
|
|
nobjs = priv->n_cert_objs;
|
|
|
|
|
rc = 0;
|
|
|
|
|
if (idx >= nobjs)
|
|
|
|
|
return -1;
|
|
|
|
|
obj = priv->cert_objs[idx];
|
|
|
|
|
cinfo = obj->data;
|
|
|
|
|
|
|
|
|
|
if (certid)
|
|
|
|
|
{
|
|
|
|
|
char *p;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
*certid = p = xtrymalloc (9+cinfo->id.len*2+1);
|
|
|
|
|
if (!*certid)
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
p = stpcpy (p, "P15-5015.");
|
|
|
|
|
for (i=0; i < cinfo->id.len; i++, p += 2)
|
|
|
|
|
sprintf (p, "%02X", cinfo->id.value[i]);
|
|
|
|
|
*p = 0;
|
|
|
|
|
}
|
|
|
|
|
if (type)
|
|
|
|
|
{
|
|
|
|
|
if (!obj->df)
|
|
|
|
|
*type = 0; /* unknown */
|
|
|
|
|
else if (obj->df->type == SC_PKCS15_CDF)
|
|
|
|
|
*type = 100;
|
|
|
|
|
else if (obj->df->type == SC_PKCS15_CDF_TRUSTED)
|
|
|
|
|
*type = 101;
|
|
|
|
|
else if (obj->df->type == SC_PKCS15_CDF_USEFUL)
|
|
|
|
|
*type = 102;
|
|
|
|
|
else
|
|
|
|
|
*type = 0; /* error -> unknown */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
2002-03-18 10:42:03 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
/* For now we only support the standard DF */
|
|
|
|
|
if (strncmp (idstr, "P15-5015.", 9) )
|
|
|
|
|
return GNUPG_Invalid_Id;
|
|
|
|
|
for (s=idstr+9, n=0; hexdigitp (s); s++, n++)
|
|
|
|
|
;
|
|
|
|
|
if (*s || (n&1))
|
|
|
|
|
return GNUPG_Invalid_Id; /* invalid or odd number of digits */
|
|
|
|
|
n /= 2;
|
|
|
|
|
if (!n || n > SC_PKCS15_MAX_ID_SIZE)
|
|
|
|
|
return GNUPG_Invalid_Id; /* empty or too large */
|
|
|
|
|
for (s=idstr+9, n=0; *s; s += 2, n++)
|
|
|
|
|
id->value[n] = xtoi_2 (s);
|
|
|
|
|
id->len = n;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* See card.c for interface description */
|
|
|
|
|
static int
|
|
|
|
|
p15_read_cert (CARD card, const char *certidstr,
|
|
|
|
|
unsigned char **cert, size_t *ncert)
|
|
|
|
|
{
|
|
|
|
|
struct sc_pkcs15_object *tmpobj;
|
|
|
|
|
struct sc_pkcs15_id certid;
|
|
|
|
|
struct sc_pkcs15_cert_info *certinfo;
|
|
|
|
|
struct sc_pkcs15_cert *certder;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
if (!card || !certidstr || !cert || !ncert)
|
|
|
|
|
return GNUPG_Invalid_Value;
|
|
|
|
|
if (!card->p15card)
|
|
|
|
|
return GNUPG_No_PKCS15_App;
|
|
|
|
|
|
|
|
|
|
rc = idstr_to_id (certidstr, &certid);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &tmpobj);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("certificate '%s' not found: %s\n",
|
|
|
|
|
certidstr, sc_strerror (rc));
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
certinfo = tmpobj->data;
|
|
|
|
|
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("failed to read certificate '%s': %s\n",
|
|
|
|
|
certidstr, sc_strerror (rc));
|
|
|
|
|
return GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*cert = xtrymalloc (certder->data_len);
|
|
|
|
|
if (!*cert)
|
|
|
|
|
{
|
|
|
|
|
sc_pkcs15_free_certificate (certder);
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
}
|
|
|
|
|
memcpy (*cert, certder->data, certder->data_len);
|
|
|
|
|
*ncert = certder->data_len;
|
|
|
|
|
sc_pkcs15_free_certificate (certder);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
|
|
|
|
|
|
2002-03-18 10:42:03 +01:00
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
static int
|
|
|
|
|
p15_prepare_key (CARD card, const char *keyidstr,
|
|
|
|
|
int (pincb)(void*, const char *, char **),
|
|
|
|
|
void *pincb_arg, struct sc_pkcs15_object **r_keyobj)
|
2002-03-18 10:42:03 +01:00
|
|
|
|
{
|
|
|
|
|
struct sc_pkcs15_id keyid;
|
|
|
|
|
struct sc_pkcs15_pin_info *pin;
|
|
|
|
|
struct sc_pkcs15_object *keyobj, *pinobj;
|
|
|
|
|
char *pinvalue;
|
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
|
|
rc = idstr_to_id (keyidstr, &keyid);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj);
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
{
|
|
|
|
|
log_error ("private key not found: %s\n", sc_strerror(rc));
|
2002-04-12 20:55:05 +02:00
|
|
|
|
return GNUPG_No_Secret_Key;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = sc_pkcs15_find_pin_by_auth_id (card->p15card,
|
|
|
|
|
&keyobj->auth_id, &pinobj);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc));
|
2002-04-12 20:55:05 +02:00
|
|
|
|
return GNUPG_Bad_PIN_Method;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
}
|
|
|
|
|
pin = pinobj->data;
|
|
|
|
|
|
|
|
|
|
/* Fixme: pack this into a verification loop */
|
|
|
|
|
/* Fixme: we might want to pass pin->min_length and
|
|
|
|
|
pin->stored_length */
|
|
|
|
|
rc = pincb (pincb_arg, pinobj->label, &pinvalue);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("PIN callback returned error: %s\n", gnupg_strerror (rc));
|
2002-04-12 20:55:05 +02:00
|
|
|
|
return rc;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = sc_pkcs15_verify_pin (card->p15card, pin,
|
|
|
|
|
pinvalue, strlen (pinvalue));
|
|
|
|
|
xfree (pinvalue);
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_info ("PIN verification failed: %s\n", sc_strerror (rc));
|
2002-04-12 20:55:05 +02:00
|
|
|
|
return GNUPG_Bad_PIN;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
/* fixme: check wheter we need to release KEYOBJ in case of an error */
|
|
|
|
|
*r_keyobj = keyobj;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* See card.c for interface description */
|
|
|
|
|
static int
|
|
|
|
|
p15_sign (CARD card, const char *keyidstr, int hashalgo,
|
|
|
|
|
int (pincb)(void*, const char *, char **),
|
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const void *indata, size_t indatalen,
|
|
|
|
|
void **outdata, size_t *outdatalen )
|
|
|
|
|
{
|
|
|
|
|
unsigned int cryptflags;
|
|
|
|
|
struct sc_pkcs15_object *keyobj;
|
|
|
|
|
int rc;
|
|
|
|
|
unsigned char *outbuf = NULL;
|
|
|
|
|
size_t outbuflen;
|
|
|
|
|
|
|
|
|
|
if (hashalgo != GCRY_MD_SHA1)
|
|
|
|
|
return GNUPG_Unsupported_Algorithm;
|
|
|
|
|
|
|
|
|
|
rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
|
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
cryptflags = SC_ALGORITHM_RSA_PAD_PKCS1;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
|
|
|
|
|
outbuflen = 1024;
|
|
|
|
|
outbuf = xtrymalloc (outbuflen);
|
|
|
|
|
if (!outbuf)
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
|
|
|
|
|
rc = sc_pkcs15_compute_signature (card->p15card, keyobj,
|
|
|
|
|
cryptflags,
|
|
|
|
|
indata, indatalen,
|
|
|
|
|
outbuf, outbuflen );
|
|
|
|
|
if (rc < 0)
|
|
|
|
|
{
|
|
|
|
|
log_error ("failed to create signature: %s\n", sc_strerror (rc));
|
|
|
|
|
rc = GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*outdatalen = rc;
|
|
|
|
|
*outdata = outbuf;
|
|
|
|
|
outbuf = NULL;
|
|
|
|
|
rc = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xfree (outbuf);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* See card.c for description */
|
|
|
|
|
static int
|
|
|
|
|
p15_decipher (CARD card, const char *keyidstr,
|
|
|
|
|
int (pincb)(void*, const char *, char **),
|
|
|
|
|
void *pincb_arg,
|
|
|
|
|
const void *indata, size_t indatalen,
|
|
|
|
|
void **outdata, size_t *outdatalen )
|
|
|
|
|
{
|
2002-04-12 20:55:05 +02:00
|
|
|
|
struct sc_pkcs15_object *keyobj;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
int rc;
|
|
|
|
|
unsigned char *outbuf = NULL;
|
|
|
|
|
size_t outbuflen;
|
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
|
2002-03-18 10:42:03 +01:00
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
if (card && card->scard && card->scard->driver
|
|
|
|
|
&& !strcasecmp (card->scard->driver->short_name, "tcos"))
|
2002-03-18 10:42:03 +01:00
|
|
|
|
{
|
2002-04-12 20:55:05 +02:00
|
|
|
|
/* very ugly hack to force the use of a local key. We need this
|
|
|
|
|
until we have fixed the initialization code for TCOS cards */
|
|
|
|
|
struct sc_pkcs15_prkey_info *prkey = keyobj->data;
|
|
|
|
|
if ( !(prkey->key_reference & 0x80))
|
|
|
|
|
{
|
|
|
|
|
prkey->key_reference |= 0x80;
|
|
|
|
|
log_debug ("using TCOS hack to force the use of local keys\n");
|
|
|
|
|
}
|
|
|
|
|
if (*keyidstr && keyidstr[strlen(keyidstr)-1] == '6')
|
|
|
|
|
{
|
|
|
|
|
prkey->key_reference |= 1;
|
|
|
|
|
log_debug ("warning: using even more TCOS hacks\n");
|
|
|
|
|
}
|
2002-03-18 10:42:03 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
outbuflen = indatalen < 256? 256 : indatalen;
|
|
|
|
|
outbuf = xtrymalloc (outbuflen);
|
|
|
|
|
if (!outbuf)
|
|
|
|
|
return GNUPG_Out_Of_Core;
|
|
|
|
|
|
2002-04-12 20:55:05 +02:00
|
|
|
|
rc = sc_pkcs15_decipher (card->p15card, keyobj,
|
2002-08-09 20:12:01 +02:00
|
|
|
|
0,
|
2002-04-12 20:55:05 +02:00
|
|
|
|
indata, indatalen,
|
|
|
|
|
outbuf, outbuflen);
|
2002-03-18 10:42:03 +01:00
|
|
|
|
if (rc < 0)
|
|
|
|
|
{
|
2002-04-12 20:55:05 +02:00
|
|
|
|
log_error ("failed to decipher the data: %s\n", sc_strerror (rc));
|
2002-03-18 10:42:03 +01:00
|
|
|
|
rc = GNUPG_Card_Error;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*outdatalen = rc;
|
|
|
|
|
*outdata = outbuf;
|
|
|
|
|
outbuf = NULL;
|
|
|
|
|
rc = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xfree (outbuf);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Bind our operations to the card */
|
|
|
|
|
void
|
|
|
|
|
card_p15_bind (CARD card)
|
|
|
|
|
{
|
|
|
|
|
card->fnc.enum_keypairs = p15_enum_keypairs;
|
2002-08-16 16:23:40 +02:00
|
|
|
|
card->fnc.enum_certs = p15_enum_certs;
|
2002-03-18 10:42:03 +01:00
|
|
|
|
card->fnc.read_cert = p15_read_cert;
|
|
|
|
|
card->fnc.sign = p15_sign;
|
|
|
|
|
card->fnc.decipher = p15_decipher;
|
|
|
|
|
}
|