xref: /openbmc/qemu/include/crypto/tlssession.h (revision 919c486c406a34823c6cef5438f1a13e2c79a7d5)
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