* gpgsm.c (main): New option --log-file.
[gnupg.git] / sm / certlist.c
index c5b8c86..177f867 100644 (file)
 
 #include "gpgsm.h"
 #include "keydb.h"
+#include "i18n.h"
+/* Return 0 if the cert is usable for encryption.  A MODE of 0 checks
+   for signing a MODE of 1 checks for encryption, a MODE of 2 checks
+   for verification and a MODE of 3 for decryption (just for
+   debugging) */
+static int
+cert_usage_p (KsbaCert cert, int mode)
+{
+  KsbaError err;
+  unsigned int use;
+
+  err = ksba_cert_get_key_usage (cert, &use);
+  if (err == KSBA_No_Data)
+    {
+      if (opt.verbose && mode < 2)
+        log_info (mode? 
+                  _("no key usage specified - accepted for encryption\n"):
+                  _("no key usage specified - accepted for signing\n"));
+      return 0;
+    }
+  if (err)
+    { 
+      log_error (_("error getting key usage information: %s\n"),
+                 ksba_strerror (err));
+      return map_ksba_err (err);
+    } 
+
+  if ((use & ((mode&1)? KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+              : KSBA_KEYUSAGE_KEY_ENCIPHERMENT)))
+    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"):
+            mode==1? _("certificate is not usable for encryption\n"):
+                     _("certificate is not usable for signing\n"));
+  return GNUPG_Wrong_Key_Usage;
+}
+
+
+/* Return 0 if the cert is usable for signing */
+int
+gpgsm_cert_use_sign_p (KsbaCert cert)
+{
+  return cert_usage_p (cert, 0);
+}
+
+
+/* Return 0 if the cert is usable for encryption */
+int
+gpgsm_cert_use_encrypt_p (KsbaCert cert)
+{
+  return cert_usage_p (cert, 1);
+}
+
+int
+gpgsm_cert_use_verify_p (KsbaCert cert)
+{
+  return cert_usage_p (cert, 2);
+}
+
+int
+gpgsm_cert_use_decrypt_p (KsbaCert cert)
+{
+  return cert_usage_p (cert, 3);
+}
 
 /* add a certificate to a list of certificate and make sure that it is
    a valid certificate */
@@ -43,7 +108,6 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
   KEYDB_HANDLE kh = NULL;
   KsbaCert cert = NULL;
 
-  /* fixme: check that we identify excactly one cert with the name */
   rc = keydb_classify_name (name, &desc);
   if (!rc)
     {
@@ -52,11 +116,43 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
         rc = GNUPG_Out_Of_Core;
       else
         {
+          int wrong_usage = 0;
+        get_next:
           rc = keydb_search (kh, &desc, 1);
           if (!rc)
             rc = keydb_get_cert (kh, &cert);
           if (!rc)
-            rc = gpgsm_validate_path (cert);
+            {
+              rc = gpgsm_cert_use_encrypt_p (cert);
+              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;
+                }
+            }
+          /* we want the error code from the first match in this case */
+          if (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 */
+              rc = keydb_search (kh, &desc, 1);
+              if (rc == -1)
+                rc = 0;
+              else if (!rc)
+                rc = GNUPG_Ambiguous_Name;
+            }
+          if (!rc)
+            rc = gpgsm_validate_path (cert, NULL);
           if (!rc)
             {
               CERTLIST cl = xtrycalloc (1, sizeof *cl);
@@ -100,7 +196,6 @@ gpgsm_find_cert (const char *name, KsbaCert *r_cert)
   KEYDB_HANDLE kh = NULL;
 
   *r_cert = NULL;
-  /* fixme: check that we identify excactly one cert with the name */
   rc = keydb_classify_name (name, &desc);
   if (!rc)
     {
@@ -112,9 +207,23 @@ gpgsm_find_cert (const char *name, KsbaCert *r_cert)
           rc = keydb_search (kh, &desc, 1);
           if (!rc)
             rc = keydb_get_cert (kh, r_cert);
+          if (!rc)
+            {
+              rc = keydb_search (kh, &desc, 1);
+              if (rc == -1)
+                rc = 0;
+              else 
+                {
+                  if (!rc)
+                    rc = GNUPG_Ambiguous_Name;
+                  ksba_cert_release (*r_cert);
+                  *r_cert = NULL;
+                }
+            }
         }
     }
   
   keydb_release (kh);
   return rc == -1? GNUPG_No_Public_Key: rc;
 }
+