]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
gnutls_verify_stored_pubkey() and gnutls_store_pubkey() allow for alternative storage...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 10 Feb 2012 11:30:23 +0000 (12:30 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 10 Feb 2012 11:31:40 +0000 (12:31 +0100)
NEWS
doc/examples/ex-verify-ssh.c
lib/includes/gnutls/gnutls.h.in
lib/verify-ssh.c
src/cli-args.def
src/cli.c

diff --git a/NEWS b/NEWS
index 7dd91dfc2382a7fc8edf8b34e992d62b1fd9aada..f117fe64270488ee57a0f62bd6b4bb9fb8802cf2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,7 +7,7 @@ See the end for copying conditions.
 ** gnutls-cli: added the --ocsp option which will verify
 the peer's certificate with OCSP.
 
-** gnutls-cli: added the --ssh and if specified, gnutls-cli
+** gnutls-cli: added the --tofu and if specified, gnutls-cli
 will use an ssh-style authentication method.
 
 ** gnutls-cli: if no --x509cafile is provided a default is
index 4816a21c9105778c46122b5b784e05d9f689863a..dd983ce5fb941eb4e19d294c66faa015a856b4c0 100644 (file)
@@ -93,7 +93,7 @@ _ssh_verify_certificate_callback (gnutls_session_t session)
   gnutls_x509_crt_deinit (cert);
   
   /* service may be obtained alternatively using getservbyport() */
-  ret = gnutls_verify_stored_pubkey(NULL, hostname, "https", 
+  ret = gnutls_verify_stored_pubkey(NULL, NULL, hostname, "https", 
                                     GNUTLS_CRT_X509, &cert_list[0], 0);
   if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND)
     {
@@ -129,7 +129,8 @@ _ssh_verify_certificate_callback (gnutls_session_t session)
   /* user trusts the key -> store it */
   if (ret != 0)
     {
-      ret = gnutls_store_pubkey(NULL, hostname, "https", GNUTLS_CRT_X509, &cert_list[0], 
+      ret = gnutls_store_pubkey(NULL, NULL, hostname, "https", 
+                                GNUTLS_CRT_X509, &cert_list[0], 
                                 0, 0);
       if (ret < 0)
         fprintf(stderr, "gnutls_store_pubkey: %s\n", gnutls_strerror(ret));
index f5adbf5863d04c45c53795ec652558e05a3f9d58..183ac946bd22372cca71348e1497d336536866fd 100644 (file)
@@ -1656,14 +1656,37 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session);
   int gnutls_hex2bin (const char *hex_data, size_t hex_size,
                       void *bin_data, size_t * bin_size);
 
-  /* ssh style functions */
-  int gnutls_verify_stored_pubkey(const char* file, 
+  /* Trust on first use (or ssh like) functions */
+
+  /* stores the provided information to a database
+   */
+  typedef int (*gnutls_trust_db_store_func) (const char* db_name, 
+                                             const char* host,
+                                             const char* service,
+                                             time_t expiration,
+                                             const gnutls_datum_t* pubkey);
+  
+  /* searches for the provided host/service pair that match the
+   * provided public key in the database. */
+  typedef int (*gnutls_trust_db_retr_func) (const char* db_name, 
+                                            const char* host,
+                                            const char* service,
+                                            const gnutls_datum_t *pubkey);
+  
+  typedef struct {
+    gnutls_trust_db_store_func store;
+    gnutls_trust_db_retr_func retrieve;
+  } trust_storage_st;
+  
+  int gnutls_verify_stored_pubkey(const char* db_name, 
+                            const trust_storage_st * tdb,
                             const char* host,
                             const char* service,
                             gnutls_certificate_type_t cert_type,
                             const gnutls_datum_t * cert, unsigned int flags);
 
-  int gnutls_store_pubkey(const char* file, 
+  int gnutls_store_pubkey(const char* db_name,
+                    const trust_storage_st * tdb,
                     const char* host,
                     const char* service,
                     gnutls_certificate_type_t cert_type,
index 23ac819e62b4e449eff8548aae9d931a52ca0961..4d085a18d5bfcb10b45be8fa8efba56a2ea0e1d2 100644 (file)
@@ -41,12 +41,23 @@ static int pgp_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rp
 static int find_stored_pubkey(const char* file, 
                               const char* host, const char* service, 
                               const gnutls_datum_t* skey);
+static 
+int store_pubkey(const char* db_name, const char* host,
+                 const char* service, time_t expiration, const gnutls_datum_t* pubkey);
+
 static int find_config_file(char* file, size_t max_size);
 #define MAX_FILENAME 512
 
+static const trust_storage_st default_storage =
+{
+  store_pubkey,
+  find_stored_pubkey
+};
+
 /**
  * gnutls_verify_stored_pubkey:
- * @file: A file specifying the stored keys (use NULL for the default)
+ * @db_name: A file specifying the stored keys (use NULL for the default)
+ * @tdb: A database structure or NULL to use the default
  * @host: The peer's name
  * @service: non-NULL if this key is specific to a service (e.g. http)
  * @cert_type: The type of the certificate
@@ -57,6 +68,17 @@ static int find_config_file(char* file, size_t max_size);
  * a list of stored public keys.  The @service field if non-NULL should
  * be a port number.
  *
+ * The @tdb variable if non-null specifies a custom back-end for
+ * the storage and retrieval of entries. If it is NULL then the
+ * default file back-end will be used.
+ *
+ * Note that if the custom storage back-end is provided the
+ * retrieval function should return %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
+ * if the host/service pair is found but key doesn't match,
+ * %GNUTLS_E_NO_CERTIFICATE_FOUND if no such host/service with
+ * the given key is found, and 0 if it was found. The storage
+ * function should return 0 on success.
+ *
  * Returns: If no associated public key is found
  * then %GNUTLS_E_NO_CERTIFICATE_FOUND will be returned. If a key
  * is found but does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
@@ -66,7 +88,8 @@ static int find_config_file(char* file, size_t max_size);
  * Since: 3.0.0
  **/
 int
-gnutls_verify_stored_pubkey(const char* file, 
+gnutls_verify_stored_pubkey(const char* db_name, 
+                            const trust_storage_st *tdb,
                             const char* host,
                             const char* service,
                             gnutls_certificate_type_t cert_type,
@@ -79,14 +102,17 @@ char local_file[MAX_FILENAME];
   if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP)
     return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
 
-  if (file == NULL)
+  if (db_name == NULL && tdb == NULL)
     {
       ret = find_config_file(local_file, sizeof(local_file));
       if (ret < 0)
         return gnutls_assert_val(ret);
-      file = local_file;
+      db_name = local_file;
     }
 
+  if (tdb == NULL)
+    tdb = &default_storage;
+
   if (cert_type == GNUTLS_CRT_X509)
     ret = x509_crt_to_raw_pubkey(cert, &pubkey);
   else
@@ -105,10 +131,9 @@ char local_file[MAX_FILENAME];
       goto cleanup;
     }
 
-  ret = find_stored_pubkey(file, host, service, &pubkey);
+  ret = tdb->retrieve(db_name, host, service, &pubkey);
   if (ret < 0)
     return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
-  
 
 cleanup:
   gnutls_free(pubkey.data);
@@ -376,9 +401,32 @@ cleanup:
   return ret;
 }
 
+static 
+int store_pubkey(const char* db_name, const char* host,
+                 const char* service, time_t expiration, 
+                 const gnutls_datum_t* pubkey)
+{
+FILE* fd;
+
+  fd = fopen(db_name, "ab+");
+  if (fd == NULL)
+    return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
+
+  if (service == NULL) service = "*";
+  if (host == NULL) host = "*";
+
+  fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, 
+    pubkey->size, pubkey->data);
+  
+  fclose(fd);
+  
+  return 0;
+}
+
 /**
  * gnutls_store_pubkey:
- * @file: A file specifying the stored keys (use NULL for the default)
+ * @db_name: A file specifying the stored keys (use NULL for the default)
+ * @tdb: A database structure or NULL to use the default
  * @host: The peer's name
  * @service: non-NULL if this key is specific to a service (e.g. http)
  * @cert_type: The type of the certificate
@@ -390,7 +438,11 @@ cleanup:
  * the list of stored public keys. The key will be considered valid until 
  * the provided expiration time.
  *
- * Note that this function is not thread safe.
+ * The @tdb variable if non-null specifies a custom back-end for
+ * the storage and retrieval of entries. If it is NULL then the
+ * default file back-end will be used.
+ *
+ * Note that this function is not thread safe with the default backend.
  *
  * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
  *   negative error value.
@@ -398,7 +450,8 @@ cleanup:
  * Since: 3.0.0
  **/
 int
-gnutls_store_pubkey(const char* file, 
+gnutls_store_pubkey(const char* db_name, 
+                    const trust_storage_st* tdb,
                     const char* host,
                     const char* service,
                     gnutls_certificate_type_t cert_type,
@@ -414,7 +467,7 @@ char local_file[MAX_FILENAME];
   if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP)
     return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
   
-  if (file == NULL)
+  if (db_name == NULL && tdb == NULL)
     {
       ret = _gnutls_find_config_path(local_file, sizeof(local_file));
       if (ret < 0)
@@ -426,8 +479,11 @@ char local_file[MAX_FILENAME];
       ret = find_config_file(local_file, sizeof(local_file));
       if (ret < 0)
         return gnutls_assert_val(ret);
-      file = local_file;
+      db_name = local_file;
     }
+
+  if (tdb == NULL)
+    tdb = &default_storage;
     
   if (cert_type == GNUTLS_CRT_X509)
     ret = x509_crt_to_raw_pubkey(cert, &pubkey);
@@ -446,20 +502,9 @@ char local_file[MAX_FILENAME];
       goto cleanup;
     }
 
-  _gnutls_debug_log("Configuration file: %s\n", file);
+  _gnutls_debug_log("Configuration file: %s\n", db_name);
 
-  fd = fopen(file, "ab+");
-  if (fd == NULL)
-    {
-      ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
-      goto cleanup;
-    }
-
-  if (service == NULL) service = "*";
-  if (host == NULL) host = "*";
-
-  fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, 
-    pubkey.size, pubkey.data);
+  tdb->store(db_name, host, service, expiration, &pubkey);
 
   ret = 0;
 
index 7f18026315510f1ee0b12156a9cb10042fdc52b5..c0d29a6b9a45ca248f2d18cdc7073d3f5bbd74dc 100644 (file)
@@ -37,11 +37,11 @@ flag = {
 };
 
 flag = {
-    name      = ssh;
-    descrip   = "Enable SSH-style authentication";
+    name      = tofu;
+    descrip   = "Enable trust on first use (SSH-style) authentication";
     disabled;
     disable   = "no";
-    doc       = "This option will, in addition to certificate authentication, perform authentication based on stored public keys.";
+    doc       = "This option will, in addition to certificate authentication, perform authentication based on previously seen public keys.";
 };
 
 flag = {
index 9eb2a6506c49712fc25320528f0499df6e57e476..c3194c605571f728e23100fbd3165ede01a09c7d 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -475,7 +475,7 @@ cert_verify_callback (gnutls_session_t session)
 {
   int rc;
   unsigned int status = 0;
-  int ssh = ENABLED_OPT(SSH);
+  int ssh = ENABLED_OPT(TOFU);
   const char* txt_service;
 
   if (!x509_cafile && !pgp_keyring)
@@ -515,8 +515,8 @@ cert_verify_callback (gnutls_session_t session)
           return -1;
         }
       
-      rc = gnutls_verify_stored_pubkey(NULL, hostname, txt_service, GNUTLS_CRT_X509,
-                                       cert, 0);
+      rc = gnutls_verify_stored_pubkey(NULL, NULL, hostname, txt_service, 
+                                       GNUTLS_CRT_X509, cert, 0);
       if (rc == GNUTLS_E_NO_CERTIFICATE_FOUND)
         {
           print_cert_info_compact(session);
@@ -548,8 +548,8 @@ cert_verify_callback (gnutls_session_t session)
       
       if (rc != 0)
         {
-          rc = gnutls_store_pubkey(NULL, hostname, txt_service, GNUTLS_CRT_X509
-                                   cert, 0, 0);
+          rc = gnutls_store_pubkey(NULL, NULL, hostname, txt_service
+                                   GNUTLS_CRT_X509, cert, 0, 0);
           if (rc < 0)
             fprintf(stderr, "Could not store key: %s\n", gnutls_strerror(rc));
         }