scd:p15: Match private keys with certificates also by labels.

* scd/app-p15.c (cdf_object_from_label): New.
(cdf_object_from_certid): Fallback to label matching.
(read_p15_info): Ditto.
(keygrip_from_prkdf): Ditto.  Replace duplicated code by a call to
cdf_object_from_objid.
--

In case there is no certificate for a private key we now also try to
find a certificate using a matching label.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2021-04-12 11:41:00 +02:00
parent 304c2e0202
commit ecb9265b8d
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
1 changed files with 59 additions and 28 deletions

View File

@ -887,6 +887,34 @@ cdf_object_from_objid (app_t app, size_t objidlen, const unsigned char *objid,
} }
/* Find a certificate object by its label and store a pointer to it at
* R_CDF. */
static gpg_error_t
cdf_object_from_label (app_t app, const char *label, cdf_object_t *r_cdf)
{
cdf_object_t cdf;
if (!label)
return gpg_error (GPG_ERR_NOT_FOUND);
for (cdf = app->app_local->certificate_info; cdf; cdf = cdf->next)
if (cdf->label && !strcmp (cdf->label, label))
break;
if (!cdf)
for (cdf = app->app_local->trusted_certificate_info; cdf; cdf = cdf->next)
if (cdf->label && !strcmp (cdf->label, label))
break;
if (!cdf)
for (cdf = app->app_local->useful_certificate_info; cdf; cdf = cdf->next)
if (cdf->label && !strcmp (cdf->label, label))
break;
if (!cdf)
return gpg_error (GPG_ERR_NOT_FOUND);
*r_cdf = cdf;
return 0;
}
/* Find a certificate object by the certificate ID CERTID and store a /* Find a certificate object by the certificate ID CERTID and store a
* pointer to it at R_CDF. */ * pointer to it at R_CDF. */
static gpg_error_t static gpg_error_t
@ -896,12 +924,24 @@ cdf_object_from_certid (app_t app, const char *certid, cdf_object_t *r_cdf)
size_t objidlen; size_t objidlen;
unsigned char *objid; unsigned char *objid;
cdf_object_t cdf; cdf_object_t cdf;
prkdf_object_t prkdf;
err = parse_certid (app, certid, &objid, &objidlen); err = parse_certid (app, certid, &objid, &objidlen);
if (err) if (err)
return err; return err;
err = cdf_object_from_objid (app, objidlen, objid, &cdf); err = cdf_object_from_objid (app, objidlen, objid, &cdf);
if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
{
/* Try again by finding the certid in the prkdf and matching by
* label. */
for (prkdf = app->app_local->private_key_info; prkdf; prkdf = prkdf->next)
if (prkdf->objidlen == objidlen
&& !memcmp (prkdf->objid, objid, objidlen))
break;
if (prkdf)
err = cdf_object_from_label (app, prkdf->label, &cdf);
}
xfree (objid); xfree (objid);
if (err) if (err)
return err; return err;
@ -3518,17 +3558,19 @@ read_p15_info (app_t app)
char *extusage; char *extusage;
char *p, *pend; char *p, *pend;
int seen; int seen;
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=");
if (cdf_object_from_objid (app, prkdf->objidlen, prkdf->objid, &cdf)) if (cdf_object_from_objid (app, prkdf->objidlen, prkdf->objid, &cdf)
&& cdf_object_from_label (app, prkdf->label, &cdf))
continue; /* No matching certificate. */ continue; /* No matching certificate. */
if (!cdf->cert) /* Read and parse the certificate. */ if (!cdf->cert) /* Read and parse the certificate. */
readcert_by_cdf (app, cdf, NULL, NULL); readcert_by_cdf (app, cdf, NULL, NULL);
if (!cdf->cert) if (!cdf->cert)
continue; /* Unsupported or broken certificate. */ continue; /* Unsupported or broken certificate. */
if (ksba_cert_get_ext_key_usages (cdf->cert, &extusage)) if ((errx=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)
@ -3801,33 +3843,22 @@ keygrip_from_prkdf (app_t app, prkdf_object_t prkdf)
xfree (prkdf->serial_number); xfree (prkdf->serial_number);
prkdf->serial_number = NULL; prkdf->serial_number = NULL;
/* FIXME: We should check whether a public key directory file and a /* We could have also checked whether a public key directory file
matching public key for PRKDF is available. This should make * and a matching public key for PRKDF is available. This would
extraction of the key much easier. My current test card doesn't * make extraction of the key faster. However, this way we don't
have one, so we can only use the fallback solution by looking for * have a way to look at extended key attributes to check gpgusage.
a matching certificate and extract the key from there. */ * FIXME: Add public key lookup if no certificate was found. */
/* Look for a matching certificate. A certificate matches if the Id /* Look for a matching certificate. A certificate matches if the id
matches the one of the private key info. */ * matches the one of the private key info. If none was found we
for (cdf = app->app_local->certificate_info; cdf; cdf = cdf->next) * also try to match on the label. */
if (cdf->objidlen == prkdf->objidlen err = cdf_object_from_objid (app, prkdf->objidlen, prkdf->objid, &cdf);
&& !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen)) if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
break; err = cdf_object_from_label (app, prkdf->label, &cdf);
if (!cdf) if (!err && !cdf)
for (cdf = app->app_local->trusted_certificate_info; cdf; cdf = cdf->next) err = gpg_error (GPG_ERR_NOT_FOUND);
if (cdf->objidlen == prkdf->objidlen if (err)
&& !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen)) goto leave;
break;
if (!cdf)
for (cdf = app->app_local->useful_certificate_info; cdf; cdf = cdf->next)
if (cdf->objidlen == prkdf->objidlen
&& !memcmp (cdf->objid, prkdf->objid, prkdf->objidlen))
break;
if (!cdf)
{
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)