1
0
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:
Werner Koch 2020-03-31 19:55:15 +02:00
parent 2bdd4fc7b6
commit 103c1576b7
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
8 changed files with 367 additions and 97 deletions

View File

@ -216,8 +216,10 @@ app_get_slot (app_t app)
/*-- app-help.c --*/ /*-- app-help.c --*/
unsigned int app_help_count_bits (const unsigned char *a, size_t len); 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, gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen,
char *hexkeygrip); char *hexkeygrip,
gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, 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, gpg_error_t app_help_pubkey_from_cert (const void *cert, size_t certlen,
unsigned char **r_pk, size_t *r_pklen); unsigned char **r_pk, size_t *r_pklen);
size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff); size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);

View File

@ -137,7 +137,7 @@ do_learn_status (app_t app, ctrl_t ctrl, unsigned int flags)
ksba_cert_release (cert); ksba_cert_release (cert);
return err; return err;
} }
err = app_help_get_keygrip_string (cert, hexkeygrip); err = app_help_get_keygrip_string (cert, hexkeygrip, NULL);
if (err) if (err)
{ {
log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid); log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid);

View File

@ -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) /* Return the KEYGRIP for the canonical encoded public key (PK,PKLEN)
* as an hex encoded string in the user provided buffer HEXKEYGRIP * 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 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; gpg_error_t err;
gcry_sexp_t s_pkey; gcry_sexp_t s_pkey;
unsigned char array[KEYGRIP_LEN]; unsigned char array[KEYGRIP_LEN];
if (r_pkey)
*r_pkey = NULL;
err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen); err = gcry_sexp_sscan (&s_pkey, NULL, pk, pklen);
if (err) if (err)
return err; /* Can't parse that S-expression. */ 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); gcry_sexp_release (s_pkey);
return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/ 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); 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 /* Return the KEYGRIP for the certificate CERT as an hex encoded
string in the user provided buffer HEXKEYGRIP which must be of at * string in the user provided buffer HEXKEYGRIP which must be of at
least 41 bytes. */ * 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 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; gpg_error_t err;
ksba_sexp_t p; ksba_sexp_t p;
size_t n; size_t n;
if (r_pkey)
*r_pkey = NULL;
p = ksba_cert_get_public_key (cert); p = ksba_cert_get_public_key (cert);
if (!p) if (!p)
return gpg_error (GPG_ERR_BUG); return gpg_error (GPG_ERR_BUG);
n = gcry_sexp_canon_len (p, 0, NULL, NULL); n = gcry_sexp_canon_len (p, 0, NULL, NULL);
if (!n) if (!n)
return gpg_error (GPG_ERR_INV_SEXP); 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); ksba_free (p);
return err; return err;
} }

View File

