summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2012-02-10 12:30:23 +0100
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2012-02-10 12:31:40 +0100
commit5196d292991628627e4ef7cc977b84f1273fe233 (patch)
treea96dee61a78ee9c160083b6a152574101ca0f20e
parent38f9998e9aaee0e8a486cad3f715fad4558a88df (diff)
downloadgnutls-5196d292991628627e4ef7cc977b84f1273fe233.tar.gz
gnutls_verify_stored_pubkey() and gnutls_store_pubkey() allow for alternative storage back-end.
-rw-r--r--NEWS2
-rw-r--r--doc/examples/ex-verify-ssh.c5
-rw-r--r--lib/includes/gnutls/gnutls.h.in29
-rw-r--r--lib/verify-ssh.c93
-rw-r--r--src/cli-args.def6
-rw-r--r--src/cli.c10
6 files changed, 107 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index 7dd91dfc23..f117fe6427 100644
--- 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
diff --git a/doc/examples/ex-verify-ssh.c b/doc/examples/ex-verify-ssh.c
index 4816a21c91..dd983ce5fb 100644
--- a/doc/examples/ex-verify-ssh.c
+++ b/doc/examples/ex-verify-ssh.c
@@ -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));
diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in
index f5adbf5863..183ac946bd 100644
--- a/lib/includes/gnutls/gnutls.h.in
+++ b/lib/includes/gnutls/gnutls.h.in
@@ -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,
diff --git a/lib/verify-ssh.c b/lib/verify-ssh.c
index 23ac819e62..4d085a18d5 100644
--- a/lib/verify-ssh.c
+++ b/lib/verify-ssh.c
@@ -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;
diff --git a/src/cli-args.def b/src/cli-args.def
index 7f18026315..c0d29a6b9a 100644
--- a/src/cli-args.def
+++ b/src/cli-args.def
@@ -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 = {
diff --git a/src/cli.c b/src/cli.c
index 9eb2a6506c..c3194c6055 100644
--- 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));
}