* import.c (gpgsm_import): Just do a basic cert check before
authorWerner Koch <wk@gnupg.org>
Tue, 15 Jan 2002 13:02:47 +0000 (13:02 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 15 Jan 2002 13:02:47 +0000 (13:02 +0000)
storing it.
* certpath.c (gpgsm_basic_cert_check): New.

* keydb.c (keydb_store_cert): New.
* import.c (store_cert): Removed and change all caller to use
the new function.
* verify.c (store_cert): Ditto.

* certlist.c (gpgsm_add_to_certlist): Validate the path

* certpath.c (gpgsm_validate_path): Check the trust list.
* call-agent.c (gpgsm_agent_istrusted): New.

sm/ChangeLog
sm/call-agent.c
sm/call-dirmngr.c
sm/certchain.c
sm/certlist.c
sm/certpath.c
sm/gpgsm.h
sm/import.c
sm/keydb.c
sm/keydb.h
sm/verify.c

index 8642333..5ea6e0c 100644 (file)
@@ -1,3 +1,19 @@
+2002-01-15  Werner Koch  <wk@gnupg.org>
+
+       * import.c (gpgsm_import): Just do a basic cert check before
+       storing it.
+       * certpath.c (gpgsm_basic_cert_check): New.
+
+       * keydb.c (keydb_store_cert): New.
+       * import.c (store_cert): Removed and change all caller to use
+       the new function.
+       * verify.c (store_cert): Ditto.
+
+       * certlist.c (gpgsm_add_to_certlist): Validate the path
+
+       * certpath.c (gpgsm_validate_path): Check the trust list.
+       * call-agent.c (gpgsm_agent_istrusted): New.
+
 2002-01-14  Werner Koch  <wk@gnupg.org>
 
        * call-dirmngr.c (inq_certificate): Changed for new interface semantic.
index 87b1024..54c2d4e 100644 (file)
@@ -182,7 +182,8 @@ start_agent (void)
       return seterr (Not_Implemented);
     }
 
-  log_debug ("connection to agent established\n");
+  if (DBG_AGENT)
+    log_debug ("connection to agent established\n");
   return 0;
 }
 
@@ -400,5 +401,31 @@ gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
   return 0;
 }
 
+\f
+/* Ask the agent whether the certificate is in the list of trusted
+   keys */
+int
+gpgsm_agent_istrusted (KsbaCert cert)
+{
+  int rc;
+  char *fpr;
+  char line[ASSUAN_LINELENGTH];
 
+  rc = start_agent ();
+  if (rc)
+    return rc;
 
+  fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
+  if (!fpr)
+    {
+      log_error ("error getting the fingerprint\n");
+      return seterr (General_Error);
+    }
+
+  snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
+  line[DIM(line)-1] = 0;
+  xfree (fpr);
+
+  rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL);
+  return map_assuan_err (rc);
+}
index 3a12534..2323e76 100644 (file)
@@ -113,7 +113,8 @@ start_dirmngr (void)
       return seterr (Not_Implemented);
     }
 
-  log_debug ("connection to dirmngr established\n");
+  if (DBG_AGENT)
+    log_debug ("connection to dirmngr established\n");
   return 0;
 }
 
@@ -206,3 +207,5 @@ gpgsm_dirmngr_isvalid (KsbaCert cert)
   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, &parm);
   return map_assuan_err (rc);
 }
+
+
index 69a9c55..e8c594e 100644 (file)
@@ -50,10 +50,13 @@ gpgsm_validate_path (KsbaCert cert)
       goto leave;
     }
 
-  gpgsm_dump_cert ("subject", cert);
+  if (DBG_X509)
+    gpgsm_dump_cert ("subject", cert);
 
   subject_cert = cert;
 
