Statistics
| Branch: | Revision:

root / ui / vnc-tls.c @ 8895919a

History | View | Annotate | Download (14.6 kB)

1 274b6fcc aliguori
/*
2 274b6fcc aliguori
 * QEMU VNC display driver: TLS helpers
3 274b6fcc aliguori
 *
4 274b6fcc aliguori
 * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
5 274b6fcc aliguori
 * Copyright (C) 2006 Fabrice Bellard
6 274b6fcc aliguori
 * Copyright (C) 2009 Red Hat, Inc
7 274b6fcc aliguori
 *
8 274b6fcc aliguori
 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 274b6fcc aliguori
 * of this software and associated documentation files (the "Software"), to deal
10 274b6fcc aliguori
 * in the Software without restriction, including without limitation the rights
11 274b6fcc aliguori
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 274b6fcc aliguori
 * copies of the Software, and to permit persons to whom the Software is
13 274b6fcc aliguori
 * furnished to do so, subject to the following conditions:
14 274b6fcc aliguori
 *
15 274b6fcc aliguori
 * The above copyright notice and this permission notice shall be included in
16 274b6fcc aliguori
 * all copies or substantial portions of the Software.
17 274b6fcc aliguori
 *
18 274b6fcc aliguori
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 274b6fcc aliguori
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 274b6fcc aliguori
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 274b6fcc aliguori
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 274b6fcc aliguori
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 274b6fcc aliguori
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 274b6fcc aliguori
 * THE SOFTWARE.
25 274b6fcc aliguori
 */
26 274b6fcc aliguori
27 de7890db Gerd Hoffmann
#include "qemu-x509.h"
28 274b6fcc aliguori
#include "vnc.h"
29 1de7afc9 Paolo Bonzini
#include "qemu/sockets.h"
30 274b6fcc aliguori
31 274b6fcc aliguori
#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
32 274b6fcc aliguori
/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
33 274b6fcc aliguori
static void vnc_debug_gnutls_log(int level, const char* str) {
34 274b6fcc aliguori
    VNC_DEBUG("%d %s", level, str);
35 274b6fcc aliguori
}
36 274b6fcc aliguori
#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
37 274b6fcc aliguori
38 274b6fcc aliguori
39 274b6fcc aliguori
#define DH_BITS 1024
40 274b6fcc aliguori
static gnutls_dh_params_t dh_params;
41 274b6fcc aliguori
42 274b6fcc aliguori
static int vnc_tls_initialize(void)
43 274b6fcc aliguori
{
44 274b6fcc aliguori
    static int tlsinitialized = 0;
45 274b6fcc aliguori
46 274b6fcc aliguori
    if (tlsinitialized)
47 274b6fcc aliguori
        return 1;
48 274b6fcc aliguori
49 274b6fcc aliguori
    if (gnutls_global_init () < 0)
50 274b6fcc aliguori
        return 0;
51 274b6fcc aliguori
52 d69eba24 Stefan Weil
    /* XXX ought to re-generate diffie-hellman params periodically */
53 274b6fcc aliguori
    if (gnutls_dh_params_init (&dh_params) < 0)
54 274b6fcc aliguori
        return 0;
55 274b6fcc aliguori
    if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
56 274b6fcc aliguori
        return 0;
57 274b6fcc aliguori
58 274b6fcc aliguori
#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
59 274b6fcc aliguori
    gnutls_global_set_log_level(10);
60 274b6fcc aliguori
    gnutls_global_set_log_function(vnc_debug_gnutls_log);
61 274b6fcc aliguori
#endif
62 274b6fcc aliguori
63 274b6fcc aliguori
    tlsinitialized = 1;
64 274b6fcc aliguori
65 274b6fcc aliguori
    return 1;
66 274b6fcc aliguori
}
67 274b6fcc aliguori
68 274b6fcc aliguori
static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
69 274b6fcc aliguori
                            const void *data,
