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_require_thread_safety: 170 * @sess: the TLS session object 171 * 172 * Mark that this TLS session will require thread safety 173 * for concurrent I/O in both directions. This must be 174 * called before the handshake is performed. 175 * 176 * This will activate a workaround for GNUTLS thread 177 * safety issues, where appropriate for the negotiated 178 * TLS session parameters. 179 */ 180 void qcrypto_tls_session_require_thread_safety(QCryptoTLSSession *sess); 181 182 /** 183 * qcrypto_tls_session_check_credentials: 184 * @sess: the TLS session object 185 * @errp: pointer to a NULL-initialized error object 186 * 187 * Validate the peer's credentials after a successful 188 * TLS handshake. It is an error to call this before 189 * qcrypto_tls_session_handshake() returns 190 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 191 * 192 * Returns 0 if the credentials validated, -1 on error 193 */ 194 int qcrypto_tls_session_check_credentials(QCryptoTLSSession *sess, 195 Error **errp); 196 197 /* 198 * These must return QCRYPTO_TLS_SESSION_ERR_BLOCK if the I/O 199 * would block, but on other errors, must fill 'errp' 200 */ 201 typedef ssize_t (*QCryptoTLSSessionWriteFunc)(const char *buf, 202 size_t len, 203 void *opaque, 204 Error **errp); 205 typedef ssize_t (*QCryptoTLSSessionReadFunc)(char *buf, 206 size_t len, 207 void *opaque, 208 Error **errp); 209 210 /** 211 * qcrypto_tls_session_set_callbacks: 212 * @sess: the TLS session object 213 * @writeFunc: callback for sending data 214 * @readFunc: callback to receiving data 215 * @opaque: data to pass to callbacks 216 * 217 * Sets the callback functions that are to be used for sending 218 * and receiving data on the underlying data channel. Typically 219 * the callbacks to write/read to/from a TCP socket, but there 220 * is no assumption made about the type of channel used. 221 * 222 * The @writeFunc callback will be passed the encrypted 223 * data to send to the remote peer. 224 * 225 * The @readFunc callback will be passed a pointer to fill 226 * with encrypted data received from the remote peer 227 */ 228 void qcrypto_tls_session_set_callbacks(QCryptoTLSSession *sess, 229 QCryptoTLSSessionWriteFunc writeFunc, 230 QCryptoTLSSessionReadFunc readFunc, 231 void *opaque); 232 233 /** 234 * qcrypto_tls_session_write: 235 * @sess: the TLS session object 236 * @buf: the plain text to send 237 * @len: the length of @buf 238 * @errp: pointer to hold returned error object 239 * 240 * Encrypt @len bytes of the data in @buf and send 241 * it to the remote peer using the callback previously 242 * registered with qcrypto_tls_session_set_callbacks() 243 * 244 * It is an error to call this before 245 * qcrypto_tls_session_handshake() returns 246 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 247 * 248 * Returns: the number of bytes sent, 249 * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the write would block, 250 * or -1 on error. 251 */ 252 ssize_t qcrypto_tls_session_write(QCryptoTLSSession *sess, 253 const char *buf, 254 size_t len, 255 Error **errp); 256 257 /** 258 * qcrypto_tls_session_read: 259 * @sess: the TLS session object 260 * @buf: to fill with plain text received 261 * @len: the length of @buf 262 * @gracefulTermination: treat premature termination as graceful EOF 263 * @errp: pointer to hold returned error object 264 * 265 * Receive up to @len bytes of data from the remote peer 266 * using the callback previously registered with 267 * qcrypto_tls_session_set_callbacks(), decrypt it and 268 * store it in @buf. 269 * 270 * If @gracefulTermination is true, then a premature termination 271 * of the TLS session will be treated as indicating EOF, as 272 * opposed to an error. 273 * 274 * It is an error to call this before 275 * qcrypto_tls_session_handshake() returns 276 * QCRYPTO_TLS_HANDSHAKE_COMPLETE 277 * 278 * Returns: the number of bytes received, 279 * or QCRYPTO_TLS_SESSION_ERR_BLOCK if the receive would block, 280 * or -1 on error. 281 */ 282 ssize_t qcrypto_tls_session_read(QCryptoTLSSession *sess, 283 char *buf, 284 size_t len, 285 bool gracefulTermination, 286 Error **errp); 287 288 /** 289 * qcrypto_tls_session_check_pending: 290 * @sess: the TLS session object 291 * 292 * Check if there are unread data in the TLS buffers that have 293 * already been read from the underlying data source. 294 * 295 * Returns: the number of bytes available or zero 296 */ 297 size_t qcrypto_tls_session_check_pending(QCryptoTLSSession *sess); 298 299 /** 300 * qcrypto_tls_session_handshake: 301 * @sess: the TLS session object 302 * @errp: pointer to a NULL-initialized error object 303 * 304 * Start, or continue, a TLS handshake sequence. If 305 * the underlying data channel is non-blocking, then 306 * this method may return control before the handshake 307 * is complete. On non-blocking channels the 308 * return value determines whether the handshake 309 * has completed, or is waiting to send or receive 310 * data. In the latter cases, the caller should setup 311 * an event loop watch and call this method again 312 * once the underlying data channel is ready to read 313 * or write again 314 */ 315 int qcrypto_tls_session_handshake(QCryptoTLSSession *sess, 316 Error **errp); 317 318 typedef enum { 319 QCRYPTO_TLS_HANDSHAKE_COMPLETE, 320 QCRYPTO_TLS_HANDSHAKE_SENDING, 321 QCRYPTO_TLS_HANDSHAKE_RECVING, 322 } QCryptoTLSSessionHandshakeStatus; 323 324 typedef enum { 325 QCRYPTO_TLS_BYE_COMPLETE, 326 QCRYPTO_TLS_BYE_SENDING, 327 QCRYPTO_TLS_BYE_RECVING, 328 } QCryptoTLSSessionByeStatus; 329 330 /** 331 * qcrypto_tls_session_bye: 332 * @session: the TLS session object 333 * @errp: pointer to a NULL-initialized error object 334 * 335 * Start, or continue, a TLS termination sequence. If the underlying 336 * data channel is non-blocking, then this method may return control 337 * before the termination is complete. The return value will indicate 338 * whether the termination has completed, or is waiting to send or 339 * receive data. In the latter cases, the caller should setup an event 340 * loop watch and call this method again once the underlying data 341 * channel is ready to read or write again. 342 */ 343 int 344 qcrypto_tls_session_bye(QCryptoTLSSession *session, Error **errp); 345 346 /** 347 * qcrypto_tls_session_get_key_size: 348 * @sess: the TLS session object 349 * @errp: pointer to a NULL-initialized error object 350 * 351 * Check the size of the data channel encryption key 352 * 353 * Returns: the length in bytes of the encryption key 354 * or -1 on error 355 */ 356 int qcrypto_tls_session_get_key_size(QCryptoTLSSession *sess, 357 Error **errp); 358 359 /** 360 * qcrypto_tls_session_get_peer_name: 361 * @sess: the TLS session object 362 * 363 * Get the identified name of the remote peer. If the 364 * TLS session was negotiated using x509 certificate 365 * credentials, this will return the CommonName from 366 * the peer's certificate. If no identified name is 367 * available it will return NULL. 368 * 369 * The returned data must be released with g_free() 370 * when no longer required. 371 * 372 * Returns: the peer's name or NULL. 373 */ 374 char *qcrypto_tls_session_get_peer_name(QCryptoTLSSession *sess); 375 376 #endif /* QCRYPTO_TLSSESSION_H */ 377