+  /* FIXME: We need to check that none of the certs didexpire */
+
   for (;;)
     {
       xfree (issuer);
@@ -100,11 +103,33 @@ gpgsm_validate_path (KsbaCert cert)
         {
           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
             {
-              log_debug ("selfsigned certificate has a BAD signatures\n");
+              log_error ("selfsigned certificate has a BAD signatures\n");
               rc = depth? GNUPG_Bad_Certificate_Path : GNUPG_Bad_Certificate;
               goto leave;
             }
-          log_debug ("selfsigned certificate is good\n");
+          rc = gpgsm_agent_istrusted (subject_cert);
+          if (!rc)
+            ;
+          else if (rc == GNUPG_Not_Trusted)
+            {
+              char *fpr = gpgsm_get_fingerprint_string (subject_cert,
+                                                        GCRY_MD_SHA1);
+              log_error (_("root certificate is not marked trusted\n"));
+              log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
+              xfree (fpr);
+              /* fixme: print a note while we have not yet the code to
+                 ask whether the cert should be netered into the trust
+                 list */
+              gpgsm_dump_cert ("issuer", subject_cert);
+              log_info ("after checking the fingerprint, you may want "
+                        "to enter it into \"~/.gnupg-test/trustlist.txt\"\n");
+            }
+          else 
+            {
+              log_error (_("checking the trust list failed: %s\n"),
+                         gnupg_strerror (rc));
+            }
+          
           break;  /* okay, a self-signed certicate is an end-point */
         }
       
@@ -116,7 +141,7 @@ gpgsm_validate_path (KsbaCert cert)
       rc = keydb_search_subject (kh, issuer);
       if (rc)
         {
-          log_debug ("failed to find issuer's certificate: rc=%d\n", rc);
+          log_error ("failed to find issuer's certificate: rc=%d\n", rc);
           rc = GNUPG_Missing_Certificate;
           goto leave;
         }
@@ -125,21 +150,25 @@ gpgsm_validate_path (KsbaCert cert)
       rc = keydb_get_cert (kh, &issuer_cert);
       if (rc)
         {
-          log_debug ("failed to get cert: rc=%d\n", rc);
+          log_error ("failed to get cert: rc=%d\n", rc);
           rc = GNUPG_General_Error;
           goto leave;
         }
 
-      log_debug ("got issuer's certificate:\n");
-      gpgsm_dump_cert ("issuer", issuer_cert);
+      if (DBG_X509)
+        {
+          log_debug ("got issuer's certificate:\n");
+          gpgsm_dump_cert ("issuer", issuer_cert);
+        }
 
       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
         {
-          log_debug ("certificate has a BAD signatures\n");
+          log_error ("certificate has a BAD signatures\n");
           rc = GNUPG_Bad_Certificate_Path;
           goto leave;
         }
-      log_debug ("certificate is good\n");
+      if (opt.verbose)
+        log_info ("certificate is good\n");
       
       keydb_search_reset (kh);
       subject_cert = issuer_cert;
@@ -159,3 +188,81 @@ gpgsm_validate_path (KsbaCert cert)
   return rc;
 }
 
+
+/* Check that the given certificate is valid but DO NOT check any
+   constraints.  We assume that the issuers certificate is already in
+   the DB and that this one is valid; which it should be because it
+   has been checked using this function. */
+int
+gpgsm_basic_cert_check (KsbaCert cert)
+{
+  int rc = 0;
+  char *issuer = NULL;
+  char *subject = NULL;
+  KEYDB_HANDLE kh = keydb_new (0);
+  KsbaCert issuer_cert = NULL;
+
+  if (!kh)
+    {
+      log_error (_("failed to allocated keyDB handle\n"));
+      rc = GNUPG_General_Error;
+      goto leave;
+    }
+
+  issuer = ksba_cert_get_issuer (cert, 0);
+  subject = ksba_cert_get_subject (cert, 0);
+  if (!issuer)
+    {
+      if (DBG_X509)
+        log_debug ("ERROR: issuer missing\n");
+      rc = GNUPG_Bad_Certificate;
+      goto leave;
+    }
+
+  if (subject && !strcmp (issuer, subject))
+    {
+      if (gpgsm_check_cert_sig (cert, cert) )
+        {
+          log_error ("selfsigned certificate has a BAD signatures\n");
+          rc = GNUPG_Bad_Certificate;
+          goto leave;
+        }
+    }
+  else
+    {
+      /* find the next cert up the tree */
+      keydb_search_reset (kh);
+      rc = keydb_search_subject (kh, issuer);
+      if (rc)
+        {
+          log_error ("failed to find issuer's certificate: rc=%d\n", rc);
+          rc = GNUPG_Missing_Certificate;
+          goto leave;
+        }
+      
+      ksba_cert_release (issuer_cert); issuer_cert = NULL;
+      rc = keydb_get_cert (kh, &issuer_cert);
+      if (rc)
+        {
+          log_error ("failed to get cert: rc=%d\n", rc);
+          rc = GNUPG_General_Error;
+          goto leave;
+        }
+
+      if (gpgsm_check_cert_sig (issuer_cert, cert) )
+        {
+          log_error ("certificate has a BAD signatures\n");
+          rc = GNUPG_Bad_Certificate;
+          goto leave;
+        }
+      if (opt.verbose)
+        log_info ("certificate is good\n");
+    }
+
+ leave:
+  xfree (issuer);
+  keydb_release (kh); 
+  ksba_cert_release (issuer_cert);
+  return rc;
+}
+
index 0035d52..c5b8c86 100644 (file)
@@ -33,7 +33,8 @@
 #include "gpgsm.h"
 #include "keydb.h"
 
