aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2021-01-27 13:11:19 +0100
committerWerner Koch <wk@gnupg.org>2021-01-27 13:28:12 +0100
commit5bcbc8cee310067aa3cc48665b0fb0595c64ae4d (patch)
treeb21465f7aba0d6f0f7958c34718e3a626213c377
parentb08418d22cc898c9d135217e07ca77f3daf3c9e9 (diff)
downloadgnupg-5bcbc8cee310067aa3cc48665b0fb0595c64ae4d.tar.gz
scd:p15: Factor the commonKeyAttributes parser out.
* scd/app-p15.c (read_ef_prkdf): Fix detection of unsupported key objects. Factor some code out to ... (parse_common_key_attr): new. --
-rw-r--r--scd/app-p15.c340
1 files changed, 206 insertions, 134 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
index a3352bbf1..c13921183 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -1033,6 +1033,173 @@ parse_common_obj_attr (unsigned char const **buffer, size_t *size,
}
+/* Parse the commonKeyAttributes. On success store the objid at
+ * (R_OBJID/R_OBJIDLEN), sets the key usage flags at USAGEFLAGS and
+ * the optiona key refrence at R_KEY_REFERENCE. The latter is only
+ * valid if true is also stored at R_KEY_REFERENCE_VALID.
+ *
+ * Example data:
+ *
+ * 21 30 12: SEQUENCE { -- commonKeyAttributes
+ * 23 04 1: OCTET STRING
+ * : 01
+ * 26 03 3: BIT STRING 6 unused bits
+ * : '1000000000'B (bit 9)
+ * 31 02 2: INTEGER 80 -- keyReference (optional)
+ * : }
+ */
+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,
+ unsigned long *r_key_reference,
+ int *r_key_reference_valid)
+{
+ gpg_error_t err;
+ int where;
+ int class, tag, constructed, ndef;
+ size_t objlen, hdrlen, nnn;
+ const unsigned char *ppp;
+ int ignore_eof = 0;
+ unsigned long ul;
+ const unsigned char *objid = NULL;
+ size_t objidlen;
+ unsigned long key_reference = 0;
+ int key_reference_valid = 0;
+
+ *r_objid = NULL;
+ *r_objidlen = 0;
+ memset (usageflags, 0, sizeof *usageflags);
+ *r_key_reference_valid = 0;
+
+ where = __LINE__;
+ err = parse_ber_header (buffer, size, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > *size || tag != TAG_SEQUENCE))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+
+ ppp = *buffer;
+ nnn = objlen;
+ *buffer += objlen;
+ *size -= objlen;
+
+ /* Get the Id. */
+ where = __LINE__;
+ err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > nnn
+ || class != CLASS_UNIVERSAL || tag != TAG_OCTET_STRING))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+
+ objid = ppp;
+ objidlen = objlen;
+ ppp += objlen;
+ nnn -= objlen;
+
+ /* Get the KeyUsageFlags. */
+ where = __LINE__;
+ err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && (objlen > nnn
+ || class != CLASS_UNIVERSAL || tag != TAG_BIT_STRING))
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+
+ err = parse_keyusage_flags (ppp, objlen, usageflags);
+ if (err)
+ goto leave;
+ ppp += objlen;
+ nnn -= objlen;
+
+ ignore_eof = 1; /* Remaining items are optional. */
+
+ /* Find the keyReference */
+ where = __LINE__;
+ err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && objlen > nnn)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+
+ if (class == CLASS_UNIVERSAL && tag == TAG_BOOLEAN)
+ {
+ /* Skip the native element. */
+ ppp += objlen;
+ nnn -= objlen;
+
+ err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && objlen > nnn)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+ }
+ if (class == CLASS_UNIVERSAL && tag == TAG_BIT_STRING)
+ {
+ /* Skip the accessFlags. */
+ ppp += objlen;
+ nnn -= objlen;
+
+ err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
+ &ndef, &objlen, &hdrlen);
+ if (!err && objlen > nnn)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ if (err)
+ goto leave;
+ }
+ if (class == CLASS_UNIVERSAL && tag == TAG_INTEGER)
+ {
+ /* This is the keyReference. */
+ for (ul=0; objlen; objlen--)
+ {
+ ul <<= 8;
+ ul |= (*ppp++) & 0xff;
+ nnn--;
+ }
+ key_reference = ul;
+ key_reference_valid = 1;
+ }
+
+ leave:
+ if (ignore_eof && gpg_err_code (err) == GPG_ERR_EOF)
+ err = 0;
+
+ if (!err)
+ {
+ if (!objid || !objidlen)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ else
+ {
+ *r_objid = xtrymalloc (objidlen);
+ if (!*r_objid)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ memcpy (*r_objid, objid, objidlen);
+ *r_objidlen = objidlen;
+ }
+ }
+ }
+ if (!err && key_reference_valid)
+ {
+ *r_key_reference = key_reference;
+ *r_key_reference_valid = 1;
+ }
+
+ if (err)
+ log_error ("p15: error parsing commonKeyAttributes at %d: %s\n",
+ where, gpg_strerror (err));
+ return err;
+
+}
+
+
/* Read and parse the Private Key Directory Files. */
/*
6034 (privatekeys)
@@ -1096,6 +1263,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
int recno = 1;
unsigned char *authid = NULL;
size_t authidlen = 0;
+ unsigned char *objid = NULL;
+ size_t objidlen = 0;
if (!fid)
return gpg_error (GPG_ERR_NO_DATA); /* No private keys. */
@@ -1112,8 +1281,6 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
p = buffer;
n = buflen;
- /* FIXME: This shares a LOT of code with read_ef_cdf! */
-
/* Loop over the records. We stop as soon as we detect a new record
starting with 0x00 or 0xff as these values are commonly used to
pad data blocks and are no valid ASN.1 encoding. Note the
@@ -1126,25 +1293,37 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
const char *errstr = NULL;
prkdf_object_t prkdf = NULL;
unsigned long ul;
- const unsigned char *objid;
- size_t objidlen;
keyusage_flags_t usageflags;
unsigned long key_reference = 0;
int key_reference_valid = 0;
const char *s;
+ where = __LINE__;
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
if (err)
;
else if (objlen > n)
err = gpg_error (GPG_ERR_INV_OBJ);
- else if (tag == TAG_SEQUENCE)
- ;
- else if (class == CLASS_CONTEXT && tag == 0)
- ; /* Seen with CardOS. */
+ else if (class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE)
+ ; /* PrivateRSAKeyAttributes */
+ else if (class == CLASS_CONTEXT)
+ {
+ switch (tag)
+ {
+ case 0: errstr = "EC key objects are not supported"; break;
+ 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;
+ }
else
- err = gpg_error (GPG_ERR_INV_OBJ);
+ {
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ goto parse_error;
+ }
if (err)
{
@@ -1152,6 +1331,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
gpg_strerror (err));
goto leave;
}
+
pp = p;
nn = objlen;
p += objlen;
@@ -1166,105 +1346,14 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
/* Parse the commonKeyAttributes. */
where = __LINE__;
- err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (!err && (objlen > nn || tag != TAG_SEQUENCE))
- err = gpg_error (GPG_ERR_INV_OBJ);
+ xfree (objid);
+ err = parse_common_key_attr (&pp, &nn,
+ &objid, &objidlen,
+ &usageflags,
+ &key_reference, &key_reference_valid);
if (err)
goto parse_error;
- {
- const unsigned char *ppp = pp;
- size_t nnn = objlen;
-
- pp += objlen;
- nn -= objlen;
-
- /* Get the Id. */
- where = __LINE__;
- err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (!err && (objlen > nnn
- || class != CLASS_UNIVERSAL || tag != TAG_OCTET_STRING))
- err = gpg_error (GPG_ERR_INV_OBJ);
- if (err)
- goto parse_error;
- objid = ppp;
- objidlen = objlen;
- ppp += objlen;
- nnn -= objlen;
-
- /* Get the KeyUsageFlags. */
- where = __LINE__;
- err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (!err && (objlen > nnn
- || class != CLASS_UNIVERSAL || tag != TAG_BIT_STRING))
- err = gpg_error (GPG_ERR_INV_OBJ);
- if (err)
- goto parse_error;
- err = parse_keyusage_flags (ppp, objlen, &usageflags);
- if (err)
- goto parse_error;
- ppp += objlen;
- nnn -= objlen;
-
- /* Find the keyReference */
- where = __LINE__;
- err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- goto leave_cki;
- if (!err && objlen > nnn)
- err = gpg_error (GPG_ERR_INV_OBJ);
- if (err)
- goto parse_error;
- if (class == CLASS_UNIVERSAL && tag == TAG_BOOLEAN)
- {
- /* Skip the native element. */
- ppp += objlen;
- nnn -= objlen;
-
- err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- goto leave_cki;
- if (!err && objlen > nnn)
- err = gpg_error (GPG_ERR_INV_OBJ);
- if (err)
- goto parse_error;
- }
- if (class == CLASS_UNIVERSAL && tag == TAG_BIT_STRING)
- {
- /* Skip the accessFlags. */
- ppp += objlen;
- nnn -= objlen;
-
- err = parse_ber_header (&ppp, &nnn, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (gpg_err_code (err) == GPG_ERR_EOF)
- goto leave_cki;
- if (!err && objlen > nnn)
- err = gpg_error (GPG_ERR_INV_OBJ);
- if (err)
- goto parse_error;
- }
- if (class == CLASS_UNIVERSAL && tag == TAG_INTEGER)
- {
- /* Yep, this is the keyReference. */
- for (ul=0; objlen; objlen--)
- {
- ul <<= 8;
- ul |= (*ppp++) & 0xff;
- nnn--;
- }
- key_reference = ul;
- key_reference_valid = 1;
- }
-
- leave_cki:
- ;
- }
-
+ log_assert (objid);
/* Skip subClassAttributes. */
where = __LINE__;
@@ -1293,29 +1382,16 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
where = __LINE__;
err = parse_ber_header (&pp, &nn, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
- if (!err && objlen > nn)
+ if (err)
+ ;
+ else if (!err && objlen > nn)
+ err = gpg_error (GPG_ERR_INV_OBJ);
+ else if (class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE)
+ ; /* A typeAttribute always starts with a sequence. */
+ else
err = gpg_error (GPG_ERR_INV_OBJ);
if (err)
goto parse_error;
- if (class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE)
- ; /* RSA */
- else if (class == CLASS_CONTEXT)
- {
- switch (tag)
- {
- case 0: errstr = "EC key objects are not supported"; break;
- 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;
- }
- else
- {
- err = gpg_error (GPG_ERR_INV_OBJ);
- goto parse_error;
- }
nn = objlen;
@@ -1351,6 +1427,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
errstr = "invalid path reference";
goto parse_error;
}
+
/* Create a new PrKDF list item. */
prkdf = xtrycalloc (1, (sizeof *prkdf
- sizeof(unsigned short)
@@ -1361,14 +1438,8 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
goto leave;
}
prkdf->objidlen = objidlen;
- prkdf->objid = xtrymalloc (objidlen);
- if (!prkdf->objid)
- {
- err = gpg_error_from_syserror ();
- xfree (prkdf);
- goto leave;
- }
- memcpy (prkdf->objid, objid, objidlen);
+ prkdf->objid = objid;
+ objid = NULL;
if (authid)
{
prkdf->authidlen = authidlen;
@@ -1498,6 +1569,7 @@ read_ef_prkdf (app_t app, unsigned short fid, prkdf_object_t *result)
leave:
xfree (authid);
+ xfree (objid);
xfree (buffer);
if (err)
release_prkdflist (prkdflist);