aboutsummaryrefslogtreecommitdiffstats
path: root/sm/certlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'sm/certlist.c')
-rw-r--r--sm/certlist.c101
1 files changed, 84 insertions, 17 deletions
diff --git a/sm/certlist.c b/sm/certlist.c
index 177f86725..ca61eb0d2 100644
--- a/sm/certlist.c
+++ b/sm/certlist.c
@@ -60,8 +60,18 @@ cert_usage_p (KsbaCert cert, int mode)
return map_ksba_err (err);
}
- if ((use & ((mode&1)? KSBA_KEYUSAGE_DIGITAL_SIGNATURE
- : KSBA_KEYUSAGE_KEY_ENCIPHERMENT)))
+ if (mode == 4)
+ {
+ if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN)))
+ return 0;
+ log_info ( _("certificate should have not been used certification\n"));
+ return GNUPG_Wrong_Key_Usage;
+ }
+
+ if ((use & ((mode&1)?
+ (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT):
+ (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
+ )
return 0;
log_info (mode==3? _("certificate should have not been used for encryption\n"):
mode==2? _("certificate should have not been used for signing\n"):
@@ -98,10 +108,35 @@ gpgsm_cert_use_decrypt_p (KsbaCert cert)
return cert_usage_p (cert, 3);
}
+int
+gpgsm_cert_use_cert_p (KsbaCert cert)
+{
+ return cert_usage_p (cert, 4);
+}
+
+
+static int
+same_subject_issuer (const char *subject, const char *issuer, KsbaCert cert)
+{
+ char *subject2 = ksba_cert_get_subject (cert, 0);
+ char *issuer2 = ksba_cert_get_subject (cert, 0);
+ int tmp;
+
+ tmp = (subject && subject2
+ && !strcmp (subject, subject2)
+ && issuer && issuer2
+ && !strcmp (issuer, issuer2));
+ xfree (subject2);
+ xfree (issuer2);
+ return tmp;
+}
+
+
+
/* add a certificate to a list of certificate and make sure that it is
a valid certificate */
int
-gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
+gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr)
{
int rc;
KEYDB_SEARCH_DESC desc;
@@ -117,6 +152,9 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
else
{
int wrong_usage = 0;
+ char *subject = NULL;
+ char *issuer = NULL;
+
get_next:
rc = keydb_search (kh, &desc, 1);
if (!rc)
@@ -127,32 +165,61 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
if (rc == GNUPG_Wrong_Key_Usage)
{
/* There might be another certificate with the
- correct usage, so we better try again */
- wrong_usage = rc;
- ksba_cert_release (cert);
- cert = NULL;
- goto get_next;
+ correct usage, so we try again */
+ if (!wrong_usage)
+ { /* save the first match */
+ wrong_usage = rc;
+ subject = ksba_cert_get_subject (cert, 0);
+ issuer = ksba_cert_get_subject (cert, 0);
+ ksba_cert_release (cert);
+ cert = NULL;
+ goto get_next;
+ }
+ else if (same_subject_issuer (subject, issuer, cert))
+ {
+ wrong_usage = rc;
+ ksba_cert_release (cert);
+ cert = NULL;
+ goto get_next;
+ }
+ else
+ wrong_usage = rc;
+
}
}
/* we want the error code from the first match in this case */
- if (wrong_usage)
+ if (rc && wrong_usage)
rc = wrong_usage;
-
+
if (!rc)
{
- /* Fixme: If we ever have two certifciates differing
- only in the key usage, we should only bail out here
- if the certificate differes just in the key usage.
- However we need to find some criteria to match the
- identities */
+ next_ambigious:
rc = keydb_search (kh, &desc, 1);
if (rc == -1)
rc = 0;
else if (!rc)
- rc = GNUPG_Ambiguous_Name;
+ {
+ KsbaCert cert2 = NULL;
+
+ /* We have to ignore ambigious names as long as
+ there only fault is a bad key usage */
+ if (!keydb_get_cert (kh, &cert2))
+ {
+ int tmp = (same_subject_issuer (subject, issuer, cert2)
+ && (gpgsm_cert_use_encrypt_p (cert2)
+ == GNUPG_Wrong_Key_Usage));
+ ksba_cert_release (cert2);
+ if (tmp)
+ goto next_ambigious;
+ }
+ rc = GNUPG_Ambiguous_Name;
+ }
}
+ xfree (subject);
+ xfree (issuer);
+
if (!rc)
- rc = gpgsm_validate_path (cert, NULL);
+ rc = gpgsm_validate_path (ctrl, cert, NULL);
if (!rc)
{
CERTLIST cl = xtrycalloc (1, sizeof *cl);