aboutsummaryrefslogtreecommitdiffstats
path: root/sm/certlist.c
diff options
context:
space:
mode:
authorRainer Perske <[email protected]>2017-10-24 15:29:04 +0000
committerWerner Koch <[email protected]>2017-10-24 15:29:04 +0000
commit1067403c8a7fb51decf30059e46901b5ee9f5b37 (patch)
tree868fcb0d7aebbf3ad7dc4e4058bf7333dcadcc02 /sm/certlist.c
parentgpgconf: Ignore non-installed components with --apply-profile. (diff)
downloadgnupg-1067403c8a7fb51decf30059e46901b5ee9f5b37.tar.gz
gnupg-1067403c8a7fb51decf30059e46901b5ee9f5b37.zip
sm: Do not expect X.509 keyids to be unique
* sm/certlist.c (gpgsm_find_cert): Add arg allow_ambiguous and use it. * sm/call-dirmngr.c (inq_certificate): Pass true to ALLOW_AMBIGUOUS (run_command_inq_cb): Ditto. * sm/gpgsm.c (main): Pass false. * sm/server.c (cmd_passwd): Pass false. -- As described in my report T1644, it is possible that multiple certificates exist with the same Distinguished Name and the same key. In this case, verifying S/MIME signatures and other actions fail with "certificate not found: Ambiguous name". For details see the bug report. To circumvent the problem, I am patching GnuPG since 2014 so that in this case the newest of the ambiguous certificates is used. This is not an ultimate solution of the problem: You should try every certificate with the same DN until verification succeeds or until all certificates fail, and if multiple certificates of a chain are ambiguous you even have to check every combination. You may even consider checking the keyUsage attributes of the ambiguous certificates to reduce the number of combinations. But in the existing case of the certificates in the German Research Network (DFN) PKI where the newest one is the valid one and all ambiguous certificates have the same keyUsage attributes, this patch has proven to be sufficient over the last three years. With every GnuPG update, I have adapted the patch, luckily I never needed to change anything except line numbers. GnuPG-bug-id: 1644 ChangeLog log written by wk, comment taken from mail. Signed-off line was missing in the plain diff. However the mail with the patch and the DCO posted as reply to that mail were both signed. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'sm/certlist.c')
-rw-r--r--sm/certlist.c40
1 files changed, 39 insertions, 1 deletions
diff --git a/sm/certlist.c b/sm/certlist.c
index 39ab03c5d..c9e275e9d 100644
--- a/sm/certlist.c
+++ b/sm/certlist.c
@@ -489,7 +489,8 @@ gpgsm_release_certlist (certlist_t list)
subjectKeyIdentifier. */
int
gpgsm_find_cert (ctrl_t ctrl,
- const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert)
+ const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
+ int allow_ambiguous)
{
int rc;
KEYDB_SEARCH_DESC desc;
@@ -537,6 +538,16 @@ gpgsm_find_cert (ctrl_t ctrl,
won't lead to ambiguous names. */
if (!rc && !keyid)
{
+ ksba_isotime_t notbefore = "";
+ const unsigned char *image = NULL;
+ size_t length = 0;
+ if (allow_ambiguous)
+ {
+ /* We want to return the newest certificate */
+ if (ksba_cert_get_validity (*r_cert, 0, notbefore))
+ *notbefore = '\0';
+ image = ksba_cert_get_image (*r_cert, &length);
+ }
next_ambiguous:
rc = keydb_search (ctrl, kh, &desc, 1);
if (rc == -1)
@@ -546,6 +557,10 @@ gpgsm_find_cert (ctrl_t ctrl,
if (!rc)
{
ksba_cert_t cert2 = NULL;
+ ksba_isotime_t notbefore2 = "";
+ const unsigned char *image2 = NULL;
+ size_t length2 = 0;
+ int cmp = 0;
if (!keydb_get_cert (kh, &cert2))
{
@@ -554,6 +569,29 @@ gpgsm_find_cert (ctrl_t ctrl,
ksba_cert_release (cert2);
goto next_ambiguous;
}
+ if (allow_ambiguous)
+ {
+ if (ksba_cert_get_validity (cert2, 0, notbefore2))
+ *notbefore2 = '\0';
+ image2 = ksba_cert_get_image (cert2, &length2);
+ cmp = strcmp (notbefore, notbefore2);
+ /* use certificate image bits as last resort for stable ordering */
+ if (!cmp)
+ cmp = memcmp (image, image2, length < length2 ? length : length2);
+ if (!cmp)
+ cmp = length < length2 ? -1 : length > length2 ? 1 : 0;
+ if (cmp < 0)
+ {
+ ksba_cert_release (*r_cert);
+ *r_cert = cert2;
+ strcpy (notbefore, notbefore2);
+ image = image2;
+ length = length2;
+ }
+ else
+ ksba_cert_release (cert2);
+ goto next_ambiguous;
+ }
ksba_cert_release (cert2);
}
rc = gpg_error (GPG_ERR_AMBIGUOUS_NAME);