-
+/* 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)
 {
@@ -55,6 +56,8 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
           if (!rc)
             rc = keydb_get_cert (kh, &cert);
           if (!rc)
+            rc = gpgsm_validate_path (cert);
+          if (!rc)
             {
               CERTLIST cl = xtrycalloc (1, sizeof *cl);
               if (!cl)
@@ -87,7 +90,8 @@ gpgsm_release_certlist (CERTLIST list)
 }
 
 \f
-/* Like gpgsm_add_to_certlist, but lookonly for one certificate */
+/* Like gpgsm_add_to_certlist, but look only for one certificate.  No
+   path validation is done */
 int
 gpgsm_find_cert (const char *name, KsbaCert *r_cert)
 {
index 69a9c55..e8c594e 100644 (file)
@@ -50,10 +50,13 @@ gpgsm_validate_path (KsbaCert cert)
       goto leave;
     }
 
-  gpgsm_dump_cert ("subject", cert);
+  if (DBG_X509)
+    gpgsm_dump_cert ("subject", cert);
 
   subject_cert = cert;
 
+  /* FIXME: We need to check that none of the certs didexpire */
+
   for (;;)
     {
       xfree (issuer);
@@ -100,11 +103,33 @@ gpgsm_validate_path (KsbaCert cert)
         {
           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
             {
-              log_debug ("selfsigned certificate has a BAD signatures\n");
+              log_error ("selfsigned certificate has a BAD signatures\n");
               rc = depth? GNUPG_Bad_Certificate_Path : GNUPG_Bad_Certificate;
               goto leave;
             }
-          log_debug ("selfsigned certificate is good\n");
+          rc = gpgsm_agent_istrusted (subject_cert);
+          if (!rc)
+            ;
+          else if (rc == GNUPG_Not_Trusted)
+            {
+              char *fpr = gpgsm_get_fingerprint_string (subject_cert,
+                                                        GCRY_MD_SHA1);
+              log_error (_("root certificate is not marked trusted\n"));
+              log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
+              xfree (fpr);
+              /* fixme: print a note while we have not yet the code to
+                 ask whether the cert should be netered into the trust
+                 list */
+              gpgsm_dump_cert ("issuer", subject_cert);
+              log_info ("after checking the fingerprint, you may want "
+                        "to enter it into \"~/.gnupg-test/trustlist.txt\"\n");
+            }
+          else 
+            {
+              log_error (_("checking the trust list failed: %s\n"),
+                         gnupg_strerror (rc));
+            }
+          
           break;  /* okay, a self-signed certicate is an end-point */
         }
       
@@ -116,7 +141,7 @@ gpgsm_validate_path (KsbaCert cert)
       rc = keydb_search_subject (kh, issuer);
       if (rc)
         {
-          log_debug ("failed to find issuer's certificate: rc=%d\n", rc);
+          log_error ("failed to find issuer's certificate: rc=%d\n", rc);
           rc = GNUPG_Missing_Certificate;
           goto leave;
         }
@@ -125,21 +150,25 @@ gpgsm_validate_path (KsbaCert cert)
       rc = keydb_get_cert (kh, &issuer_cert);
       if (rc)
         {
-          log_debug ("failed to get cert: rc=%d\n", rc);
+          log_error ("failed to get cert: rc=%d\n", rc);
           rc = GNUPG_General_Error;
           goto leave;
         }
 
-      log_debug ("got issuer's certificate:\n");
-      gpgsm_dump_cert ("issuer", issuer_cert);
+      if (DBG_X509)
+        {
+          log_debug ("got issuer's certificate:\n");
+          gpgsm_dump_cert ("issuer", issuer_cert);
+        }
 
       if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
         {
-          log_debug ("certificate has a BAD signatures\n");
+          log_error ("certificate has a BAD signatures\n");
           rc = GNUPG_Bad_Certificate_Path;
           goto leave;
         }
-      log_debug ("certificate is good\n");
+      if (opt.verbose)
+        log_info ("certificate is good\n");
       
       keydb_search_reset (kh);
       subject_cert = issuer_cert;
@@ -159,3 +188,81 @@ gpgsm_validate_path (KsbaCert cert)
   return rc;
 }
 