70 274b6fcc aliguori
                            size_t len) {
71 274b6fcc aliguori
    struct VncState *vs = (struct VncState *)transport;
72 274b6fcc aliguori
    int ret;
73 274b6fcc aliguori
74 274b6fcc aliguori
 retry:
75 274b6fcc aliguori
    ret = send(vs->csock, data, len, 0);
76 274b6fcc aliguori
    if (ret < 0) {
77 274b6fcc aliguori
        if (errno == EINTR)
78 274b6fcc aliguori
            goto retry;
79 274b6fcc aliguori
        return -1;
80 274b6fcc aliguori
    }
81 274b6fcc aliguori
    return ret;
82 274b6fcc aliguori
}
83 274b6fcc aliguori
84 274b6fcc aliguori
85 274b6fcc aliguori
static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
86 274b6fcc aliguori
                            void *data,
87 274b6fcc aliguori
                            size_t len) {
88 274b6fcc aliguori
    struct VncState *vs = (struct VncState *)transport;
89 274b6fcc aliguori
    int ret;
90 274b6fcc aliguori
91 274b6fcc aliguori
 retry:
92 00aa0040 Blue Swirl
    ret = qemu_recv(vs->csock, data, len, 0);
93 274b6fcc aliguori
    if (ret < 0) {
94 274b6fcc aliguori
        if (errno == EINTR)
95 274b6fcc aliguori
            goto retry;
96 274b6fcc aliguori
        return -1;
97 274b6fcc aliguori
    }
98 274b6fcc aliguori
    return ret;
99 274b6fcc aliguori
}
100 274b6fcc aliguori
101 274b6fcc aliguori
102 7d2a929f Andre Przywara
static gnutls_anon_server_credentials_t vnc_tls_initialize_anon_cred(void)
103 274b6fcc aliguori
{
104 7d2a929f Andre Przywara
    gnutls_anon_server_credentials_t anon_cred;
105 274b6fcc aliguori
    int ret;
106 274b6fcc aliguori
107 274b6fcc aliguori
    if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
108 274b6fcc aliguori
        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
109 274b6fcc aliguori
        return NULL;
110 274b6fcc aliguori
    }
111 274b6fcc aliguori
112 274b6fcc aliguori
    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
113 274b6fcc aliguori
114 274b6fcc aliguori
    return anon_cred;
115 274b6fcc aliguori
}
116 274b6fcc aliguori
117 274b6fcc aliguori
118 274b6fcc aliguori
static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
119 274b6fcc aliguori
{
120 274b6fcc aliguori
    gnutls_certificate_credentials_t x509_cred;
121 274b6fcc aliguori
    int ret;
122 274b6fcc aliguori
123 274b6fcc aliguori
    if (!vd->tls.x509cacert) {
124 274b6fcc aliguori
        VNC_DEBUG("No CA x509 certificate specified\n");
125 274b6fcc aliguori
        return NULL;
126 274b6fcc aliguori
    }
127 274b6fcc aliguori
    if (!vd->tls.x509cert) {
128 274b6fcc aliguori
        VNC_DEBUG("No server x509 certificate specified\n");
129 274b6fcc aliguori
        return NULL;
130 274b6fcc aliguori
    }
131 274b6fcc aliguori
    if (!vd->tls.x509key) {
132 274b6fcc aliguori
        VNC_DEBUG("No server private key specified\n");
133 274b6fcc aliguori
        return NULL;
134 274b6fcc aliguori
    }
135 274b6fcc aliguori
136 274b6fcc aliguori
    if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
137 274b6fcc aliguori
        VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
138 274b6fcc aliguori
        return NULL;
139 274b6fcc aliguori
    }
140 274b6fcc aliguori
    if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
141 274b6fcc aliguori
                                                      vd->tls.x509cacert,
142 274b6fcc aliguori
                                                      GNUTLS_X509_FMT_PEM)) < 0) {
143 274b6fcc aliguori
        VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
144 274b6fcc aliguori
        gnutls_certificate_free_credentials(x509_cred);
145 274b6fcc aliguori
        return NULL;
146 274b6fcc aliguori
    }
147 274b6fcc aliguori
148 274b6fcc aliguori
    if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
149 274b6fcc aliguori
                                                     vd->tls.x509cert,
150 274b6fcc aliguori
                                                     vd->tls.x509key,
151 274b6fcc aliguori
                                                     GNUTLS_X509_FMT_PEM)) < 0) {
152 274b6fcc aliguori
        VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
153 274b6fcc aliguori
        gnutls_certificate_free_credentials(x509_cred);
154 274b6fcc aliguori
        return NULL;
155 274b6fcc aliguori
    }
