summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-09-15 15:42:58 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-09-15 15:42:58 +0100
commit619622424dba749feef752d76d79ef2569f7f250 (patch)
treeb5b3e718e5075781da039fe3f6966aaec4922cdd /include
parent1078f5db8ada5097600443838492ef07103790c2 (diff)
parent3e305e4a4752f70c0b5c3cf5b43ec957881714f7 (diff)
downloadqemu-619622424dba749feef752d76d79ef2569f7f250.zip
Merge remote-tracking branch 'remotes/berrange/tags/vnc-crypto-v9-for-upstream' into staging
Merge vnc-crypto-v9 # gpg: Signature made Tue 15 Sep 2015 15:32:38 BST using RSA key ID 15104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" * remotes/berrange/tags/vnc-crypto-v9-for-upstream: ui: convert VNC server to use QCryptoTLSSession ui: fix return type for VNC I/O functions to be ssize_t crypto: introduce new module for handling TLS sessions crypto: add sanity checking of TLS x509 credentials crypto: introduce new module for TLS x509 credentials crypto: introduce new module for TLS anonymous credentials crypto: introduce new base module for TLS credentials qom: allow QOM to be linked into tools binaries crypto: move crypto objects out of libqemuutil.la tests: remove repetition in unit test object deps qapi: allow override of default enum prefix naming Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'include')
-rw-r--r--include/crypto/tlscreds.h68
-rw-r--r--include/crypto/tlscredsanon.h112
-rw-r--r--include/crypto/tlscredsx509.h113
-rw-r--r--include/crypto/tlssession.h322
4 files changed, 615 insertions, 0 deletions
diff --git a/include/crypto/tlscreds.h b/include/crypto/tlscreds.h
new file mode 100644
index 0000000000..21761b7ce1
--- /dev/null
+++ b/include/crypto/tlscreds.h
@@ -0,0 +1,68 @@
+/*
+ * QEMU crypto TLS credential support
+ *
+ * Copyright (c) 2015 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 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_TLSCRED_H__
+#define QCRYPTO_TLSCRED_H__
+
+#include "qemu-common.h"
+#include "qapi/error.h"
+#include "qom/object.h"
+
+#ifdef CONFIG_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#define TYPE_QCRYPTO_TLS_CREDS "tls-creds"
+#define QCRYPTO_TLS_CREDS(obj) \
+ OBJECT_CHECK(QCryptoTLSCreds, (obj), TYPE_QCRYPTO_TLS_CREDS)
+
+typedef struct QCryptoTLSCreds QCryptoTLSCreds;
+typedef struct QCryptoTLSCredsClass QCryptoTLSCredsClass;
+
+#define QCRYPTO_TLS_CREDS_DH_PARAMS "dh-params.pem"
+
+
+/**
+ * QCryptoTLSCreds:
+ *
+ * The QCryptoTLSCreds object is an abstract base for different
+ * types of TLS handshake credentials. Most commonly the
+ * QCryptoTLSCredsX509 subclass will be used to provide x509
+ * certificate credentials.
+ */
+
+struct QCryptoTLSCreds {
+ Object parent_obj;
+ char *dir;
+ QCryptoTLSCredsEndpoint endpoint;
+#ifdef CONFIG_GNUTLS
+ gnutls_dh_params_t dh_params;
+#endif
+ bool verifyPeer;
+};
+
+
+struct QCryptoTLSCredsClass {
+ ObjectClass parent_class;
+};
+
+
+#endif /* QCRYPTO_TLSCRED_H__ */
+
diff --git a/include/crypto/tlscredsanon.h b/include/crypto/tlscredsanon.h
new file mode 100644
index 0000000000..d3976b84b9
--- /dev/null
+++ b/include/crypto/tlscredsanon.h
@@ -0,0 +1,112 @@
+/*
+ * QEMU crypto TLS anonymous credential support
+ *
+ * Copyright (c) 2015 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 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_TLSCRED_ANON_H__
+#define QCRYPTO_TLSCRED_ANON_H__
+
+#include "crypto/tlscreds.h"
+
+#define TYPE_QCRYPTO_TLS_CREDS_ANON "tls-creds-anon"
+#define QCRYPTO_TLS_CREDS_ANON(obj) \
+ OBJECT_CHECK(QCryptoTLSCredsAnon, (obj), TYPE_QCRYPTO_TLS_CREDS_ANON)
+
+
+typedef struct QCryptoTLSCredsAnon QCryptoTLSCredsAnon;
+typedef struct QCryptoTLSCredsAnonClass QCryptoTLSCredsAnonClass;
+
+/**
+ * QCryptoTLSCredsAnon:
+ *
+ * The QCryptoTLSCredsAnon object provides a representation
+ * of anonymous credentials used perform a TLS handshake.
+ * This is primarily provided for backwards compatibility and
+ * its use is discouraged as it has poor security characteristics
+ * due to lacking MITM attack protection amongst other problems.
+ *
+ * This is a user creatable object, which can be instantiated
+ * via object_new_propv():
+ *
+ * <example>
+ * <title>Creating anonymous TLS credential objects in code</title>
+ * <programlisting>
+ * Object *obj;
+ * Error *err = NULL;
+ * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_ANON,
+ * "tlscreds0",
+ * &err,
+ * "endpoint", "server",
+ * "dir", "/path/x509/cert/dir",
+ * "verify-peer", "yes",
+ * NULL);
+ * </programlisting>
+ * </example>
+ *
+ * Or via QMP:
+ *
+ * <example>
+ * <title>Creating anonymous TLS credential objects via QMP</title>
+ * <programlisting>
+ * {
+ * "execute": "object-add", "arguments": {
+ * "id": "tlscreds0",
+ * "qom-type": "tls-creds-anon",
+ * "props": {
+ * "endpoint": "server",
+ * "dir": "/path/to/x509/cert/dir",
+ * "verify-peer": false
+ * }
+ * }
+ * }
+ * </programlisting>
+ * </example>
+ *
+ *
+ * Or via the CLI:
+ *
+ * <example>
+ * <title>Creating anonymous TLS credential objects via CLI</title>
+ * <programlisting>
+ * qemu-system-x86_64 -object tls-creds-anon,id=tlscreds0,\
+ * endpoint=server,verify-peer=off,\
+ * dir=/path/to/x509/certdir/
+ * </programlisting>
+ * </example>
+ *
+ */
+
+
+struct QCryptoTLSCredsAnon {
+ QCryptoTLSCreds parent_obj;
+#ifdef CONFIG_GNUTLS
+ union {
+ gnutls_anon_server_credentials_t server;
+ gnutls_anon_client_credentials_t client;
+ } data;
+#endif
+};
+
+
+struct QCryptoTLSCredsAnonClass {
+ QCryptoTLSCredsClass parent_class;
+};
+
+
+#endif /* QCRYPTO_TLSCRED_H__ */
+
diff --git a/include/crypto/tlscredsx509.h b/include/crypto/tlscredsx509.h
new file mode 100644
index 0000000000..b9785fddcf
--- /dev/null
+++ b/include/crypto/tlscredsx509.h
@@ -0,0 +1,113 @@
+/*
+ * QEMU crypto TLS x509 credential support
+ *
+ * Copyright (c) 2015 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 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_TLSCRED_X509_H__
+#define QCRYPTO_TLSCRED_X509_H__
+
+#include "crypto/tlscreds.h"
+
+#define TYPE_QCRYPTO_TLS_CREDS_X509 "tls-creds-x509"
+#define QCRYPTO_TLS_CREDS_X509(obj) \
+ OBJECT_CHECK(QCryptoTLSCredsX509, (obj), TYPE_QCRYPTO_TLS_CREDS_X509)
+
+typedef struct QCryptoTLSCredsX509 QCryptoTLSCredsX509;
+typedef struct QCryptoTLSCredsX509Class QCryptoTLSCredsX509Class;
+
+#define QCRYPTO_TLS_CREDS_X509_CA_CERT "ca-cert.pem"
+#define QCRYPTO_TLS_CREDS_X509_CA_CRL "ca-crl.pem"
+#define QCRYPTO_TLS_CREDS_X509_SERVER_KEY "server-key.pem"
+#define QCRYPTO_TLS_CREDS_X509_SERVER_CERT "server-cert.pem"
+#define QCRYPTO_TLS_CREDS_X509_CLIENT_KEY "client-key.pem"
+#define QCRYPTO_TLS_CREDS_X509_CLIENT_CERT "client-cert.pem"
+
+
+/**
+ * QCryptoTLSCredsX509:
+ *
+ * The QCryptoTLSCredsX509 object provides a representation
+ * of x509 credentials used to perform a TLS handshake.
+ *
+ * This is a user creatable object, which can be instantiated
+ * via object_new_propv():
+ *
+ * <example>
+ * <title>Creating x509 TLS credential objects in code</title>
+ * <programlisting>
+ * Object *obj;
+ * Error *err = NULL;
+ * obj = object_new_propv(TYPE_QCRYPTO_TLS_CREDS_X509,
+ * "tlscreds0",
+ * &err,
+ * "endpoint", "server",
+ * "dir", "/path/x509/cert/dir",
+ * "verify-peer", "yes",
+ * NULL);
+ * </programlisting>
+ * </example>
+ *
+ * Or via QMP:
+ *
+ * <example>
+ * <title>Creating x509 TLS credential objects via QMP</title>
+ * <programlisting>
+ * {
+ * "execute": "object-add", "arguments": {
+ * "id": "tlscreds0",
+ * "qom-type": "tls-creds-x509",
+ * "props": {
+ * "endpoint": "server",
+ * "dir": "/path/to/x509/cert/dir",
+ * "verify-peer": false
+ * }
+ * }
+ * }
+ * </programlisting>
+ * </example>
+ *
+ *
+ * Or via the CLI:
+ *
+ * <example>
+ * <title>Creating x509 TLS credential objects via CLI</title>
+ * <programlisting>
+ * qemu-system-x86_64 -object tls-creds-x509,id=tlscreds0,\
+ * endpoint=server,verify-peer=off,\
+ * dir=/path/to/x509/certdir/
+ * </programlisting>
+ * </example>
+ *
+ */
+
+struct QCryptoTLSCredsX509 {
+ QCryptoTLSCreds parent_obj;
+#ifdef CONFIG_GNUTLS
+ gnutls_certificate_credentials_t data;
+#endif
+ bool sanityCheck;
+};
+
+
+struct QCryptoTLSCredsX509Class {
+ QCryptoTLSCredsClass parent_class;
+};
+
+
+#endif /* QCRYPTO_TLSCRED_X509_H__ */
+
diff --git a/include/crypto/tlssession.h b/include/crypto/tlssession.h
new file mode 100644
index 0000000000..b38fe6954d
--- /dev/null
+++ b/include/crypto/tlssession.h
@@ -0,0 +1,322 @@
+/*
+ * QEMU crypto TLS session support
+ *
+ * Copyright (c) 2015 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 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, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QCRYPTO_TLS_SESSION_H__
+#define QCRYPTO_TLS_SESSION_H__
+
+#include "crypto/tlscreds.h"
+
+/**
+ * QCryptoTLSSession:
+ *
+ * The QCryptoTLSSession object encapsulates the
+ * logic to integrate with a TLS providing library such
+ * as GNUTLS, to setup and run TLS sessions.
+ *
+ * The API is designed such that it has no assumption about
+ * the type of transport it is running over. It may be a
+ * traditional TCP socket, or something else entirely. The
+ * only requirement is a full-duplex stream of some kind.
+ *
+ * <example>
+ * <title>Using TLS session objects</title>
+ * <programlisting>
+ * static ssize_t mysock_send(const char *buf, size_t len,
+ * void *opaque)
+ * {
+ * int fd = GPOINTER_TO_INT(opaque);
+ *
+ * return write(*fd, buf, len);
+ * }
+ *
+ * static ssize_t mysock_recv(const char *buf, size_t len,
+ * void *opaque)
+ * {
+ * int fd = GPOINTER_TO_INT(opaque);
+ *
+ * return read(*fd, buf, len);
+ * }
+ *
+ * static int mysock_run_tls(int sockfd,
+ * QCryptoTLSCreds *creds,
+ * Error *erp)
+ * {
+ * QCryptoTLSSession *sess;
+ *
+ * sess = qcrypto_tls_session_new(creds,
+ * "vnc.example.com",
+ * NULL,
+ * QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
+ * errp);
+ * if (sess == NULL) {
+ * return -1;
+ * }
+ *
+ * qcrypto_tls_session_set_callbacks(sess,
+ * mysock_send,
+ * mysock_recv
+ * GINT_TO_POINTER(fd));
+ *
+ * while (1) {
+ * if (qcrypto_tls_session_handshake(sess, errp) < 0) {
+ * qcrypto_tls_session_free(sess);
+ * return -1;
+ * }
+ *
+ * switch(qcrypto_tls_session_get_handshake_status(sess)) {
+ * case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
+ * if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
+ * qcrypto_tls_session_free(sess);
+ * return -1;
+ * }
+ * goto done;
+ * case QCRYPTO_TLS_HANDSHAKE_RECVING:
+ * ...wait for GIO_IN event on fd...
+ * break;
+ * case QCRYPTO_TLS_HANDSHAKE_SENDING:
+ * ...wait for GIO_OUT event on fd...
+ * break;
+ * }
+ * }
+ * done:
+ *
+ * ....send/recv payload data on sess...
+ *
+ * qcrypto_tls_session_free(sess):
+ * }
+ * </programlisting>
+ * </example>
+ */
+
+typedef struct QCryptoTLSSession QCryptoTLSSession;
+
+
+/**
+ * qcrypto_tls_session_new:
+ * @creds: pointer to a TLS credentials object
+ * @hostname: optional hostname to validate
+ * @aclname: optional ACL to validate peer credentials against
+ * @endpoint: role of the TLS session, client or server
+ * @errp: pointer to an uninitialized error object
+ *
+ * Create a new TLS session object that will be used to
+ * negotiate a TLS session over an arbitrary data channel.
+ * The session object can operate as either the server or
+ * client, according to the value of the @endpoint argument.
+ *
+ * For clients, the @hostname parameter should hold the full
+ * unmodified hostname as requested by the user. This will
+ * be used to verify the against the hostname reported in
+ * the server's credentials (aka x509 certificate).
+ *
+ * The @aclname parameter (optionally) specifies the name
+ * of an access control list that will be used to validate
+ * the peer's credentials. For x509 credentials, the ACL
+ * will be matched against the CommonName shown in the peer's
+ * certificate. If the session is acting as a server, setting
+ * an ACL will require that the client provide a validate
+ * x509 client certificate.
+ *
+ * After creating the session object, the I/O callbacks
+ * must be set using the qcrypto_tls_session_set_callbacks()
+ * method. A TLS handshake sequence must then be completed
+ * using qcrypto_tls_session_handshake(), before payload
+ * data is permitted to be sent/received.
+ *
+ * The session object must be released by calling
+ * qcrypto_tls_session_free() when no longer required
+ *
+ * Returns: a TLS session object, or NULL on error.
+ */
+QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds,
+ const char *hostname,
+ const char *aclname,
+ QCryptoTLSCredsEndpoint endpoint,
+ Error **errp);
+
+/**
+ * qcrypto_tls_session_free:
+ * @sess: the TLS session object
+ *
+ * Release all memory associated with the TLS session
+ * object previously allocated by qcrypto_tls_session_new()
+ */
+void qcrypto_tls_session_free(QCryptoTLSSession *sess);
+
+/**
+ * qcrypto_tls_session_check_credentials:
+ * @sess: the TLS session object
+ * @errp: pointer to an uninitialized error object
+ *
+ * Validate the peer's credentials after a successful
+ * TLS handshake. It is an error to call this before
+ * qcrypto_tls_session_get_handshake_status() returns
+ * QCRYPTO_TLS_HANDSHAKE_COMPLETE
+ *
+ * Returns 0 if the credentials validated, -1 on error
+ */
+int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
+ Error **errp);
+
+typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
+ size_t len,
+ void *opaque);
+typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
+ size_t len,
+ void *opaque);
+
+/**
+ * qcrypto_tls_session_set_callbacks:
+ * @sess: the TLS session object
+ * @writeFunc: callback for sending data
+ * @readFunc: callback to receiving data
+ * @opaque: data to pass to callbacks
+ *
+ * Sets the callback functions that are to be used for sending
+ * and receiving data on the underlying data channel. Typically
+ * the callbacks to write/read to/from a TCP socket, but there
+ * is no assumption made about the type of channel used.
+ *
+ * The @writeFunc callback will be passed the encrypted
+ * data to send to the remote peer.
+ *
+ * The @readFunc callback will be passed a pointer to fill
+ * with encrypted data received from the remote peer
+ */
+void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
+ QCryptoTLSSessionWriteFunc writeFunc,
+ QCryptoTLSSessionReadFunc readFunc,
+ void *opaque);
+
+/**
+ * qcrypto_tls_session_write:
+ * @sess: the TLS session object
+ * @buf: the plain text to send
+ * @len: the length of @buf
+ *
+ * Encrypt @len bytes of the data in @buf and send
+ * it to the remote peer using the callback previously
+ * registered with qcrypto_tls_session_set_callbacks()
+ *
+ * It is an error to call this before
+ * qcrypto_tls_session_get_handshake_status() returns
+ * QCRYPTO_TLS_HANDSHAKE_COMPLETE
+ *
+ * Returns: the number of bytes sent, or -1 on error
+ */
+ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
+ const char *buf,
+ size_t len);
+
+/**
+ * qcrypto_tls_session_read:
+ * @sess: the TLS session object
+ * @buf: to fill with plain text received
+ * @len: the length of @buf
+ *
+ * Receive up to @len bytes of data from the remote peer
+ * using the callback previously registered with
+ * qcrypto_tls_session_set_callbacks(), decrypt it and
+ * store it in @buf.
+ *
+ * It is an error to call this before
+ * qcrypto_tls_session_get_handshake_status() returns
+ * QCRYPTO_TLS_HANDSHAKE_COMPLETE
+ *
+ * Returns: the number of bytes received, or -1 on error
+ */
+ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
+ char *buf,
+ size_t len);
+
+/**
+ * qcrypto_tls_session_handshake:
+ * @sess: the TLS session object
+ * @errp: pointer to an uninitialized error object
+ *
+ * Start, or continue, a TLS handshake sequence. If
+ * the underlying data channel is non-blocking, then
+ * this method may return control before the handshake
+ * is complete. On non-blocking channels the
+ * qcrypto_tls_session_get_handshake_status() method
+ * should be used to determine whether the handshake
+ * has completed, or is waiting to send or receive
+ * data. In the latter cases, the caller should setup
+ * an event loop watch and call this method again
+ * once the underlying data channel is ready to read
+ * or write again
+ */
+int qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
+ Error **errp);
+
+typedef enum {
+ QCRYPTO_TLS_HANDSHAKE_COMPLETE,
+ QCRYPTO_TLS_HANDSHAKE_SENDING,
+ QCRYPTO_TLS_HANDSHAKE_RECVING,
+} QCryptoTLSSessionHandshakeStatus;
+
+/**
+ * qcrypto_tls_session_get_handshake_status:
+ * @sess: the TLS session object
+ *
+ * Check the status of the TLS handshake. This
+ * is used with non-blocking data channels to
+ * determine whether the handshake is waiting
+ * to send or receive further data to/from the
+ * remote peer.
+ *
+ * Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE
+ * it is permitted to send/receive payload data on
+ * the channel
+ */
+QCryptoTLSSessionHandshakeStatus
+qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
+
+/**
+ * qcrypto_tls_session_get_key_size:
+ * @sess: the TLS session object
+ * @errp: pointer to an uninitialized error object
+ *
+ * Check the size of the data channel encryption key
+ *
+ * Returns: the length in bytes of the encryption key
+ * or -1 on error
+ */
+int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
+ Error **errp);
+
+/**
+ * qcrypto_tls_session_get_peer_name:
+ * @sess: the TLS session object
+ *
+ * Get the identified name of the remote peer. If the
+ * TLS session was negotiated using x509 certificate
+ * credentials, this will return the CommonName from
+ * the peer's certificate. If no identified name is
+ * available it will return NULL.
+ *
+ * The returned data must be released with g_free()
+ * when no longer required.
+ *
+ * Returns: the peer's name or NULL.
+ */
+char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess);
+
+#endif /* QCRYPTO_TLS_SESSION_H__ */