diff options
-rw-r--r-- | doc/cha-cert-auth.texi | 13 | ||||
-rw-r--r-- | doc/cha-gtls-examples.texi | 5 | ||||
-rw-r--r-- | doc/examples/ex-verify-ssh.c | 8 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 6 | ||||
-rw-r--r-- | lib/verify-ssh.c | 51 |
5 files changed, 44 insertions, 39 deletions
diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi index 7fb41a60dd..a2656ad94d 100644 --- a/doc/cha-cert-auth.texi +++ b/doc/cha-cert-auth.texi @@ -87,7 +87,7 @@ acceptable. The framework is illustrated on @ref{fig:x509}. * X.509 distinguished names:: * Verifying X.509 certificate paths:: * Verifying a certificate in the context of TLS session:: -* Verifying a certificate using SSH-style authentication:: +* Verifying a certificate using trust on first use authentication:: @end menu @node X.509 certificate structure @@ -277,15 +277,16 @@ about the peer's identity. It is required to verify if the certificate's owner is the one you expect. For more information consult @xcite{RFC2818} and section @ref{ex:verify} for an example. -@node Verifying a certificate using SSH-style authentication -@subsection Verifying a certificate using SSH-style authentication +@node Verifying a certificate using trust on first use authentication +@subsection Verifying a certificate using trust on first use authentication @cindex verifying certificate paths @cindex SSH-style authentication +@cindex Trust on first use @tindex gnutls_certificate_verify_flags -It is possible to use an SSH-style authentication method in GnuTLS. -That means that having seen and associated a public key with a host -is enough to trust it on the subsequent connections. +It is possible to use a trust on first use (similar to SSH) authentication +method in GnuTLS. That means that having seen and associated a public key +with a host is enough to trust it on the subsequent connections. A hybrid system with X.509 and SSH authentication is shown in @ref{Simple client example with SSH-style certificate verification}. diff --git a/doc/cha-gtls-examples.texi b/doc/cha-gtls-examples.texi index 9d253a0045..637653c46a 100644 --- a/doc/cha-gtls-examples.texi +++ b/doc/cha-gtls-examples.texi @@ -70,8 +70,9 @@ resumption. This is an alternative verification function that will use the X.509 certificate authorities for verification, but also assume an -SSH-like authentication system. That is the user is prompted on unknown -public keys and known public keys are considered trusted. +trust on first use (SSH-like) authentication system. That is the user is +prompted on unknown public keys and known public keys are considered +trusted. @verbatiminclude examples/ex-verify-ssh.c diff --git a/doc/examples/ex-verify-ssh.c b/doc/examples/ex-verify-ssh.c index c9a66b27bc..fb211c5746 100644 --- a/doc/examples/ex-verify-ssh.c +++ b/doc/examples/ex-verify-ssh.c @@ -92,8 +92,10 @@ _ssh_verify_certificate_callback (gnutls_session_t session) gnutls_x509_crt_deinit (cert); - ret = gnutls_verify_stored_pubkey(NULL, NULL, hostname, "443", - GNUTLS_CRT_X509, &cert_list[0], 0); + /* service may be obtained alternatively using getservbyport() */ + ret = gnutls_verify_stored_pubkey(NULL, hostname, "https", + GNUTLS_CRT_X509, &cert_list[0], + 0, 0); if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) { fprintf(stderr, "Host %s is not known.", hostname); @@ -128,7 +130,7 @@ _ssh_verify_certificate_callback (gnutls_session_t session) /* user trusts the key -> store it */ if (ret != 0) { - ret = gnutls_store_pubkey(NULL, NULL, hostname, "443", GNUTLS_CRT_X509, &cert_list[0], 0); + ret = gnutls_store_pubkey(NULL, hostname, "https", GNUTLS_CRT_X509, &cert_list[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 415e282719..f5adbf5863 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1658,18 +1658,18 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); /* ssh style functions */ int gnutls_verify_stored_pubkey(const char* file, - const char* application, 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, - const char* application, const char* host, const char* service, gnutls_certificate_type_t cert_type, - const gnutls_datum_t * cert, unsigned int flags); + const gnutls_datum_t * cert, + time_t expiration, + unsigned int flags); /* Gnutls error codes. The mapping to a TLS alert is also shown in diff --git a/lib/verify-ssh.c b/lib/verify-ssh.c index 8d6562f705..23ac819e62 100644 --- a/lib/verify-ssh.c +++ b/lib/verify-ssh.c @@ -38,7 +38,7 @@ static int raw_pubkey_to_base64(gnutls_datum_t* pubkey); 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 find_stored_pubkey(const char* file, const char* application, +static int find_stored_pubkey(const char* file, const char* host, const char* service, const gnutls_datum_t* skey); static int find_config_file(char* file, size_t max_size); @@ -47,7 +47,6 @@ static int find_config_file(char* file, size_t max_size); /** * gnutls_verify_stored_pubkey: * @file: A file specifying the stored keys (use NULL for the default) - * @application: non-NULL with an application name if this key is application-specific * @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 @@ -68,7 +67,6 @@ static int find_config_file(char* file, size_t max_size); **/ int gnutls_verify_stored_pubkey(const char* file, - const char* application, const char* host, const char* service, gnutls_certificate_type_t cert_type, @@ -107,7 +105,7 @@ char local_file[MAX_FILENAME]; goto cleanup; } - ret = find_stored_pubkey(file, application, host, service, &pubkey); + ret = find_stored_pubkey(file, host, service, &pubkey); if (ret < 0) return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND); @@ -117,15 +115,16 @@ cleanup: return ret; } -static int parse_line(char* line, const char* application, - size_t application_len, +static int parse_line(char* line, const char* host, size_t host_len, const char* service, size_t service_len, + time_t now, const gnutls_datum_t *skey) { char* p, *kp; char* savep = NULL; size_t kp_len; +time_t expiration; /* read version */ p = strtok_r(line, "|", &savep); @@ -135,31 +134,32 @@ size_t kp_len; if (strncmp(p, "g0", 2) != 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - /* read application */ + /* read host */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - if (p[0] != '*' && strcmp(p, application)!=0) + if (p[0] != '*' && strcmp(p, host) != 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - /* read host */ + /* read service */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - if (p[0] != '*' && strcmp(p, host) != 0) + if (p[0] != '*' && strcmp(p, service) != 0) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - /* read service */ + /* read expiration */ p = strtok_r(NULL, "|", &savep); if (p == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); - if (p[0] != '*' && strcmp(p, service) != 0) - return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); + expiration = (time_t)atol(p); + if (expiration > 0 && now > expiration) + return gnutls_assert_val(GNUTLS_E_EXPIRED); - /* read service */ + /* read key */ kp = strtok_r(NULL, "|", &savep); if (kp == NULL) return gnutls_assert_val(GNUTLS_E_PARSING_ERROR); @@ -180,7 +180,7 @@ size_t kp_len; /* Returns the base64 key if found */ -static int find_stored_pubkey(const char* file, const char* application, +static int find_stored_pubkey(const char* file, const char* host, const char* service, const gnutls_datum_t* skey) { @@ -188,11 +188,11 @@ FILE* fd; char* line = NULL; size_t line_size = 0; int ret, l2, mismatch = 0; -size_t application_len = 0, host_len = 0, service_len = 0; +size_t host_len = 0, service_len = 0; +time_t now = gnutls_time(0); if (host != NULL) host_len = strlen(host); if (service != NULL) service_len = strlen(service); - if (application != NULL) application_len = strlen(application); fd = fopen(file, "rb"); if (fd == NULL) @@ -203,8 +203,7 @@ size_t application_len = 0, host_len = 0, service_len = 0; l2 = getline(&line, &line_size, fd); if (l2 > 0) { - ret = parse_line(line, application, application_len, - host, host_len, service, service_len, skey); + ret = parse_line(line, host, host_len, service, service_len, now, skey); if (ret == 0) /* found */ { goto cleanup; @@ -380,15 +379,16 @@ cleanup: /** * gnutls_store_pubkey: * @file: A file specifying the stored keys (use NULL for the default) - * @application: non-NULL with an application name if this key is application-specific * @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 * @cert: The data of the certificate + * @expiration: The expiration time (use 0 to disable expiration) * @flags: should be 0. * * This function will store to verify the provided certificate to - * the list of stored public keys. + * 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. * @@ -399,11 +399,12 @@ cleanup: **/ int gnutls_store_pubkey(const char* file, - const char* application, const char* host, const char* service, gnutls_certificate_type_t cert_type, - const gnutls_datum_t * cert, unsigned int flags) + const gnutls_datum_t * cert, + time_t expiration, + unsigned int flags) { FILE* fd = NULL; gnutls_datum_t pubkey = { NULL, 0 }; @@ -454,11 +455,11 @@ char local_file[MAX_FILENAME]; goto cleanup; } - if (application == NULL) application = "*"; if (service == NULL) service = "*"; if (host == NULL) host = "*"; - fprintf(fd, "|g0|%s|%s|%s|%.*s\n", application, host, service, pubkey.size, pubkey.data); + fprintf(fd, "|g0|%s|%s|%lu|%.*s\n", host, service, (unsigned long)expiration, + pubkey.size, pubkey.data); ret = 0; |