scd:p15: Support special extended usage flags for OpenPGP keys.

* scd/app-p15.c (struct gpgusage_flags_s): New.
(struct prkdf_object_s): Add field gpgusage.
(struct app_local_s): Add field any_gpgusage.
(dump_gpgusage_flags): New.
(read_p15_info): Parse athe gpgusage flags.
(do_getattr): Take care of the gpgusage flags.
--

This features allows to mark keys to be used for OpenPGP.  This is
done by putting additional extended key infos into the certificate
stored on the cards.  Only if any such extended key usage is detected
for a stored certificate this new mode chimes in.

This feature gives the card issuer a high flexibility on how to make
sure certain keys are used with OpenPGP.
This commit is contained in:
Werner Koch 2021-03-10 11:03:02 +01:00
parent a1f281eeec
commit 08b5ac492a
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 98 additions and 6 deletions

View File

@ -1562,6 +1562,11 @@ Status codes are:
1.3.6.1.4.1.11591.2.4.1.4 gpgSubCertID attribute
1.3.6.1.4.1.11591.2.5 LDAP URL extensions
1.3.6.1.4.1.11591.2.5.1 gpgNtds=1 (auth. with current AD user)
1.3.6.1.4.1.11591.2.6 GnuPG extended key usage
1.3.6.1.4.1.11591.2.6.1 use for certification key
1.3.6.1.4.1.11591.2.6.2 use for signing key
1.3.6.1.4.1.11591.2.6.3 use for encryption key
1.3.6.1.4.1.11591.2.6.4 use for authentication key
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
#+end_example

View File