+
+/* Check that the given certificate is valid but DO NOT check any
+   constraints.  We assume that the issuers certificate is already in
+   the DB and that this one is valid; which it should be because it
+   has been checked using this function. */
+int
+gpgsm_basic_cert_check (KsbaCert cert)
+{
+  int rc = 0;
+  char *issuer = NULL;
+  char *subject = NULL;
+  KEYDB_HANDLE kh = keydb_new (0);
+  KsbaCert issuer_cert = NULL;
+
+  if (!kh)
+    {
+      log_error (_("failed to allocated keyDB handle\n"));
+      rc = GNUPG_General_Error;
+      goto leave;
+    }
+
+  issuer = ksba_cert_get_issuer (cert, 0);
+  subject = ksba_cert_get_subject (cert, 0);
+  if (!issuer)
+    {
+      if (DBG_X509)
+        log_debug ("ERROR: issuer missing\n");
+      rc = GNUPG_Bad_Certificate;
+      goto leave;
+    }
+
+  if (subject && !strcmp (issuer, subject))
+    {
+      if (gpgsm_check_cert_sig (cert, cert) )
+        {
+          log_error ("selfsigned certificate has a BAD signatures\n");
+          rc = GNUPG_Bad_Certificate;
+          goto leave;
+        }
+    }
+  else
+    {
+      /* find the next cert up the tree */
+      keydb_search_reset (kh);
+      rc = keydb_search_subject (kh, issuer);
+      if (rc)
+        {
+          log_error ("failed to find issuer's certificate: rc=%d\n", rc);
+          rc = GNUPG_Missing_Certificate;
+          goto leave;
+        }
+      
+      ksba_cert_release (issuer_cert); issuer_cert = NULL;
+      rc = keydb_get_cert (kh, &issuer_cert);
+      if (rc)
+        {
+          log_error ("failed to get cert: rc=%d\n", rc);
+          rc = GNUPG_General_Error;
+          goto leave;
+        }
+
+      if (gpgsm_check_cert_sig (issuer_cert, cert) )
+        {
+          log_error ("certificate has a BAD signatures\n");
+          rc = GNUPG_Bad_Certificate;
+          goto leave;
+        }
+      if (opt.verbose)
+        log_info ("certificate is good\n");
+    }
+
+ leave:
+  xfree (issuer);
+  keydb_release (kh); 
+  ksba_cert_release (issuer_cert);
+  return rc;
+}
+
index 481bd2b..43755a9 100644 (file)
@@ -158,6 +158,7 @@ int gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo,
 
 /*-- certpath.c --*/
 int gpgsm_validate_path (KsbaCert cert);
+int gpgsm_basic_cert_check (KsbaCert cert);
 
 /*-- cetlist.c --*/
 int gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr);
@@ -195,6 +196,7 @@ int gpgsm_agent_pkdecrypt (const char *keygrip,
                            KsbaConstSexp  ciphertext, 
                            char **r_buf, size_t *r_buflen);
 int gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey);
+int gpgsm_agent_istrusted (KsbaCert cert);
 
 /*-- call-dirmngr.c --*/
 int gpgsm_dirmngr_isvalid (KsbaCert cert);
index 0e9618c..02db655 100644 (file)
 #include "i18n.h"
 
 
