Commit 274b6fcc78401b6300bf86f9b656c13fd7e63619

Authored by aliguori
1 parent 5f5aed22

Add more missing files

Major FAIL with my checkin scripts.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>



git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6731 c046a42c-6fe2-441c-8c8c-71466251a162
vnc-auth-vencrypt.c 0 → 100644
  1 +/*
  2 + * QEMU VNC display driver: VeNCrypt authentication setup
  3 + *
  4 + * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  5 + * Copyright (C) 2006 Fabrice Bellard
  6 + * Copyright (C) 2009 Red Hat, Inc
  7 + *
  8 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  9 + * of this software and associated documentation files (the "Software"), to deal
  10 + * in the Software without restriction, including without limitation the rights
  11 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 + * copies of the Software, and to permit persons to whom the Software is
  13 + * furnished to do so, subject to the following conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 + * THE SOFTWARE.
  25 + */
  26 +
  27 +#include "vnc.h"
  28 +
  29 +
  30 +static void start_auth_vencrypt_subauth(VncState *vs)
  31 +{
  32 + switch (vs->vd->subauth) {
  33 + case VNC_AUTH_VENCRYPT_TLSNONE:
  34 + case VNC_AUTH_VENCRYPT_X509NONE:
  35 + VNC_DEBUG("Accept TLS auth none\n");
  36 + vnc_write_u32(vs, 0); /* Accept auth completion */
  37 + start_client_init(vs);
  38 + break;
  39 +
  40 + case VNC_AUTH_VENCRYPT_TLSVNC:
  41 + case VNC_AUTH_VENCRYPT_X509VNC:
  42 + VNC_DEBUG("Start TLS auth VNC\n");
  43 + start_auth_vnc(vs);
  44 + break;
  45 +
  46 +#ifdef CONFIG_VNC_SASL
  47 + case VNC_AUTH_VENCRYPT_TLSSASL:
  48 + case VNC_AUTH_VENCRYPT_X509SASL:
  49 + VNC_DEBUG("Start TLS auth SASL\n");
  50 + return start_auth_sasl(vs);
  51 +#endif /* CONFIG_VNC_SASL */
  52 +
  53 + default: /* Should not be possible, but just in case */
  54 + VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth);
  55 + vnc_write_u8(vs, 1);
  56 + if (vs->minor >= 8) {
  57 + static const char err[] = "Unsupported authentication type";
  58 + vnc_write_u32(vs, sizeof(err));
  59 + vnc_write(vs, err, sizeof(err));
  60 + }
  61 + vnc_client_error(vs);
  62 + }
  63 +}
  64 +
  65 +static void vnc_tls_handshake_io(void *opaque);
  66 +
  67 +static int vnc_start_vencrypt_handshake(struct VncState *vs) {
  68 + int ret;
  69 +
  70 + if ((ret = gnutls_handshake(vs->tls.session)) < 0) {
  71 + if (!gnutls_error_is_fatal(ret)) {
  72 + VNC_DEBUG("Handshake interrupted (blocking)\n");
  73 + if (!gnutls_record_get_direction(vs->tls.session))
  74 + qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
  75 + else
  76 + qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
  77 + return 0;
  78 + }
  79 + VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
  80 + vnc_client_error(vs);
  81 + return -1;
  82 + }
  83 +
  84 + if (vs->vd->tls.x509verify) {
  85 + if (vnc_tls_validate_certificate(vs) < 0) {
  86 + VNC_DEBUG("Client verification failed\n");
  87 + vnc_client_error(vs);
  88 + return -1;
  89 + } else {
  90 + VNC_DEBUG("Client verification passed\n");
  91 + }
  92 + }
  93 +
  94 + VNC_DEBUG("Handshake done, switching to TLS data mode\n");
  95 + vs->tls.wiremode = VNC_WIREMODE_TLS;
  96 + qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
  97 +
  98 + start_auth_vencrypt_subauth(vs);
  99 +
  100 + return 0;
  101 +}
  102 +
  103 +static void vnc_tls_handshake_io(void *opaque) {
  104 + struct VncState *vs = (struct VncState *)opaque;
  105 +
  106 + VNC_DEBUG("Handshake IO continue\n");
  107 + vnc_start_vencrypt_handshake(vs);
  108 +}
  109 +
  110 +
  111 +
  112 +#define NEED_X509_AUTH(vs) \
  113 + ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \
  114 + (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \
  115 + (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \
  116 + (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL)
  117 +
  118 +
  119 +static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len)
  120 +{
  121 + int auth = read_u32(data, 0);
  122 +
  123 + if (auth != vs->vd->subauth) {
  124 + VNC_DEBUG("Rejecting auth %d\n", auth);
  125 + vnc_write_u8(vs, 0); /* Reject auth */
  126 + vnc_flush(vs);
  127 + vnc_client_error(vs);
  128 + } else {
  129 + VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
  130 + vnc_write_u8(vs, 1); /* Accept auth */
  131 + vnc_flush(vs);
  132 +
  133 + if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) {
  134 + VNC_DEBUG("Failed to setup TLS\n");
  135 + return 0;
  136 + }
  137 +
  138 + VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
  139 + if (vnc_start_vencrypt_handshake(vs) < 0) {
  140 + VNC_DEBUG("Failed to start TLS handshake\n");
  141 + return 0;
  142 + }
  143 + }
  144 + return 0;
  145 +}
  146 +
  147 +static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len)
  148 +{
  149 + if (data[0] != 0 ||
  150 + data[1] != 2) {
  151 + VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]);
  152 + vnc_write_u8(vs, 1); /* Reject version */
  153 + vnc_flush(vs);
  154 + vnc_client_error(vs);
  155 + } else {
  156 + VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
  157 + vnc_write_u8(vs, 0); /* Accept version */
  158 + vnc_write_u8(vs, 1); /* Number of sub-auths */
  159 + vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
  160 + vnc_flush(vs);
  161 + vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
  162 + }
  163 + return 0;
  164 +}
  165 +
  166 +
  167 +void start_auth_vencrypt(VncState *vs)
  168 +{
  169 + /* Send VeNCrypt version 0.2 */
  170 + vnc_write_u8(vs, 0);
  171 + vnc_write_u8(vs, 2);
  172 +
  173 + vnc_read_when(vs, protocol_client_vencrypt_init, 2);
  174 +}
  175 +
