summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS9
-rw-r--r--doc/cha-cert-auth.texi15
-rw-r--r--doc/cha-gtls-app.texi42
-rw-r--r--doc/examples/ex-client-x509.c95
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/auto-verify.c147
-rw-r--r--lib/gnutls_alert.c1
-rw-r--r--lib/gnutls_cert.c2
-rw-r--r--lib/gnutls_errors.c2
-rw-r--r--lib/gnutls_handshake.c2
-rw-r--r--lib/gnutls_int.h8
-rw-r--r--lib/gnutls_priority.c5
-rw-r--r--lib/gnutls_x509.c3
-rw-r--r--lib/includes/gnutls/gnutls.h.in60
-rw-r--r--lib/libgnutls.map3
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/auto-verify.c561
17 files changed, 833 insertions, 126 deletions
diff --git a/NEWS b/NEWS
index 261259de97..b350d9d06a 100644
--- a/NEWS
+++ b/NEWS
@@ -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();
+
+}