diff options
-rw-r--r-- | NEWS | 9 | ||||
-rw-r--r-- | doc/cha-cert-auth.texi | 15 | ||||
-rw-r--r-- | doc/cha-gtls-app.texi | 42 | ||||
-rw-r--r-- | doc/examples/ex-client-x509.c | 95 | ||||
-rw-r--r-- | lib/Makefile.am | 2 | ||||
-rw-r--r-- | lib/auto-verify.c | 147 | ||||
-rw-r--r-- | lib/gnutls_alert.c | 1 | ||||
-rw-r--r-- | lib/gnutls_cert.c | 2 | ||||
-rw-r--r-- | lib/gnutls_errors.c | 2 | ||||
-rw-r--r-- | lib/gnutls_handshake.c | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 8 | ||||
-rw-r--r-- | lib/gnutls_priority.c | 5 | ||||
-rw-r--r-- | lib/gnutls_x509.c | 3 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 60 | ||||
-rw-r--r-- | lib/libgnutls.map | 3 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/auto-verify.c | 561 |
17 files changed, 833 insertions, 126 deletions
@@ -5,6 +5,10 @@ See the end for copying conditions. * Version 3.3.23 (unreleased) +** libgnutls: Backported the new simple verification functions. That avoids the + need to install a callback to perform certificate verification. See + doc/examples/ex-client-x509.c for usage. + ** libgnutls: Corrected behavior of ALPN extension parsing during session resumption. Report and patches by Yuriy M. Kaminskiy. @@ -42,7 +46,10 @@ See the end for copying conditions. reply. Report and reproducer by Thomas Klute. ** API and ABI modifications: -No changes since last version. +gnutls_session_set_verify_function: Added +gnutls_session_set_verify_cert: Added +gnutls_session_set_verify_cert2: Added +gnutls_session_get_verify_cert_status: Added * Version 3.3.22 (released 2016-03-10) diff --git a/doc/cha-cert-auth.texi b/doc/cha-cert-auth.texi index 10a74776b7..64c47ff1e1 100644 --- a/doc/cha-cert-auth.texi +++ b/doc/cha-cert-auth.texi @@ -354,14 +354,19 @@ via a file, a directory or use the system-specified certificate authories. Unless the authorities are application specific, it is generally recommended to use the system trust storage (see @funcref{gnutls_certificate_set_x509_system_trust}). -Unlike the previous section it is not required to setup a trusted list, and -the function @funcref{gnutls_certificate_verify_peers3} -is used to verify the peer's certificate chain and identity. The reported -verification status is identical to the verification functions described +Unlike the previous section it is not required to setup a trusted list, and there +are two approaches to verify the peer's certificate and identity. +The recommended in GnuTLS 3.5.0 and later is via the @funcref{gnutls_session_set_verify_cert}, +but for older GnuTLS versions you may use an explicit callback set via +@funcref{gnutls_certificate_set_verify_function} and then utilize +@funcref{gnutls_certificate_verify_peers3} for verification. +The reported verification status is identical to the verification functions described in the previous section. + Note that in certain cases it is required to check the marked purpose of the end certificate (e.g. @code{GNUTLS_KP_TLS_WWW_SERVER}); in these cases -the more advanced @funcref{gnutls_certificate_verify_peers} should be used instead. +the more advanced @funcref{gnutls_session_set_verify_cert2} and +@funcref{gnutls_certificate_verify_peers} should be used instead. There is also the possibility to pass some input to the verification functions in the form of flags. For @funcref{gnutls_x509_trust_list_verify_crt2} the diff --git a/doc/cha-gtls-app.texi b/doc/cha-gtls-app.texi index ce48be7c4f..1df8676488 100644 --- a/doc/cha-gtls-app.texi +++ b/doc/cha-gtls-app.texi @@ -576,23 +576,25 @@ the following functions, applicable to X.509 and OpenPGP certificates. @showfuncC{gnutls_certificate_set_x509_system_trust,gnutls_certificate_set_x509_trust_file,gnutls_certificate_set_openpgp_keyring_file} -The peer's certificate is not automatically verified and one -must call @funcref{gnutls_certificate_verify_peers3} -after a successful handshake to verify the certificate's signature and the owner -of the certificate. The verification status returned can be printed using -@funcref{gnutls_certificate_verification_status_print}. - -Alternatively the verification can occur during the handshake -by using @funcref{gnutls_certificate_set_verify_function}. - -The functions above provide a brief verification output. If a +The peer's certificate will be automatically verified if +@funcref{gnutls_session_set_verify_cert} is called prior to handshake. + +Alternatively, one must set a callback function during the handshake +using @funcref{gnutls_certificate_set_verify_function}, which +will verify the peer's certificate once received. The verification +should happen using @funcref{gnutls_certificate_verify_peers3} within +the callback. It will verify the certificate's signature and the owner +of the certificate. That will provide a brief verification output. If a detailed output is required one should call @funcref{gnutls_certificate_get_peers} to obtain the raw certificate of the peer and verify it using the functions discussed in @ref{X.509 certificates}. -@showfuncdesc{gnutls_certificate_verify_peers3} +In both the automatic and the manual cases, the verification status returned +can be printed using @funcref{gnutls_certificate_verification_status_print}. -@showfuncdesc{gnutls_certificate_set_verify_function} +@showfuncdesc{gnutls_session_set_verify_cert} + +@showfuncB{gnutls_certificate_verify_peers3,gnutls_certificate_set_verify_function} @node SRP credentials @@ -826,15 +828,15 @@ exchange. @showfuncdesc{gnutls_handshake_set_timeout} -The handshake process doesn't ensure the verification -of the peer's identity. When certificates are in use, -this can be done, either after the handshake is complete, or during -the handshake if @funcref{gnutls_certificate_set_verify_function} -has been used. In both cases the @funcref{gnutls_certificate_verify_peers2} function can be -used to verify the peer's certificate (see @ref{Certificate authentication} -for more information). +In GnuTLS 3.5.0 and later it is recommended to use @funcref{gnutls_session_set_verify_cert} +for the handshake process to ensure the verification of the peer's identity. + +In older GnuTLS versions it is required to manually verify the peer's certificate +during the handshake by using @funcref{gnutls_certificate_set_verify_function}, and +@funcref{gnutls_certificate_verify_peers2}. See @ref{Certificate authentication} +for more information. -@showfuncA{gnutls_certificate_verify_peers2} +@showfuncB{gnutls_session_set_verify_cert,gnutls_certificate_verify_peers2} @node Data transfer and termination @section Data transfer and termination diff --git a/doc/examples/ex-client-x509.c b/doc/examples/ex-client-x509.c index 8ee429a1b2..25cd076e7e 100644 --- a/doc/examples/ex-client-x509.c +++ b/doc/examples/ex-client-x509.c @@ -22,18 +22,19 @@ extern int tcp_connect(void); extern void tcp_close(int sd); -static int _verify_certificate_callback(gnutls_session_t session); int main(void) { - int ret, sd, ii; + int ret, sd, ii, type; gnutls_session_t session; char buffer[MAX_BUF + 1]; const char *err; + unsigned status; gnutls_certificate_credentials_t xcred; + gnutls_datum_t out; - if (gnutls_check_version("3.1.4") == NULL) { - fprintf(stderr, "GnuTLS 3.1.4 or later is required for this example\n"); + if (gnutls_check_version("3.3.23") == NULL) { + fprintf(stderr, "GnuTLS 3.3.23 or later is required for this example\n"); exit(1); } @@ -47,8 +48,6 @@ int main(void) */ gnutls_certificate_set_x509_trust_file(xcred, CAFILE, GNUTLS_X509_FMT_PEM); - gnutls_certificate_set_verify_function(xcred, - _verify_certificate_callback); /* If client holds a certificate it can be set using the following: * @@ -66,7 +65,7 @@ int main(void) gnutls_server_name_set(session, GNUTLS_NAME_DNS, "my_host_name", strlen("my_host_name")); - /* use default priorities */ + /* It is recommended to use the default priorities */ gnutls_set_default_priority(session); #if 0 /* if more fine-graned control is required */ @@ -83,6 +82,7 @@ int main(void) /* put the x509 credentials to the current session */ gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + gnutls_session_set_verify_cert(session, "my_host_name", 0); /* connect to the peer */ @@ -98,7 +98,6 @@ int main(void) ret = gnutls_handshake(session); } while (ret < 0 && gnutls_error_is_fatal(ret) == 0); - if (ret < 0) { fprintf(stderr, "*** Handshake failed\n"); gnutls_perror(ret); @@ -111,6 +110,21 @@ int main(void) gnutls_free(desc); } + /* check certificate verification status */ + type = gnutls_certificate_type_get(session); + status = gnutls_session_get_verify_cert_status(session); + ret = + gnutls_certificate_verification_status_print(status, type, + &out, 0); + if (ret < 0) { + printf("Error\n"); + return GNUTLS_E_CERTIFICATE_ERROR; + } + + printf("%s", out.data); + gnutls_free(out.data); + + /* send data */ gnutls_record_send(session, MSG, strlen(MSG)); ret = gnutls_record_recv(session, buffer, MAX_BUF); @@ -146,68 +160,3 @@ int main(void) return 0; } - -/* This function will verify the peer's certificate, and check - * if the hostname matches, as well as the activation, expiration dates. - */ -static int _verify_certificate_callback(gnutls_session_t session) -{ - unsigned int status; - int ret, type; - const char *hostname; - gnutls_datum_t out; - - /* read hostname */ - hostname = gnutls_session_get_ptr(session); - - /* This verification function uses the trusted CAs in the credentials - * structure. So you must have installed one or more CA certificates. - */ - - /* The following demonstrate two different verification functions, - * the more flexible gnutls_certificate_verify_peers(), as well - * as the old gnutls_certificate_verify_peers3(). */ -#if 1 - { - gnutls_typed_vdata_st data[2]; - - memset(data, 0, sizeof(data)); - - data[0].type = GNUTLS_DT_DNS_HOSTNAME; - data[0].data = (void*)hostname; - - data[1].type = GNUTLS_DT_KEY_PURPOSE_OID; - data[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER; - - ret = gnutls_certificate_verify_peers(session, data, 2, - &status); - } -#else - ret = gnutls_certificate_verify_peers3(session, hostname, - &status); -#endif - if (ret < 0) { - printf("Error\n"); - return GNUTLS_E_CERTIFICATE_ERROR; - } - - type = gnutls_certificate_type_get(session); - - ret = - gnutls_certificate_verification_status_print(status, type, - &out, 0); - if (ret < 0) { - printf("Error\n"); - return GNUTLS_E_CERTIFICATE_ERROR; - } - - printf("%s", out.data); - - gnutls_free(out.data); - - if (status != 0) /* Certificate is not trusted */ - return GNUTLS_E_CERTIFICATE_ERROR; - - /* notify gnutls to continue handshake normally */ - return 0; -} diff --git a/lib/Makefile.am b/lib/Makefile.am index 955fa10bb2..6e95ce6397 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -82,7 +82,7 @@ COBJECTS = gnutls_range.c gnutls_record.c \ random.c crypto-api.c gnutls_privkey.c gnutls_pcert.c \ gnutls_pubkey.c locks.c gnutls_dtls.c system_override.c \ crypto-backend.c verify-tofu.c pin.c tpm.c fips.c \ - safe-memset.c inet_pton.c + safe-memset.c inet_pton.c auto-verify.c if ENABLE_SELF_CHECKS COBJECTS += crypto-selftests.c crypto-selftests-pk.c diff --git a/lib/auto-verify.c b/lib/auto-verify.c new file mode 100644 index 0000000000..1de1442c2b --- /dev/null +++ b/lib/auto-verify.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 Red Hat, Inc. + * + * Author: Nikos Mavrogiannopoulos + * + * This file is part of GnuTLS. + * + * The GnuTLS is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + * + */ + +#include "gnutls_int.h" +#include "gnutls_errors.h" +#include <auth/cert.h> +#include <gnutls/gnutls.h> + +/* This file implements the client certificate auto verification functionality. + */ + +/* The actual verification callback. */ +static int auto_verify_cb(gnutls_session_t session) +{ + unsigned int status; + int ret; + + if (session->internals.vc_elements == 0) { + ret = gnutls_certificate_verify_peers2(session, &status); + } else { + ret = gnutls_certificate_verify_peers(session, session->internals.vc_data, + session->internals.vc_elements, &status); + } + if (ret < 0) { + return gnutls_assert_val(GNUTLS_E_CERTIFICATE_ERROR); + } + + session->internals.vc_status = status; + + if (status != 0) /* Certificate is not trusted */ + return gnutls_assert_val(GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR); + + /* notify gnutls to continue handshake normally */ + return 0; +} + +/** + * gnutls_session_set_verify_cert: + * @session: is a gnutls session + * @hostname: is the expected name of the peer; may be %NULL + * @flags: flags for certificate verification -- #gnutls_certificate_verify_flags + * + * This function instructs GnuTLS to verify the peer's certificate + * using the provided hostname. If the verification fails the handshake + * will also fail with %GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR. In that + * case the verification result can be obtained using gnutls_session_get_verify_cert_status(). + * + * The @hostname pointer provided must remain valid for the lifetime + * of the session. More precisely it should be available during any subsequent + * handshakes. If no hostname is provided, no hostname verification + * will be performed. For a more advanced verification function check + * gnutls_session_set_verify_cert2(). + * + * The gnutls_session_set_verify_cert() function is intended to be used by TLS + * clients to verify the server's certificate. + * + * Since: 3.5.0 + **/ +void gnutls_session_set_verify_cert(gnutls_session_t session, + const char *hostname, unsigned flags) +{ + if (hostname) { + session->internals.vc_sdata.type = GNUTLS_DT_DNS_HOSTNAME; + session->internals.vc_sdata.data = (void*)hostname; + session->internals.vc_sdata.size = 0; + session->internals.vc_elements = 1; + session->internals.vc_data = &session->internals.vc_sdata; + } else { + session->internals.vc_elements = 0; + } + + if (flags) + session->internals.additional_verify_flags |= flags; + + gnutls_session_set_verify_function(session, auto_verify_cb); +} + +/** + * gnutls_session_set_verify_cert2: + * @session: is a gnutls session + * @data: an array of typed data + * @elements: the number of data elements + * @flags: flags for certificate verification -- #gnutls_certificate_verify_flags + * + * This function instructs GnuTLS to verify the peer's certificate + * using the provided typed data information. If the verification fails the handshake + * will also fail with %GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR. In that + * case the verification result can be obtained using gnutls_session_get_verify_cert_status(). + * + * The acceptable typed data are the same as in gnutls_certificate_verify_peers(), + * and once set must remain valid for the lifetime of the session. More precisely + * they should be available during any subsequent handshakes. + * + * Since: 3.5.0 + **/ +void gnutls_session_set_verify_cert2(gnutls_session_t session, + gnutls_typed_vdata_st * data, + unsigned elements, + unsigned flags) +{ + session->internals.vc_data = data; + session->internals.vc_elements = elements; + + if (flags) + session->internals.additional_verify_flags |= flags; + + gnutls_session_set_verify_function(session, auto_verify_cb); +} + +/** + * gnutls_session_get_verify_cert_status: + * @session: is a gnutls session + * + * This function returns the status of the verification when initiated + * via auto-verification, i.e., by gnutls_session_set_verify_cert2() or + * gnutls_session_set_verify_cert(). If no certificate verification + * was occurred then the return value would be set to ((unsigned int)-1). + * + * The certificate verification status is the same as in gnutls_certificate_verify_peers(). + * + * Returns: the certificate verification status. + * + * Since: 3.5.0 + **/ +unsigned int gnutls_session_get_verify_cert_status(gnutls_session_t session) +{ + return session->internals.vc_status; +} diff --git a/lib/gnutls_alert.c b/lib/gnutls_alert.c index 66270dc18a..1d183930ed 100644 --- a/lib/gnutls_alert.c +++ b/lib/gnutls_alert.c @@ -228,6 +228,7 @@ int gnutls_error_to_alert(int err, int *level) case GNUTLS_E_ASN1_SYNTAX_ERROR: case GNUTLS_E_ASN1_DER_OVERFLOW: case GNUTLS_E_CERTIFICATE_ERROR: + case GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR: ret = GNUTLS_A_BAD_CERTIFICATE; _level = GNUTLS_AL_FATAL; break; diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c index 7064aadbf6..bd99c7fc61 100644 --- a/lib/gnutls_cert.c +++ b/lib/gnutls_cert.c @@ -600,7 +600,7 @@ _gnutls_openpgp_crt_verify_peers(gnutls_session_t session, return GNUTLS_E_NO_CERTIFICATE_FOUND; } - verify_flags = cred->verify_flags | session->internals.priorities.additional_verify_flags; + verify_flags = cred->verify_flags | session->internals.additional_verify_flags; /* generate a list of gnutls_certs based on the auth info * raw certs. diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c index 50f2a0ff2c..91a0fa7925 100644 --- a/lib/gnutls_errors.c +++ b/lib/gnutls_errors.c @@ -153,6 +153,8 @@ static const gnutls_error_entry error_entries[] = { GNUTLS_E_RECORD_LIMIT_REACHED), ERROR_ENTRY(N_("Error in the certificate."), GNUTLS_E_CERTIFICATE_ERROR), + ERROR_ENTRY(N_("Error in the certificate verification."), + GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR), ERROR_ENTRY(N_("Could not authenticate peer."), GNUTLS_E_AUTH_ERROR), ERROR_ENTRY(N_ diff --git a/lib/gnutls_handshake.c b/lib/gnutls_handshake.c index d8cc93ce15..d28f543345 100644 --- a/lib/gnutls_handshake.c +++ b/lib/gnutls_handshake.c @@ -2530,6 +2530,8 @@ int gnutls_handshake(gnutls_session_t session) session->internals.handshake_in_progress = 1; gettime(&session->internals.dtls.handshake_start_time); + session->internals.vc_status = -1; + if (session->internals.handshake_timeout_ms && session->internals.handshake_endtime == 0) session->internals.handshake_endtime = session->internals.dtls.handshake_start_time.tv_sec + diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 3db0e1f699..83b3b5b035 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -1,5 +1,6 @@ /* - * Copyright (C) 2000-2012 Free Software Foundation, Inc. + * Copyright (C) 2000-2015 Free Software Foundation, Inc. + * Copyright (C) 2015 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -1002,6 +1003,11 @@ typedef struct { /* a verify callback to override the verify callback from the credentials * structure */ gnutls_certificate_verify_function *verify_callback; + gnutls_typed_vdata_st *vc_data; + gnutls_typed_vdata_st vc_sdata; + unsigned vc_elements; + unsigned vc_status; + unsigned int additional_verify_flags; /* may be set by priorities or the vc functions */ /* If you add anything here, check _gnutls_handshake_internal_state_clear(). */ diff --git a/lib/gnutls_priority.c b/lib/gnutls_priority.c index f60674c174..72c6d1e3a3 100644 --- a/lib/gnutls_priority.c +++ b/lib/gnutls_priority.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2004-2012 Free Software Foundation, Inc. + * Copyright (C) 2004-2015 Free Software Foundation, Inc. + * Copyright (C) 2015 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * @@ -637,6 +638,8 @@ gnutls_priority_set(gnutls_session_t session, gnutls_priority_t priority) session->internals.priorities.compression.algorithms == 0) return gnutls_assert_val(GNUTLS_E_NO_PRIORITIES_WERE_SET); + session->internals.additional_verify_flags |= priority->additional_verify_flags; + return 0; } diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c index 22dea94fdf..648a0b9e5a 100644 --- a/lib/gnutls_x509.c +++ b/lib/gnutls_x509.c @@ -224,8 +224,7 @@ _gnutls_x509_cert_verify_peers(gnutls_session_t session, } verify_flags = - cred->verify_flags | session->internals.priorities. - additional_verify_flags; + cred->verify_flags | session->internals.additional_verify_flags; /* generate a list of gnutls_certs based on the auth info * raw certs. */ diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index c249f7b75f..ffcf04302b 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -1168,6 +1168,45 @@ char *gnutls_session_get_desc(gnutls_session_t session); typedef int gnutls_certificate_verify_function(gnutls_session_t); void gnutls_session_set_verify_function(gnutls_session_t session, gnutls_certificate_verify_function * func); +/** + * gnutls_vdata_types_t: + * @GNUTLS_DT_UNKNOWN: Unknown data type. + * @GNUTLS_DT_DNS_HOSTNAME: The data contain a null-terminated DNS hostname; the hostname will be + * matched using the RFC6125 rules. + * @GNUTLS_DT_RFC822NAME: The data contain a null-terminated email address; the email will be + * matched against the RFC822Name field of the certificate, or the EMAIL DN component if the + * former isn't available. Prior to matching the email address will be converted to ACE + * (ASCII-compatible-encoding). + * @GNUTLS_DT_KEY_PURPOSE_OID: The data contain a null-terminated key purpose OID. It will be matched + * against the certificate's Extended Key Usage extension. + * + * Enumeration of different typed-data options. They are used as input to certificate + * verification functions to provide information about the name and purpose of the + * certificate. Only a single option of a type can be provided to the relevant functions. + */ +typedef enum { + GNUTLS_DT_UNKNOWN = 0, + GNUTLS_DT_DNS_HOSTNAME = 1, + GNUTLS_DT_KEY_PURPOSE_OID = 2, + GNUTLS_DT_RFC822NAME = 3 +} gnutls_vdata_types_t; + +typedef struct { + gnutls_vdata_types_t type; + unsigned char *data; + unsigned int size; +} gnutls_typed_vdata_st; + +void gnutls_session_set_verify_cert(gnutls_session_t session, + const char *hostname, unsigned flags); + +void +gnutls_session_set_verify_cert2(gnutls_session_t session, + gnutls_typed_vdata_st * data, + unsigned elements, unsigned flags); + +unsigned int gnutls_session_get_verify_cert_status(gnutls_session_t); + int gnutls_session_set_premaster(gnutls_session_t session, unsigned int entity, gnutls_protocol_t version, @@ -1941,26 +1980,6 @@ int gnutls_certificate_verify_peers3(gnutls_session_t session, const char *hostname, unsigned int *status); -/** - * gnutls_vdata_types_t: - * @GNUTLS_DT_UNKNOWN: Unknown data type. - * @GNUTLS_DT_DNS_HOSTNAME: The data contain a null-terminated DNS hostname. - * @GNUTLS_DT_KEY_PURPOSE_OID: The data contain a null-terminated key purpose OID. - * - * Enumeration of different key exchange algorithms. - */ -typedef enum { - GNUTLS_DT_UNKNOWN = 0, - GNUTLS_DT_DNS_HOSTNAME = 1, - GNUTLS_DT_KEY_PURPOSE_OID = 2 -} gnutls_vdata_types_t; - -typedef struct { - gnutls_vdata_types_t type; - unsigned char *data; - unsigned int size; -} gnutls_typed_vdata_st; - int gnutls_certificate_verify_peers(gnutls_session_t session, gnutls_typed_vdata_st * data, @@ -2346,6 +2365,7 @@ int gnutls_fips140_mode_enabled(void); #define GNUTLS_E_AUTH_ERROR -343 #define GNUTLS_E_NO_APPLICATION_PROTOCOL -344 #define GNUTLS_E_SOCKETS_INIT_ERROR -345 +#define GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR -348 #define GNUTLS_E_SELF_TEST_ERROR -400 #define GNUTLS_E_NO_SELF_TEST -401 diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 8430932682..801b048b81 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -1026,6 +1026,9 @@ GNUTLS_3_1_0 { gnutls_x509_othername_to_virtual; _gnutls_global_init_skip; gnutls_session_set_verify_function; + gnutls_session_set_verify_cert; + gnutls_session_set_verify_cert2; + gnutls_session_get_verify_cert_status; } GNUTLS_3_0_0; GNUTLS_FIPS140 { diff --git a/tests/Makefile.am b/tests/Makefile.am index 665ce276a1..b1cdf90bc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -89,7 +89,7 @@ ctests = mini-record-2 simple gc set_pkcs12_cred certder certuniqueid \ fips-test mini-global-load name-constraints x509-extensions \ long-session-id mini-x509-callbacks-intr \ crlverify init_fds mini-rehandshake-2 sign-md5-rep global-init-override \ - version-checks mini-server-name mini-session-verify-function + version-checks mini-server-name mini-session-verify-function auto-verify if ENABLE_PKCS11 if !HAVE_BUGGY_P11_KIT diff --git a/tests/auto-verify.c b/tests/auto-verify.c new file mode 100644 index 0000000000..afd489105d --- /dev/null +++ b/tests/auto-verify.c @@ -0,0 +1,561 @@ +/* + * Copyright (C) 2008-2012 Free Software Foundation, Inc. + * + * Author: Simon Josefsson + * + * 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 <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <gnutls/gnutls.h> +#include <gnutls/x509.h> +#include "utils.h" +#include "eagain-common.h" + +/* This tests gnutls_certificate_set_x509_key() */ + +const char *side; + +static void tls_log_func(int level, const char *str) +{ + fprintf(stderr, "%s|<%d>| %s", side, level, str); +} + +static unsigned char ca_cert_pem[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIC4DCCAcigAwIBAgIBADANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwRDQS0w\n" +"MCIYDzIwMTQwNDA5MDgwMjM0WhgPOTk5OTEyMzEyMzU5NTlaMA8xDTALBgNVBAMT\n" +"BENBLTAwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCuLSye8pe3yWKZ\n" +"Yp7tLQ4ImwLqqh1aN7x9pc5spLDj6krVArzkyyYDcWvtQNDjErEfLUrZZrCc4aIl\n" +"oU1Ghb92kI8ofZnHFbj3z5zdcWqiPppj5Y+hRdc4LszTWb+itrD9Ht/D67EK+m7W\n" +"ev6xxUdyiBYUmb2O3CnPZpUVshMRtEe45EDGI5hUgL2n4Msj41htTq8hATYPXgoq\n" +"gQUyXFpKAX5XDCyOG+FC6jmEys7UCRYv3SCl7TPWJ4cm+lHcFI2/OTOCBvMlKN2J\n" +"mWCdfnudZldqthin+8fR9l4nbuutOfPNt1Dj9InDzWZ1W/o4LrjKa7fsvszj2Z5A\n" +"Fn+xN/4zAgMBAAGjQzBBMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcE\n" +"ADAdBgNVHQ4EFgQUwRHwbXyPosKNNkBiZduEwL5ZCwswDQYJKoZIhvcNAQELBQAD\n" +"ggEBAEKr0b7WoJL+L8St/LEITU/i7FwFrCP6DkbaNo0kgzPmwnvNmw88MLI6UKwE\n" +"JecnjFhurRBBZ4FA85ucNyizeBnuXqFcyJ20+XziaXGPKV/ugKyYv9KBoTYkQOCh\n" +"nbOthmDqjvy2UYQj0BU2dOywkjUKWhYHEZLBpZYck0Orynxydwil5Ncsz4t3smJw\n" +"ahzCW8SzBFTiO99qQBCH2RH1PbUYzfAnJxZS2VScpcqlu9pr+Qv7r8E3p9qHxnQM\n" +"gO5laWO6lc13rNsbZRrtlCvacsiDSuDnS8EVXm0ih4fAntpRHacPbXZbOPQqJ/+1\n" +"G7/qJ6cDC/9aW+fU80ogTkAoFg4=\n" +"-----END CERTIFICATE-----\n"; + +const gnutls_datum_t ca_cert = { ca_cert_pem, + sizeof(ca_cert_pem) +}; + +static unsigned char server_cert_pem[] = +"-----BEGIN CERTIFICATE-----\n" +"MIIDOjCCAiKgAwIBAgIMU0T+mwoDu5uVLKeeMA0GCSqGSIb3DQEBCwUAMA8xDTAL\n" +"BgNVBAMTBENBLTEwIhgPMjAxNDA0MDkwODAyMzVaGA85OTk5MTIzMTIzNTk1OVow\n" +"EzERMA8GA1UEAxMIc2VydmVyLTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" +"AoIBAQDXfvgsMWXHNf3iUaEoZSNztZZr6+UdBkoUhbdWJDR+GwR+GHfnYaYHsuqb\n" +"bNEl/QFI+8Jeth0SmG7TNB+b/AlHFoBm8TwBt7H+Mn6AQIdo872Vs262UkHgbZN6\n" +"dEQeRCgiXmlsOVe+MVpf79Xi32MYz1FZ/ueS6tr8sIDhECThIZkq2eulVjAV86N2\n" +"zQ72Ml1k8rPw4SdK5OFhcXNdXr6CsAol8MmiORKDF0iAZxwtFVc00nBGqQC5rwrN\n" +"3A8czH5TsvyvrcW0mwV2XOVvZM5kFM1T/X0jF6RQHiGGFBYK4s6JZxSSOhJMFYYh\n" +"koPEKsuVZdmBJ2yTTdGumHZfG9LDAgMBAAGjgY0wgYowDAYDVR0TAQH/BAIwADAU\n" +"BgNVHREEDTALgglsb2NhbGhvc3QwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0P\n" +"AQH/BAUDAwegADAdBgNVHQ4EFgQURXiN5VD5vgqAprhd/37ldGKv4/4wHwYDVR0j\n" +"BBgwFoAU8MUzmkotjSmVa5r1ejMkMQ6BiZYwDQYJKoZIhvcNAQELBQADggEBABSU\n" +"cmMX0nGeg43itPnLjSTIUuYEamRhfsFDwgRYQn5w+BcFG1p0scBRxLAShUEb9A2A\n" +"oEJV4rQDpCn9bcMrMHhTCR5sOlLh/2o9BROjK0+DjQLDkooQK5xa+1GYEiy6QYCx\n" +"QjdCCnMhHh24oP2/vUggRKhevvD2QQFKcCDT6n13RFYm+HX82gIh6SAtRs0oahY5\n" +"k9CM9TYRPzXy+tQqhZisJzc8BLTW/XA97kAJW6+hUhPir7AYR6BKJhNeIxcN/yMy\n" +"jsHzWDLezip/8q+kzw658V5e40hne7ZaJycGUaUdLVnJcpNtBgGE82TRS/XZSQKF\n" +"fpy8FLGcJynqlIOzdKs=\n" +"-----END CERTIFICATE-----\n" +"-----BEGIN CERTIFICATE-----\n" +"MIIDATCCAemgAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwRDQS0w\n" +"MCIYDzIwMTQwNDA5MDgwMjM0WhgPOTk5OTEyMzEyMzU5NTlaMA8xDTALBgNVBAMT\n" +"BENBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZq3sA+mjFadII\n" +"EMDHfj1fYh+UOUSa8c814E9NfCdYZ9Z11BmPpBeR5mXV12j1DKjkTlqTUL7s4lVR\n" +"RKfyAdCpQIfeXHDeTYYUq2uBnbi5YMG5Y+WbCiYacgRU3IypYrSzaeh1mY7GiEFe\n" +"U/NaImHLCf+TdAvTJ3Fo0QPe5QN2Lrv6l//cqOv7enZ91KRWxClDMM6EAr+C/7dk\n" +"rOTXRrCuH/e/KVBXEJ/YeSYPmBIwolGktRrGdsVagdqYArr4dhJ7VThIVRUX1Ijl\n" +"THCLstI/LuD8WkDccU3ZSdm47f2U43p/+rSO0MiNOXiaskeK56G/9DbJEeETUbzm\n" +"/B2712MVAgMBAAGjZDBiMA8GA1UdEwEB/wQFMAMBAf8wDwYDVR0PAQH/BAUDAwcE\n" +"ADAdBgNVHQ4EFgQU8MUzmkotjSmVa5r1ejMkMQ6BiZYwHwYDVR0jBBgwFoAUwRHw\n" +"bXyPosKNNkBiZduEwL5ZCwswDQYJKoZIhvcNAQELBQADggEBACKxBPj9u1t52uIF\n" +"eQ2JPb8/u+MBttvSLo0qPKXwpc4q8hNclh66dpqGWiF0iSumsKyKU54r6CIF9Ikm\n" +"t1V1GR9Ll4iTnz3NdIt1w3ns8rSlU5O/dgKysK/1C/5xJWEUYtEO5mnyi4Zaf8FB\n" +"hKmQ1aWF5dTB81PVAQxyCiFEnH7YumK7pJeIpnCOPIqLZLUHfrTUeL8zONF4i5Sb\n" +"7taZ8SQ6b7IaioU+NJ50uT2wy34lsyvCWf76Azezv9bggkdNDo/7ktMgsfRrSyM8\n" +"+MVob5ePGTjKx5yMy/sy2vUkkefwW3RiEss/y2JRb8Hw7nDlA9ttilYKFwGFwRvw\n" +"KRsXqo8=\n" +"-----END CERTIFICATE-----\n"; + +const gnutls_datum_t server_cert = { server_cert_pem, + sizeof(server_cert_pem) +}; + +static unsigned char server_key_pem[] = +"-----BEGIN RSA PRIVATE KEY-----\n" +"MIIEpAIBAAKCAQEA1374LDFlxzX94lGhKGUjc7WWa+vlHQZKFIW3ViQ0fhsEfhh3\n" +"52GmB7Lqm2zRJf0BSPvCXrYdEphu0zQfm/wJRxaAZvE8Abex/jJ+gECHaPO9lbNu\n" +"tlJB4G2TenREHkQoIl5pbDlXvjFaX+/V4t9jGM9RWf7nkura/LCA4RAk4SGZKtnr\n" +"pVYwFfOjds0O9jJdZPKz8OEnSuThYXFzXV6+grAKJfDJojkSgxdIgGccLRVXNNJw\n" +"RqkAua8KzdwPHMx+U7L8r63FtJsFdlzlb2TOZBTNU/19IxekUB4hhhQWCuLOiWcU\n" +"kjoSTBWGIZKDxCrLlWXZgSdsk03Rrph2XxvSwwIDAQABAoIBAB7trDS7ij4DM8MN\n" +"sDGaAnKS91nZ63I0+uDjKCMG4znOKuDmJh9hVnD4bs+L2KC5JTwSVh09ygJnOlC5\n" +"xGegzrwTMK6VpOUiNjujh6BkooqfoPAhZpxoReguEeKbWUN2yMPWBQ9xU3SKpMvs\n" +"IiiDozdmWeiuuxHM/00REA49QO3Gnx2logeB+fcvXXD1UiZV3x0xxSApiJt1sr2r\n" +"NmqSyGdNUgpmnTP8zbKnDaRe5Wj4tj1TCTLE/HZ0tzdRuwlkIqvcpGg1LMtKm5N8\n" +"xIWjTGMFwGjG+OF8LGqHLH+28pI3iMB6QqO2YLwOp+WZKImKP3+Dp3s8lCw8t8cm\n" +"q5/Qc9ECgYEA2xwxm+pFkrFmZNLCakP/6S5AZqpfSBRUlF/uX2pBKO7o6I6aOV9o\n" +"zq2QWYIZfdyD+9MvAFUQ36sWfTVWpGA34WGtsGtcRRygKKTigpJHvBldaPxiuYuk\n" +"xbS54nWUdix/JzyQAy22xJXlp4XJvtFJjHhA2td0XA7tfng9n8jmvEUCgYEA+8cA\n" +"uFIQFbaZ2y6pnOvlVj8OH0f1hZa9M+3q01fWy1rnDAsLrIzJy8TZnBtpDwy9lAun\n" +"Sa6wzu6qeHmF17xwk5U7BCyK2Qj/9KhRLg1mnDebQ/CiLSAaJVnrYFp9Du96fTkN\n" +"ollvbFiGF92QwPTDf2f1gHZQEPwa+f/ox37ad2cCgYEAwMgXpfUD7cOEMeV2BQV7\n" +"XnDBXRM97i9lE38sPmtAlYFPD36Yly4pCt+PCBH9181zmtf+nK47wG/Jw7RwXQQD\n" +"ZpwItBZiArTi/Z/FY9jMoOU4WKznOBVzjjgq7ONDEo6n+Z/BnepUyraQb0q5bNi7\n" +"e4o6ldHHoU/JCeNFZRbgXHkCgYA6vJU9at+XwS6phHxLQHkTIsivoYD0tlLTX4it\n" +"30sby8wk8hq6GWomYHkHwxlCSo2bkRBozxkuXV1ll6wSxUJaG7FV6vJFaaUUtYOi\n" +"w7uRbCOLuQKMlnWjCxQvOUz9g/7GYd39ZvHoi8pUnPrdGPzWpzEN1AwfukCs2/e5\n" +"Oq3KtwKBgQCkHmDU8h0kOfN28f8ZiyjJemQMNoOGiJqnGexaKvsRd+bt4H+7DsWQ\n" +"OnyKm/oR0wCCSmFM5aQc6GgzPD7orueKVYHChbY7HLTWKRHNs6Rlk+6hXJvOld0i\n" +"Cl7KqL2x2ibGMtt4LtSntdzWqa87N7vCWMSTmvd8uLgflBs33xUIiQ==\n" +"-----END RSA PRIVATE KEY-----\n"; + +static unsigned char cert_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 cli_cert = { cert_pem, sizeof(cert_pem) - 1}; + +static unsigned char key_pem[] = + "-----BEGIN RSA PRIVATE KEY-----\n" + "MIICXAIBAAKBgQC7ZkP18sXXtozMxd/1iDuxyUtqDqGtIFBACIChT1yj0Phsz+Y8\n" + "9+wEdhMXi2SJIlvA3VN8O+18BLuAuSi+jpvGjqClEsv1Vx6i57u3M0mf47tKrmpN\n" + "aP/JEeIyjc49gAuNde/YAIGPKAQDoCKNYQQH+rY3fSEHSdIJYWmYkKNYqQIDAQAB\n" + "AoGADpmARG5CQxS+AesNkGmpauepiCz1JBF/JwnyiX6vEzUh0Ypd39SZztwrDxvF\n" + "PJjQaKVljml1zkJpIDVsqvHdyVdse8M+Qn6hw4x2p5rogdvhhIL1mdWo7jWeVJTF\n" + "RKB7zLdMPs3ySdtcIQaF9nUAQ2KJEvldkO3m/bRJFEp54k0CQQDYy+RlTmwRD6hy\n" + "7UtMjR0H3CSZJeQ8svMCxHLmOluG9H1UKk55ZBYfRTsXniqUkJBZ5wuV1L+pR9EK\n" + "ca89a+1VAkEA3UmBelwEv2u9cAU1QjKjmwju1JgXbrjEohK+3B5y0ESEXPAwNQT9\n" + "TrDM1m9AyxYTWLxX93dI5QwNFJtmbtjeBQJARSCWXhsoaDRG8QZrCSjBxfzTCqZD\n" + "ZXtl807ymCipgJm60LiAt0JLr4LiucAsMZz6+j+quQbSakbFCACB8SLV1QJBAKZQ\n" + "YKf+EPNtnmta/rRKKvySsi3GQZZN+Dt3q0r094XgeTsAqrqujVNfPhTMeP4qEVBX\n" + "/iVX2cmMTSh3w3z8MaECQEp0XJWDVKOwcTW6Ajp9SowtmiZ3YDYo1LF9igb4iaLv\n" + "sWZGfbnU3ryjvkb6YuFjgtzbZDZHWQCo8/cOtOBmPdk=\n" + "-----END RSA PRIVATE KEY-----\n"; +const gnutls_datum_t cli_key = { key_pem, sizeof(key_pem) - 1}; + +const gnutls_datum_t server_key = { server_key_pem, + sizeof(server_key_pem) +}; + +static +void test_failure(void) +{ + int exit_code = EXIT_SUCCESS; + int ret; + /* Server stuff. */ + gnutls_certificate_credentials_t serverx509cred; + gnutls_session_t server; + int sret = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_certificate_credentials_t clientx509cred; + gnutls_session_t client; + int cret = GNUTLS_E_AGAIN; + gnutls_x509_crt_t *crts; + unsigned int crts_size; + unsigned i; + gnutls_typed_vdata_st vdata[2]; + gnutls_x509_privkey_t pkey; + unsigned status; + + to_server_len = 0; + to_client_len = 0; + + ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &server_cert, GNUTLS_X509_FMT_PEM, + GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_privkey_init(&pkey); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(pkey, &server_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + /* Init server */ + gnutls_certificate_allocate_credentials(&serverx509cred); + gnutls_certificate_set_x509_key(serverx509cred, crts, crts_size, pkey); + gnutls_x509_privkey_deinit(pkey); + for (i=0;i<crts_size;i++) + gnutls_x509_crt_deinit(crts[i]); + gnutls_free(crts); + + gnutls_init(&server, GNUTLS_SERVER); + gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, + serverx509cred); + gnutls_priority_set_direct(server, + "NORMAL:-CIPHER-ALL:+AES-128-GCM", + NULL); + gnutls_transport_set_push_function(server, server_push); + gnutls_transport_set_pull_function(server, server_pull); + gnutls_transport_set_ptr(server, server); + gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUEST); + + /* Init client */ + /* Init client */ + ret = gnutls_certificate_allocate_credentials(&clientx509cred); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_key_mem(clientx509cred, + &cli_cert, &cli_key, + GNUTLS_X509_FMT_PEM); + + ret = gnutls_init(&client, GNUTLS_CLIENT); + if (ret < 0) + exit(1); + + ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, + clientx509cred); + if (ret < 0) + exit(1); + + gnutls_priority_set_direct(client, "NORMAL", NULL); + gnutls_transport_set_push_function(client, client_push); + gnutls_transport_set_pull_function(client, client_pull); + gnutls_transport_set_ptr(client, client); + + memset(vdata, 0, sizeof(vdata)); + + /* check with wrong hostname */ + vdata[0].type = GNUTLS_DT_DNS_HOSTNAME; + vdata[0].data = (void*)"localhost1"; + + vdata[1].type = GNUTLS_DT_KEY_PURPOSE_OID; + vdata[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER; + + gnutls_session_set_verify_cert2(client, vdata, 2, 0); + + HANDSHAKE_EXPECT(client, server, GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR, GNUTLS_E_AGAIN); + + status = gnutls_session_get_verify_cert_status(client); + + if (status == 0) { + fail("should not have accepted!\n"); + exit(1); + } + + gnutls_deinit(client); + gnutls_deinit(server); + + gnutls_certificate_free_credentials(serverx509cred); + gnutls_certificate_free_credentials(clientx509cred); + + if (debug > 0) { + if (exit_code == 0) + fprintf(stderr, "%s: Self-test successful", __func__); + else + fprintf(stderr, "%s: Self-test failed", __func__); + } +} + +static +void test_success1(void) +{ + int exit_code = EXIT_SUCCESS; + int ret; + /* Server stuff. */ + gnutls_certificate_credentials_t serverx509cred; + gnutls_session_t server; + int sret = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_certificate_credentials_t clientx509cred; + gnutls_session_t client; + int cret = GNUTLS_E_AGAIN; + gnutls_x509_crt_t *crts; + unsigned int crts_size; + unsigned i; + gnutls_typed_vdata_st vdata[2]; + gnutls_x509_privkey_t pkey; + unsigned status; + + to_server_len = 0; + to_client_len = 0; + + ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &server_cert, GNUTLS_X509_FMT_PEM, + GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_privkey_init(&pkey); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(pkey, &server_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + /* Init server */ + gnutls_certificate_allocate_credentials(&serverx509cred); + gnutls_certificate_set_x509_key(serverx509cred, crts, crts_size, pkey); + gnutls_x509_privkey_deinit(pkey); + for (i=0;i<crts_size;i++) + gnutls_x509_crt_deinit(crts[i]); + gnutls_free(crts); + + gnutls_init(&server, GNUTLS_SERVER); + gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, + serverx509cred); + gnutls_priority_set_direct(server, + "NORMAL:-CIPHER-ALL:+AES-128-GCM", + NULL); + gnutls_transport_set_push_function(server, server_push); + gnutls_transport_set_pull_function(server, server_pull); + gnutls_transport_set_ptr(server, server); + gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUEST); + + /* Init client */ + /* Init client */ + ret = gnutls_certificate_allocate_credentials(&clientx509cred); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_key_mem(clientx509cred, + &cli_cert, &cli_key, + GNUTLS_X509_FMT_PEM); + + ret = gnutls_init(&client, GNUTLS_CLIENT); + if (ret < 0) + exit(1); + + ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, + clientx509cred); + if (ret < 0) + exit(1); + + gnutls_priority_set_direct(client, "NORMAL", NULL); + gnutls_transport_set_push_function(client, client_push); + gnutls_transport_set_pull_function(client, client_pull); + gnutls_transport_set_ptr(client, client); + + memset(vdata, 0, sizeof(vdata)); + + /* check with wrong hostname */ + vdata[0].type = GNUTLS_DT_DNS_HOSTNAME; + vdata[0].data = (void*)"localhost"; + + vdata[1].type = GNUTLS_DT_KEY_PURPOSE_OID; + vdata[1].data = (void*)GNUTLS_KP_TLS_WWW_SERVER; + + gnutls_session_set_verify_cert2(client, vdata, 2, 0); + + HANDSHAKE(client, server); + + status = gnutls_session_get_verify_cert_status(client); + + if (status != 0) { + fail("%s: should have accepted: %u!\n", __func__, status); + exit(1); + } + + gnutls_deinit(client); + gnutls_deinit(server); + + gnutls_certificate_free_credentials(serverx509cred); + gnutls_certificate_free_credentials(clientx509cred); + + if (debug > 0) { + if (exit_code == 0) + fprintf(stderr, "%s: Self-test successful", __func__); + else + fprintf(stderr, "%s: Self-test failed", __func__); + } +} + +static +void test_success2(void) +{ + int exit_code = EXIT_SUCCESS; + int ret; + /* Server stuff. */ + gnutls_certificate_credentials_t serverx509cred; + gnutls_session_t server; + int sret = GNUTLS_E_AGAIN; + /* Client stuff. */ + gnutls_certificate_credentials_t clientx509cred; + gnutls_session_t client; + int cret = GNUTLS_E_AGAIN; + gnutls_x509_crt_t *crts; + unsigned int crts_size; + unsigned i; + gnutls_x509_privkey_t pkey; + unsigned status; + + to_server_len = 0; + to_client_len = 0; + + ret = gnutls_x509_crt_list_import2(&crts, &crts_size, &server_cert, GNUTLS_X509_FMT_PEM, + GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = gnutls_x509_privkey_init(&pkey); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + ret = + gnutls_x509_privkey_import(pkey, &server_key, + GNUTLS_X509_FMT_PEM); + if (ret < 0) { + fprintf(stderr, "error: %s\n", gnutls_strerror(ret)); + exit(1); + } + + /* Init server */ + gnutls_certificate_allocate_credentials(&serverx509cred); + gnutls_certificate_set_x509_key(serverx509cred, crts, crts_size, pkey); + gnutls_x509_privkey_deinit(pkey); + for (i=0;i<crts_size;i++) + gnutls_x509_crt_deinit(crts[i]); + gnutls_free(crts); + + gnutls_init(&server, GNUTLS_SERVER); + gnutls_credentials_set(server, GNUTLS_CRD_CERTIFICATE, + serverx509cred); + gnutls_priority_set_direct(server, + "NORMAL:-CIPHER-ALL:+AES-128-GCM", + NULL); + gnutls_transport_set_push_function(server, server_push); + gnutls_transport_set_pull_function(server, server_pull); + gnutls_transport_set_ptr(server, server); + gnutls_certificate_server_set_request(server, GNUTLS_CERT_REQUEST); + + /* Init client */ + /* Init client */ + ret = gnutls_certificate_allocate_credentials(&clientx509cred); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_trust_mem(clientx509cred, &ca_cert, GNUTLS_X509_FMT_PEM); + if (ret < 0) + exit(1); + + ret = gnutls_certificate_set_x509_key_mem(clientx509cred, + &cli_cert, &cli_key, + GNUTLS_X509_FMT_PEM); + + ret = gnutls_init(&client, GNUTLS_CLIENT); + if (ret < 0) + exit(1); + + ret = gnutls_credentials_set(client, GNUTLS_CRD_CERTIFICATE, + clientx509cred); + if (ret < 0) + exit(1); + + gnutls_priority_set_direct(client, "NORMAL", NULL); + gnutls_transport_set_push_function(client, client_push); + gnutls_transport_set_pull_function(client, client_pull); + gnutls_transport_set_ptr(client, client); + + gnutls_session_set_verify_cert(client, "localhost", 0); + + HANDSHAKE(client, server); + + status = gnutls_session_get_verify_cert_status(client); + + if (status != 0) { + fail("%s: should have accepted: %u!\n", __func__, status); + exit(1); + } + + gnutls_deinit(client); + gnutls_deinit(server); + + gnutls_certificate_free_credentials(serverx509cred); + gnutls_certificate_free_credentials(clientx509cred); + + if (debug > 0) { + if (exit_code == 0) + fprintf(stderr, "%s: Self-test successful", __func__); + else + fprintf(stderr, "%s: Self-test failed", __func__); + } +} + +void doit(void) +{ + global_init(); + + /* General init. */ + gnutls_global_set_log_function(tls_log_func); + if (debug) + gnutls_global_set_log_level(2); + + test_failure(); + test_success1(); + test_success2(); + + gnutls_global_deinit(); + +} |