From d51a5ca1084c69c0ed304126a7aaa0a648b2eba6 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 25 Feb 2021 12:34:02 +0100 Subject: [PATCH] scd:p15: Read out the access flags. * scd/app-p15.c (struct keyaccess_flags_s): New. (struct prkdf_object_s): Add field accessflags. (dump_keyusage_flags): New. (dump_keyaccess_flags): New. (parse_keyaccess_flags): New. (parse_common_key_attr): Return access flags. (read_ef_prkdf): Parse the access flags. Allow for ECkeys. (read_ef_pukdf): Ditto. Use new functions for printing. (read_p15_info): Use new fucntion for printing. --- scd/app-p15.c | 209 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 141 insertions(+), 68 deletions(-) diff --git a/scd/app-p15.c b/scd/app-p15.c index f3177fa84..bfd77094e 100644 --- a/scd/app-p15.c +++ b/scd/app-p15.c @@ -166,6 +166,19 @@ struct keyusage_flags_s typedef struct keyusage_flags_s keyusage_flags_t; +/* A bit array with for the key access flags from the + commonKeyAttributes. */ +struct keyaccess_flags_s +{ + unsigned int any:1; /* Any access flag set. */ + unsigned int sensitive:1; + unsigned int extractable:1; + unsigned int always_sensitive:1; + unsigned int never_extractable:1; + unsigned int local:1; +}; +typedef struct keyaccess_flags_s keyaccess_flags_t; + /* This is an object to store information about a Certificate Directory File (CDF) in a format suitable for further processing by @@ -233,6 +246,9 @@ struct prkdf_object_s /* The key's usage flags. */ keyusage_flags_t usageflags; + /* The key's access flags. */ + keyaccess_flags_t accessflags; + /* Extended key usage flags. Only used if .valid is set. This * information is computed from an associated certificate15. */ struct { @@ -1089,6 +1105,101 @@ parse_keyusage_flags (const unsigned char *der, size_t derlen, } +static void +dump_keyusage_flags (keyusage_flags_t usageflags) +{ + const char *s = ""; + + log_info ("p15: usage="); + if (usageflags.encrypt) + log_printf ("%sencrypt", s), s = ","; + if (usageflags.decrypt) + log_printf ("%sdecrypt", s), s = ","; + if (usageflags.sign ) + log_printf ("%ssign", s), s = ","; + if (usageflags.sign_recover) + log_printf ("%ssign_recover", s), s = ","; + if (usageflags.wrap ) + log_printf ("%swrap", s), s = ","; + if (usageflags.unwrap ) + log_printf ("%sunwrap", s), s = ","; + if (usageflags.verify ) + log_printf ("%sverify", s), s = ","; + if (usageflags.verify_recover) + log_printf ("%sverify_recover", s), s = ","; + if (usageflags.derive ) + log_printf ("%sderive", s), s = ","; + if (usageflags.non_repudiation) + log_printf ("%snon_repudiation", s), s = ","; +} + + +static void +dump_keyaccess_flags (keyaccess_flags_t accessflags) +{ + const char *s = ""; + + log_info ("p15: access="); + if (accessflags.sensitive) + log_printf ("%ssensitive", s), s = ","; + if (accessflags.extractable) + log_printf ("%sextractable", s), s = ","; + if (accessflags.always_sensitive) + log_printf ("%salways_sensitive", s), s = ","; + if (accessflags.never_extractable) + log_printf ("%snever_extractable", s), s = ","; + if (accessflags.local) + log_printf ("%slocal", s), s = ","; +} + + +/* Parse the BIT STRING with the keyAccessFlags from the + CommonKeyAttributes. */ +static gpg_error_t +parse_keyaccess_flags (const unsigned char *der, size_t derlen, + keyaccess_flags_t *accessflags) +{ + unsigned int bits, mask; + int i, unused, full; + + memset (accessflags, 0, sizeof *accessflags); + if (!derlen) + return gpg_error (GPG_ERR_INV_OBJ); + + unused = *der++; derlen--; + if ((!derlen && unused) || unused/8 > derlen) + return gpg_error (GPG_ERR_ENCODING_PROBLEM); + full = derlen - (unused+7)/8; + unused %= 8; + mask = 0; + for (i=1; unused; i <<= 1, unused--) + mask |= i; + + /* First octet */ + if (derlen) + { + bits = *der++; derlen--; + if (full) + full--; + else + { + bits &= ~mask; + mask = 0; + } + } + else + bits = 0; + if ((bits & 0x10)) accessflags->local = 1; + if ((bits & 0x08)) accessflags->never_extractable = 1; + if ((bits & 0x04)) accessflags->always_sensitive = 1; + if ((bits & 0x02)) accessflags->extractable = 1; + if ((bits & 0x01)) accessflags->sensitive = 1; + + accessflags->any = 1; + return 0; +} + + /* Parse the commonObjectAttributes and store a malloced authid at * (r_authid,r_authidlen). (NULL,0) is stored on error or if no * authid is found. IF R_LABEL is not NULL the label is stored there @@ -1230,6 +1341,7 @@ static gpg_error_t parse_common_key_attr (unsigned char const **buffer, size_t *size, unsigned char **r_objid, size_t *r_objidlen, keyusage_flags_t *usageflags, + keyaccess_flags_t *accessflags, unsigned long *r_key_reference, int *r_key_reference_valid) { @@ -1248,6 +1360,7 @@ parse_common_key_attr (unsigned char const **buffer, size_t *size, *r_objid = NULL; *r_objidlen = 0; memset (usageflags, 0, sizeof *usageflags); + memset (accessflags, 0, sizeof *accessflags); *r_key_reference_valid = 0; where = __LINE__; @@ -1320,7 +1433,10 @@ parse_common_key_attr (unsigned char const **buffer, size_t *size, } if (class == CLASS_UNIVERSAL && tag == TAG_BIT_STRING) { - /* Skip the accessFlags. */ + /* These are the keyAccessFlags. */ + err = parse_keyaccess_flags (ppp, objlen, accessflags); + if (err) + goto leave; ppp += objlen; nnn -= objlen; @@ -1381,12 +1497,11 @@ parse_common_key_attr (unsigned char const **buffer, size_t *size, /* Read and parse the Private Key Directory Files. * * Sample object: - * * SEQUENCE { * SEQUENCE { -- commonObjectAttributes * UTF8String 'SK.CH.DS' * BIT STRING 6 unused bits - * '01'B (bit 0) + * '01'B (bit 0) -- flags: non-modifiable,private * OCTET STRING --authid * 07 * } @@ -1394,7 +1509,7 @@ parse_common_key_attr (unsigned char const **buffer, size_t *size, * OCTET STRING * 01 * BIT STRING 6 unused bits - * '1000000000'B (bit 9) + * '1000000000'B (bit 9) -- keyusage: non-repudiation * INTEGER 80 -- keyReference (optional) * } * [1] { -- keyAttributes @@ -1408,34 +1523,13 @@ parse_common_key_attr (unsigned char const **buffer, size_t *size, * } * } * - * Sample for EC objects - * [1] { -- keyAttributes - * [0] { --privateECKeyAttributes - * SEQUENCE { -- objectValue - * UTF8String '840b8a098d582647778e25a8465c5601' - * BIT STRING 6 unused bits - * '11'B - * OCTET STRING 01 - * } - * SEQUENCE { -- keyInfo - * OCTET STRING 69AE183E6D5BF45B98872C569506326C76AF460F - * BIT STRING 4 unused bits - * '0100'B (bit 2) - * BIT STRING 3 unused bits - * '11101'B - * INTEGER 3 - * } - * [0] { - * SEQUENCE {} - * } - * [1] { - * SEQUENCE { - * SEQUENCE { - * OCTET STRING 50 72 4B 03 - * } - * INTEGER 33 - * } - * } + * Sample part for EC objects: + * [1] { -- keyAttributes + * SEQUENCE { + * SEQUENCE { + * OCTET STRING 50 72 4B 03 + * } + * INTEGER 33 -- Not in PKCS#15v1.1, need to buy 6718-15? * } * } */ @@ -1478,6 +1572,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) prkdf_object_t prkdf = NULL; unsigned long ul; keyusage_flags_t usageflags; + keyaccess_flags_t accessflags; unsigned long key_reference = 0; int key_reference_valid = 0; @@ -1494,13 +1589,14 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) { switch (tag) { - case 0: errstr = "EC key objects are not supported"; break; + case 0: break; /* PrivateECKeyAttributes */ case 1: errstr = "DH key objects are not supported"; break; case 2: errstr = "DSA key objects are not supported"; break; case 3: errstr = "KEA key objects are not supported"; break; default: errstr = "unknown privateKeyObject"; break; } - goto parse_error; + if (errstr) + goto parse_error; } else { @@ -1533,7 +1629,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) xfree (objid); err = parse_common_key_attr (&pp, &nn, &objid, &objidlen, - &usageflags, + &usageflags, &accessflags, &key_reference, &key_reference_valid); if (err) goto parse_error; @@ -1641,6 +1737,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result) prkdf->path[i] = ((pp[0] << 8) | pp[1]); prkdf->usageflags = usageflags; + prkdf->accessflags = accessflags; prkdf->key_reference = key_reference; prkdf->key_reference_valid = key_reference_valid; @@ -1776,9 +1873,9 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result) pukdf_object_t pukdf = NULL; unsigned long ul; keyusage_flags_t usageflags; + keyaccess_flags_t accessflags; unsigned long key_reference = 0; int key_reference_valid = 0; - const char *s; err = parse_ber_header (&p, &n, &class, &tag, &constructed, &ndef, &objlen, &hdrlen); @@ -1832,7 +1929,7 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result) xfree (objid); err = parse_common_key_attr (&pp, &nn, &objid, &objidlen, - &usageflags, + &usageflags, &accessflags, &key_reference, &key_reference_valid); if (err) goto parse_error; @@ -1941,6 +2038,7 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result) pukdf->path[i] = ((pp[0] << 8) | pp[1]); pukdf->usageflags = usageflags; + pukdf->accessflags = accessflags; pukdf->key_reference = key_reference; pukdf->key_reference_valid = key_reference_valid; @@ -2004,21 +2102,9 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result) } if (pukdf->key_reference_valid) log_printf (" keyref=0x%02lX", pukdf->key_reference); - log_info ("p15: usage="); - s = ""; - if (pukdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ","; - if (pukdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ","; - if (pukdf->usageflags.sign ) log_printf ("%ssign", s), s = ","; - if (pukdf->usageflags.sign_recover) - log_printf ("%ssign_recover", s), s = ","; - if (pukdf->usageflags.wrap ) log_printf ("%swrap", s), s = ","; - if (pukdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ","; - if (pukdf->usageflags.verify ) log_printf ("%sverify", s), s = ","; - if (pukdf->usageflags.verify_recover) - log_printf ("%sverify_recover", s), s = ","; - if (pukdf->usageflags.derive ) log_printf ("%sderive", s), s = ","; - if (pukdf->usageflags.non_repudiation) - log_printf ("%snon_repudiation", s), s = ","; + if (pukdf->accessflags.any) + dump_keyaccess_flags (pukdf->accessflags); + dump_keyusage_flags (pukdf->usageflags); log_printf ("\n"); } @@ -3392,7 +3478,6 @@ read_p15_info (app_t app) if (opt.verbose) { int i; - const char *s; for (prkdf = app->app_local->private_key_info; prkdf; prkdf = prkdf->next) { @@ -3414,21 +3499,9 @@ read_p15_info (app_t app) } if (prkdf->key_reference_valid) log_printf (" keyref=0x%02lX", prkdf->key_reference); - log_info ("p15: usage="); - s = ""; - if (prkdf->usageflags.encrypt) log_printf ("%sencrypt", s), s = ","; - if (prkdf->usageflags.decrypt) log_printf ("%sdecrypt", s), s = ","; - if (prkdf->usageflags.sign ) log_printf ("%ssign", s), s = ","; - if (prkdf->usageflags.sign_recover) - log_printf ("%ssign_recover", s), s = ","; - if (prkdf->usageflags.wrap ) log_printf ("%swrap", s), s = ","; - if (prkdf->usageflags.unwrap ) log_printf ("%sunwrap", s), s = ","; - if (prkdf->usageflags.verify ) log_printf ("%sverify", s), s = ","; - if (prkdf->usageflags.verify_recover) - log_printf ("%sverify_recover", s), s = ","; - if (prkdf->usageflags.derive ) log_printf ("%sderive", s), s = ","; - if (prkdf->usageflags.non_repudiation) - log_printf ("%snon_repudiation", s), s = ","; + if (prkdf->accessflags.any) + dump_keyaccess_flags (prkdf->accessflags); + dump_keyusage_flags (prkdf->usageflags); if (prkdf->extusage.valid) log_info ("p15: extusage=%s%s%s%s%s", prkdf->extusage.sign? "sign":"",