156 274b6fcc aliguori
157 274b6fcc aliguori
    if (vd->tls.x509cacrl) {
158 274b6fcc aliguori
        if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
159 274b6fcc aliguori
                                                        vd->tls.x509cacrl,
160 274b6fcc aliguori
                                                        GNUTLS_X509_FMT_PEM)) < 0) {
161 274b6fcc aliguori
            VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
162 274b6fcc aliguori
            gnutls_certificate_free_credentials(x509_cred);
163 274b6fcc aliguori
            return NULL;
164 274b6fcc aliguori
        }
165 274b6fcc aliguori
    }
166 274b6fcc aliguori
167 274b6fcc aliguori
    gnutls_certificate_set_dh_params (x509_cred, dh_params);
168 274b6fcc aliguori
169 274b6fcc aliguori
    return x509_cred;
170 274b6fcc aliguori
}
171 274b6fcc aliguori
172 274b6fcc aliguori
173 274b6fcc aliguori
int vnc_tls_validate_certificate(struct VncState *vs)
174 274b6fcc aliguori
{
175 274b6fcc aliguori
    int ret;
176 274b6fcc aliguori
    unsigned int status;
177 274b6fcc aliguori
    const gnutls_datum_t *certs;
178 274b6fcc aliguori
    unsigned int nCerts, i;
179 274b6fcc aliguori
    time_t now;
180 274b6fcc aliguori
181 274b6fcc aliguori
    VNC_DEBUG("Validating client certificate\n");
182 274b6fcc aliguori
    if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
183 274b6fcc aliguori
        VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
184 274b6fcc aliguori
        return -1;
185 274b6fcc aliguori
    }
186 274b6fcc aliguori
187 274b6fcc aliguori
    if ((now = time(NULL)) == ((time_t)-1)) {
188 274b6fcc aliguori
        return -1;
189 274b6fcc aliguori
    }
190 274b6fcc aliguori
191 274b6fcc aliguori
    if (status != 0) {
192 274b6fcc aliguori
        if (status & GNUTLS_CERT_INVALID)
193 274b6fcc aliguori
            VNC_DEBUG("The certificate is not trusted.\n");
194 274b6fcc aliguori
195 274b6fcc aliguori
        if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
196 274b6fcc aliguori
            VNC_DEBUG("The certificate hasn't got a known issuer.\n");
197 274b6fcc aliguori
198 274b6fcc aliguori
        if (status & GNUTLS_CERT_REVOKED)
199 274b6fcc aliguori
            VNC_DEBUG("The certificate has been revoked.\n");
200 274b6fcc aliguori
201 274b6fcc aliguori
        if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
202 274b6fcc aliguori
            VNC_DEBUG("The certificate uses an insecure algorithm\n");
203 274b6fcc aliguori
204 274b6fcc aliguori
        return -1;
205 274b6fcc aliguori
    } else {
206 274b6fcc aliguori
        VNC_DEBUG("Certificate is valid!\n");
207 274b6fcc aliguori
    }
208 274b6fcc aliguori
209 274b6fcc aliguori
    /* Only support x509 for now */
210 274b6fcc aliguori
    if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
211 274b6fcc aliguori
        return -1;
212 274b6fcc aliguori
213 274b6fcc aliguori
    if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
214 274b6fcc aliguori
        return -1;
215 274b6fcc aliguori
216 274b6fcc aliguori
    for (i = 0 ; i < nCerts ; i++) {
217 274b6fcc aliguori
        gnutls_x509_crt_t cert;
218 274b6fcc aliguori
        VNC_DEBUG ("Checking certificate chain %d\n", i);
219 274b6fcc aliguori
        if (gnutls_x509_crt_init (&cert) < 0)
220 274b6fcc aliguori
            return -1;
221 274b6fcc aliguori
222 274b6fcc aliguori
        if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
223 274b6fcc aliguori
            gnutls_x509_crt_deinit (cert);
224 274b6fcc aliguori
            return -1;
225 274b6fcc aliguori
        }
226 274b6fcc aliguori
227 274b6fcc aliguori
        if (gnutls_x509_crt_get_expiration_time (cert) < now) {
228 274b6fcc aliguori
            VNC_DEBUG("The certificate has expired\n");
229 274b6fcc aliguori
            gnutls_x509_crt_deinit (cert);
230 274b6fcc aliguori
            return -1;
231 274b6fcc aliguori
        }
