qemu/include/crypto/tlssession.h
<<
>>
Prefs
   1/*
   2 * QEMU crypto TLS session support
   3 *
   4 * Copyright (c) 2015 Red Hat, Inc.
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
  18 *
  19 */
  20
  21#ifndef QCRYPTO_TLSSESSION_H
  22#define QCRYPTO_TLSSESSION_H
  23
  24#include "crypto/tlscreds.h"
  25
  26/**
  27 * QCryptoTLSSession:
  28 *
  29 * The QCryptoTLSSession object encapsulates the
  30 * logic to integrate with a TLS providing library such
  31 * as GNUTLS, to setup and run TLS sessions.
  32 *
  33 * The API is designed such that it has no assumption about
  34 * the type of transport it is running over. It may be a
  35 * traditional TCP socket, or something else entirely. The
  36 * only requirement is a full-duplex stream of some kind.
  37 *
  38 * <example>
  39 *   <title>Using TLS session objects</title>
  40 *   <programlisting>
  41 * static ssize_t mysock_send(const char *buf, size_t len,
  42 *                            void *opaque)
  43 * {
  44 *    int fd = GPOINTER_TO_INT(opaque);
  45 *
  46 *    return write(*fd, buf, len);
  47 * }
  48 *
  49 * static ssize_t mysock_recv(const char *buf, size_t len,
  50 *                            void *opaque)
  51 * {
  52 *    int fd = GPOINTER_TO_INT(opaque);
  53 *
  54 *    return read(*fd, buf, len);
  55 * }
  56 *
  57 * static int mysock_run_tls(int sockfd,
  58 *                           QCryptoTLSCreds *creds,
  59 *                           Error **errp)
  60 * {
  61 *    QCryptoTLSSession *sess;
  62 *
  63 *    sess = qcrypto_tls_session_new(creds,
  64 *                                   "vnc.example.com",
  65 *                                   NULL,
  66 *                                   QCRYPTO_TLS_CREDS_ENDPOINT_CLIENT,
  67 *                                   errp);
  68 *    if (sess == NULL) {
  69 *       return -1;
  70 *    }
  71 *
  72 *    qcrypto_tls_session_set_callbacks(sess,
  73 *                                      mysock_send,
  74 *                                      mysock_recv
  75 *                                      GINT_TO_POINTER(fd));
  76 *
  77 *    while (1) {
  78 *       if (qcrypto_tls_session_handshake(sess, errp) < 0) {
  79 *           qcrypto_tls_session_free(sess);
  80 *           return -1;
  81 *       }
  82 *
  83 *       switch(qcrypto_tls_session_get_handshake_status(sess)) {
  84 *       case QCRYPTO_TLS_HANDSHAKE_COMPLETE:
  85 *           if (qcrypto_tls_session_check_credentials(sess, errp) < )) {
  86 *               qcrypto_tls_session_free(sess);
  87 *               return -1;
  88 *           }
  89 *           goto done;
  90 *       case QCRYPTO_TLS_HANDSHAKE_RECVING:
  91 *           ...wait for GIO_IN event on fd...
  92 *           break;
  93 *       case QCRYPTO_TLS_HANDSHAKE_SENDING:
  94 *           ...wait for GIO_OUT event on fd...
  95 *           break;
  96 *       }
  97 *    }
  98 *   done:
  99 *
 100 *    ....send/recv payload data on sess...
 101 *
 102 *    qcrypto_tls_session_free(sess):
 103 * }
 104 *   </programlisting>
 105 * </example>
 106 */
 107
 108typedef struct QCryptoTLSSession QCryptoTLSSession;
 109
 110
 111/**
 112 * qcrypto_tls_session_new:
 113 * @creds: pointer to a TLS credentials object
 114 * @hostname: optional hostname to validate
 115 * @aclname: optional ACL to validate peer credentials against
 116 * @endpoint: role of the TLS session, client or server
 117 * @errp: pointer to a NULL-initialized error object
 118 *
 119 * Create a new TLS session object that will be used to
 120 * negotiate a TLS session over an arbitrary data channel.
 121 * The session object can operate as either the server or
 122 * client, according to the value of the @endpoint argument.
 123 *
 124 * For clients, the @hostname parameter should hold the full
 125 * unmodified hostname as requested by the user. This will
 126 * be used to verify the against the hostname reported in
 127 * the server's credentials (aka x509 certificate).
 128 *
 129 * The @aclname parameter (optionally) specifies the name
 130 * of an access control list that will be used to validate
 131 * the peer's credentials. For x509 credentials, the ACL
 132 * will be matched against the CommonName shown in the peer's
 133 * certificate. If the session is acting as a server, setting
 134 * an ACL will require that the client provide a validate
 135 * x509 client certificate.
 136 *
 137 * After creating the session object, the I/O callbacks
 138 * must be set using the qcrypto_tls_session_set_callbacks()
 139 * method. A TLS handshake sequence must then be completed
 140 * using qcrypto_tls_session_handshake(), before payload
 141 * data is permitted to be sent/received.
 142 *
 143 * The session object must be released by calling
 144 * qcrypto_tls_session_free() when no longer required
 145 *
 146 * Returns: a TLS session object, or NULL on error.
 147 */
 148QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds,
 149                                           const char *hostname,
 150                                           const char *aclname,
 151                                           QCryptoTLSCredsEndpoint endpoint,
 152                                           Error **errp);
 153
 154/**
 155 * qcrypto_tls_session_free:
 156 * @sess: the TLS session object
 157 *
 158 * Release all memory associated with the TLS session
 159 * object previously allocated by qcrypto_tls_session_new()
 160 */
 161void qcrypto_tls_session_free(QCryptoTLSSession *sess);
 162
 163G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free)
 164
 165/**
 166 * qcrypto_tls_session_check_credentials:
 167 * @sess: the TLS session object
 168 * @errp: pointer to a NULL-initialized error object
 169 *
 170 * Validate the peer's credentials after a successful
 171 * TLS handshake. It is an error to call this before
 172 * qcrypto_tls_session_get_handshake_status() returns
 173 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 174 *
 175 * Returns 0 if the credentials validated, -1 on error
 176 */
 177int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess,
 178                                          Error **errp);
 179
 180typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf,
 181                                              size_t len,
 182                                              void *opaque);
 183typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf,
 184                                             size_t len,
 185                                             void *opaque);
 186
 187/**
 188 * qcrypto_tls_session_set_callbacks:
 189 * @sess: the TLS session object
 190 * @writeFunc: callback for sending data
 191 * @readFunc: callback to receiving data
 192 * @opaque: data to pass to callbacks
 193 *
 194 * Sets the callback functions that are to be used for sending
 195 * and receiving data on the underlying data channel. Typically
 196 * the callbacks to write/read to/from a TCP socket, but there
 197 * is no assumption made about the type of channel used.
 198 *
 199 * The @writeFunc callback will be passed the encrypted
 200 * data to send to the remote peer.
 201 *
 202 * The @readFunc callback will be passed a pointer to fill
 203 * with encrypted data received from the remote peer
 204 */
 205void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess,
 206                                       QCryptoTLSSessionWriteFunc writeFunc,
 207                                       QCryptoTLSSessionReadFunc readFunc,
 208                                       void *opaque);
 209
 210/**
 211 * qcrypto_tls_session_write:
 212 * @sess: the TLS session object
 213 * @buf: the plain text to send
 214 * @len: the length of @buf
 215 *
 216 * Encrypt @len bytes of the data in @buf and send
 217 * it to the remote peer using the callback previously
 218 * registered with qcrypto_tls_session_set_callbacks()
 219 *
 220 * It is an error to call this before
 221 * qcrypto_tls_session_get_handshake_status() returns
 222 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 223 *
 224 * Returns: the number of bytes sent, or -1 on error
 225 */
 226ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess,
 227                                  const char *buf,
 228                                  size_t len);
 229
 230/**
 231 * qcrypto_tls_session_read:
 232 * @sess: the TLS session object
 233 * @buf: to fill with plain text received
 234 * @len: the length of @buf
 235 *
 236 * Receive up to @len bytes of data from the remote peer
 237 * using the callback previously registered with
 238 * qcrypto_tls_session_set_callbacks(), decrypt it and
 239 * store it in @buf.
 240 *
 241 * It is an error to call this before
 242 * qcrypto_tls_session_get_handshake_status() returns
 243 * QCRYPTO_TLS_HANDSHAKE_COMPLETE
 244 *
 245 * Returns: the number of bytes received, or -1 on error
 246 */
 247ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess,
 248                                 char *buf,
 249                                 size_t len);
 250
 251/**
 252 * qcrypto_tls_session_handshake:
 253 * @sess: the TLS session object
 254 * @errp: pointer to a NULL-initialized error object
 255 *
 256 * Start, or continue, a TLS handshake sequence. If
 257 * the underlying data channel is non-blocking, then
 258 * this method may return control before the handshake
 259 * is complete. On non-blocking channels the
 260 * qcrypto_tls_session_get_handshake_status() method
 261 * should be used to determine whether the handshake
 262 * has completed, or is waiting to send or receive
 263 * data. In the latter cases, the caller should setup
 264 * an event loop watch and call this method again
 265 * once the underlying data channel is ready to read
 266 * or write again
 267 */
 268int qcrypto_tls_session_handshake(QCryptoTLSSession *sess,
 269                                  Error **errp);
 270
 271typedef enum {
 272    QCRYPTO_TLS_HANDSHAKE_COMPLETE,
 273    QCRYPTO_TLS_HANDSHAKE_SENDING,
 274    QCRYPTO_TLS_HANDSHAKE_RECVING,
 275} QCryptoTLSSessionHandshakeStatus;
 276
 277/**
 278 * qcrypto_tls_session_get_handshake_status:
 279 * @sess: the TLS session object
 280 *
 281 * Check the status of the TLS handshake. This
 282 * is used with non-blocking data channels to
 283 * determine whether the handshake is waiting
 284 * to send or receive further data to/from the
 285 * remote peer.
 286 *
 287 * Once this returns QCRYPTO_TLS_HANDSHAKE_COMPLETE
 288 * it is permitted to send/receive payload data on
 289 * the channel
 290 */
 291QCryptoTLSSessionHandshakeStatus
 292qcrypto_tls_session_get_handshake_status(QCryptoTLSSession *sess);
 293
 294/**
 295 * qcrypto_tls_session_get_key_size:
 296 * @sess: the TLS session object
 297 * @errp: pointer to a NULL-initialized error object
 298 *
 299 * Check the size of the data channel encryption key
 300 *
 301 * Returns: the length in bytes of the encryption key
 302 * or -1 on error
 303 */
 304int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess,
 305                                     Error **errp);
 306
 307/**
 308 * qcrypto_tls_session_get_peer_name:
 309 * @sess: the TLS session object
 310 *
 311 * Get the identified name of the remote peer. If the
 312 * TLS session was negotiated using x509 certificate
 313 * credentials, this will return the CommonName from
 314 * the peer's certificate. If no identified name is
 315 * available it will return NULL.
 316 *
 317 * The returned data must be released with g_free()
 318 * when no longer required.
 319 *
 320 * Returns: the peer's name or NULL.
 321 */
 322char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess);
 323
 324#endif /* QCRYPTO_TLSSESSION_H */
 325