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