232 274b6fcc aliguori
233 274b6fcc aliguori
        if (gnutls_x509_crt_get_activation_time (cert) > now) {
234 274b6fcc aliguori
            VNC_DEBUG("The certificate is not yet activated\n");
235 274b6fcc aliguori
            gnutls_x509_crt_deinit (cert);
236 274b6fcc aliguori
            return -1;
237 274b6fcc aliguori
        }
238 274b6fcc aliguori
239 274b6fcc aliguori
        if (gnutls_x509_crt_get_activation_time (cert) > now) {
240 274b6fcc aliguori
            VNC_DEBUG("The certificate is not yet activated\n");
241 274b6fcc aliguori
            gnutls_x509_crt_deinit (cert);
242 274b6fcc aliguori
            return -1;
243 274b6fcc aliguori
        }
244 274b6fcc aliguori
245 274b6fcc aliguori
        if (i == 0) {
246 274b6fcc aliguori
            size_t dnameSize = 1024;
247 7267c094 Anthony Liguori
            vs->tls.dname = g_malloc(dnameSize);
248 274b6fcc aliguori
        requery:
249 274b6fcc aliguori
            if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
250 274b6fcc aliguori
                if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
251 7267c094 Anthony Liguori
                    vs->tls.dname = g_realloc(vs->tls.dname, dnameSize);
252 274b6fcc aliguori
                    goto requery;
253 274b6fcc aliguori
                }
254 274b6fcc aliguori
                gnutls_x509_crt_deinit (cert);
255 274b6fcc aliguori
                VNC_DEBUG("Cannot get client distinguished name: %s",
256 274b6fcc aliguori
                          gnutls_strerror (ret));
257 274b6fcc aliguori
                return -1;
258 274b6fcc aliguori
            }
259 274b6fcc aliguori
260 274b6fcc aliguori
            if (vs->vd->tls.x509verify) {
261 274b6fcc aliguori
                int allow;
262 274b6fcc aliguori
                if (!vs->vd->tls.acl) {
263 274b6fcc aliguori
                    VNC_DEBUG("no ACL activated, allowing access");
264 274b6fcc aliguori
                    gnutls_x509_crt_deinit (cert);
265 274b6fcc aliguori
                    continue;
266 274b6fcc aliguori
                }
267 274b6fcc aliguori
268 274b6fcc aliguori
                allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
269 274b6fcc aliguori
                                                  vs->tls.dname);
270 274b6fcc aliguori
271 274b6fcc aliguori
                VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
272 274b6fcc aliguori
                          vs->tls.dname, allow ? "allowed" : "denied");
273 274b6fcc aliguori
                if (!allow) {
274 274b6fcc aliguori
                    gnutls_x509_crt_deinit (cert);
275 274b6fcc aliguori
                    return -1;
276 274b6fcc aliguori
                }
277 274b6fcc aliguori
            }
278 274b6fcc aliguori
        }
279 274b6fcc aliguori
280 274b6fcc aliguori
        gnutls_x509_crt_deinit (cert);
281 274b6fcc aliguori
    }
282 274b6fcc aliguori
283 274b6fcc aliguori
    return 0;
284 274b6fcc aliguori
}
285 274b6fcc aliguori
286 f40d5508 Gerd Hoffmann
#if defined(GNUTLS_VERSION_NUMBER) && \
287 f40d5508 Gerd Hoffmann
    GNUTLS_VERSION_NUMBER >= 0x020200 /* 2.2.0 */
