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