From: Nikos Mavrogiannopoulos Date: Sat, 18 Feb 2012 09:57:06 +0000 (+0100) Subject: The public key storage backend was made extendable. X-Git-Tag: gnutls_3_0_13~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=4f07c19f3638d4917cf20b995eae41d3d2dbd65c;p=thirdparty%2Fgnutls.git The public key storage backend was made extendable. Added self test for the pubkey trust default backend. --- diff --git a/.gitignore b/.gitignore index 66c80cb1e4..e4758e8e3d 100644 --- a/.gitignore +++ b/.gitignore @@ -590,3 +590,4 @@ tests/mini-loss-time tests/dtls/dtls-stress doc/gnutls.epub doc/gnutls.xml +tests/mini-tdb diff --git a/NEWS b/NEWS index 51675e25af..0527110d8b 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,11 @@ gnutls_priority_sign_list: Added gnutls_priority_protocol_list: Added gnutls_priority_compression_list: Added gnutls_priority_ecc_curve_list: Added +gnutls_tdb_init: Added +gnutls_tdb_set_store_func: Added +gnutls_tdb_set_store_commitment_func: Added +gnutls_tdb_set_verify_func: Added +gnutls_tdb_deinit: Added * Version 3.0.12 (released 2012-01-20) diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi index 56bc7f7043..30fb7caa30 100644 --- a/doc/cha-cert-auth.texi +++ b/doc/cha-cert-auth.texi @@ -310,25 +310,9 @@ not yet active. The storage and verification functions may be used with the default text file based back-end, or another back-end may be specified. That -should contain storage and retrieval functions as shown below. -@example - typedef int (*gnutls_tdb_store_func) (const char* db_name, - const char* host, - const char* service, - time_t expiration, - const gnutls_datum_t* pubkey); - typedef int (*gnutls_tdb_store_commitment_func) (const char* db_name, - const char* host, - const char* service, - time_t expiration, - gnutls_digest_algorithm_t halgo, - const gnutls_datum_t* hash); - - typedef int (*gnutls_tdb_retr_func) (const char* db_name, - const char* host, - const char* service, - const gnutls_datum_t *pubkey); -@end example +should contain storage and retrieval functions and specified as below. + +@showfuncE{gnutls_tdb_init,gnutls_tdb_deinit,gnutls_tdb_set_verify_func,gnutls_tdb_set_store_func,gnutls_tdb_set_store_commitment_func} @node OpenPGP certificates @section @acronym{OpenPGP} certificates diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index b9f89a5eb3..7e623e17c0 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1675,21 +1675,30 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); /* searches for the provided host/service pair that match the * provided public key in the database. */ - typedef int (*gnutls_tdb_retr_func) (const char* db_name, + typedef int (*gnutls_tdb_verify_func) (const char* db_name, const char* host, const char* service, const gnutls_datum_t *pubkey); + struct gnutls_tdb_int; + typedef struct gnutls_tdb_int *gnutls_tdb_t; + + int gnutls_tdb_init(gnutls_tdb_t*); + void gnutls_tdb_set_store_func(gnutls_tdb_t, gnutls_tdb_store_func); + void gnutls_tdb_set_store_commitment_func(gnutls_tdb_t, gnutls_tdb_store_commitment_func); + void gnutls_tdb_set_verify_func(gnutls_tdb_t, gnutls_tdb_verify_func); + void gnutls_tdb_deinit(gnutls_tdb_t); + int gnutls_verify_stored_pubkey(const char* db_name, - gnutls_tdb_retr_func retrieve, + gnutls_tdb_t, const char* host, const char* service, gnutls_certificate_type_t cert_type, const gnutls_datum_t * cert, unsigned int flags); int gnutls_store_commitment(const char* db_name, - gnutls_tdb_store_commitment_func ctore, + gnutls_tdb_t, const char* host, const char* service, gnutls_digest_algorithm_t hash_algo, @@ -1698,7 +1707,7 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); unsigned int flags); int gnutls_store_pubkey(const char* db_name, - gnutls_tdb_store_func store, + gnutls_tdb_t, const char* host, const char* service, gnutls_certificate_type_t cert_type, diff --git a/lib/libgnutls.map b/lib/libgnutls.map index ee8c480c1b..5849918055 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -775,6 +775,11 @@ GNUTLS_3_0_0 { gnutls_store_commitment; gnutls_store_pubkey; gnutls_dtls_get_timeout; + gnutls_tdb_init; + gnutls_tdb_set_store_func; + gnutls_tdb_set_store_commitment_func; + gnutls_tdb_set_verify_func; + gnutls_tdb_deinit; } GNUTLS_2_12; GNUTLS_PRIVATE { diff --git a/lib/verify-tofu.c b/lib/verify-tofu.c index 3881e558ed..11300aad79 100644 --- a/lib/verify-tofu.c +++ b/lib/verify-tofu.c @@ -36,10 +36,16 @@ #include #include +struct gnutls_tdb_int { + gnutls_tdb_store_func store; + gnutls_tdb_store_commitment_func cstore; + gnutls_tdb_verify_func verify; +}; + static int raw_pubkey_to_base64(const gnutls_datum_t* raw, gnutls_datum_t * b64); static int x509_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey); static int pgp_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey); -static int retrieve_pubkey(const char* file, +static int verify_pubkey(const char* file, const char* host, const char* service, const gnutls_datum_t* skey); @@ -57,10 +63,17 @@ static int find_config_file(char* file, size_t max_size); void *_gnutls_file_mutex; +struct gnutls_tdb_int default_tdb = { + store_pubkey, + store_commitment, + verify_pubkey +}; + + /** * gnutls_verify_stored_pubkey: * @db_name: A file specifying the stored keys (use NULL for the default) - * @retrieve: A retrieval function or NULL to use the default + * @tdb: A storage 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 @@ -93,7 +106,7 @@ void *_gnutls_file_mutex; **/ int gnutls_verify_stored_pubkey(const char* db_name, - gnutls_tdb_retr_func retrieve, + gnutls_tdb_t tdb, const char* host, const char* service, gnutls_certificate_type_t cert_type, @@ -106,7 +119,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 (db_name == NULL && retrieve == NULL) + if (db_name == NULL && tdb == NULL) { ret = find_config_file(local_file, sizeof(local_file)); if (ret < 0) @@ -114,8 +127,8 @@ char local_file[MAX_FILENAME]; db_name = local_file; } - if (retrieve == NULL) - retrieve = retrieve_pubkey; + if (tdb == NULL) + tdb = &default_tdb; if (cert_type == GNUTLS_CRT_X509) ret = x509_crt_to_raw_pubkey(cert, &pubkey); @@ -128,7 +141,7 @@ char local_file[MAX_FILENAME]; goto cleanup; } - ret = retrieve(db_name, host, service, &pubkey); + ret = tdb->verify(db_name, host, service, &pubkey); if (ret < 0) return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND); @@ -287,7 +300,7 @@ time_t expiration; /* Returns the base64 key if found */ -static int retrieve_pubkey(const char* file, +static int verify_pubkey(const char* file, const char* host, const char* service, const gnutls_datum_t* pubkey) { @@ -523,7 +536,7 @@ int ret; if (host == NULL) host = "*"; fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, - pubkey->size, pubkey->data); + b64key.size, b64key.data); ret = 0; @@ -564,7 +577,7 @@ char buffer[MAX_HASH_SIZE*2+1]; /** * gnutls_store_pubkey: * @db_name: A file specifying the stored keys (use NULL for the default) - * @store: A storage function or NULL to use the default + * @tdb: A storage 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 @@ -587,7 +600,7 @@ char buffer[MAX_HASH_SIZE*2+1]; **/ int gnutls_store_pubkey(const char* db_name, - gnutls_tdb_store_func store, + gnutls_tdb_t tdb, const char* host, const char* service, gnutls_certificate_type_t cert_type, @@ -603,7 +616,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 (db_name == NULL && store == NULL) + if (db_name == NULL && tdb == NULL) { ret = _gnutls_find_config_path(local_file, sizeof(local_file)); if (ret < 0) @@ -618,8 +631,8 @@ char local_file[MAX_FILENAME]; db_name = local_file; } - if (store == NULL) - store = store_pubkey; + if (tdb == NULL) + tdb = &default_tdb; if (cert_type == GNUTLS_CRT_X509) ret = x509_crt_to_raw_pubkey(cert, &pubkey); @@ -633,7 +646,7 @@ char local_file[MAX_FILENAME]; _gnutls_debug_log("Configuration file: %s\n", db_name); - store(db_name, host, service, expiration, &pubkey); + tdb->store(db_name, host, service, expiration, &pubkey); ret = 0; @@ -647,7 +660,7 @@ cleanup: /** * gnutls_store_commitment: * @db_name: A file specifying the stored keys (use NULL for the default) - * @cstore: A storage function or NULL to use the default + * @tdb: A storage 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) * @hash_algo: The hash algorithm type @@ -672,7 +685,7 @@ cleanup: **/ int gnutls_store_commitment(const char* db_name, - gnutls_tdb_store_commitment_func cstore, + gnutls_tdb_t tdb, const char* host, const char* service, gnutls_digest_algorithm_t hash_algo, @@ -690,7 +703,7 @@ char local_file[MAX_FILENAME]; if (_gnutls_hash_get_algo_len(hash_algo) != hash->size) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - if (db_name == NULL && cstore == NULL) + if (db_name == NULL && tdb == NULL) { ret = _gnutls_find_config_path(local_file, sizeof(local_file)); if (ret < 0) @@ -705,12 +718,12 @@ char local_file[MAX_FILENAME]; db_name = local_file; } - if (cstore == NULL) - cstore = store_commitment; + if (tdb == NULL) + tdb = &default_tdb; _gnutls_debug_log("Configuration file: %s\n", db_name); - cstore(db_name, host, service, expiration, hash_algo, hash); + tdb->cstore(db_name, host, service, expiration, hash_algo, hash); ret = 0; @@ -737,3 +750,89 @@ int ret; return 0; } + +/** + * gnutls_tdb_init: + * @tdb: The structure to be initialized + * + * This function will initialize a public key trust storage structure. + * + * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a + * negative error value. + **/ +int gnutls_tdb_init(gnutls_tdb_t* tdb) +{ + *tdb = gnutls_calloc (1, sizeof (struct gnutls_tdb_int)); + + if (!*tdb) + return GNUTLS_E_MEMORY_ERROR; + + return 0; +} + +/** + * gnutls_set_store_func: + * @tdb: The trust storage + * @store: The storage function + * + * This function will associate a storage function with the + * trust storage structure. The function is of the following form. + * + * gnutls_tdb_store_func(const char* db_name, const char* host, + * const char* service, time_t expiration, + * const gnutls_datum_t* pubkey); + * + **/ +void gnutls_tdb_set_store_func(gnutls_tdb_t tdb, gnutls_tdb_store_func store) +{ + tdb->store = store; +} + +/** + * gnutls_set_store_commitment_func: + * @tdb: The trust storage + * @cstore: The commitment storage function + * + * This function will associate a commitment (hash) storage function with the + * trust storage structure. The function is of the following form. + * + * gnutls_tdb_store_commitment_func(const char* db_name, const char* host, + * const char* service, time_t expiration, + * gnutls_digest_algorithm_t, const gnutls_datum_t* hash); + * + **/ +void gnutls_tdb_set_store_commitment_func(gnutls_tdb_t tdb, + gnutls_tdb_store_commitment_func cstore) +{ + tdb->cstore = cstore; +} + +/** + * gnutls_set_verify_func: + * @tdb: The trust storage + * @verify: The verification function + * + * This function will associate a retrieval function with the + * trust storage structure. The function is of the following form. + * + * gnutls_tdb_verify_func(const char* db_name, const char* host, + * const char* service, const gnutls_datum_t* pubkey); + * + **/ +void gnutls_tdb_set_verify_func(gnutls_tdb_t tdb, gnutls_tdb_verify_func verify) +{ + tdb->verify = verify; +} + +/** + * gnutls_tdb_deinit: + * @tdb: The structure to be deinitialized + * + * This function will deinitialize a public key trust storage structure. + **/ +void gnutls_tdb_deinit(gnutls_tdb_t tdb) +{ + gnutls_free(tdb); +} + + diff --git a/tests/Makefile.am b/tests/Makefile.am index b2b637bbf7..c74d5f04b6 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -67,7 +67,7 @@ ctests = mini-deflate simple gc set_pkcs12_cred certder certuniqueid \ nul-in-x509-names x509_altname pkcs12_encode mini-x509 \ mini-x509-rehandshake rng-fork mini-eagain-dtls mini-loss \ x509cert x509cert-tl infoaccess rsa-encrypt-decrypt \ - mini-loss-time + mini-loss-time mini-tdb if ENABLE_OCSP ctests += ocsp diff --git a/tests/mini-deflate.c b/tests/mini-deflate.c index 674338cbe2..7ed3a99d4b 100644 --- a/tests/mini-deflate.c +++ b/tests/mini-deflate.c @@ -1,7 +1,7 @@ /* * Copyright (C) 2008-2012 Free Software Foundation, Inc. * - * Author: Simon Josefsson + * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * diff --git a/tests/mini-tdb.c b/tests/mini-tdb.c new file mode 100644 index 0000000000..90e187a9e6 --- /dev/null +++ b/tests/mini-tdb.c @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2012 Free Software Foundation, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include "utils.h" + +/* This will test whether the default public key storage backend + * is operating properly */ + +static void +tls_log_func (int level, const char *str) +{ + fprintf (stderr, "|<%d>| %s", level, str); +} + +static unsigned char server_cert_pem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIICVjCCAcGgAwIBAgIERiYdMTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n" + "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTIxWhcNMDgwNDE3MTMyOTIxWjA3MRsw\n" + "GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz\n" + "Lm9yZzCBnDALBgkqhkiG9w0BAQEDgYwAMIGIAoGA17pcr6MM8C6pJ1aqU46o63+B\n" + "dUxrmL5K6rce+EvDasTaDQC46kwTHzYWk95y78akXrJutsoKiFV1kJbtple8DDt2\n" + "DZcevensf9Op7PuFZKBroEjOd35znDET/z3IrqVgbtm2jFqab7a+n2q9p/CgMyf1\n" + "tx2S5Zacc1LWn9bIjrECAwEAAaOBkzCBkDAMBgNVHRMBAf8EAjAAMBoGA1UdEQQT\n" + "MBGCD3Rlc3QuZ251dGxzLm9yZzATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHQ8B\n" + "Af8EBQMDB6AAMB0GA1UdDgQWBBTrx0Vu5fglyoyNgw106YbU3VW0dTAfBgNVHSME\n" + "GDAWgBTpPBz7rZJu5gakViyi4cBTJ8jylTALBgkqhkiG9w0BAQUDgYEAaFEPTt+7\n" + "bzvBuOf7+QmeQcn29kT6Bsyh1RHJXf8KTk5QRfwp6ogbp94JQWcNQ/S7YDFHglD1\n" + "AwUNBRXwd3riUsMnsxgeSDxYBfJYbDLeohNBsqaPDJb7XailWbMQKfAbFQ8cnOxg\n" + "rOKLUQRWJ0K3HyXRMhbqjdLIaQiCvQLuizo=\n" "-----END CERTIFICATE-----\n"; + +const gnutls_datum_t server_cert = { server_cert_pem, + sizeof (server_cert_pem) +}; + +static char client_pem[] = + "-----BEGIN CERTIFICATE-----\n" + "MIICHjCCAYmgAwIBAgIERiYdNzALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251\n" + "VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTI3WhcNMDgwNDE3MTMyOTI3WjAdMRsw\n" + "GQYDVQQDExJHbnVUTFMgdGVzdCBjbGllbnQwgZwwCwYJKoZIhvcNAQEBA4GMADCB\n" + "iAKBgLtmQ/Xyxde2jMzF3/WIO7HJS2oOoa0gUEAIgKFPXKPQ+GzP5jz37AR2ExeL\n" + "ZIkiW8DdU3w77XwEu4C5KL6Om8aOoKUSy/VXHqLnu7czSZ/ju0quak1o/8kR4jKN\n" + "zj2AC41179gAgY8oBAOgIo1hBAf6tjd9IQdJ0glhaZiQo1ipAgMBAAGjdjB0MAwG\n" + "A1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDwYDVR0PAQH/BAUDAweg\n" + "ADAdBgNVHQ4EFgQUTLkKm/odNON+3svSBxX+odrLaJEwHwYDVR0jBBgwFoAU6Twc\n" + "+62SbuYGpFYsouHAUyfI8pUwCwYJKoZIhvcNAQEFA4GBALujmBJVZnvaTXr9cFRJ\n" + "jpfc/3X7sLUsMvumcDE01ls/cG5mIatmiyEU9qI3jbgUf82z23ON/acwJf875D3/\n" + "U7jyOsBJ44SEQITbin2yUeJMIm1tievvdNXBDfW95AM507ShzP12sfiJkJfjjdhy\n" + "dc8Siq5JojruiMizAf0pA7in\n" "-----END CERTIFICATE-----\n"; +const gnutls_datum_t client_cert = { (void*)client_pem, sizeof (client_pem) }; + +#define TMP_FILE "mini-tdb-tmp" + +#define SHA1_HASH "\x53\x4b\x3b\xdc\x5e\xc8\x44\x4c\x02\x20\xbf\x39\x48\x6f\x4c\xfe\xcd\x25\x52\x10" + +void doit(void) +{ + gnutls_datum_t der_cert, der_cert2; + int ret; + gnutls_datum_t hash; + + /* the sha1 hash of the server's pubkey */ + hash.data = (void*)SHA1_HASH; + hash.size = sizeof(SHA1_HASH)-1; + + /* General init. */ + gnutls_global_init (); + gnutls_global_set_log_function (tls_log_func); + if (debug) + gnutls_global_set_log_level (2); + + ret = gnutls_pem_base64_decode_alloc("CERTIFICATE", &server_cert, &der_cert); + if (ret < 0) + { + fail("base64 decoding\n"); + goto fail; + } + + ret = gnutls_pem_base64_decode_alloc("CERTIFICATE", &client_cert, &der_cert2); + if (ret < 0) + { + fail("base64 decoding\n"); + goto fail; + } + + remove(TMP_FILE); + + /* verify whether the stored hash verification succeeeds */ + ret = gnutls_store_commitment(TMP_FILE, NULL, "localhost", "https", + GNUTLS_DIG_SHA1, &hash, 0, 0); + if (ret != 0) + { + fail("commitment storage: %s\n", gnutls_strerror(ret)); + goto fail; + } + + if (debug) + success("Commitment storage: passed\n"); + + ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", + GNUTLS_CRT_X509, &der_cert, 0); + remove(TMP_FILE); + + if (ret != 0) + { + fail("commitment verification: %s\n", gnutls_strerror(ret)); + goto fail; + } + + if (debug) + success("Commitment verification: passed\n"); + + /* verify whether the stored pubkey verification succeeeds */ + ret = gnutls_store_pubkey(TMP_FILE, NULL, "localhost", "https", + GNUTLS_CRT_X509, &der_cert, 0, 0); + if (ret != 0) + { + fail("storage: %s\n", gnutls_strerror(ret)); + goto fail; + } + + if (debug) + success("Public key storage: passed\n"); + + ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", + GNUTLS_CRT_X509, &der_cert, 0); + if (ret != 0) + { + fail("pubkey verification: %s\n", gnutls_strerror(ret)); + goto fail; + } + + ret = gnutls_verify_stored_pubkey(TMP_FILE, NULL, "localhost", "https", + GNUTLS_CRT_X509, &der_cert2, 0); + remove(TMP_FILE); + if (ret == 0) + { + fail("verification succeed when shouldn't!\n"); + goto fail; + } + + if (debug) + success("Public key verification: passed\n"); + + + gnutls_global_deinit(); + gnutls_free(der_cert.data); + gnutls_free(der_cert2.data); + + return; +fail: + remove(TMP_FILE); + exit(1); +}