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