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