mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
scd:p15: Support attribute KEY-FPR.
* scd/app-p15.c: Include openpgpdefs.h. (struct prkdf_object_s): Add fields have_keytime and ecdh_kdf. (read_p15_info): Set ecdh_kdf. (keygrip_from_prkdf): Flag that we have the keytime. (send_keypairinfo): Send the key time only if valid. (send_key_fpr_line): New. (send_key_fpr): New. (do_getattr): Add KEY-FPR. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
2f2bdd9c08
commit
30f90fc857
@ -1599,6 +1599,7 @@ Status codes are:
|
|||||||
1.3.6.1.4.1.11591.2.2 X.509 extensions
|
1.3.6.1.4.1.11591.2.2 X.509 extensions
|
||||||
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
|
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
|
||||||
1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
|
1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
|
||||||
|
1.3.6.1.4.1.11591.2.2.10 OpenPGP KDF/KEK parameter
|
||||||
1.3.6.1.4.1.11591.2.3 CMS contentType
|
1.3.6.1.4.1.11591.2.3 CMS contentType
|
||||||
1.3.6.1.4.1.11591.2.3.1 OpenPGP keyblock (as octet string)
|
1.3.6.1.4.1.11591.2.3.1 OpenPGP keyblock (as octet string)
|
||||||
1.3.6.1.4.1.11591.2.4 LDAP stuff
|
1.3.6.1.4.1.11591.2.4 LDAP stuff
|
||||||
@ -1617,6 +1618,8 @@ Status codes are:
|
|||||||
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
|
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
|
The OpenPGP KDF/KEK parameter extension is used to convey additional
|
||||||
|
info for OpenPGP keys as an X.509 extensions.
|
||||||
|
|
||||||
|
|
||||||
* Debug flags
|
* Debug flags
|
||||||
|
175
scd/app-p15.c
175
scd/app-p15.c
@ -42,6 +42,7 @@
|
|||||||
#include "../common/i18n.h"
|
#include "../common/i18n.h"
|
||||||
#include "../common/tlv.h"
|
#include "../common/tlv.h"
|
||||||
#include "../common/host2net.h"
|
#include "../common/host2net.h"
|
||||||
|
#include "../common/openpgpdefs.h"
|
||||||
#include "apdu.h" /* fixme: we should move the card detection to a
|
#include "apdu.h" /* fixme: we should move the card detection to a
|
||||||
separate file */
|
separate file */
|
||||||
|
|
||||||
@ -254,6 +255,7 @@ struct prkdf_object_s
|
|||||||
unsigned int keygrip_valid:1;
|
unsigned int keygrip_valid:1;
|
||||||
unsigned int key_reference_valid:1;
|
unsigned int key_reference_valid:1;
|
||||||
unsigned int have_off:1;
|
unsigned int have_off:1;
|
||||||
|
unsigned int have_keytime:1;
|
||||||
|
|
||||||
/* Flag indicating that the corresponding PIN has already been
|
/* Flag indicating that the corresponding PIN has already been
|
||||||
* verified. Note that for cards which are able to return the
|
* verified. Note that for cards which are able to return the
|
||||||
@ -310,6 +312,10 @@ struct prkdf_object_s
|
|||||||
* certificate or NULL if not known. */
|
* certificate or NULL if not known. */
|
||||||
char *serial_number;
|
char *serial_number;
|
||||||
|
|
||||||
|
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
|
||||||
|
* availabale. .*/
|
||||||
|
unsigned char ecdh_kdf[4];
|
||||||
|
|
||||||
/* 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;
|
||||||
@ -635,7 +641,6 @@ do_deinit (app_t app)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Do a select and a read for the file with EFID. EFID_DESC is a
|
/* Do a select and a read for the file with EFID. EFID_DESC is a
|
||||||
desctription of the EF to be used with error messages. On success
|
desctription of the EF to be used with error messages. On success
|
||||||
BUFFER and BUFLEN contain the entire content of the EF. The caller
|
BUFFER and BUFLEN contain the entire content of the EF. The caller
|
||||||
@ -3557,8 +3562,7 @@ read_p15_info (app_t app)
|
|||||||
cdf_object_t cdf;
|
cdf_object_t cdf;
|
||||||
char *extusage;
|
char *extusage;
|
||||||
char *p, *pend;
|
char *p, *pend;
|
||||||
int seen;
|
int seen, i;
|
||||||
gpg_error_t errx;
|
|
||||||
|
|
||||||
if (opt.debug)
|
if (opt.debug)
|
||||||
log_printhex (prkdf->objid, prkdf->objidlen, "p15: prkdf id=");
|
log_printhex (prkdf->objid, prkdf->objidlen, "p15: prkdf id=");
|
||||||
@ -3570,7 +3574,38 @@ read_p15_info (app_t app)
|
|||||||
if (!cdf->cert)
|
if (!cdf->cert)
|
||||||
continue; /* Unsupported or broken certificate. */
|
continue; /* Unsupported or broken certificate. */
|
||||||
|
|
||||||
if ((errx=ksba_cert_get_ext_key_usages (cdf->cert, &extusage)))
|
if (prkdf->is_ecc)
|
||||||
|
{
|
||||||
|
const char *oid;
|
||||||
|
const unsigned char *der;
|
||||||
|
size_t off, derlen, objlen, hdrlen;
|
||||||
|
int class, tag, constructed, ndef;
|
||||||
|
|
||||||
|
for (i=0; !(err = ksba_cert_get_extension
|
||||||
|
(cdf->cert, i, &oid, NULL, &off, &derlen)); i++)
|
||||||
|
if (!strcmp (oid, "1.3.6.1.4.1.11591.2.2.10") )
|
||||||
|
break;
|
||||||
|
if (!err && (der = ksba_cert_get_image (cdf->cert, NULL)))
|
||||||
|
{
|
||||||
|
der += off;
|
||||||
|
err = parse_ber_header (&der, &derlen, &class, &tag, &constructed,
|
||||||
|
&ndef, &objlen, &hdrlen);
|
||||||
|
if (!err && (objlen > derlen || tag != TAG_OCTET_STRING || ndef))
|
||||||
|
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
derlen = objlen;
|
||||||
|
if (opt.debug)
|
||||||
|
log_printhex (der, derlen, "p15: OpenPGP KDF parms:");
|
||||||
|
/* Store them if they match the known OpenPGP format. */
|
||||||
|
if (derlen == 4 && der[0] == 3 && der[1] == 1)
|
||||||
|
memcpy (prkdf->ecdh_kdf, der, 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ksba_cert_get_ext_key_usages (cdf->cert, &extusage))
|
||||||
continue; /* No extended key usage attribute. */
|
continue; /* No extended key usage attribute. */
|
||||||
|
|
||||||
if (opt.debug)
|
if (opt.debug)
|
||||||
@ -3933,6 +3968,7 @@ keygrip_from_prkdf (app_t app, prkdf_object_t prkdf)
|
|||||||
ksba_cert_get_validity (cert, 0, isot);
|
ksba_cert_get_validity (cert, 0, isot);
|
||||||
t = isotime2epoch (isot);
|
t = isotime2epoch (isot);
|
||||||
prkdf->keytime = (t == (time_t)(-1))? 0 : (u32)t;
|
prkdf->keytime = (t == (time_t)(-1))? 0 : (u32)t;
|
||||||
|
prkdf->have_keytime = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!err && !prkdf->keyalgostr)
|
if (!err && !prkdf->keyalgostr)
|
||||||
@ -4053,7 +4089,7 @@ send_keypairinfo (app_t app, ctrl_t ctrl, prkdf_object_t prkdf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
log_assert (strlen (prkdf->keygrip) == 40);
|
log_assert (strlen (prkdf->keygrip) == 40);
|
||||||
if (prkdf->keytime)
|
if (prkdf->keytime && prkdf->have_keytime)
|
||||||
snprintf (keytime, sizeof keytime, "%lu",
|
snprintf (keytime, sizeof keytime, "%lu",
|
||||||
(unsigned long)prkdf->keytime);
|
(unsigned long)prkdf->keytime);
|
||||||
else
|
else
|
||||||
@ -4320,6 +4356,98 @@ compare_aodf_objid (const void *arg_a, const void *arg_b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_key_fpr_line (ctrl_t ctrl, int number, const unsigned char *fpr)
|
||||||
|
{
|
||||||
|
char buf[41];
|
||||||
|
char numbuf[25];
|
||||||
|
|
||||||
|
bin2hex (fpr, 20, buf);
|
||||||
|
if (number == -1)
|
||||||
|
*numbuf = 0; /* Don't print the key number */
|
||||||
|
else
|
||||||
|
snprintf (numbuf, sizeof numbuf, "%d", number);
|
||||||
|
send_status_info (ctrl, "KEY-FPR",
|
||||||
|
numbuf, (size_t)strlen(numbuf),
|
||||||
|
buf, (size_t)strlen (buf),
|
||||||
|
NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* If possible Emit a FPR-KEY status line for the private key object
|
||||||
|
* PRKDF using NUMBER as index. */
|
||||||
|
static void
|
||||||
|
send_key_fpr (app_t app, ctrl_t ctrl, prkdf_object_t prkdf, int number)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
cdf_object_t cdf;
|
||||||
|
unsigned char *pk, *fixed_pk;
|
||||||
|
size_t pklen, fixed_pklen;
|
||||||
|
const unsigned char *m, *e, *q;
|
||||||
|
size_t mlen, elen, qlen;
|
||||||
|
unsigned char fpr20[20];
|
||||||
|
|
||||||
|
if (cdf_object_from_objid (app, prkdf->objidlen, prkdf->objid, &cdf)
|
||||||
|
&& cdf_object_from_label (app, prkdf->label, &cdf))
|
||||||
|
return;
|
||||||
|
if (!cdf->cert)
|
||||||
|
readcert_by_cdf (app, cdf, NULL, NULL);
|
||||||
|
if (!cdf->cert)
|
||||||
|
return;
|
||||||
|
if (!prkdf->have_keytime)
|
||||||
|
return;
|
||||||
|
pk = ksba_cert_get_public_key (cdf->cert);
|
||||||
|
if (!pk)
|
||||||
|
return;
|
||||||
|
pklen = gcry_sexp_canon_len (pk, 0, NULL, &err);
|
||||||
|
|
||||||
|
if (uncompress_ecc_q_in_canon_sexp (pk, pklen, &fixed_pk, &fixed_pklen))
|
||||||
|
{
|
||||||
|
xfree (pk);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (fixed_pk)
|
||||||
|
{
|
||||||
|
xfree (pk); pk = NULL;
|
||||||
|
pk = fixed_pk;
|
||||||
|
pklen = fixed_pklen;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (prkdf->keyalgo)
|
||||||
|
{
|
||||||
|
case GCRY_PK_RSA:
|
||||||
|
if (!get_rsa_pk_from_canon_sexp (pk, pklen,
|
||||||
|
&m, &mlen, &e, &elen)
|
||||||
|
&& !compute_openpgp_fpr_rsa (4,
|
||||||
|
prkdf->keytime,
|
||||||
|
m, mlen, e, elen,
|
||||||
|
fpr20, NULL))
|
||||||
|
send_key_fpr_line (ctrl, number, fpr20);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GCRY_PK_ECC:
|
||||||
|
case GCRY_PK_ECDSA:
|
||||||
|
case GCRY_PK_ECDH:
|
||||||
|
case GCRY_PK_EDDSA:
|
||||||
|
/* Note that NUMBER 2 indicates the encryption key. */
|
||||||
|
if (!get_ecc_q_from_canon_sexp (pk, pklen, &q, &qlen)
|
||||||
|
&& !compute_openpgp_fpr_ecc (4,
|
||||||
|
prkdf->keytime,
|
||||||
|
prkdf->keyalgostr,
|
||||||
|
number == 2,
|
||||||
|
q, qlen,
|
||||||
|
prkdf->ecdh_kdf, 4,
|
||||||
|
fpr20, NULL))
|
||||||
|
send_key_fpr_line (ctrl, number, fpr20);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: /* No Fingerprint for an unknown algo. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
xfree (pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Implement the GETATTR command. This is similar to the LEARN
|
/* Implement the GETATTR command. This is similar to the LEARN
|
||||||
command but returns just one value via the status interface. */
|
command but returns just one value via the status interface. */
|
||||||
@ -4530,6 +4658,43 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (name, "KEY-FPR"))
|
||||||
|
{
|
||||||
|
/* Send KEY-FPR for the two openpgp keys. */
|
||||||
|
for (prkdf = app->app_local->private_key_info; prkdf;
|
||||||
|
prkdf = prkdf->next)
|
||||||
|
{
|
||||||
|
if (app->app_local->any_gpgusage)
|
||||||
|
{
|
||||||
|
if (prkdf->gpgusage.sign)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (prkdf->usageflags.sign || prkdf->usageflags.sign_recover)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prkdf)
|
||||||
|
send_key_fpr (app, ctrl, prkdf, 1);
|
||||||
|
for (prkdf = app->app_local->private_key_info; prkdf;
|
||||||
|
prkdf = prkdf->next)
|
||||||
|
{
|
||||||
|
if (app->app_local->any_gpgusage)
|
||||||
|
{
|
||||||
|
if (prkdf->gpgusage.encr)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (prkdf->usageflags.decrypt || prkdf->usageflags.unwrap)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prkdf)
|
||||||
|
send_key_fpr (app, ctrl, prkdf, 2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return gpg_error (GPG_ERR_INV_NAME);
|
return gpg_error (GPG_ERR_INV_NAME);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user