diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/crypto/tlscreds.h | 68 | ||||
-rw-r--r-- | include/crypto/tlscredsanon.h | 112 | ||||
-rw-r--r-- | include/crypto/tlscredsx509.h | 113 | ||||
-rw-r--r-- | include/crypto/tlssession.h | 322 |
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__ */ |