-static void
-store_cert (KsbaCert cert)
-{
-  KEYDB_HANDLE kh;
-  int rc;
-
-  kh = keydb_new (0);
-  if (!kh)
-    {
-      log_error (_("failed to allocated keyDB handle\n"));
-      return;
-    }
-  rc = keydb_locate_writable (kh, 0);
-  if (rc)
-      log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
-
-  rc = keydb_insert_cert (kh, cert);
-  if (rc)
-    {
-      log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
-    }
-  keydb_release (kh);               
-}
-
-
-
 \f
 int
 gpgsm_import (CTRL ctrl, int in_fd)
@@ -100,8 +74,8 @@ gpgsm_import (CTRL ctrl, int in_fd)
       goto leave;
     }
 
-  if ( !gpgsm_validate_path (cert) )
-    store_cert (cert);
+  if ( !gpgsm_basic_cert_check (cert) )
+    keydb_store_cert (cert);
 
  leave:
   ksba_cert_release (cert);
index 17074e8..34e7adc 100644 (file)
@@ -1143,3 +1143,58 @@ keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc)
   return 0;
 }
 
+\f
+/* Store the certificate in the key Db but make sure that it does not
+   already exists.  We do this simply by comparing the fingerprint */
+int
+keydb_store_cert (KsbaCert cert)
+{
+  KEYDB_HANDLE kh;
+  int rc;
+  unsigned char fpr[20];
+
+  if (!gpgsm_get_fingerprint (cert, 0, fpr, NULL))
+    {
+      log_error (_("failed to get the fingerprint\n"));
+      return GNUPG_General_Error;
+    }
+
+  kh = keydb_new (0);
+  if (!kh)
+    {
+      log_error (_("failed to allocate keyDB handle\n"));
+      return GNUPG_Out_Of_Core;
+    }
+
+  rc = keydb_search_fpr (kh, fpr);
+  if (rc != -1)
+    {
+      keydb_release (kh);
+      if (!rc)
+        return 0; /* okay */
+      log_error (_("problem looking for existing certificate: %s\n"),
+                 gnupg_strerror (rc));
+      return rc;
+    }
+
+  rc = keydb_locate_writable (kh, 0);
+  if (rc)
+    {
+      log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
+      keydb_release (kh);
+      return rc;
+    }
+
+  rc = keydb_insert_cert (kh, cert);
+  if (rc)
+    {
+      log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
+      keydb_release (kh);
+      return rc;
+    }
+  keydb_release (kh);               
+  return 0;
+}
+
+
+
index 4fdda9d..9032c52 100644 (file)
@@ -62,6 +62,8 @@ int keydb_search_subject (KEYDB_HANDLE hd, const char *issuer);
 
 int keydb_classify_name (const char *name, KEYDB_SEARCH_DESC *desc);
 
+int keydb_store_cert (KsbaCert cert);
+
 
 #endif /*GNUPG_KEYDB_H*/
 
index 350e4f4..3dd85c0 100644 (file)
@@ -57,32 +57,6 @@ strtimestamp (time_t atime)
 
 
 
-/* fixme: duplicated from import.c */
-static void
-store_cert (KsbaCert cert)
-{
-  KEYDB_HANDLE kh;
-  int rc;
-
-  kh = keydb_new (0);
-  if (!kh)
-    {
-      log_error (_("failed to allocated keyDB handle\n"));
-      return;
-    }
-  rc = keydb_locate_writable (kh, 0);
-  if (rc)
-      log_error (_("error finding writable keyDB: %s\n"), gnupg_strerror (rc));
-
-  rc = keydb_insert_cert (kh, cert);
-  if (rc)
-    {
-      log_error (_("error storing certificate: %s\n"), gnupg_strerror (rc));
-    }
-  keydb_release (kh);               
-}
-
-
 /* Hash the data for a detached signature */
 static void
 hash_data (int fd, GCRY_MD_HD md)
@@ -265,10 +239,11 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
 
   for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
     {
-      log_debug ("storing certifcate %d\n", i);
-      /* Fixme: we should mark the stored certificates as temporary
-         and put them in a cache first */
-      store_cert (cert);
+      /* Fixme: it might be better to check the validity of the
+         certificate first before entering it into the DB.  This way
+         we would avoid cluttering the DB with invalid
+         certificates. */
+      keydb_store_cert (cert);
       ksba_cert_release (cert);
     }