vnc-auth-vencrypt.h 0 → 100644
  1 +/*
  2 + * QEMU VNC display driver
  3 + *
  4 + * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  5 + * Copyright (C) 2006 Fabrice Bellard
  6 + * Copyright (C) 2009 Red Hat, Inc
  7 + *
  8 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  9 + * of this software and associated documentation files (the "Software"), to deal
  10 + * in the Software without restriction, including without limitation the rights
  11 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 + * copies of the Software, and to permit persons to whom the Software is
  13 + * furnished to do so, subject to the following conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 + * THE SOFTWARE.
  25 + */
  26 +
  27 +
  28 +#ifndef __QEMU_VNC_AUTH_VENCRYPT_H__
  29 +#define __QEMU_VNC_AUTH_VENCRYPT_H__
  30 +
  31 +void start_auth_vencrypt(VncState *vs);
  32 +
  33 +#endif /* __QEMU_VNC_AUTH_VENCRYPT_H__ */
vnc-tls.c 0 → 100644
  1 +/*
  2 + * QEMU VNC display driver: TLS helpers
  3 + *
  4 + * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  5 + * Copyright (C) 2006 Fabrice Bellard
  6 + * Copyright (C) 2009 Red Hat, Inc
  7 + *
  8 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  9 + * of this software and associated documentation files (the "Software"), to deal
  10 + * in the Software without restriction, including without limitation the rights
  11 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 + * copies of the Software, and to permit persons to whom the Software is
  13 + * furnished to do so, subject to the following conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 + * THE SOFTWARE.
  25 + */
  26 +
  27 +#include "vnc.h"
  28 +#include "qemu_socket.h"
  29 +
  30 +#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
  31 +/* Very verbose, so only enabled for _VNC_DEBUG >= 2 */
  32 +static void vnc_debug_gnutls_log(int level, const char* str) {
  33 + VNC_DEBUG("%d %s", level, str);
  34 +}
  35 +#endif /* defined(_VNC_DEBUG) && _VNC_DEBUG >= 2 */
  36 +
  37 +
  38 +#define DH_BITS 1024
  39 +static gnutls_dh_params_t dh_params;
  40 +
  41 +static int vnc_tls_initialize(void)
  42 +{
  43 + static int tlsinitialized = 0;
  44 +
  45 + if (tlsinitialized)
  46 + return 1;
  47 +
  48 + if (gnutls_global_init () < 0)
  49 + return 0;
  50 +
  51 + /* XXX ought to re-generate diffie-hellmen params periodically */
  52 + if (gnutls_dh_params_init (&dh_params) < 0)
  53 + return 0;
  54 + if (gnutls_dh_params_generate2 (dh_params, DH_BITS) < 0)
  55 + return 0;
  56 +
  57 +#if defined(_VNC_DEBUG) && _VNC_DEBUG >= 2
  58 + gnutls_global_set_log_level(10);
  59 + gnutls_global_set_log_function(vnc_debug_gnutls_log);
  60 +#endif
  61 +
  62 + tlsinitialized = 1;
  63 +
  64 + return 1;
  65 +}
  66 +
  67 +static ssize_t vnc_tls_push(gnutls_transport_ptr_t transport,
  68 + const void *data,
  69 + size_t len) {
  70 + struct VncState *vs = (struct VncState *)transport;
  71 + int ret;
  72 +
  73 + retry:
  74 + ret = send(vs->csock, data, len, 0);
  75 + if (ret < 0) {
  76 + if (errno == EINTR)
  77 + goto retry;
  78 + return -1;
  79 + }
  80 + return ret;
  81 +}
  82 +
  83 +
  84 +static ssize_t vnc_tls_pull(gnutls_transport_ptr_t transport,
  85 + void *data,
  86 + size_t len) {
  87 + struct VncState *vs = (struct VncState *)transport;
  88 + int ret;
  89 +
  90 + retry:
  91 + ret = recv(vs->csock, data, len, 0);
  92 + if (ret < 0) {
  93 + if (errno == EINTR)
  94 + goto retry;
  95 + return -1;
  96 + }
  97 + return ret;
  98 +}
  99 +
  100 +
  101 +static gnutls_anon_server_credentials vnc_tls_initialize_anon_cred(void)
  102 +{
  103 + gnutls_anon_server_credentials anon_cred;
  104 + int ret;
  105 +
  106 + if ((ret = gnutls_anon_allocate_server_credentials(&anon_cred)) < 0) {
  107 + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
  108 + return NULL;
  109 + }
  110 +
  111 + gnutls_anon_set_server_dh_params(anon_cred, dh_params);
  112 +
  113 + return anon_cred;
  114 +}
  115 +
  116 +
  117 +static gnutls_certificate_credentials_t vnc_tls_initialize_x509_cred(VncDisplay *vd)
  118 +{
  119 + gnutls_certificate_credentials_t x509_cred;
  120 + int ret;
  121 +
  122 + if (!vd->tls.x509cacert) {
  123 + VNC_DEBUG("No CA x509 certificate specified\n");
  124 + return NULL;
  125 + }
  126 + if (!vd->tls.x509cert) {
  127 + VNC_DEBUG("No server x509 certificate specified\n");
  128 + return NULL;
  129 + }
  130 + if (!vd->tls.x509key) {
  131 + VNC_DEBUG("No server private key specified\n");
  132 + return NULL;
  133 + }
  134 +
  135 + if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) {
  136 + VNC_DEBUG("Cannot allocate credentials %s\n", gnutls_strerror(ret));
  137 + return NULL;
  138 + }
  139 + if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
  140 + vd->tls.x509cacert,
  141 + GNUTLS_X509_FMT_PEM)) < 0) {
  142 + VNC_DEBUG("Cannot load CA certificate %s\n", gnutls_strerror(ret));
  143 + gnutls_certificate_free_credentials(x509_cred);
  144 + return NULL;
  145 + }
  146 +
  147 + if ((ret = gnutls_certificate_set_x509_key_file (x509_cred,
  148 + vd->tls.x509cert,
  149 + vd->tls.x509key,
  150 + GNUTLS_X509_FMT_PEM)) < 0) {
  151 + VNC_DEBUG("Cannot load certificate & key %s\n", gnutls_strerror(ret));
  152 + gnutls_certificate_free_credentials(x509_cred);
  153 + return NULL;
  154 + }
  155 +
  156 + if (vd->tls.x509cacrl) {
  157 + if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
  158 + vd->tls.x509cacrl,
  159 + GNUTLS_X509_FMT_PEM)) < 0) {
  160 + VNC_DEBUG("Cannot load CRL %s\n", gnutls_strerror(ret));
  161 + gnutls_certificate_free_credentials(x509_cred);
  162 + return NULL;
  163 + }
  164 + }
  165 +
  166 + gnutls_certificate_set_dh_params (x509_cred, dh_params);
  167 +
  168 + return x509_cred;
  169 +}
  170 +
  171 +
  172 +int vnc_tls_validate_certificate(struct VncState *vs)
  173 +{
  174 + int ret;
  175 + unsigned int status;
  176 + const gnutls_datum_t *certs;
  177 + unsigned int nCerts, i;
  178 + time_t now;
  179 +
  180 + VNC_DEBUG("Validating client certificate\n");
  181 + if ((ret = gnutls_certificate_verify_peers2 (vs->tls.session, &status)) < 0) {
  182 + VNC_DEBUG("Verify failed %s\n", gnutls_strerror(ret));
  183 + return -1;
  184 + }
  185 +
  186 + if ((now = time(NULL)) == ((time_t)-1)) {
  187 + return -1;
  188 + }
  189 +
  190 + if (status != 0) {
  191 + if (status & GNUTLS_CERT_INVALID)
  192 + VNC_DEBUG("The certificate is not trusted.\n");
  193 +
  194 + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
  195 + VNC_DEBUG("The certificate hasn't got a known issuer.\n");
  196 +
  197 + if (status & GNUTLS_CERT_REVOKED)
  198 + VNC_DEBUG("The certificate has been revoked.\n");
  199 +
  200 + if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
  201 + VNC_DEBUG("The certificate uses an insecure algorithm\n");
  202 +
  203 + return -1;
  204 + } else {
  205 + VNC_DEBUG("Certificate is valid!\n");
  206 + }
  207 +
  208 + /* Only support x509 for now */
  209 + if (gnutls_certificate_type_get(vs->tls.session) != GNUTLS_CRT_X509)
  210 + return -1;
  211 +
  212 + if (!(certs = gnutls_certificate_get_peers(vs->tls.session, &nCerts)))
  213 + return -1;
  214 +
  215 + for (i = 0 ; i < nCerts ; i++) {
  216 + gnutls_x509_crt_t cert;
  217 + VNC_DEBUG ("Checking certificate chain %d\n", i);
  218 + if (gnutls_x509_crt_init (&cert) < 0)
  219 + return -1;
  220 +
  221 + if (gnutls_x509_crt_import(cert, &certs[i], GNUTLS_X509_FMT_DER) < 0) {
  222 + gnutls_x509_crt_deinit (cert);
  223 + return -1;
  224 + }
  225 +
  226 + if (gnutls_x509_crt_get_expiration_time (cert) < now) {
  227 + VNC_DEBUG("The certificate has expired\n");
  228 + gnutls_x509_crt_deinit (cert);
  229 + return -1;
  230 + }
  231 +
  232 + if (gnutls_x509_crt_get_activation_time (cert) > now) {
  233 + VNC_DEBUG("The certificate is not yet activated\n");
  234 + gnutls_x509_crt_deinit (cert);
  235 + return -1;
  236 + }
  237 +
  238 + if (gnutls_x509_crt_get_activation_time (cert) > now) {
  239 + VNC_DEBUG("The certificate is not yet activated\n");
  240 + gnutls_x509_crt_deinit (cert);
  241 + return -1;
  242 + }
  243 +
  244 + if (i == 0) {
  245 + size_t dnameSize = 1024;
  246 + vs->tls.dname = qemu_malloc(dnameSize);
  247 + requery:
  248 + if ((ret = gnutls_x509_crt_get_dn (cert, vs->tls.dname, &dnameSize)) != 0) {
  249 + if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
  250 + vs->tls.dname = qemu_realloc(vs->tls.dname, dnameSize);
  251 + goto requery;
  252 + }
  253 + gnutls_x509_crt_deinit (cert);
  254 + VNC_DEBUG("Cannot get client distinguished name: %s",
  255 + gnutls_strerror (ret));
  256 + return -1;
  257 + }
  258 +
  259 + if (vs->vd->tls.x509verify) {
  260 + int allow;
  261 + if (!vs->vd->tls.acl) {
  262 + VNC_DEBUG("no ACL activated, allowing access");
  263 + gnutls_x509_crt_deinit (cert);
  264 + continue;
  265 + }
  266 +
  267 + allow = qemu_acl_party_is_allowed(vs->vd->tls.acl,
  268 + vs->tls.dname);
  269 +
  270 + VNC_DEBUG("TLS x509 ACL check for %s is %s\n",
  271 + vs->tls.dname, allow ? "allowed" : "denied");
  272 + if (!allow) {
  273 + gnutls_x509_crt_deinit (cert);
  274 + return -1;
  275 + }
  276 + }
  277 + }
  278 +
  279 + gnutls_x509_crt_deinit (cert);
  280 + }
  281 +
  282 + return 0;
  283 +}
  284 +
  285 +
  286 +int vnc_tls_client_setup(struct VncState *vs,
  287 + int needX509Creds) {
  288 + static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
  289 + static const int protocol_priority[]= { GNUTLS_TLS1_1, GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
  290 + static const int kx_anon[] = {GNUTLS_KX_ANON_DH, 0};
  291 + static const int kx_x509[] = {GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA, GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0};
  292 +
  293 + VNC_DEBUG("Do TLS setup\n");
  294 + if (vnc_tls_initialize() < 0) {
  295 + VNC_DEBUG("Failed to init TLS\n");
  296 + vnc_client_error(vs);
  297 + return -1;
  298 + }
  299 + if (vs->tls.session == NULL) {
  300 + if (gnutls_init(&vs->tls.session, GNUTLS_SERVER) < 0) {
  301 + vnc_client_error(vs);
  302 + return -1;
  303 + }
  304 +
  305 + if (gnutls_set_default_priority(vs->tls.session) < 0) {
  306 + gnutls_deinit(vs->tls.session);
  307 + vs->tls.session = NULL;
  308 + vnc_client_error(vs);
  309 + return -1;
  310 + }
  311 +
  312 + if (gnutls_kx_set_priority(vs->tls.session, needX509Creds ? kx_x509 : kx_anon) < 0) {
  313 + gnutls_deinit(vs->tls.session);
  314 + vs->tls.session = NULL;
  315 + vnc_client_error(vs);
  316 + return -1;
  317 + }
  318 +
  319 + if (gnutls_certificate_type_set_priority(vs->tls.session, cert_type_priority) < 0) {
  320 + gnutls_deinit(vs->tls.session);
  321 + vs->tls.session = NULL;
  322 + vnc_client_error(vs);
  323 + return -1;
  324 + }
  325 +
  326 + if (gnutls_protocol_set_priority(vs->tls.session, protocol_priority) < 0) {
  327 + gnutls_deinit(vs->tls.session);
  328 + vs->tls.session = NULL;
  329 + vnc_client_error(vs);
  330 + return -1;
  331 + }
  332 +
  333 + if (needX509Creds) {
  334 + gnutls_certificate_server_credentials x509_cred = vnc_tls_initialize_x509_cred(vs->vd);
  335 + if (!x509_cred) {
  336 + gnutls_deinit(vs->tls.session);
  337 + vs->tls.session = NULL;
  338 + vnc_client_error(vs);
  339 + return -1;
  340 + }
  341 + if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_CERTIFICATE, x509_cred) < 0) {
  342 + gnutls_deinit(vs->tls.session);
  343 + vs->tls.session = NULL;
  344 + gnutls_certificate_free_credentials(x509_cred);
  345 + vnc_client_error(vs);
  346 + return -1;
  347 + }
  348 + if (vs->vd->tls.x509verify) {
  349 + VNC_DEBUG("Requesting a client certificate\n");
  350 + gnutls_certificate_server_set_request (vs->tls.session, GNUTLS_CERT_REQUEST);
  351 + }
  352 +
  353 + } else {
  354 + gnutls_anon_server_credentials anon_cred = vnc_tls_initialize_anon_cred();
  355 + if (!anon_cred) {
  356 + gnutls_deinit(vs->tls.session);
  357 + vs->tls.session = NULL;
  358 + vnc_client_error(vs);
  359 + return -1;
  360 + }
  361 + if (gnutls_credentials_set(vs->tls.session, GNUTLS_CRD_ANON, anon_cred) < 0) {
  362 + gnutls_deinit(vs->tls.session);
  363 + vs->tls.session = NULL;
  364 + gnutls_anon_free_server_credentials(anon_cred);
  365 + vnc_client_error(vs);
  366 + return -1;
  367 + }
  368 + }
  369 +
  370 + gnutls_transport_set_ptr(vs->tls.session, (gnutls_transport_ptr_t)vs);
  371 + gnutls_transport_set_push_function(vs->tls.session, vnc_tls_push);
  372 + gnutls_transport_set_pull_function(vs->tls.session, vnc_tls_pull);
  373 + }
  374 + return 0;
  375 +}
  376 +
  377 +
  378 +void vnc_tls_client_cleanup(struct VncState *vs)
  379 +{
  380 + if (vs->tls.session) {
  381 + gnutls_deinit(vs->tls.session);
  382 + vs->tls.session = NULL;
  383 + }
  384 + vs->tls.wiremode = VNC_WIREMODE_CLEAR;
  385 + free(vs->tls.dname);
  386 +}
  387 +
  388 +
  389 +
  390 +static int vnc_set_x509_credential(VncDisplay *vd,
  391 + const char *certdir,
  392 + const char *filename,
  393 + char **cred,
  394 + int ignoreMissing)
  395 +{
  396 + struct stat sb;
  397 +
  398 + if (*cred) {
  399 + qemu_free(*cred);
  400 + *cred = NULL;
  401 + }
  402 +
  403 + *cred = qemu_malloc(strlen(certdir) + strlen(filename) + 2);
  404 +
  405 + strcpy(*cred, certdir);
  406 + strcat(*cred, "/");
  407 + strcat(*cred, filename);
  408 +
  409 + VNC_DEBUG("Check %s\n", *cred);
  410 + if (stat(*cred, &sb) < 0) {
  411 + qemu_free(*cred);
  412 + *cred = NULL;
  413 + if (ignoreMissing && errno == ENOENT)
  414 + return 0;
  415 + return -1;
  416 + }
  417 +
  418 + return 0;
  419 +}
  420 +
  421 +
  422 +#define X509_CA_CERT_FILE "ca-cert.pem"
  423 +#define X509_CA_CRL_FILE "ca-crl.pem"
  424 +#define X509_SERVER_KEY_FILE "server-key.pem"
  425 +#define X509_SERVER_CERT_FILE "server-cert.pem"
  426 +
  427 +
  428 +int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
  429 + const char *certdir)
  430 +{
  431 + if (vnc_set_x509_credential(vd, certdir, X509_CA_CERT_FILE, &vd->tls.x509cacert, 0) < 0)
  432 + goto cleanup;
  433 + if (vnc_set_x509_credential(vd, certdir, X509_CA_CRL_FILE, &vd->tls.x509cacrl, 1) < 0)
  434 + goto cleanup;
  435 + if (vnc_set_x509_credential(vd, certdir, X509_SERVER_CERT_FILE, &vd->tls.x509cert, 0) < 0)
  436 + goto cleanup;
  437 + if (vnc_set_x509_credential(vd, certdir, X509_SERVER_KEY_FILE, &vd->tls.x509key, 0) < 0)
  438 + goto cleanup;
  439 +
  440 + return 0;
  441 +
  442 + cleanup:
  443 + qemu_free(vd->tls.x509cacert);
  444 + qemu_free(vd->tls.x509cacrl);
  445 + qemu_free(vd->tls.x509cert);
  446 + qemu_free(vd->tls.x509key);
  447 + vd->tls.x509cacert = vd->tls.x509cacrl = vd->tls.x509cert = vd->tls.x509key = NULL;
  448 + return -1;
  449 +}
  450 +