288 f40d5508 Gerd Hoffmann
289 f40d5508 Gerd Hoffmann
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
290 f40d5508 Gerd Hoffmann
{
291 f40d5508 Gerd Hoffmann
    const char *priority = x509 ? "NORMAL" : "NORMAL:+ANON-DH";
292 f40d5508 Gerd Hoffmann
    int rc;
293 f40d5508 Gerd Hoffmann
294 f40d5508 Gerd Hoffmann
    rc = gnutls_priority_set_direct(s, priority, NULL);
295 f40d5508 Gerd Hoffmann
    if (rc != GNUTLS_E_SUCCESS) {
296 f40d5508 Gerd Hoffmann
        return -1;
297 f40d5508 Gerd Hoffmann
    }
298 f40d5508 Gerd Hoffmann
    return 0;
299 f40d5508 Gerd Hoffmann
}
300 f40d5508 Gerd Hoffmann
301 f40d5508 Gerd Hoffmann
#else
302 f40d5508 Gerd Hoffmann
303 f40d5508 Gerd Hoffmann
static int vnc_set_gnutls_priority(gnutls_session_t s, int x509)
304 f40d5508 Gerd Hoffmann
{
305 f40d5508 Gerd Hoffmann
    static const int cert_types[] = { GNUTLS_CRT_X509, 0 };
306 f40d5508 Gerd Hoffmann
    static const int protocols[] = {
307 f40d5508 Gerd Hoffmann
        GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0
308 f40d5508 Gerd Hoffmann
    };
309 f40d5508 Gerd Hoffmann
    static const int kx_anon[] = { GNUTLS_KX_ANON_DH, 0 };
310 f40d5508 Gerd Hoffmann
    static const int kx_x509[] = {
311 f40d5508 Gerd Hoffmann
        GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
312 f40d5508 Gerd Hoffmann
        GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0
313 f40d5508 Gerd Hoffmann
    };
314 f40d5508 Gerd Hoffmann
    int rc;
315 f40d5508 Gerd Hoffmann
316 f40d5508 Gerd Hoffmann
    rc = gnutls_kx_set_priority(s, x509 ? kx_x509 : kx_anon);
317 f40d5508 Gerd Hoffmann
    if (rc != GNUTLS_E_SUCCESS) {
318 f40d5508 Gerd Hoffmann
        return -1;
319 f40d5508 Gerd Hoffmann
    }
320 f40d5508 Gerd Hoffmann
321 f40d5508 Gerd Hoffmann
    rc = gnutls_certificate_type_set_priority(s, cert_types);
322 f40d5508 Gerd Hoffmann
    if (rc != GNUTLS_E_SUCCESS) {
323 f40d5508 Gerd Hoffmann
        return -1;
324 f40d5508 Gerd Hoffmann
    }
325 f40d5508 Gerd Hoffmann
326 f40d5508 Gerd Hoffmann
    rc = gnutls_protocol_set_priority(s, protocols);
327 f40d5508 Gerd Hoffmann
    if (rc != GNUTLS_E_SUCCESS) {
328 f40d5508 Gerd Hoffmann
        return -1;
329 f40d5508 Gerd Hoffmann
    }
330 f40d5508 Gerd Hoffmann
    return 0;
331 f40d5508 Gerd Hoffmann
}
332 f40d5508 Gerd Hoffmann
333 f40d5508 Gerd Hoffmann
#endif
334 274b6fcc aliguori
335 274b6fcc aliguori
int vnc_tls_client_setup(struct VncState *vs,
336 274b6fcc aliguori
                         int needX509Creds) {
337 0057a0d5 Tim Hardeck
    VncStateTLS *tls;
338 274b6fcc aliguori
339 274b6fcc aliguori
    VNC_DEBUG("Do TLS setup\n");
340 0057a0d5 Tim Hardeck
#ifdef CONFIG_VNC_WS
341 0057a0d5 Tim Hardeck
    if (vs->websocket) {
342 0057a0d5 Tim Hardeck
        tls = &vs->ws_tls;
343 0057a0d5 Tim Hardeck
    } else
344 0057a0d5 Tim Hardeck
#endif /* CONFIG_VNC_WS */
345 0057a0d5 Tim Hardeck
    {
346 0057a0d5 Tim Hardeck
        tls = &vs->tls;
347 0057a0d5 Tim Hardeck
    }
348 274b6fcc aliguori
    if (vnc_tls_initialize() < 0) {
349 274b6fcc aliguori
        VNC_DEBUG("Failed to init TLS\n");
350 274b6fcc aliguori
        vnc_client_error(vs);
351 274b6fcc aliguori
        return -1;
352 274b6fcc aliguori
    }
353 0057a0d5 Tim Hardeck
    if (tls->session == NULL) {
354 0057a0d5 Tim Hardeck
        if (gnutls_init(&tls->session, GNUTLS_SERVER) < 0) {
355 274b6fcc aliguori
            vnc_client_error(vs);
356 274b6fcc aliguori
            return -1;
357 274b6fcc aliguori
        }
358 274b6fcc aliguori
359 0057a0d5 Tim Hardeck
        if (gnutls_set_default_priority(tls->session) < 0) {
360 0057a0d5 Tim Hardeck
            gnutls_deinit(tls->session);
361 0057a0d5 Tim Hardeck
            tls->session = NULL;
362 274b6fcc aliguori
            vnc_client_error(vs);
363 274b6fcc aliguori
            return -1;
364 274b6fcc aliguori
        }
365 274b6fcc aliguori
366 0057a0d5 Tim Hardeck
        if (vnc_set_gnutls_priority(tls->session, needX509Creds) < 0) {
367 0057a0d5 Tim Hardeck
            gnutls_deinit(tls->session);
368 0057a0d5 Tim Hardeck
            tls->session = NULL;
369 274b6fcc aliguori
            vnc_client_error(vs);
370 274b6fcc aliguori
            return -1;
371 274b6fcc aliguori
        }
372 274b6fcc aliguori
373 274b6fcc aliguori
        if (needX509Creds) {
374 274b6fcc aliguori
            gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
375 274b6fcc aliguori
            if (!x509_cred) {
376 0057a0d5 Tim Hardeck
                gnutls_deinit(tls->session);
377 0057a0d5 Tim Hardeck
                tls->session = NULL;
378 274b6fcc aliguori
                vnc_client_error(vs);
379 274b6fcc aliguori
                return -1;
380 274b6fcc aliguori
            }
381 0057a0d5 Tim Hardeck
            if (gnutls_credentials_set(tls->session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
382 0057a0d5 Tim Hardeck
                gnutls_deinit(tls->session);
383 0057a0d5 Tim Hardeck
                tls->session = NULL;
384 274b6fcc aliguori
                gnutls_certificate_free_credentials(x509_cred);
385 274b6fcc aliguori
                vnc_client_error(vs);
386 274b6fcc aliguori
                return -1;
387 274b6fcc aliguori
            }
388 274b6fcc aliguori
            if (vs->vd->tls.x509verify) {
389 274b6fcc aliguori
                VNC_DEBUG("Requesting a client certificate\n");
390 0057a0d5 Tim Hardeck
                gnutls_certificate_server_set_request (tls->session, GNUTLS_CERT_REQUEST);
391 274b6fcc aliguori
            }
392 274b6fcc aliguori
393 274b6fcc aliguori
        } else {
394 7d2a929f Andre Przywara
            gnutls_anon_server_credentials_t anon_cred = vnc_tls_initialize_anon_cred();
395 274b6fcc aliguori
            if (!anon_cred) {
396 0057a0d5 Tim Hardeck
                gnutls_deinit(tls->session);
397 0057a0d5 Tim Hardeck
                tls->session = NULL;
398 274b6fcc aliguori
                vnc_client_error(vs);
399 274b6fcc aliguori
                return -1;
400 274b6fcc aliguori
            }
401 0057a0d5 Tim Hardeck
            if (gnutls_credentials_set(tls->session, GNUTLS_CRD_ANON, anon_cred) < 0) {
402 0057a0d5 Tim Hardeck
                gnutls_deinit(tls->session);
403 0057a0d5 Tim Hardeck
                tls->session = NULL;
404 274b6fcc aliguori
                gnutls_anon_free_server_credentials(anon_cred);
405 274b6fcc aliguori
                vnc_client_error(vs);
406 274b6fcc aliguori
                return -1;
407 274b6fcc aliguori
            }
408 274b6fcc aliguori
        }
409 274b6fcc aliguori
410 0057a0d5 Tim Hardeck
        gnutls_transport_set_ptr(tls->session, (gnutls_transport_ptr_t)vs);
411 0057a0d5 Tim Hardeck
        gnutls_transport_set_push_function(tls->session, vnc_tls_push);
412 0057a0d5 Tim Hardeck
        gnutls_transport_set_pull_function(tls->session, vnc_tls_pull);
413 274b6fcc aliguori
    }
414 274b6fcc aliguori
    return 0;
415 274b6fcc aliguori
}
416 274b6fcc aliguori
417 274b6fcc aliguori
418 274b6fcc aliguori
void vnc_tls_client_cleanup(struct VncState *vs)
419 274b6fcc aliguori
{
420 274b6fcc aliguori
    if (vs->tls.session) {
421 274b6fcc aliguori
        gnutls_deinit(vs->tls.session);
422 274b6fcc aliguori
        vs->tls.session = NULL;
423 274b6fcc aliguori
    }
424 274b6fcc aliguori
    vs->tls.wiremode = VNC_WIREMODE_CLEAR;
425 ae878b17 Stefan Weil
    g_free(vs->tls.dname);
426 0057a0d5 Tim Hardeck
#ifdef CONFIG_VNC_WS
427 0057a0d5 Tim Hardeck
    if (vs->ws_tls.session) {
428 0057a0d5 Tim Hardeck
        gnutls_deinit(vs->ws_tls.session);
429 0057a0d5 Tim Hardeck
        vs->ws_tls.session = NULL;
430 0057a0d5 Tim Hardeck
    }
431 0057a0d5 Tim Hardeck
    vs->ws_tls.wiremode = VNC_WIREMODE_CLEAR;
432 0057a0d5 Tim Hardeck
    g_free(vs->ws_tls.dname);
433 0057a0d5 Tim Hardeck
#endif /* CONFIG_VNC_WS */
434 274b6fcc aliguori
}
435 274b6fcc aliguori
436 274b6fcc aliguori
437 274b6fcc aliguori
438 274b6fcc aliguori
static int vnc_set_x509_credential(VncDisplay *vd,
439 274b6fcc aliguori
                                   const char *certdir,
440 274b6fcc aliguori
                                   const char *filename,
441 274b6fcc aliguori
                                   char **cred,
442 274b6fcc aliguori
                                   int ignoreMissing)
443 274b6fcc aliguori
{
444 274b6fcc aliguori
    struct stat sb;
445 274b6fcc aliguori
446 274b6fcc aliguori
    if (*cred) {
447 7267c094 Anthony Liguori
        g_free(*cred);
448 274b6fcc aliguori
        *cred = NULL;
449 274b6fcc aliguori
    }
450 274b6fcc aliguori
451 7267c094 Anthony Liguori
    *cred = g_malloc(strlen(certdir) + strlen(filename) + 2);
452 274b6fcc aliguori
453 274b6fcc aliguori
    strcpy(*cred, certdir);
454 274b6fcc aliguori
    strcat(*cred, "/");
455 274b6fcc aliguori
    strcat(*cred, filename);
456 274b6fcc aliguori
457 274b6fcc aliguori
    VNC_DEBUG("Check %s\n", *cred);
458 274b6fcc aliguori
    if (stat(*cred, &sb) < 0) {
459 7267c094 Anthony Liguori
        g_free(*cred);
460 274b6fcc aliguori
        *cred = NULL;
461 274b6fcc aliguori
        if (ignoreMissing && errno == ENOENT)
462 274b6fcc aliguori
            return 0;
463 274b6fcc aliguori
        return -1;
464 274b6fcc aliguori
    }
465 274b6fcc aliguori
466 274b6fcc aliguori
    return 0;
467 274b6fcc aliguori
}
468 274b6fcc aliguori
469 274b6fcc aliguori
470 274b6fcc aliguori
int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
471 274b6fcc aliguori
                               const char *certdir)
472 274b6fcc aliguori
{
473 274b6fcc aliguori
    if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
474 274b6fcc aliguori
        goto cleanup;
475 274b6fcc aliguori
    if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
476 274b6fcc aliguori
        goto cleanup;
477 274b6fcc aliguori
    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
478 274b6fcc aliguori
        goto cleanup;
479 274b6fcc aliguori
    if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
480 274b6fcc aliguori
        goto cleanup;
481 274b6fcc aliguori
482 274b6fcc aliguori
    return 0;
483 274b6fcc aliguori
484 274b6fcc aliguori
 cleanup:
485 7267c094 Anthony Liguori
    g_free(vd->tls.x509cacert);
486 7267c094 Anthony Liguori
    g_free(vd->tls.x509cacrl);
487 7267c094 Anthony Liguori
    g_free(vd->tls.x509cert);
488 7267c094 Anthony Liguori
    g_free(vd->tls.x509key);
489 274b6fcc aliguori
    vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
490 274b6fcc aliguori
    return -1;
491 274b6fcc aliguori
}