aboutsummaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2024-02-19 15:50:22 +0000
committerWerner Koch <[email protected]>2024-02-20 08:17:38 +0000
commit3341017ff12599ff627b37fbe3c516df937c7989 (patch)
tree3147b2b87b3983ebd36ff055e25e4f2cf772d909 /scd
parentscd:p15: Take derive usage into account for decryption. (diff)
downloadgnupg-3341017ff12599ff627b37fbe3c516df937c7989.tar.gz
gnupg-3341017ff12599ff627b37fbe3c516df937c7989.zip
scd:p15: Handle duplicate certificate ids.
* scd/app-p15.c (struct app_local_s): Add field cdf_dup_counter. (objid_in_cdflist_p): New. (read_p15_info): Clear the counter. (read_ef_cdf): Detect and fix duplicate IDs. -- GnuPG-bug-id: 7001 Reported-by: Mario Haustein <[email protected]>
Diffstat (limited to 'scd')
-rw-r--r--scd/app-p15.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/scd/app-p15.c b/scd/app-p15.c
index 347683f57..df7a74355 100644
--- a/scd/app-p15.c
+++ b/scd/app-p15.c
@@ -520,6 +520,9 @@ struct app_local_s
/* Information on all useful certificates. */
cdf_object_t useful_certificate_info;
+ /* Counter to make object ids of certificates unique. */
+ unsigned int cdf_dup_counter;
+
/* Information on all public keys. */
prkdf_object_t public_key_info;
@@ -2419,6 +2422,22 @@ read_ef_pukdf (app_t app, unsigned short fid, pukdf_object_t *result)
}
+/* Return true id CDFLIST has the given object id. */
+static int
+objid_in_cdflist_p (cdf_object_t cdflist,
+ const unsigned char *objid, size_t objidlen)
+{
+ cdf_object_t cdf;
+
+ if (!objid || !objidlen)
+ return 0;
+ for (cdf = cdflist; cdf; cdf = cdf->next)
+ if (cdf->objidlen == objidlen && !memcmp (cdf->objid, objid, objidlen))
+ return 1;
+ return 0;
+}
+
+
/* Read and parse the Certificate Directory Files identified by FID.
On success a newlist of CDF object gets stored at RESULT and the
caller is then responsible of releasing this list. On error a
@@ -2464,6 +2483,7 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
unsigned long ul;
const unsigned char *objid;
size_t objidlen;
+ int objidextralen;
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
@@ -2588,8 +2608,19 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
label = NULL;
}
- cdf->objidlen = objidlen;
- cdf->objid = xtrymalloc (objidlen);
+ /* Card's have been found in the wild which do not have unique
+ * IDs for their certificate objects. If we detect this we
+ * append a counter to the ID. */
+ objidextralen =
+ (objid_in_cdflist_p (cdflist, objid, objidlen)
+ || objid_in_cdflist_p (app->app_local->certificate_info,
+ objid, objidlen)
+ || objid_in_cdflist_p (app->app_local->trusted_certificate_info,
+ objid, objidlen)
+ || objid_in_cdflist_p (app->app_local->useful_certificate_info,
+ objid, objidlen));
+ cdf->objidlen = objidlen + objidextralen;
+ cdf->objid = xtrymalloc (objidlen + objidextralen);
if (!cdf->objid)
{
err = gpg_error_from_syserror ();
@@ -2597,6 +2628,16 @@ read_ef_cdf (app_t app, unsigned short fid, int cdftype, cdf_object_t *result)
goto leave;
}
memcpy (cdf->objid, objid, objidlen);
+ if (objidextralen)
+ {
+ if (app->app_local->cdf_dup_counter == 255)
+ {
+ log_error ("p15: too many duplicate certificate ids\n");
+ err = gpg_error (GPG_ERR_TOO_MANY);
+ goto parse_error;
+ }
+ cdf->objid[objidlen] = ++app->app_local->cdf_dup_counter;
+ }
cdf->pathlen = objlen/2;
for (i=0; i < cdf->pathlen; i++, pp += 2, nn -= 2)
@@ -3664,6 +3705,7 @@ read_p15_info (app_t app)
log_assert (!app->app_local->certificate_info);
log_assert (!app->app_local->trusted_certificate_info);
log_assert (!app->app_local->useful_certificate_info);
+ app->app_local->cdf_dup_counter = 0;
err = read_ef_cdf (app, app->app_local->odf.certificates, 'c',
&app->app_local->certificate_info);
if (!err || gpg_err_code (err) == GPG_ERR_NO_DATA)