summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-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
11 files changed, 209 insertions, 26 deletions
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 {