vnc-tls.h 0 → 100644
  1 +/*
  2 + * QEMU VNC display driver. TLS helpers
  3 + *
  4 + * Copyright (C) 2006 Anthony Liguori <anthony@codemonkey.ws>
  5 + * Copyright (C) 2006 Fabrice Bellard
  6 + * Copyright (C) 2009 Red Hat, Inc
  7 + *
  8 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  9 + * of this software and associated documentation files (the "Software"), to deal
  10 + * in the Software without restriction, including without limitation the rights
  11 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12 + * copies of the Software, and to permit persons to whom the Software is
  13 + * furnished to do so, subject to the following conditions:
  14 + *
  15 + * The above copyright notice and this permission notice shall be included in
  16 + * all copies or substantial portions of the Software.
  17 + *
  18 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24 + * THE SOFTWARE.
  25 + */
  26 +
  27 +
  28 +#ifndef __QEMU_VNC_TLS_H__
  29 +#define __QEMU_VNC_TLS_H__
  30 +
  31 +#include <gnutls/gnutls.h>
  32 +#include <gnutls/x509.h>
  33 +
  34 +#include "acl.h"
  35 +
  36 +enum {
  37 + VNC_WIREMODE_CLEAR,
  38 + VNC_WIREMODE_TLS,
  39 +};
  40 +
  41 +typedef struct VncDisplayTLS VncDisplayTLS;
  42 +typedef struct VncStateTLS VncStateTLS;
  43 +
  44 +/* Server state */
  45 +struct VncDisplayTLS {
  46 + int x509verify; /* Non-zero if server requests & validates client cert */
  47 + qemu_acl *acl;
  48 +
  49 + /* Paths to x509 certs/keys */
  50 + char *x509cacert;
  51 + char *x509cacrl;
  52 + char *x509cert;
  53 + char *x509key;
  54 +};
  55 +
  56 +/* Per client state */
  57 +struct VncStateTLS {
  58 + /* Whether data is being TLS encrypted yet */
  59 + int wiremode;
  60 + gnutls_session_t session;
  61 +
  62 + /* Client's Distinguished Name from the x509 cert */
  63 + char *dname;
  64 +};
  65 +
  66 +int vnc_tls_client_setup(VncState *vs, int x509Creds);
  67 +void vnc_tls_client_cleanup(VncState *vs);
  68 +
  69 +int vnc_tls_validate_certificate(VncState *vs);
  70 +
  71 +int vnc_tls_set_x509_creds_dir(VncDisplay *vd,
  72 + const char *path);
  73 +
  74 +
  75 +#endif /* __QEMU_VNC_TLS_H__ */
  76 +