@ -61,6 +61,10 @@ static const char oid_kp_ms_smartcardLogon[] = "1.3.6.1.4.1.311.20.2.2";
static const char oid_kp_anyExtendedKeyUsage[] = "2.5.29.37.0";
static const char oid_kp_gpgUsageCert[] = "1.3.6.1.4.1.11591.2.6.1";
static const char oid_kp_gpgUsageSign[] = "1.3.6.1.4.1.11591.2.6.2";
static const char oid_kp_gpgUsageEncr[] = "1.3.6.1.4.1.11591.2.6.3";
static const char oid_kp_gpgUsageAuth[] = "1.3.6.1.4.1.11591.2.6.4";
/* Types of cards we know and which needs special treatment. */
typedef enum
@ -180,6 +184,18 @@ struct keyaccess_flags_s
typedef struct keyaccess_flags_s keyaccess_flags_t;
/* A bit array with for the gpg usage flags. */
struct gpgusage_flags_s
{
unsigned int any:1; /* Any of the next flags are set. */
unsigned int cert:1; /* 1.3.6.1.4.1.11591.2.6.1 */
unsigned int sign:1; /* 1.3.6.1.4.1.11591.2.6.2 */
unsigned int encr:1; /* 1.3.6.1.4.1.11591.2.6.3 */
unsigned int auth:1; /* 1.3.6.1.4.1.11591.2.6.4 */
};
typedef struct gpgusage_flags_s gpgusage_flags_t;
/* This is an object to store information about a Certificate
Directory File (CDF) in a format suitable for further processing by
us. To keep memory management, simple we use a linked list of
@ -258,6 +274,11 @@ struct prkdf_object_s
unsigned int auth:1;
} extusage;
/* OpenPGP key features for this key. This is taken from special
* extended key usage flags different from those tracked in EXTUSAGE
* above. There is also no valid flag as in EXTUSAGE. */
gpgusage_flags_t gpgusage;
/* The keygrip of the key. This is used as a cache. */
char keygrip[2*KEYGRIP_LEN+1];
@ -400,6 +421,9 @@ struct app_local_s
/* Flag indicating whether we may use direct path selection. */
int direct_path_selection;
/* Flag indicating whether the card has any key with a gpgusage set. */
int any_gpgusage;
/* Structure with the EFIDs of the objects described in the ODF
file. */
struct
@ -1153,6 +1177,23 @@ dump_keyaccess_flags (keyaccess_flags_t accessflags)
}
static void
dump_gpgusage_flags (gpgusage_flags_t gpgusage)
{
const char *s = "";
log_info ("p15: gpgusage=");
if (gpgusage.cert)
log_printf ("%scert", s), s = ",";
if (gpgusage.sign)
log_printf ("%ssign", s), s = ",";
if (gpgusage.encr)
log_printf ("%sencr", s), s = ",";
if (gpgusage.auth)
log_printf ("%sauth", s), s = ",";
}
/* Parse the BIT STRING with the keyAccessFlags from the
CommonKeyAttributes. */
static gpg_error_t
@ -1877,6 +1918,7 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
unsigned long key_reference = 0;
int key_reference_valid = 0;
where = __LINE__;
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
if (err)
@ -3421,11 +3463,13 @@ read_p15_info (app_t app)
* certificate; if we want to change this strategy we should walk
* over the certificates and then find the corresponsing private key
* objects. */
app->app_local->any_gpgusage = 0;
for (prkdf = app->app_local->private_key_info; prkdf; prkdf = prkdf->next)
{
cdf_object_t cdf;
char *extusage;
char *p, *pend;
int seen;
if (opt.debug)
log_printhex (prkdf->objid, prkdf->objidlen, "p15: prkdf id=");
@ -3448,6 +3492,7 @@ read_p15_info (app_t app)
if ( *pend == 'C' ) /* Look only at critical usages. */
{
prkdf->extusage.valid = 1;
seen = 1;
if (!strcmp (p, oid_kp_codeSigning)
|| !strcmp (p, oid_kp_timeStamping)
|| !strcmp (p, oid_kp_ocspSigning)
@ -3466,8 +3511,42 @@ read_p15_info (app_t app)
prkdf->extusage.encr = 1;
prkdf->extusage.auth = 1;
}
else
seen = 0;
}
else
seen = 0;
/* Now check the gpg Usage. Here we don't care about
* critical or non-critical here. */
if (seen)
; /* No more need to look for other caps. */
else if (!strcmp (p, oid_kp_gpgUsageCert))
{
prkdf->gpgusage.cert = 1;
prkdf->gpgusage.any = 1;
app->app_local->any_gpgusage = 1;
}
else if (!strcmp (p, oid_kp_gpgUsageSign))
{
prkdf->gpgusage.sign = 1;
prkdf->gpgusage.any = 1;
app->app_local->any_gpgusage = 1;
}
else if (strcmp (!p, oid_kp_gpgUsageEncr))
{
prkdf->gpgusage.encr = 1;
prkdf->gpgusage.any = 1;
app->app_local->any_gpgusage = 1;
}
else if (!strcmp (p, oid_kp_gpgUsageAuth))
{
prkdf->gpgusage.auth = 1;
prkdf->gpgusage.any = 1;
app->app_local->any_gpgusage = 1;
}
/* Skip to next item. */
if ((p = strchr (pend, '\n')))
p++;
}
@ -3511,6 +3590,8 @@ read_p15_info (app_t app)
((prkdf->extusage.sign || prkdf->extusage.encr)
&& prkdf->extusage.auth)?",":"",
prkdf->extusage.auth? "auth":"");
if (prkdf->gpgusage.any)
dump_gpgusage_flags (prkdf->gpgusage);
log_printf ("\n");
}
@ -3842,8 +3923,7 @@ readcert_by_cdf (app_t app, cdf_object_t cdf,
image = ksba_cert_get_image (cdf->cert, &imagelen);
if (!image)
{
log_error ("p15: ksba_cert_get_image failed: %s\n",
gpg_strerror (err));
log_error ("p15: ksba_cert_get_image failed\n");
return gpg_error (GPG_ERR_INTERNAL);
}
*r_cert = xtrymalloc (imagelen);
@ -4004,7 +4084,11 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
char *buf;
/* We return the ID of the first private key capable of the
* requested action. Note that we do not yet return
* requested action. IF any gpgusage flag has been set for the
* card we use the key only if both the P15 usage and the
* gpgusage are set. This allows allows to single out the keys
* dedicated to OpenPGP. */
/* FIXME: This changed: Note that we do not yet return
* non_repudiation keys for $SIGNKEYID because our D-Trust
* testcard uses rsaPSS, which is not supported by gpgsm and not
* covered by the VS-NfD approval. */
@ -4012,13 +4096,16 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
prkdf = prkdf->next)
{
if (name[1] == 'A' && (prkdf->usageflags.sign
|| prkdf->usageflags.sign_recover))
|| prkdf->usageflags.sign_recover)
&& (!app->app_local->any_gpgusage || prkdf->gpgusage.auth))
break;
else if (name[1] == 'E' && (prkdf->usageflags.decrypt
|| prkdf->usageflags.unwrap))
|| prkdf->usageflags.unwrap)
&& (!app->app_local->any_gpgusage || prkdf->gpgusage.encr))
break;
else if (name[1] == 'S' && (prkdf->usageflags.sign
|| prkdf->usageflags.sign_recover))
|| prkdf->usageflags.sign_recover)
&& (!app->app_local->any_gpgusage || prkdf->gpgusage.sign))
break;
}
if (prkdf)