scd:piv: Avoid conflict when writing a cert.

* scd/app-piv.c (map_curve_name_to_oid): New.
(my_cmp_public_key): New.
(do_writecert): Replace simple memcmp by cmp_canon_sexp.
--

GnuPG-bug-id: 5061
This commit is contained in:
Werner Koch 2020-09-11 15:47:39 +02:00
parent b6ba6a79ce
commit fbc1b199fd
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
1 changed files with 63 additions and 1 deletions

View File

@ -3355,6 +3355,66 @@ do_genkey (app_t app, ctrl_t ctrl, const char *keyrefstr, const char *keytype,
}
/* Map some names to an OID. */
static const unsigned char *
map_curve_name_to_oid (const unsigned char *name, size_t *namelenp)
{
if (*namelenp == 8 && !memcmp (name, "nistp256", 8))
{
*namelenp = 19;
return "1.2.840.10045.3.1.7";
}
if (*namelenp == 8 && !memcmp (name, "nistp384", 8))
{
*namelenp = 12;
return "1.3.132.0.34";
}
if (*namelenp == 8 && !memcmp (name, "nistp521", 8))
{
*namelenp = 12;
return "1.3.132.0.35";
}
return name;
}
/* Communication object for my_cmp_public_key. */
struct my_cmp_public_key_parm_s {
int curve_seen;
};
/* Compare function used with cmp_canon_sexp. */
static int
my_cmp_public_key (void *opaque, int depth,
const unsigned char *aval, size_t alen,
const unsigned char *bval, size_t blen)
{
struct my_cmp_public_key_parm_s *parm = opaque;
(void)depth;
if (parm->curve_seen)
{
/* Last token was "curve" - canonicalize its argument. */
parm->curve_seen = 0;
aval = map_curve_name_to_oid (aval, &alen);
bval = map_curve_name_to_oid (bval, &blen);
}
else if (alen == 5 && !memcmp (aval, "curve", 5))
parm->curve_seen = 1;
else
parm->curve_seen = 0;
if (alen > blen)
return 1;
else if (alen < blen)
return -1;
else
return memcmp (aval, bval, alen);
}
/* Write the certificate (CERT,CERTLEN) to the card at CERTREFSTR.
* CERTREFSTR is either the OID of the certificate's container data
* object or of the form "PIV.<two_hexdigit_keyref>". */
@ -3370,6 +3430,7 @@ do_writecert (app_t app, ctrl_t ctrl,
unsigned char *pk = NULL;
unsigned char *orig_pk = NULL;
size_t pklen, orig_pklen;
struct my_cmp_public_key_parm_s cmp_parm = { 0 };
(void)ctrl;
(void)pincb; /* Not used; instead authentication is needed. */
@ -3403,7 +3464,8 @@ do_writecert (app_t app, ctrl_t ctrl,
err = app_help_pubkey_from_cert (cert, certlen, &pk, &pklen);
if (err)
goto leave; /* No public key in new certificate. */
if (orig_pklen != pklen || memcmp (orig_pk, pk, pklen))
if (cmp_canon_sexp (orig_pk, orig_pklen, pk, pklen,
my_cmp_public_key, &cmp_parm))
{
err = gpg_error (GPG_ERR_CONFLICT);
goto leave;