mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd:p15: Support signing with CardOS 5 cards.
* scd/app-help.c (app_help_get_keygrip_string_pk): Add optional arg r_pkey and change all callers. (app_help_get_keygrip_string): Ditto. * scd/app-p15.c (struct cdf_object_s): Use bit flags (struct aodf_object_s): Ditto. Add field 'fid'. (struct prkdf_object_s): Ditto. Add fields keygrip, keyalgo, and keynbits. (parse_certid): Allow a keygrip instead of a certid aka keyref. (read_ef_aodf): Store the FID. (keygripstr_from_prkdf): Rename to ... (keygrip_from_prkdf): this. Remove arg r_gripstr and implement cache. Change callers to directly use the values from the object. Also store the algo and length of the key ion the object. (keyref_from_keyinfo): New. Factored out code. (do_sign): Support SHA-256 and >2048 bit RSA keys. (do_with_keygrip): New. (app_select_p15): Register new function. -- This has been tested with a D-Trust card featuring 3072 bit keys. Note that non-repudiation key for a qualified signature does not yet work because we do not yet support rsaPSS padding. Thus a gpgsm --learn shows a couple of Bad Signature errors for this key. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
2bdd4fc7b6
commit
103c1576b7
@ -216,8 +216,10 @@ app_get_slot (app_t app)
|
||||
/*-- app-help.c --*/
|
||||
unsigned int app_help_count_bits (const unsigned char *a, size_t len);
|
||||
gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen,
|
||||
char *hexkeygrip);
|
||||
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
|
||||
char *hexkeygrip,
|
||||
gcry_sexp_t *r_pkey);
|
||||
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip,
|
||||
gcry_sexp_t *r_pkey);
|
||||
gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen,
|
||||
unsigned char **r_pk, size_t *r_pklen);
|
||||
size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
|
@ -137,7 +137,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
|
||||
ksba_cert_release (cert);
|
||||
return err;
|
||||
}
|
||||
err = app_help_get_keygrip_string (cert, hexkeygrip);
|
||||
err = app_help_get_keygrip_string (cert, hexkeygrip, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid);
|
||||
|
@ -53,14 +53,21 @@ app_help_count_bits (const unsigned char *a, size_t len)
|
||||
|
||||
/* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN)
|
||||
* as an hex encoded string in the user provided buffer HEXKEYGRIP
|
||||
* which must be of at least 41 bytes. */
|
||||
* which must be of at least 41 bytes. If R_PKEY is not NULL and the
|
||||
* function succeeded, the S-expression representing the key is
|
||||
* stored there. The caller needs to call gcry_sexp_release on
|
||||
* that. */
|
||||
gpg_error_t
|
||||
app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip)
|
||||
app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip,
|
||||
gcry_sexp_t *r_pkey)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t s_pkey;
|
||||
unsigned char array[KEYGRIP_LEN];
|
||||
|
||||
if (r_pkey)
|
||||
*r_pkey = NULL;
|
||||
|
||||
err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen);
|
||||
if (err)
|
||||
return err; /* Can't parse that S-expression. */
|
||||
@ -69,7 +76,11 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip)
|
||||
gcry_sexp_release (s_pkey);
|
||||
return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
|
||||
}
|
||||
gcry_sexp_release (s_pkey);
|
||||
|
||||
if (r_pkey)
|
||||
*r_pkey = s_pkey;
|
||||
else
|
||||
gcry_sexp_release (s_pkey);
|
||||
|
||||
bin2hex (array, KEYGRIP_LEN, hexkeygrip);
|
||||
|
||||
@ -78,22 +89,28 @@ app_help_get_keygrip_string_pk (const void *pk, size_t pklen, char *hexkeygrip)
|
||||
|
||||
|
||||
/* Return the KEYGRIP for the certificate CERT as an hex encoded
|
||||
string in the user provided buffer HEXKEYGRIP which must be of at
|
||||
least 41 bytes. */
|
||||
* string in the user provided buffer HEXKEYGRIP which must be of at
|
||||
* least 41 bytes. If R_PKEY is not NULL and the function succeeded,
|
||||
* the S-expression representing the key is stored there. The caller
|
||||
* needs to call gcry_sexp_release on that. */
|
||||
gpg_error_t
|
||||
app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
|
||||
app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip,
|
||||
gcry_sexp_t *r_pkey)
|
||||
{
|
||||
gpg_error_t err;
|
||||
ksba_sexp_t p;
|
||||
size_t n;
|
||||
|
||||
if (r_pkey)
|
||||
*r_pkey = NULL;
|
||||
|
||||
p = ksba_cert_get_public_key (cert);
|
||||
if (!p)
|
||||
return gpg_error (GPG_ERR_BUG);
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
return gpg_error (GPG_ERR_INV_SEXP);
|
||||
err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip);
|
||||
err = app_help_get_keygrip_string_pk ((void*)p, n, hexkeygrip, r_pkey);
|
||||
ksba_free (p);
|
||||
return err;
|
||||
}
|
||||
|
414
scd/app-p15.c
414
scd/app-p15.c
@ -138,6 +138,9 @@ struct cdf_object_s
|
||||
/* Link to next item when used in a linked list. */
|
||||
struct cdf_object_s *next;
|
||||
|
||||
/* Flags to indicate whether fields are valid. */
|
||||
unsigned int have_off:1;
|
||||
|
||||
/* Length and allocated buffer with the Id of this object.
|
||||
* This field is used for X.509 in PKCS#11 to make it easier to
|
||||
* match a private key with a certificate. */
|
||||
@ -149,8 +152,6 @@ struct cdf_object_s
|
||||
size_t imagelen;
|
||||
unsigned char *image;
|
||||
|
||||
/* Set to true if a length and offset is available. */
|
||||
int have_off;
|
||||
/* The offset and length of the object. They are only valid if
|
||||
HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
|
||||
unsigned long off, len;
|
||||
@ -174,6 +175,25 @@ struct prkdf_object_s
|
||||
/* Link to next item when used in a linked list. */
|
||||
struct prkdf_object_s *next;
|
||||
|
||||
/* Flags to indicate whether fields are valid. */
|
||||
unsigned int keygrip_valid:1;
|
||||
unsigned int key_reference_valid:1;
|
||||
unsigned int have_off:1;
|
||||
|
||||
/* The key's usage flags. */
|
||||
keyusage_flags_t usageflags;
|
||||
|
||||
/* The keygrip of the key. This is used as a cache. */
|
||||
char keygrip[2*KEYGRIP_LEN+1];
|
||||
|
||||
/* The Gcrypt algo identifier for the key. It is valid if the
|
||||
* keygrip is also valid. */
|
||||
int keyalgo;
|
||||
|
||||
/* The length of the key in bits (e.g. for RSA the length of the
|
||||
* modulus). It is valid if the keygrip is also valid. */
|
||||
unsigned int keynbits;
|
||||
|
||||
/* Length and allocated buffer with the Id of this object. */
|
||||
size_t objidlen;
|
||||
unsigned char *objid;
|
||||
@ -183,17 +203,11 @@ struct prkdf_object_s
|
||||
size_t authidlen;
|
||||
unsigned char *authid;
|
||||
|
||||
/* The key's usage flags. */
|
||||
keyusage_flags_t usageflags;
|
||||
|
||||
/* The keyReference and a flag telling whether it is valid. */
|
||||
unsigned long key_reference;
|
||||
int key_reference_valid;
|
||||
|
||||
/* Set to true if a length and offset is available. */
|
||||
int have_off;
|
||||
/* The offset and length of the object. They are only valid if
|
||||
HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
|
||||
* HAVE_OFF is true otherwise they are set to 0. */
|
||||
unsigned long off, len;
|
||||
|
||||
/* The length of the path as given in the PrKDF and the path itself.
|
||||
@ -214,6 +228,9 @@ struct aodf_object_s
|
||||
/* Link to next item when used in a linked list. */
|
||||
struct aodf_object_s *next;
|
||||
|
||||
/* Flags to indicate whether fields are valid. */
|
||||
unsigned int have_off:1;
|
||||
|
||||
/* Length and allocated buffer with the Id of this object. */
|
||||
size_t objidlen;
|
||||
unsigned char *objid;
|
||||
@ -223,6 +240,9 @@ struct aodf_object_s
|
||||
size_t authidlen;
|
||||
unsigned char *authid;
|
||||
|
||||
/* The file ID of this AODF. */
|
||||
unsigned short fid;
|
||||
|
||||
/* The PIN Flags. */
|
||||
struct
|
||||
{
|
||||
@ -261,9 +281,6 @@ struct aodf_object_s
|
||||
char pad_char;
|
||||
int pad_char_valid;
|
||||
|
||||
|
||||
/* Set to true if a length and offset is available. */
|
||||
int have_off;
|
||||
/* The offset and length of the object. They are only valid if
|
||||
HAVE_OFF is true and set to 0 if HAVE_OFF is false. */
|
||||
unsigned long off, len;
|
||||
@ -326,6 +343,7 @@ struct app_local_s
|
||||
|
||||
|
||||
/*** Local prototypes. ***/
|
||||
static gpg_error_t keygrip_from_prkdf (app_t app, prkdf_object_t prkdf);
|
||||
static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
|
||||
unsigned char **r_cert, size_t *r_certlen);
|
||||
|
||||
@ -498,35 +516,55 @@ parse_certid (app_t app, const char *certid,
|
||||
*r_objid = NULL;
|
||||
*r_objidlen = 0;
|
||||
|
||||
if (app->app_local->home_df)
|
||||
snprintf (tmpbuf, sizeof tmpbuf,
|
||||
"P15-%04X.", (unsigned int)(app->app_local->home_df & 0xffff));
|
||||
else
|
||||
strcpy (tmpbuf, "P15.");
|
||||
if (strncmp (certid, tmpbuf, strlen (tmpbuf)) )
|
||||
if (certid[0] != 'P' && strlen (certid) == 40) /* This is a keygrip. */
|
||||
{
|
||||
if (!strncmp (certid, "P15.", 4)
|
||||
|| (!strncmp (certid, "P15-", 4)
|
||||
&& hexdigitp (certid+4)
|
||||
&& hexdigitp (certid+5)
|
||||
&& hexdigitp (certid+6)
|
||||
&& hexdigitp (certid+7)
|
||||
&& certid[8] == '.'))
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
}
|
||||
certid += strlen (tmpbuf);
|
||||
prkdf_object_t keyinfo;
|
||||
|
||||
for (keyinfo = app->app_local->private_key_info;
|
||||
keyinfo; keyinfo = keyinfo->next)
|
||||
if (!keygrip_from_prkdf (app, keyinfo)
|
||||
&& !strcmp (certid, keyinfo->keygrip))
|
||||
break;
|
||||
if (!keyinfo || !keyinfo->objidlen || !keyinfo->objid)
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
objidlen = keyinfo->objidlen;
|
||||
objid = xtrymalloc (objidlen);
|
||||
if (!objid)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (objid, keyinfo->objid, keyinfo->objidlen);
|
||||
}
|
||||
else /* This is a usual keyref. */
|
||||
{
|
||||
if (app->app_local->home_df)
|
||||
snprintf (tmpbuf, sizeof tmpbuf, "P15-%04X.",
|
||||
(unsigned int)(app->app_local->home_df & 0xffff));
|
||||
else
|
||||
strcpy (tmpbuf, "P15.");
|
||||
if (strncmp (certid, tmpbuf, strlen (tmpbuf)) )
|
||||
{
|
||||
if (!strncmp (certid, "P15.", 4)
|
||||
|| (!strncmp (certid, "P15-", 4)
|
||||
&& hexdigitp (certid+4)
|
||||
&& hexdigitp (certid+5)
|
||||
&& hexdigitp (certid+6)
|
||||
&& hexdigitp (certid+7)
|
||||
&& certid[8] == '.'))
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
}
|
||||
certid += strlen (tmpbuf);
|
||||
for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++)
|
||||
;
|
||||
if (*s || !objidlen || (objidlen%2))
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
objidlen /= 2;
|
||||
objid = xtrymalloc (objidlen);
|
||||
if (!objid)
|
||||
return gpg_error_from_syserror ();
|
||||
for (s=certid, i=0; i < objidlen; i++, s+=2)
|
||||
objid[i] = xtoi_2 (s);
|
||||
}
|
||||
|
||||
for (s=certid, objidlen=0; hexdigitp (s); s++, objidlen++)
|
||||
;
|
||||
if (*s || !objidlen || (objidlen%2))
|
||||
return gpg_error (GPG_ERR_INV_ID);
|
||||
objidlen /= 2;
|
||||
objid = xtrymalloc (objidlen);
|
||||
if (!objid)
|
||||
return gpg_error_from_syserror ();
|
||||
for (s=certid, i=0; i < objidlen; i++, s+=2)
|
||||
objid[i] = xtoi_2 (s);
|
||||
*r_objid = objid;
|
||||
*r_objidlen = objidlen;
|
||||
return 0;
|
||||
@ -1644,6 +1682,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
|
||||
aodf = xtrycalloc (1, sizeof *aodf);
|
||||
if (!aodf)
|
||||
goto no_core;
|
||||
aodf->fid = fid;
|
||||
|
||||
/* Parse the commonObjectAttributes. */
|
||||
where = __LINE__;
|
||||
@ -2552,21 +2591,26 @@ send_certinfo (app_t app, ctrl_t ctrl, const char *certtype,
|
||||
|
||||
|
||||
/* Get the keygrip of the private key object PRKDF. On success the
|
||||
keygrip gets returned in the caller provided 41 byte buffer
|
||||
R_GRIPSTR. */
|
||||
* keygrip, the algo and the length are stored in the KEYGRIP,
|
||||
* KEYALFO, and KEYNBITS fields of the PRKDF object. */
|
||||
static gpg_error_t
|
||||
keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
|
||||
keygrip_from_prkdf (app_t app, prkdf_object_t prkdf)
|
||||
{
|
||||
gpg_error_t err;
|
||||
cdf_object_t cdf;
|
||||
unsigned char *der;
|
||||
size_t derlen;
|
||||
ksba_cert_t cert;
|
||||
gcry_sexp_t s_pkey = NULL;
|
||||
|
||||
/* Easy if we got a cached version. */
|
||||
if (prkdf->keygrip_valid)
|
||||
return 0;
|
||||
|
||||
/* FIXME: We should check whether a public key directory file and a
|
||||
matching public key for PRKDF is available. This should make
|
||||
extraction of the key much easier. My current test card doesn't
|
||||
have one, so we can only use the fallback solution bu looking for
|
||||
have one, so we can only use the fallback solution by looking for
|
||||
a matching certificate and extract the key from there. */
|
||||
|
||||
/* Look for a matching certificate. A certificate matches if the Id
|
||||
@ -2586,24 +2630,68 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
|
||||
&& !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen))
|
||||
break;
|
||||
if (!cdf)
|
||||
return gpg_error (GPG_ERR_NOT_FOUND);
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = readcert_by_cdf (app, cdf, &der, &derlen);
|
||||
if (err)
|
||||
return err;
|
||||
goto leave;
|
||||
|
||||
err = ksba_cert_new (&cert);
|
||||
if (!err)
|
||||
err = ksba_cert_init_from_mem (cert, der, derlen);
|
||||
xfree (der);
|
||||
if (!err)
|
||||
err = app_help_get_keygrip_string (cert, r_gripstr);
|
||||
err = app_help_get_keygrip_string (cert, prkdf->keygrip, &s_pkey);
|
||||
ksba_cert_release (cert);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
prkdf->keyalgo = get_pk_algo_from_key (s_pkey);
|
||||
if (!prkdf->keyalgo)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
prkdf->keynbits = gcry_pk_get_nbits (s_pkey);
|
||||
if (!prkdf->keynbits)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
prkdf->keygrip_valid = 1; /* Yeah, got everything. */
|
||||
|
||||
leave:
|
||||
gcry_sexp_release (s_pkey);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Return a malloced keyref string for KEYINFO. Returns NULL on
|
||||
* malloc failure. */
|
||||
static char *
|
||||
keyref_from_keyinfo (app_t app, prkdf_object_t keyinfo)
|
||||
{
|
||||
char *buf, *p;
|
||||
|
||||
buf = xtrymalloc (4 + 5 + keyinfo->objidlen*2 + 1);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
p = stpcpy (buf, "P15");
|
||||
if (app->app_local->home_df)
|
||||
{
|
||||
snprintf (p, 6, "-%04X",
|
||||
(unsigned int)(app->app_local->home_df & 0xffff));
|
||||
p += 5;
|
||||
}
|
||||
p = stpcpy (p, ".");
|
||||
bin2hex (keyinfo->objid, keyinfo->objidlen, p);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* Helper to do_learn_status: Send information about all known
|
||||
@ -2616,36 +2704,26 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t keyinfo)
|
||||
|
||||
for (; keyinfo; keyinfo = keyinfo->next)
|
||||
{
|
||||
char gripstr[40+1];
|
||||
char *buf, *p;
|
||||
char *buf;
|
||||
int j;
|
||||
|
||||
buf = xtrymalloc (9 + keyinfo->objidlen*2 + 1);
|
||||
buf = keyref_from_keyinfo (app, keyinfo);
|
||||
if (!buf)
|
||||
return gpg_error_from_syserror ();
|
||||
p = stpcpy (buf, "P15");
|
||||
if (app->app_local->home_df)
|
||||
{
|
||||
snprintf (p, 6, "-%04X",
|
||||
(unsigned int)(app->app_local->home_df & 0xffff));
|
||||
p += 5;
|
||||
}
|
||||
p = stpcpy (p, ".");
|
||||
bin2hex (keyinfo->objid, keyinfo->objidlen, p);
|
||||
|
||||
err = keygripstr_from_prkdf (app, keyinfo, gripstr);
|
||||
err = keygrip_from_prkdf (app, keyinfo);
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: error getting keygrip from ");
|
||||
for (j=0; j < keyinfo->pathlen; j++)
|
||||
log_printf ("%04hX", keyinfo->path[j]);
|
||||
log_printf ("%s%04hX", j?"/":"", keyinfo->path[j]);
|
||||
log_printf (": %s\n", gpg_strerror (err));
|
||||
}
|
||||
else
|
||||
{
|
||||
assert (strlen (gripstr) == 40);
|
||||
log_assert (strlen (keyinfo->keygrip) == 40);
|
||||
send_status_info (ctrl, "KEYPAIRINFO",
|
||||
gripstr, 40,
|
||||
keyinfo->keygrip, 2*KEYGRIP_LEN,
|
||||
buf, strlen (buf),
|
||||
NULL, (size_t)0);
|
||||
}
|
||||
@ -3029,6 +3107,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
const void *indata, size_t indatalen,
|
||||
unsigned char **outdata, size_t *outdatalen )
|
||||
{
|
||||
static unsigned char sha256_prefix[19] = /* OID: 2.16.840.1.101.3.4.2.1 */
|
||||
{ 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48,
|
||||
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 };
|
||||
static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
|
||||
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
|
||||
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
|
||||
@ -3038,19 +3119,26 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
|
||||
gpg_error_t err;
|
||||
int i;
|
||||
unsigned char data[36]; /* Must be large enough for a SHA-1 digest
|
||||
+ the largest OID prefix above and also
|
||||
fit the 36 bytes of md5sha1. */
|
||||
unsigned char data[32+19]; /* Must be large enough for a SHA-256 digest
|
||||
* + the largest OID prefix above and also
|
||||
* fit the 36 bytes of md5sha1. */
|
||||
prkdf_object_t prkdf; /* The private key object. */
|
||||
aodf_object_t aodf; /* The associated authentication object. */
|
||||
int no_data_padding = 0; /* True if the card want the data without padding.*/
|
||||
int mse_done = 0; /* Set to true if the MSE has been done. */
|
||||
unsigned int hashlen; /* Length of the hash. */
|
||||
unsigned int datalen; /* Length of the data to sign (prefix+hash). */
|
||||
unsigned char *dataptr;
|
||||
int exmode, le_value;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
log_debug ("p15:sign: keyidstr='%s' indatalen=%zu\n", keyidstr, indatalen);
|
||||
if (!keyidstr || !*keyidstr)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (indatalen != 20 && indatalen != 16 && indatalen != 35 && indatalen != 36)
|
||||
if (indatalen != 20 && indatalen != 16
|
||||
&& indatalen != 35 && indatalen != 36
|
||||
&& indatalen != (32+19))
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf);
|
||||
@ -3081,12 +3169,19 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
log_error ("p15: authentication object for %s missing\n", keyidstr);
|
||||
return gpg_error (GPG_ERR_INV_CARD);
|
||||
}
|
||||
if (aodf->authid)
|
||||
|
||||
|
||||
if (opt.verbose)
|
||||
{
|
||||
log_error ("p15: PIN verification is protected by an "
|
||||
"additional authentication token\n");
|
||||
return gpg_error (GPG_ERR_BAD_PIN_METHOD);
|
||||
log_info ("p15: using AODF %04hX id=", aodf->fid);
|
||||
for (i=0; i < aodf->objidlen; i++)
|
||||
log_printf ("%02X", aodf->objid[i]);
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
if (aodf->authid && opt.verbose)
|
||||
log_info ("p15: PIN is controlled by another authentication token\n");
|
||||
|
||||
if (aodf->pinflags.integrity_protected
|
||||
|| aodf->pinflags.confidentiality_protected)
|
||||
{
|
||||
@ -3284,6 +3379,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
else
|
||||
pinvaluelen = strlen (pinvalue);
|
||||
|
||||
log_printhex (pinvalue, pinvaluelen,
|
||||
"about to verify with ref %lu pin:",
|
||||
aodf->pin_reference_valid? aodf->pin_reference : 0);
|
||||
err = iso7816_verify (app_get_slot (app),
|
||||
aodf->pin_reference_valid? aodf->pin_reference : 0,
|
||||
pinvalue, pinvaluelen);
|
||||
@ -3304,6 +3402,7 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
if (hashalgo != MD_USER_TLS_MD5SHA1)
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
memcpy (data, indata, indatalen);
|
||||
datalen = hashlen = 36;
|
||||
}
|
||||
else if (indatalen == 35)
|
||||
{
|
||||
@ -3318,17 +3417,56 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
else
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
memcpy (data, indata, indatalen);
|
||||
datalen = 35;
|
||||
hashlen = 20;
|
||||
}
|
||||
else if (indatalen == 32 + 19)
|
||||
{
|
||||
/* Seems to be a prepared SHA256 DER object. */
|
||||
if (hashalgo == GCRY_MD_SHA256 && !memcmp (indata, sha256_prefix, 19))
|
||||
;
|
||||
else
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
memcpy (data, indata, indatalen);
|
||||
datalen = 51;
|
||||
hashlen = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Need to prepend the prefix. */
|
||||
if (hashalgo == GCRY_MD_SHA1)
|
||||
memcpy (data, sha1_prefix, 15);
|
||||
if (hashalgo == GCRY_MD_SHA256)
|
||||
{
|
||||
memcpy (data, sha256_prefix, 19);
|
||||
memcpy (data+19, indata, indatalen);
|
||||
datalen = 51;
|
||||
hashlen = 32;
|
||||
}
|
||||
else if (hashalgo == GCRY_MD_SHA1)
|
||||
{
|
||||
memcpy (data, sha1_prefix, 15);
|
||||
memcpy (data+15, indata, indatalen);
|
||||
datalen = 35;
|
||||
hashlen = 20;
|
||||
}
|
||||
else if (hashalgo == GCRY_MD_RMD160)
|
||||
memcpy (data, rmd160_prefix, 15);
|
||||
{
|
||||
memcpy (data, rmd160_prefix, 15);
|
||||
memcpy (data+15, indata, indatalen);
|
||||
datalen = 35;
|
||||
hashlen = 20;
|
||||
}
|
||||
else
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
memcpy (data+15, indata, indatalen);
|
||||
}
|
||||
|
||||
|
||||
/* We need some more info about the key - get the keygrip to
|
||||
* populate these fields. */
|
||||
err = keygrip_from_prkdf (app, prkdf);
|
||||
if (err)
|
||||
{
|
||||
log_error ("p15: keygrip_from_prkdf failed: %s\n", gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Manage security environment needs to be weaked for certain cards. */
|
||||
@ -3364,15 +3502,32 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
|
||||
return err;
|
||||
}
|
||||
|
||||
if (hashalgo == MD_USER_TLS_MD5SHA1)
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
0, data, 36, 0, outdata, outdatalen);
|
||||
else if (no_data_padding)
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
0, data+15, 20, 0,outdata,outdatalen);
|
||||
|
||||
dataptr = data;
|
||||
if (no_data_padding)
|
||||
{
|
||||
dataptr += datalen - hashlen;
|
||||
datalen = hashlen;
|
||||
}
|
||||
|
||||
if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048)
|
||||
{
|
||||
exmode = 1;
|
||||
le_value = prkdf->keynbits / 8;
|
||||
}
|
||||
else
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
0, data, 35, 0, outdata, outdatalen);
|
||||
{
|
||||
exmode = 0;
|
||||
le_value = 0;
|
||||
}
|
||||
|
||||
err = iso7816_compute_ds (app_get_slot (app),
|
||||
exmode, dataptr, datalen,
|
||||
le_value, outdata, outdatalen);
|
||||
|
||||
if (!err)
|
||||
log_printhex (*outdata, *outdatalen, "sign output:");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@ -3412,6 +3567,100 @@ do_auth (app_t app, ctrl_t ctrl, const char *keyidstr,
|
||||
}
|
||||
|
||||
|
||||
/* Process the various keygrip based info requests. */
|
||||
static gpg_error_t
|
||||
do_with_keygrip (app_t app, ctrl_t ctrl, int action,
|
||||
const char *want_keygripstr, int capability)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *serialno = NULL;
|
||||
int as_data = 0;
|
||||
prkdf_object_t keyinfo;
|
||||
|
||||
/* First a quick check for valid parameters. */
|
||||
switch (action)
|
||||
{
|
||||
case KEYGRIP_ACTION_LOOKUP:
|
||||
if (!want_keygripstr)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
goto leave;
|
||||
}
|
||||
break;
|
||||
case KEYGRIP_ACTION_SEND_DATA:
|
||||
as_data = 1;
|
||||
break;
|
||||
case KEYGRIP_ACTION_WRITE_STATUS:
|
||||
break;
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Allocate the s/n string if needed. */
|
||||
if (action != KEYGRIP_ACTION_LOOKUP)
|
||||
{
|
||||
serialno = app_get_serialno (app);
|
||||
if (!serialno)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
for (keyinfo = app->app_local->private_key_info;
|
||||
keyinfo; keyinfo = keyinfo->next)
|
||||
{
|
||||
|
||||
if (keygrip_from_prkdf (app, keyinfo))
|
||||
continue;
|
||||
|
||||
if (action == KEYGRIP_ACTION_LOOKUP)
|
||||
{
|
||||
if (!strcmp (keyinfo->keygrip, want_keygripstr))
|
||||
{
|
||||
err = 0; /* Found */
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (!want_keygripstr || !strcmp (keyinfo->keygrip, want_keygripstr))
|
||||
{
|
||||
char *keyref;
|
||||
|
||||
/* FIXME: Consider ... */
|
||||
(void)capability;
|
||||
|
||||
keyref = keyref_from_keyinfo (app, keyinfo);
|
||||
if (!keyref)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
send_keyinfo (ctrl, as_data, keyinfo->keygrip, serialno, keyref);
|
||||
if (want_keygripstr)
|
||||
{
|
||||
err = 0; /* Found */
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return an error so that the dispatcher keeps on looping over the
|
||||
* other applications. For clarity we use a different error code
|
||||
* when listing all keys. Note that in lookup mode WANT_KEYGRIPSTR
|
||||
* is not NULL. */
|
||||
if (!want_keygripstr)
|
||||
err = gpg_error (GPG_ERR_TRUE);
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
|
||||
leave:
|
||||
xfree (serialno);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Assume that EF(DIR) has been selected. Read its content and figure
|
||||
out the home EF of pkcs#15. Return that home DF or 0 if not found
|
||||
@ -3604,6 +3853,7 @@ app_select_p15 (app_t app)
|
||||
app->fnc.decipher = NULL;
|
||||
app->fnc.change_pin = NULL;
|
||||
app->fnc.check_pin = NULL;
|
||||
app->fnc.with_keygrip = do_with_keygrip;
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
|
@ -1356,7 +1356,7 @@ get_keygrip_by_tag (app_t app, unsigned int tag,
|
||||
err = ksba_cert_init_from_mem (cert, certbuf, certbuflen);
|
||||
if (err)
|
||||
goto leave;
|
||||
err = app_help_get_keygrip_string (cert, *r_keygripstr);
|
||||
err = app_help_get_keygrip_string (cert, *r_keygripstr, NULL);
|
||||
}
|
||||
|
||||
leave:
|
||||
@ -1564,7 +1564,7 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags,
|
||||
char idbuf[50];
|
||||
const char *usage;
|
||||
|
||||
err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr);
|
||||
err = app_help_get_keygrip_string_pk (pk, pklen, keygripstr, NULL);
|
||||
if (err)
|
||||
{
|
||||
log_error ("app_help_get_keygrip_string_pk failed: %s\n",
|
||||
|
@ -1355,7 +1355,7 @@ keygripstr_from_prkdf (app_t app, prkdf_object_t prkdf, char *r_gripstr)
|
||||
err = ksba_cert_init_from_mem (cert, der, derlen);
|
||||
xfree (der);
|
||||
if (!err)
|
||||
err = app_help_get_keygrip_string (cert, r_gripstr);
|
||||
err = app_help_get_keygrip_string (cert, r_gripstr, NULL);
|
||||
ksba_cert_release (cert);
|
||||
|
||||
return err;
|
||||
|
@ -2251,7 +2251,7 @@ app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str,
|
||||
log_debug ("slot %d, app %s: calling with_keygrip(%s)\n",
|
||||
c->slot, xstrapptype (a),
|
||||
action == KEYGRIP_ACTION_SEND_DATA? "send_data":
|
||||
action == KEYGRIP_ACTION_WRITE_STATUS? "write_data":
|
||||
action == KEYGRIP_ACTION_WRITE_STATUS? "status":
|
||||
action == KEYGRIP_ACTION_LOOKUP? "lookup":"?");
|
||||
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
|
||||
goto leave_the_loop; /* ACTION_LOOKUP succeeded. */
|
||||
|
@ -648,7 +648,8 @@ do_readkey (card_t card, ctrl_t ctrl, const char *line,
|
||||
{
|
||||
char keygripstr[KEYGRIP_LEN*2+1];
|
||||
|
||||
rc = app_help_get_keygrip_string_pk (*pk_p, *pklen_p, keygripstr);
|
||||
rc = app_help_get_keygrip_string_pk (*pk_p, *pklen_p,
|
||||
keygripstr, NULL);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("app_help_get_keygrip_string failed: %s\n",
|
||||
|
Loading…
x
Reference in New Issue
Block a user