This provides two modules for handling TLS
* virNetTLSContext provides the process-wide state, in particular
all the x509 credentials, DH params and x509 whitelists
* virNetTLSSession provides the per-connection state, ie the
TLS session itself.
The virNetTLSContext provides APIs for validating a TLS session's
x509 credentials. The virNetTLSSession includes APIs for performing
the initial TLS handshake and sending/recving encrypted data
* src/Makefile.am: Add to libvirt-net-rpc.la
* src/rpc/virnettlscontext.c, src/rpc/virnettlscontext.h: Generic
TLS handling code
---
po/POTFILES.in | 1 +
src/Makefile.am | 6 +-
src/rpc/virnettlscontext.c | 664 ++++++++++++++++++++++++++++++++++++++++++++
src/rpc/virnettlscontext.h | 90 ++++++
4 files changed, 760 insertions(+), 1 deletions(-)
create mode 100644 src/rpc/virnettlscontext.c
create mode 100644 src/rpc/virnettlscontext.h
diff --git a/po/POTFILES.in b/po/POTFILES.in
index bc45b3d..39cecdd 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -60,6 +60,7 @@ src/qemu/qemu_security_dac.c
src/remote/remote_driver.c
src/rpc/virnetmessage.c
src/rpc/virnetsocket.c
+src/rpc/virnettlscontext.c
src/secret/secret_driver.c
src/security/security_apparmor.c
src/security/security_driver.c
diff --git a/src/Makefile.am b/src/Makefile.am
index a19b304..10fce7d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1121,12 +1121,16 @@ EXTRA_DIST += $(LIBVIRT_QEMU_SYMBOL_FILE)
noinst_LTLIBRARIES += libvirt-net-rpc.la
libvirt_net_rpc_la_SOURCES = \
+ ../daemon/event.c \
rpc/virnetmessage.h rpc/virnetmessage.c \
rpc/virnetprotocol.h rpc/virnetprotocol.c \
- rpc/virnetsocket.h rpc/virnetsocket.c
+ rpc/virnetsocket.h rpc/virnetsocket.c \
+ rpc/virnettlscontext.h rpc/virnettlscontext.c
libvirt_net_rpc_la_CFLAGS = \
+ $(GNUTLS_CFLAGS) \
$(AM_CFLAGS)
libvirt_net_rpc_la_LDFLAGS = \
+ $(GNUTLS_LIBS) \
$(AM_LDFLAGS) \
$(CYGWIN_EXTRA_LDFLAGS) \
$(MINGW_EXTRA_LDFLAGS)
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c
new file mode 100644
index 0000000..02da41a
--- /dev/null
+++ b/src/rpc/virnettlscontext.c
@@ -0,0 +1,664 @@
+/*
+ * virnettlscontext.c: TLS encryption/x509 handling
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+#include <unistd.h>
+#include <fnmatch.h>
+#include <stdlib.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include "gnutls_1_0_compat.h"
+
+#include "virnettlscontext.h"
+
+#include "memory.h"
+#include "virterror_internal.h"
+#include "util.h"
+#include "logging.h"
+
+#define DH_BITS 1024
+
+#define VIR_FROM_THIS VIR_FROM_RPC
+
+#define virNetError(code, ...) \
+ virReportErrorHelper(NULL, VIR_FROM_RPC, code, __FILE__, \
+ __FUNCTION__, __LINE__, __VA_ARGS__)
+
+struct _virNetTLSContext {
+ int refs;
+
+ gnutls_certificate_credentials_t x509cred;
+ gnutls_dh_params_t dhParams;
+
+ bool isServer;
+ bool requireValidCert;
+ const char *const*x509dnWhitelist;
+};
+
+struct _virNetTLSSession {
+ int refs;
+
+ bool handshakeComplete;
+
+ char *hostname;
+ gnutls_session_t session;
+ virNetTLSSessionWriteFunc writeFunc;
+ virNetTLSSessionReadFunc readFunc;
+ void *opaque;
+};
+
+
+static int
+virNetTLSContextCheckCertFile(const char *type, const char *file)
+{
+ if (access(file, R_OK) < 0) {
+ virReportSystemError(errno,
+ _("Cannot read %s '%s'"),
+ type, file);
+ return -1;
+ }
+ return 0;
+}
+
+
+static void virNetTLSLog(int level, const char *str) {
+ VIR_DEBUG("%d %s", level, str);
+}
+
+static virNetTLSContextPtr virNetTLSContextNew(const char *ca_file,
+ const char *crl_file,
+ const char *cert_file,
+ const char *key_file,
+ const char *const*x509dnWhitelist,
+ bool requireValidCert,
+ bool isServer)
+{
+ virNetTLSContextPtr ctxt;
+ char *gnutlsdebug;
+ int err;
+
+ if (VIR_ALLOC(ctxt) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ ctxt->refs = 1;
+
+ /* Initialise GnuTLS. */
+ gnutls_global_init();
+
+ if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) {
+ int val;
+ if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0)
+ val = 10;
+ gnutls_global_set_log_level(val);
+ gnutls_global_set_log_function(virNetTLSLog);
+ VIR_DEBUG0("Enabled GNUTLS debug");
+ }
+
+
+ err = gnutls_certificate_allocate_credentials(&ctxt->x509cred);
+ if (err) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to allocate x509 credentials: %s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+
+ if (ca_file && ca_file[0] != '\0') {
+ if (virNetTLSContextCheckCertFile("CA certificate", ca_file) < 0)
+ goto error;
+
+ VIR_DEBUG("loading CA cert from %s", ca_file);
+ err = gnutls_certificate_set_x509_trust_file(ctxt->x509cred,
+ ca_file,
+ GNUTLS_X509_FMT_PEM);
+ if (err < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to set x509 CA certificate: %s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+ }
+
+ if (crl_file && crl_file[0] != '\0') {
+ if (virNetTLSContextCheckCertFile("CA revocation list", crl_file) <
0)
+ goto error;
+
+ VIR_DEBUG("loading CRL from %s", crl_file);
+ err = gnutls_certificate_set_x509_crl_file(ctxt->x509cred,
+ crl_file,
+ GNUTLS_X509_FMT_PEM);
+ if (err < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to set x509 certificate revocation list:
%s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+ }
+
+ if (cert_file && cert_file[0] != '\0' && key_file &&
key_file[0] != '\0') {
+ if (virNetTLSContextCheckCertFile("server certificate", cert_file) <
0)
+ goto error;
+ if (virNetTLSContextCheckCertFile("server key", key_file) < 0)
+ goto error;
+ VIR_DEBUG("loading cert and key from %s and %s", cert_file, key_file);
+ err =
+ gnutls_certificate_set_x509_key_file(ctxt->x509cred,
+ cert_file, key_file,
+ GNUTLS_X509_FMT_PEM);
+ if (err < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to set x509 key and certificate: %s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+ }
+
+ /* Generate Diffie Hellman parameters - for use with DHE
+ * kx algorithms. These should be discarded and regenerated
+ * once a day, once a week or once a month. Depending on the
+ * security requirements.
+ */
+ if (isServer) {
+ err = gnutls_dh_params_init(&ctxt->dhParams);
+ if (err < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to initialize diffie-hellman parameters:
%s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+ err = gnutls_dh_params_generate2(ctxt->dhParams, DH_BITS);
+ if (err < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to generate diffie-hellman parameters: %s"),
+ gnutls_strerror (err));
+ goto error;
+ }
+
+ gnutls_certificate_set_dh_params(ctxt->x509cred,
+ ctxt->dhParams);
+ }
+
+ ctxt->requireValidCert = requireValidCert;
+ ctxt->x509dnWhitelist = x509dnWhitelist;
+ ctxt->isServer = isServer;
+
+ return ctxt;
+
+error:
+ if (isServer)
+ gnutls_dh_params_deinit(ctxt->dhParams);
+ gnutls_certificate_free_credentials(ctxt->x509cred);
+ VIR_FREE(ctxt);
+ return NULL;
+}
+
+
+virNetTLSContextPtr virNetTLSContextNewServer(const char *ca_file,
+ const char *crl_file,
+ const char *cert_file,
+ const char *key_file,
+ const char *const*x509dnWhitelist,
+ bool requireValidCert)
+{
+ return virNetTLSContextNew(ca_file, crl_file, cert_file, key_file,
+ x509dnWhitelist, requireValidCert, true);
+}
+
+virNetTLSContextPtr virNetTLSContextNewClient(const char *ca_file,
+ const char *cert_file,
+ const char *key_file,
+ bool requireValidCert)
+{
+ return virNetTLSContextNew(ca_file, NULL, cert_file, key_file,
+ NULL, requireValidCert, false);
+}
+
+
+void virNetTLSContextRef(virNetTLSContextPtr ctxt)
+{
+ ctxt->refs++;
+}
+
+
+/* Check DN is on tls_allowed_dn_list. */
+static int
+virNetTLSContextCheckDN(virNetTLSContextPtr ctxt,
+ const char *dname)
+{
+ const char *const*wildcards;
+
+ /* If the list is not set, allow any DN. */
+ wildcards = ctxt->x509dnWhitelist;
+ if (!wildcards)
+ return 1;
+
+ while (*wildcards) {
+ if (fnmatch (*wildcards, dname, 0) == 0)
+ return 1;
+ wildcards++;
+ }
+
+ /* Print the client's DN. */
+ DEBUG(_("Failed whitelist check for client DN '%s'"), dname);
+
+ return 0; // Not found.
+}
+
+static int virNetTLSContextValidCertificate(virNetTLSContextPtr ctxt,
+ virNetTLSSessionPtr sess)
+{
+ int ret;
+ unsigned int status;
+ const gnutls_datum_t *certs;
+ unsigned int nCerts, i;
+ time_t now;
+ char name[256];
+ size_t namesize = sizeof name;
+
+ memset(name, 0, namesize);
+
+ if ((ret = gnutls_certificate_verify_peers2(sess->session, &status)) < 0){
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Unable to verify TLS peer: %s"),
+ gnutls_strerror(ret));
+ goto authdeny;
+ }
+
+ if ((now = time(NULL)) == ((time_t)-1)) {
+ virReportSystemError(errno, "%s",
+ _("cannot get current time"));
+ goto authfail;
+ }
+
+ if (status != 0) {
+ const char *reason = _("Invalid certificate");
+
+ if (status & GNUTLS_CERT_INVALID)
+ reason = _("The certificate is not trusted.");
+
+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ reason = _("The certificate hasn't got a known issuer.");
+
+ if (status & GNUTLS_CERT_REVOKED)
+ reason = _("The certificate has been revoked.");
+
+#ifndef GNUTLS_1_0_COMPAT
+ if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
+ reason = _("The certificate uses an insecure algorithm");
+#endif
+
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Certificate failed validation: %s"),
+ reason);
+ goto authdeny;
+ }
+
+ if (gnutls_certificate_type_get(sess->session) != GNUTLS_CRT_X509) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("Only x509 certificates are supported"));
+ goto authdeny;
+ }
+
+ if (!(certs = gnutls_certificate_get_peers(sess->session, &nCerts))) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("The certificate has no peers"));
+ goto authdeny;
+ }
+
+ for (i = 0; i < nCerts; i++) {
+ gnutls_x509_crt_t cert;
+
+ if (gnutls_x509_crt_init (&cert) < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("Unable to initialize certificate"));
+ goto authfail;
+ }
+
+ if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("Unable to load certificate"));
+ gnutls_x509_crt_deinit(cert);
+ goto authfail;
+ }
+
+ if (gnutls_x509_crt_get_expiration_time(cert) < now) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("The client certificate has expired"));
+ gnutls_x509_crt_deinit(cert);
+ goto authdeny;
+ }
+
+ if (gnutls_x509_crt_get_activation_time(cert) > now) {
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("The client certificate is not yet active"));
+ gnutls_x509_crt_deinit(cert);
+ goto authdeny;
+ }
+
+ if (i == 0) {
+ ret = gnutls_x509_crt_get_dn(cert, name, &namesize);
+ if (ret != 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed to get certificate distinguished name:
%s"),
+ gnutls_strerror(ret));
+ gnutls_x509_crt_deinit(cert);
+ goto authfail;
+ }
+
+ if (!virNetTLSContextCheckDN(ctxt, name)) {
+ /* This is the most common error: make it informative. */
+ virNetError(VIR_ERR_SYSTEM_ERROR, "%s",
+ _("Client's Distinguished Name is not on the list
"
+ "of allowed clients (tls_allowed_dn_list). Use
"
+ "'certtool -i --infile clientcert.pem' to view
the"
+ "Distinguished Name field in the client
certificate,"
+ "or run this daemon with --verbose option."));
+ gnutls_x509_crt_deinit(cert);
+ goto authdeny;
+ }
+
+ if (sess->hostname &&
+ !gnutls_x509_crt_check_hostname(cert, sess->hostname)) {
+ virNetError(VIR_ERR_RPC,
+ _("Certificate's owner does not match the hostname
(%s)"),
+ sess->hostname);
+ gnutls_x509_crt_deinit(cert);
+ goto authdeny;
+ }
+ }
+ }
+
+#if 0
+ PROBE(CLIENT_TLS_ALLOW, "fd=%d, name=%s",
+ virNetServerClientGetFD(client), name);
+#endif
+ return 0;
+
+authdeny:
+#if 0
+ PROBE(CLIENT_TLS_DENY, "fd=%d, name=%s",
+ virNetServerClientGetFD(client), name);
+#endif
+ return -1;
+
+authfail:
+#if 0
+ PROBE(CLIENT_TLS_FAIL, "fd=%d",
+ virNetServerClientGetFD(client));
+#endif
+ return -1;
+}
+
+int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt,
+ virNetTLSSessionPtr sess) {
+ if (virNetTLSContextValidCertificate(ctxt, sess) < 0) {
+ if (ctxt->requireValidCert) {
+ virNetError(VIR_ERR_AUTH_FAILED, "%s",
+ _("Failed to verify peer's certificate"));
+ return -1;
+ }
+ VIR_INFO0(_("Ignoring bad certificate at user request"));
+ }
+ return 0;
+}
+
+void virNetTLSContextFree(virNetTLSContextPtr ctxt)
+{
+ if (!ctxt)
+ return;
+
+ ctxt->refs--;
+ if (ctxt->refs > 0)
+ return;
+
+ gnutls_dh_params_deinit(ctxt->dhParams);
+ gnutls_certificate_free_credentials(ctxt->x509cred);
+ VIR_FREE(ctxt);
+}
+
+
+
+static ssize_t
+virNetTLSSessionPush(void *opaque, const void *buf, size_t len)
+{
+ virNetTLSSessionPtr sess = opaque;
+ if (!sess->writeFunc) {
+ VIR_WARN0("TLS session push with missing read function");
+ errno = EIO;
+ return -1;
+ };
+
+ return sess->writeFunc(buf, len, sess->opaque);
+}
+
+
+static ssize_t
+virNetTLSSessionPull(void *opaque, void *buf, size_t len)
+{
+ virNetTLSSessionPtr sess = opaque;
+ if (!sess->readFunc) {
+ VIR_WARN0("TLS session pull with missing read function");
+ errno = EIO;
+ return -1;
+ };
+
+ return sess->readFunc(buf, len, sess->opaque);
+}
+
+
+virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt,
+ const char *hostname)
+{
+ virNetTLSSessionPtr sess;
+ int err;
+ static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+
+ if (VIR_ALLOC(sess) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ sess->refs = 1;
+ if (hostname &&
+ !(sess->hostname = strdup(hostname))) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if ((err = gnutls_init(&sess->session,
+ ctxt->isServer ? GNUTLS_SERVER : GNUTLS_CLIENT)) != 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed to initialize TLS session: %s"),
+ gnutls_strerror(err));
+ goto error;
+ }
+
+ /* avoid calling all the priority functions, since the defaults
+ * are adequate.
+ */
+ if ((err = gnutls_set_default_priority(sess->session)) != 0 ||
+ (err = gnutls_certificate_type_set_priority(sess->session,
+ cert_type_priority))) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed to set TLS session priority %s"),
+ gnutls_strerror(err));
+ goto error;
+ }
+
+ if ((err = gnutls_credentials_set(sess->session,
+ GNUTLS_CRD_CERTIFICATE,
+ ctxt->x509cred)) != 0) {
+ virNetError(VIR_ERR_SYSTEM_ERROR,
+ _("Failed set TLS x509 credentials: %s"),
+ gnutls_strerror(err));
+ goto error;
+ }
+
+ /* request client certificate if any.
+ */
+ if (ctxt->isServer) {
+ gnutls_certificate_server_set_request(sess->session, GNUTLS_CERT_REQUEST);
+
+ gnutls_dh_set_prime_bits(sess->session, DH_BITS);
+ }
+
+ gnutls_transport_set_ptr(sess->session, sess);
+ gnutls_transport_set_push_function(sess->session,
+ virNetTLSSessionPush);
+ gnutls_transport_set_pull_function(sess->session,
+ virNetTLSSessionPull);
+
+ return sess;
+
+error:
+ virNetTLSSessionFree(sess);
+ return NULL;
+}
+
+
+void virNetTLSSessionRef(virNetTLSSessionPtr sess)
+{
+ sess->refs++;
+}
+
+void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess,
+ virNetTLSSessionWriteFunc writeFunc,
+ virNetTLSSessionReadFunc readFunc,
+ void *opaque)
+{
+ sess->writeFunc = writeFunc;
+ sess->readFunc = readFunc;
+ sess->opaque = opaque;
+}
+
+
+ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess,
+ const char *buf, size_t len)
+{
+ int ret;
+ ret = gnutls_record_send(sess->session, buf, len);
+
+ switch (ret) {
+ case GNUTLS_E_AGAIN:
+ errno = EAGAIN;
+ break;
+ case GNUTLS_E_INTERRUPTED:
+ errno = EINTR;
+ break;
+ case 0:
+ break;
+ default:
+ errno = EIO;
+ }
+
+ return ret >= 0 ? ret : -1;
+}
+
+ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess,
+ char *buf, size_t len)
+{
+ int ret;
+
+ ret = gnutls_record_recv(sess->session, buf, len);
+
+ switch (ret) {
+ case GNUTLS_E_AGAIN:
+ errno = EAGAIN;
+ break;
+ case GNUTLS_E_INTERRUPTED:
+ errno = EINTR;
+ break;
+ case 0:
+ break;
+ default:
+ errno = EIO;
+ }
+
+ return ret >= 0 ? ret : -1;
+}
+
+int virNetTLSSessionHandshake(virNetTLSSessionPtr sess)
+{
+ VIR_DEBUG("sess=%p", sess);
+ int ret = gnutls_handshake(sess->session);
+
+ if (ret == 0) {
+ sess->handshakeComplete = true;
+ VIR_DEBUG0("Handshake is complete");
+ return 0;
+ }
+ if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
+ return 1;
+
+#if 0
+ PROBE(CLIENT_TLS_FAIL, "fd=%d",
+ virNetServerClientGetFD(client));
+#endif
+
+ virNetError(VIR_ERR_AUTH_FAILED,
+ _("TLS handshake failed %s"),
+ gnutls_strerror (ret));
+ return -1;
+}
+
+virNetTLSSessionHandshakeStatus
+virNetTLSSessionGetHandshakeStatus(virNetTLSSessionPtr sess)
+{
+ if (sess->handshakeComplete)
+ return VIR_NET_TLS_HANDSHAKE_COMPLETE;
+ else if (gnutls_record_get_direction (sess->session) == 0)
+ return VIR_NET_TLS_HANDSHAKE_RECVING;
+ else
+ return VIR_NET_TLS_HANDSHAKE_SENDING;
+}
+
+int virNetTLSSessionGetKeySize(virNetTLSSessionPtr sess)
+{
+ gnutls_cipher_algorithm_t cipher;
+ int ssf;
+
+ cipher = gnutls_cipher_get(sess->session);
+ if (!(ssf = gnutls_cipher_get_key_size(cipher))) {
+ virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("invalid cipher size for TLS session"));
+ return -1;
+ }
+
+ return ssf;
+}
+
+
+void virNetTLSSessionFree(virNetTLSSessionPtr sess)
+{
+ if (!sess)
+ return;
+
+ sess->refs--;
+ if (sess->refs > 0)
+ return;
+
+ VIR_FREE(sess->hostname);
+ gnutls_deinit(sess->session);
+ VIR_FREE(sess);
+}
diff --git a/src/rpc/virnettlscontext.h b/src/rpc/virnettlscontext.h
new file mode 100644
index 0000000..88db141
--- /dev/null
+++ b/src/rpc/virnettlscontext.h
@@ -0,0 +1,90 @@
+/*
+ * virnettlscontext.h: TLS encryption/x509 handling
+ *
+ * Copyright (C) 2010 Red Hat, Inc.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __VIR_NET_TLS_CONTEXT_H__
+# define __VIR_NET_TLS_CONTEXT_H__
+
+# include <stdbool.h>
+# include <sys/types.h>
+
+typedef struct _virNetTLSContext virNetTLSContext;
+typedef virNetTLSContext *virNetTLSContextPtr;
+
+typedef struct _virNetTLSSession virNetTLSSession;
+typedef virNetTLSSession *virNetTLSSessionPtr;
+
+
+virNetTLSContextPtr virNetTLSContextNewServer(const char *ca_file,
+ const char *crl_file,
+ const char *cert_file,
+ const char *key_file,
+ const char *const*x509dnWhitelist,
+ bool requireValidCert);
+
+virNetTLSContextPtr virNetTLSContextNewClient(const char *ca_file,
+ const char *cert_file,
+ const char *key_file,
+ bool requireValidCert);
+
+void virNetTLSContextRef(virNetTLSContextPtr ctxt);
+
+int virNetTLSContextCheckCertificate(virNetTLSContextPtr ctxt,
+ virNetTLSSessionPtr sess);
+
+void virNetTLSContextFree(virNetTLSContextPtr ctxt);
+
+
+typedef ssize_t (*virNetTLSSessionWriteFunc)(const char *buf, size_t len,
+ void *opaque);
+typedef ssize_t (*virNetTLSSessionReadFunc)(char *buf, size_t len,
+ void *opaque);
+
+virNetTLSSessionPtr virNetTLSSessionNew(virNetTLSContextPtr ctxt,
+ const char *hostname);
+
+void virNetTLSSessionSetIOCallbacks(virNetTLSSessionPtr sess,
+ virNetTLSSessionWriteFunc writeFunc,
+ virNetTLSSessionReadFunc readFunc,
+ void *opaque);
+
+void virNetTLSSessionRef(virNetTLSSessionPtr sess);
+
+ssize_t virNetTLSSessionWrite(virNetTLSSessionPtr sess,
+ const char *buf, size_t len);
+ssize_t virNetTLSSessionRead(virNetTLSSessionPtr sess,
+ char *buf, size_t len);
+
+int virNetTLSSessionHandshake(virNetTLSSessionPtr sess);
+
+typedef enum {
+ VIR_NET_TLS_HANDSHAKE_COMPLETE,
+ VIR_NET_TLS_HANDSHAKE_SENDING,
+ VIR_NET_TLS_HANDSHAKE_RECVING,
+} virNetTLSSessionHandshakeStatus;
+
+virNetTLSSessionHandshakeStatus
+virNetTLSSessionGetHandshakeStatus(virNetTLSSessionPtr sess);
+
+int virNetTLSSessionGetKeySize(virNetTLSSessionPtr sess);
+
+void virNetTLSSessionFree(virNetTLSSessionPtr sess);
+
+
+#endif
--
1.7.2.3