@ -138,6 +138,9 @@ struct cdf_object_s
/* Link to next item when used in a linked list. */ /* Link to next item when used in a linked list. */
struct cdf_object_s *next; 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. /* 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 * This field is used for X.509 in PKCS#11 to make it easier to
* match a private key with a certificate. */ * match a private key with a certificate. */
@ -149,8 +152,6 @@ struct cdf_object_s
size_t imagelen; size_t imagelen;
unsigned char *image; 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 /* 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 and set to 0 if HAVE_OFF is false. */
unsigned long off, len; unsigned long off, len;
@ -174,6 +175,25 @@ struct prkdf_object_s
/* Link to next item when used in a linked list. */ /* Link to next item when used in a linked list. */
struct prkdf_object_s *next; 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. */ /* Length and allocated buffer with the Id of this object. */
size_t objidlen; size_t objidlen;
unsigned char *objid; unsigned char *objid;
@ -183,17 +203,11 @@ struct prkdf_object_s
size_t authidlen; size_t authidlen;
unsigned char *authid; unsigned char *authid;
/* The key's usage flags. */
keyusage_flags_t usageflags;
/* The keyReference and a flag telling whether it is valid. */ /* The keyReference and a flag telling whether it is valid. */
unsigned long key_reference; 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 /* 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; unsigned long off, len;
/* The length of the path as given in the PrKDF and the path itself. /* 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. */ /* Link to next item when used in a linked list. */
struct aodf_object_s *next; 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. */ /* Length and allocated buffer with the Id of this object. */
size_t objidlen; size_t objidlen;
unsigned char *objid; unsigned char *objid;
@ -223,6 +240,9 @@ struct aodf_object_s
size_t authidlen; size_t authidlen;
unsigned char *authid; unsigned char *authid;
/* The file ID of this AODF. */
unsigned short fid;
/* The PIN Flags. */ /* The PIN Flags. */
struct struct
{ {
@ -261,9 +281,6 @@ struct aodf_object_s
char pad_char; char pad_char;
int pad_char_valid; 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 /* 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 and set to 0 if HAVE_OFF is false. */
unsigned long off, len; unsigned long off, len;
@ -326,6 +343,7 @@ struct app_local_s
/*** Local prototypes. ***/ /*** 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, static gpg_error_t readcert_by_cdf (app_t app, cdf_object_t cdf,
unsigned char **r_cert, size_t *r_certlen); unsigned char **r_cert, size_t *r_certlen);
@ -498,35 +516,55 @@ parse_certid (app_t app, const char *certid,
*r_objid = NULL; *r_objid = NULL;
*r_objidlen = 0; *r_objidlen = 0;
if (app->app_local->home_df) if (certid[0] != 'P' && strlen (certid) == 40) /* This is a keygrip. */
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) prkdf_object_t keyinfo;
|| (!strncmp (certid, "P15-", 4)
&& hexdigitp (certid+4) for (keyinfo = app->app_local->private_key_info;
&& hexdigitp (certid+5) keyinfo; keyinfo = keyinfo->next)
&& hexdigitp (certid+6) if (!keygrip_from_prkdf (app, keyinfo)
&& hexdigitp (certid+7) && !strcmp (certid, keyinfo->keygrip))
&& certid[8] == '.')) break;
return gpg_error (GPG_ERR_NOT_FOUND); if (!keyinfo || !keyinfo->objidlen || !keyinfo->objid)
return gpg_error (GPG_ERR_INV_ID); return gpg_error (GPG_ERR_NOT_FOUND);
} objidlen = keyinfo->objidlen;
certid += strlen (tmpbuf); 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_objid = objid;
*r_objidlen = objidlen; *r_objidlen = objidlen;
return 0; return 0;
@ -1644,6 +1682,7 @@ read_ef_aodf (app_t app, unsigned short fid, aodf_object_t *result)
aodf = xtrycalloc (1, sizeof *aodf); aodf = xtrycalloc (1, sizeof *aodf);
if (!aodf) if (!aodf)
goto no_core; goto no_core;
aodf->fid = fid;
/* Parse the commonObjectAttributes. */ /* Parse the commonObjectAttributes. */
where = __LINE__; 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 /* Get the keygrip of the private key object PRKDF. On success the
keygrip gets returned in the caller provided 41 byte buffer * keygrip, the algo and the length are stored in the KEYGRIP,
R_GRIPSTR. */ * KEYALFO, and KEYNBITS fields of the PRKDF object. */
static gpg_error_t 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; gpg_error_t err;
cdf_object_t cdf; cdf_object_t cdf;
unsigned char *der; unsigned char *der;
size_t derlen; size_t derlen;
ksba_cert_t cert; 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 /* FIXME: We should check whether a public key directory file and a
matching public key for PRKDF is available. This should make matching public key for PRKDF is available. This should make
extraction of the key much easier. My current test card doesn't 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. */ a matching certificate and extract the key from there. */
/* Look for a matching certificate. A certificate matches if the Id /* 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)) && !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen))
break; break;
if (!cdf) 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); err = readcert_by_cdf (app, cdf, &der, &derlen);
if (err) if (err)
return err; goto leave;
err = ksba_cert_new (&cert); err = ksba_cert_new (&cert);
if (!err) if (!err)
err = ksba_cert_init_from_mem (cert, der, derlen); err = ksba_cert_init_from_mem (cert, der, derlen);
xfree (der); xfree (der);
if (!err) 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); 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 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 /* 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) for (; keyinfo; keyinfo = keyinfo->next)
{ {
char gripstr[40+1]; char *buf;
char *buf, *p;
int j; int j;
buf = xtrymalloc (9 + keyinfo->objidlen*2 + 1); buf = keyref_from_keyinfo (app, keyinfo);
if (!buf) if (!buf)
return gpg_error_from_syserror (); 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) if (err)
{ {
log_error ("p15: error getting keygrip from "); log_error ("p15: error getting keygrip from ");
for (j=0; j < keyinfo->pathlen; j++) 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)); log_printf (": %s\n", gpg_strerror (err));
} }
else else
{ {
assert (strlen (gripstr) == 40); log_assert (strlen (keyinfo->keygrip) == 40);
send_status_info (ctrl, "KEYPAIRINFO", send_status_info (ctrl, "KEYPAIRINFO",
gripstr, 40, keyinfo->keygrip, 2*KEYGRIP_LEN,
buf, strlen (buf), buf, strlen (buf),
NULL, (size_t)0); 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, const void *indata, size_t indatalen,
unsigned char **outdata, size_t *outdatalen ) 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 */ static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 }; 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; gpg_error_t err;
int i; int i;
unsigned char data[36]; /* Must be large enough for a SHA-1 digest unsigned char data[32+19]; /* Must be large enough for a SHA-256 digest
+ the largest OID prefix above and also * + the largest OID prefix above and also
fit the 36 bytes of md5sha1. */ * fit the 36 bytes of md5sha1. */
prkdf_object_t prkdf; /* The private key object. */ prkdf_object_t prkdf; /* The private key object. */
aodf_object_t aodf; /* The associated authentication object. */ aodf_object_t aodf; /* The associated authentication object. */
int no_data_padding = 0; /* True if the card want the data without padding.*/ 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. */ 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; (void)ctrl;
log_debug ("p15:sign: keyidstr='%s' indatalen=%zu\n", keyidstr, indatalen);
if (!keyidstr || !*keyidstr) if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE); 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); return gpg_error (GPG_ERR_INV_VALUE);
err = prkdf_object_from_keyidstr (app, keyidstr, &prkdf); 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); log_error ("p15: authentication object for %s missing\n", keyidstr);
return gpg_error (GPG_ERR_INV_CARD); return gpg_error (GPG_ERR_INV_CARD);
} }
if (aodf->authid)
if (opt.verbose)
{ {
log_error ("p15: PIN verification is protected by an " log_info ("p15: using AODF %04hX id=", aodf->fid);
"additional authentication token\n"); for (i=0; i < aodf->objidlen; i++)
return gpg_error (GPG_ERR_BAD_PIN_METHOD); 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 if (aodf->pinflags.integrity_protected
|| aodf->pinflags.confidentiality_protected) || aodf->pinflags.confidentiality_protected)
{ {
@ -3284,6 +3379,9 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
else else
pinvaluelen = strlen (pinvalue); 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), err = iso7816_verify (app_get_slot (app),
aodf->pin_reference_valid? aodf->pin_reference : 0, aodf->pin_reference_valid? aodf->pin_reference : 0,
pinvalue, pinvaluelen); 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) if (hashalgo != MD_USER_TLS_MD5SHA1)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data, indata, indatalen); memcpy (data, indata, indatalen);
datalen = hashlen = 36;
} }
else if (indatalen == 35) else if (indatalen == 35)
{ {
@ -3318,17 +3417,56 @@ do_sign (app_t app, ctrl_t ctrl, const char *keyidstr, int hashalgo,
else else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
memcpy (data, indata, indatalen); 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 else
{ {
/* Need to prepend the prefix. */ /* Need to prepend the prefix. */
if (hashalgo == GCRY_MD_SHA1) if (hashalgo == GCRY_MD_SHA256)
memcpy (data, sha1_prefix, 15); {
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) 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 else
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM); 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. */ /* 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; return err;
} }
if (hashalgo == MD_USER_TLS_MD5SHA1)
err = iso7816_compute_ds (app_get_slot (app), dataptr = data;
0, data, 36, 0, outdata, outdatalen); if (no_data_padding)
else if (no_data_padding) {
err = iso7816_compute_ds (app_get_slot (app), dataptr += datalen - hashlen;
0, data+15, 20, 0,outdata,outdatalen); datalen = hashlen;
}
if (prkdf->keyalgo == GCRY_PK_RSA && prkdf->keynbits > 2048)
{
exmode = 1;
le_value = prkdf->keynbits / 8;
}
else 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; 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 /* 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 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.decipher = NULL;
app->fnc.change_pin = NULL; app->fnc.change_pin = NULL;
app->fnc.check_pin = NULL; app->fnc.check_pin = NULL;
app->fnc.with_keygrip = do_with_keygrip;
leave: leave:
if (rc) if (rc)

View File

@ -1356,7 +1356,7 @@ get_keygrip_by_tag (app_t app, unsigned int tag,
err = ksba_cert_init_from_mem (cert, certbuf, certbuflen); err = ksba_cert_init_from_mem (cert, certbuf, certbuflen);
if (err) if (err)
goto leave; goto leave;
err = app_help_get_keygrip_string (cert, *r_keygripstr); err = app_help_get_keygrip_string (cert, *r_keygripstr, NULL);
} }
leave: leave:
@ -1564,7 +1564,7 @@ do_readkey (app_t app, ctrl_t ctrl, const char *keyrefstr, unsigned int flags,
char idbuf[50]; char idbuf[50];
const char *usage; 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) if (err)
{ {
log_error ("app_help_get_keygrip_string_pk failed: %s\n", log_error ("app_help_get_keygrip_string_pk failed: %s\n",

View File

@ -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); err = ksba_cert_init_from_mem (cert, der, derlen);
xfree (der); xfree (der);
if (!err) 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); ksba_cert_release (cert);
return err; return err;

View File

@ -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", log_debug ("slot %d, app %s: calling with_keygrip(%s)\n",
c->slot, xstrapptype (a), c->slot, xstrapptype (a),
action == KEYGRIP_ACTION_SEND_DATA? "send_data": 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":"?"); action == KEYGRIP_ACTION_LOOKUP? "lookup":"?");
if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability)) if (!a->fnc.with_keygrip (a, ctrl, action, keygrip_str, capability))
goto leave_the_loop; /* ACTION_LOOKUP succeeded. */ goto leave_the_loop; /* ACTION_LOOKUP succeeded. */

View File

@ -648,7 +648,8 @@ do_readkey (card_t card, ctrl_t ctrl, const char *line,
{ {
char keygripstr[KEYGRIP_LEN*2+1]; 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) if (rc)
{ {
log_error ("app_help_get_keygrip_string failed: %s\n", log_error ("app_help_get_keygrip_string failed: %s\n",