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 * int ret = qcrypto_tls_session_handshake(sess, errp); 79 * 80 * if (ret < 0) { 81 * qcrypto_tls_session_free(sess); 82 * return -1; 83 * } 84 * 85 * switch(ret) { 86 * case QCRYPTO_TLS_HANDSHAKE_COMPLETE: 87 * if (qcrypto_tls_session_check_credentials(sess, errp) < )) { 88 * qcrypto_tls_session_free(sess); 89 * return -1; 90 * } 91 * goto done; 92 * case QCRYPTO_TLS_HANDSHAKE_RECVING: 93 * ...wait for GIO_IN event on fd... 94 * break; 95 * case QCRYPTO_TLS_HANDSHAKE_SENDING: 96 * ...wait for GIO_OUT event on fd... 97 * break; 98 * } 99 * } 100 * done: 101 * 102 * ....send/recv payload data on sess... 103 * 104 * qcrypto_tls_session_free(sess): 105 * } 106 * </programlisting> 107 * </example> 108 */ 109 110 typedef struct QCryptoTLSSession QCryptoTLSSession; 111 112 #define QCRYPTO_TLS_SESSION_ERR_BLOCK -2 113 114 /** 115 * qcrypto_tls_session_new: 116 * @creds: pointer to a TLS credentials object 117 * @hostname: optional hostname to validate 118 * @aclname: optional ACL to validate peer credentials against 119 * @endpoint: role of the TLS session, client or server 120 * @errp: pointer to a NULL-initialized error object 121 * 122 * Create a new TLS session object that will be used to 123 * negotiate a TLS session over an arbitrary data channel. 124 * The session object can operate as either the server or 125 * client, according to the value of the @endpoint argument. 126 * 127 * For clients, the @hostname parameter should hold the full 128 * unmodified hostname as requested by the user. This will 129 * be used to verify the against the hostname reported in 130 * the server's credentials (aka x509 certificate). 131 * 132 * The @aclname parameter (optionally) specifies the name 133 * of an access control list that will be used to validate 134 * the peer's credentials. For x509 credentials, the ACL 135 * will be matched against the CommonName shown in the peer's 136 * certificate. If the session is acting as a server, setting 137 * an ACL will require that the client provide a validate 138 * x509 client certificate. 139 * 140 * After creating the session object, the I/O callbacks 141 * must be set using the qcrypto_tls_session_set_callbacks() 142 * method. A TLS handshake sequence must then be completed 143 * using qcrypto_tls_session_handshake(), before payload 144 * data is permitted to be sent/received. 145 * 146 * The session object must be released by calling 147 * qcrypto_tls_session_free() when no longer required 148 * 149 * Returns: a TLS session object, or NULL on error. 150 */ 151 QCryptoTLSSession *qcrypto_tls_session_new(QCryptoTLSCreds *creds, 152 const char *hostname, 153 const char *aclname, 154 QCryptoTLSCredsEndpoint endpoint, 155 Error **errp); 156 157 /** 158 * qcrypto_tls_session_free: 159 * @sess: the TLS session object 160 * 161 * Release all memory associated with the TLS session 162 * object previously allocated by qcrypto_tls_session_new() 163 */ 164 void qcrypto_tls_session_free(QCryptoTLSSession *sess); 165 166 G_DEFINE_AUTOPTR_CLEANUP_FUNC(QCryptoTLSSession, qcrypto_tls_session_free) 167 168 /** 169 * qcrypto_tls_session_check_credentials: 170 * @sess: the TLS session object 171 * @errp: pointer to a NULL-initialized error object 172 * 173 * Validate the peer's credentials after a successful 174 * TLS handshake. It is an error to call this before 175 * qcrypto_tls_session_handshake() returns 176 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 177 * 178 * Returns 0 if the credentials validated, -1 on error 179 */ 180 int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess, 181 Error **errp); 182 183 /* 184 * These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O 185 * would block, but on other errors, must fill 'errp' 186 */ 187 typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf, 188 size_t len, 189 void *opaque, 190 Error **errp); 191 typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf, 192 size_t len, 193 void *opaque, 194 Error **errp); 195 196 /** 197 * qcrypto_tls_session_set_callbacks: 198 * @sess: the TLS session object 199 * @writeFunc: callback for sending data 200 * @readFunc: callback to receiving data 201 * @opaque: data to pass to callbacks 202 * 203 * Sets the callback functions that are to be used for sending 204 * and receiving data on the underlying data channel. Typically 205 * the callbacks to write/read to/from a TCP socket, but there 206 * is no assumption made about the type of channel used. 207 * 208 * The @writeFunc callback will be passed the encrypted 209 * data to send to the remote peer. 210 * 211 * The @readFunc callback will be passed a pointer to fill 212 * with encrypted data received from the remote peer 213 */ 214 void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess, 215 QCryptoTLSSessionWriteFunc writeFunc, 216 QCryptoTLSSessionReadFunc readFunc, 217 void *opaque); 218 219 /** 220 * qcrypto_tls_session_write: 221 * @sess: the TLS session object 222 * @buf: the plain text to send 223 * @len: the length of @buf 224 * @errp: pointer to hold returned error object 225 * 226 * Encrypt @len bytes of the data in @buf and send 227 * it to the remote peer using the callback previously 228 * registered with qcrypto_tls_session_set_callbacks() 229 * 230 * It is an error to call this before 231 * qcrypto_tls_session_handshake() returns 232 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 233 * 234 * Returns: the number of bytes sent, 235 * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the write would block, 236 * or -1 on error. 237 */ 238 ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess, 239 const char *buf, 240 size_t len, 241 Error **errp); 242 243 /** 244 * qcrypto_tls_session_read: 245 * @sess: the TLS session object 246 * @buf: to fill with plain text received 247 * @len: the length of @buf 248 * @gracefulTermination: treat premature termination as graceful EOF 249 * @errp: pointer to hold returned error object 250 * 251 * Receive up to @len bytes of data from the remote peer 252 * using the callback previously registered with 253 * qcrypto_tls_session_set_callbacks(), decrypt it and 254 * store it in @buf. 255 * 256 * If @gracefulTermination is true, then a premature termination 257 * of the TLS session will be treated as indicating EOF, as 258 * opposed to an error. 259 * 260 * It is an error to call this before 261 * qcrypto_tls_session_handshake() returns 262 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 263 * 264 * Returns: the number of bytes received, 265 * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the receive would block, 266 * or -1 on error. 267 */ 268 ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess, 269 char *buf, 270 size_t len, 271 bool gracefulTermination, 272 Error **errp); 273 274 /** 275 * qcrypto_tls_session_check_pending: 276 * @sess: the TLS session object 277 * 278 * Check if there are unread data in the TLS buffers that have 279 * already been read from the underlying data source. 280 * 281 * Returns: the number of bytes available or zero 282 */ 283 size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess); 284 285 /** 286 * qcrypto_tls_session_handshake: 287 * @sess: the TLS session object 288 * @errp: pointer to a NULL-initialized error object 289 * 290 * Start, or continue, a TLS handshake sequence. If 291 * the underlying data channel is non-blocking, then 292 * this method may return control before the handshake 293 * is complete. On non-blocking channels the 294 * return value determines whether the handshake 295 * has completed, or is waiting to send or receive 296 * data. In the latter cases, the caller should setup 297 * an event loop watch and call this method again 298 * once the underlying data channel is ready to read 299 * or write again 300 */ 301 int qcrypto_tls_session_handshake(QCryptoTLSSession *sess, 302 Error **errp); 303 304 typedef enum { 305 QCRYPTO_TLS_HANDSHAKE_COMPLETE, 306 QCRYPTO_TLS_HANDSHAKE_SENDING, 307 QCRYPTO_TLS_HANDSHAKE_RECVING, 308 } QCryptoTLSSessionHandshakeStatus; 309 310 typedef enum { 311 QCRYPTO_TLS_BYE_COMPLETE, 312 QCRYPTO_TLS_BYE_SENDING, 313 QCRYPTO_TLS_BYE_RECVING, 314 } QCryptoTLSSessionByeStatus; 315 316 /** 317 * qcrypto_tls_session_bye: 318 * @session: the TLS session object 319 * @errp: pointer to a NULL-initialized error object 320 * 321 * Start, or continue, a TLS termination sequence. If the underlying 322 * data channel is non-blocking, then this method may return control 323 * before the termination is complete. The return value will indicate 324 * whether the termination has completed, or is waiting to send or 325 * receive data. In the latter cases, the caller should setup an event 326 * loop watch and call this method again once the underlying data 327 * channel is ready to read or write again. 328 */ 329 int 330 qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp); 331 332 /** 333 * qcrypto_tls_session_get_key_size: 334 * @sess: the TLS session object 335 * @errp: pointer to a NULL-initialized error object 336 * 337 * Check the size of the data channel encryption key 338 * 339 * Returns: the length in bytes of the encryption key 340 * or -1 on error 341 */ 342 int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess, 343 Error **errp); 344 345 /** 346 * qcrypto_tls_session_get_peer_name: 347 * @sess: the TLS session object 348 * 349 * Get the identified name of the remote peer. If the 350 * TLS session was negotiated using x509 certificate 351 * credentials, this will return the CommonName from 352 * the peer's certificate. If no identified name is 353 * available it will return NULL. 354 * 355 * The returned data must be released with g_free() 356 * when no longer required. 357 * 358 * Returns: the peer's name or NULL. 359 */ 360 char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess); 361 362 #endif /* QCRYPTO_TLSSESSION_H */ 363