root / vnc-auth-vencrypt.c @ 9f107513
History | View | Annotate | Download (5.6 kB)
1 | 274b6fcc | aliguori | /*
|
---|---|---|---|
2 | 274b6fcc | aliguori | * QEMU VNC display driver: VeNCrypt authentication setup
|
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 | 274b6fcc | aliguori | #include "vnc.h" |
28 | 274b6fcc | aliguori | |
29 | 274b6fcc | aliguori | |
30 | 274b6fcc | aliguori | static void start_auth_vencrypt_subauth(VncState *vs) |
31 | 274b6fcc | aliguori | { |
32 | 274b6fcc | aliguori | switch (vs->vd->subauth) {
|
33 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_TLSNONE:
|
34 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_X509NONE:
|
35 | 274b6fcc | aliguori | VNC_DEBUG("Accept TLS auth none\n");
|
36 | 274b6fcc | aliguori | vnc_write_u32(vs, 0); /* Accept auth completion */ |
37 | 274b6fcc | aliguori | start_client_init(vs); |
38 | 274b6fcc | aliguori | break;
|
39 | 274b6fcc | aliguori | |
40 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_TLSVNC:
|
41 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_X509VNC:
|
42 | 274b6fcc | aliguori | VNC_DEBUG("Start TLS auth VNC\n");
|
43 | 274b6fcc | aliguori | start_auth_vnc(vs); |
44 | 274b6fcc | aliguori | break;
|
45 | 274b6fcc | aliguori | |
46 | 274b6fcc | aliguori | #ifdef CONFIG_VNC_SASL
|
47 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_TLSSASL:
|
48 | 274b6fcc | aliguori | case VNC_AUTH_VENCRYPT_X509SASL:
|
49 | 274b6fcc | aliguori | VNC_DEBUG("Start TLS auth SASL\n");
|
50 | 274b6fcc | aliguori | return start_auth_sasl(vs);
|
51 | 274b6fcc | aliguori | #endif /* CONFIG_VNC_SASL */ |
52 | 274b6fcc | aliguori | |
53 | 274b6fcc | aliguori | default: /* Should not be possible, but just in case */ |
54 | 274b6fcc | aliguori | VNC_DEBUG("Reject subauth %d server bug\n", vs->vd->auth);
|
55 | 274b6fcc | aliguori | vnc_write_u8(vs, 1);
|
56 | 274b6fcc | aliguori | if (vs->minor >= 8) { |
57 | 274b6fcc | aliguori | static const char err[] = "Unsupported authentication type"; |
58 | 274b6fcc | aliguori | vnc_write_u32(vs, sizeof(err));
|
59 | 274b6fcc | aliguori | vnc_write(vs, err, sizeof(err));
|
60 | 274b6fcc | aliguori | } |
61 | 274b6fcc | aliguori | vnc_client_error(vs); |
62 | 274b6fcc | aliguori | } |
63 | 274b6fcc | aliguori | } |
64 | 274b6fcc | aliguori | |
65 | 274b6fcc | aliguori | static void vnc_tls_handshake_io(void *opaque); |
66 | 274b6fcc | aliguori | |
67 | 274b6fcc | aliguori | static int vnc_start_vencrypt_handshake(struct VncState *vs) { |
68 | 274b6fcc | aliguori | int ret;
|
69 | 274b6fcc | aliguori | |
70 | 274b6fcc | aliguori | if ((ret = gnutls_handshake(vs->tls.session)) < 0) { |
71 | 274b6fcc | aliguori | if (!gnutls_error_is_fatal(ret)) {
|
72 | 274b6fcc | aliguori | VNC_DEBUG("Handshake interrupted (blocking)\n");
|
73 | 274b6fcc | aliguori | if (!gnutls_record_get_direction(vs->tls.session))
|
74 | 274b6fcc | aliguori | qemu_set_fd_handler(vs->csock, vnc_tls_handshake_io, NULL, vs);
|
75 | 274b6fcc | aliguori | else
|
76 | 274b6fcc | aliguori | qemu_set_fd_handler(vs->csock, NULL, vnc_tls_handshake_io, vs);
|
77 | 274b6fcc | aliguori | return 0; |
78 | 274b6fcc | aliguori | } |
79 | 274b6fcc | aliguori | VNC_DEBUG("Handshake failed %s\n", gnutls_strerror(ret));
|
80 | 274b6fcc | aliguori | vnc_client_error(vs); |
81 | 274b6fcc | aliguori | return -1; |
82 | 274b6fcc | aliguori | } |
83 | 274b6fcc | aliguori | |
84 | 274b6fcc | aliguori | if (vs->vd->tls.x509verify) {
|
85 | 274b6fcc | aliguori | if (vnc_tls_validate_certificate(vs) < 0) { |
86 | 274b6fcc | aliguori | VNC_DEBUG("Client verification failed\n");
|
87 | 274b6fcc | aliguori | vnc_client_error(vs); |
88 | 274b6fcc | aliguori | return -1; |
89 | 274b6fcc | aliguori | } else {
|
90 | 274b6fcc | aliguori | VNC_DEBUG("Client verification passed\n");
|
91 | 274b6fcc | aliguori | } |
92 | 274b6fcc | aliguori | } |
93 | 274b6fcc | aliguori | |
94 | 274b6fcc | aliguori | VNC_DEBUG("Handshake done, switching to TLS data mode\n");
|
95 | 274b6fcc | aliguori | vs->tls.wiremode = VNC_WIREMODE_TLS; |
96 | 274b6fcc | aliguori | qemu_set_fd_handler2(vs->csock, NULL, vnc_client_read, vnc_client_write, vs);
|
97 | 274b6fcc | aliguori | |
98 | 274b6fcc | aliguori | start_auth_vencrypt_subauth(vs); |
99 | 274b6fcc | aliguori | |
100 | 274b6fcc | aliguori | return 0; |
101 | 274b6fcc | aliguori | } |
102 | 274b6fcc | aliguori | |
103 | 274b6fcc | aliguori | static void vnc_tls_handshake_io(void *opaque) { |
104 | 274b6fcc | aliguori | struct VncState *vs = (struct VncState *)opaque; |
105 | 274b6fcc | aliguori | |
106 | 274b6fcc | aliguori | VNC_DEBUG("Handshake IO continue\n");
|
107 | 274b6fcc | aliguori | vnc_start_vencrypt_handshake(vs); |
108 | 274b6fcc | aliguori | } |
109 | 274b6fcc | aliguori | |
110 | 274b6fcc | aliguori | |
111 | 274b6fcc | aliguori | |
112 | 274b6fcc | aliguori | #define NEED_X509_AUTH(vs) \
|
113 | 274b6fcc | aliguori | ((vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509NONE || \ |
114 | 274b6fcc | aliguori | (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509VNC || \ |
115 | 274b6fcc | aliguori | (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509PLAIN || \ |
116 | 274b6fcc | aliguori | (vs)->vd->subauth == VNC_AUTH_VENCRYPT_X509SASL) |
117 | 274b6fcc | aliguori | |
118 | 274b6fcc | aliguori | |
119 | 274b6fcc | aliguori | static int protocol_client_vencrypt_auth(VncState *vs, uint8_t *data, size_t len) |
120 | 274b6fcc | aliguori | { |
121 | 274b6fcc | aliguori | int auth = read_u32(data, 0); |
122 | 274b6fcc | aliguori | |
123 | 274b6fcc | aliguori | if (auth != vs->vd->subauth) {
|
124 | 274b6fcc | aliguori | VNC_DEBUG("Rejecting auth %d\n", auth);
|
125 | 274b6fcc | aliguori | vnc_write_u8(vs, 0); /* Reject auth */ |
126 | 274b6fcc | aliguori | vnc_flush(vs); |
127 | 274b6fcc | aliguori | vnc_client_error(vs); |
128 | 274b6fcc | aliguori | } else {
|
129 | 274b6fcc | aliguori | VNC_DEBUG("Accepting auth %d, setting up TLS for handshake\n", auth);
|
130 | 274b6fcc | aliguori | vnc_write_u8(vs, 1); /* Accept auth */ |
131 | 274b6fcc | aliguori | vnc_flush(vs); |
132 | 274b6fcc | aliguori | |
133 | 274b6fcc | aliguori | if (vnc_tls_client_setup(vs, NEED_X509_AUTH(vs)) < 0) { |
134 | 274b6fcc | aliguori | VNC_DEBUG("Failed to setup TLS\n");
|
135 | 274b6fcc | aliguori | return 0; |
136 | 274b6fcc | aliguori | } |
137 | 274b6fcc | aliguori | |
138 | 274b6fcc | aliguori | VNC_DEBUG("Start TLS VeNCrypt handshake process\n");
|
139 | 274b6fcc | aliguori | if (vnc_start_vencrypt_handshake(vs) < 0) { |
140 | 274b6fcc | aliguori | VNC_DEBUG("Failed to start TLS handshake\n");
|
141 | 274b6fcc | aliguori | return 0; |
142 | 274b6fcc | aliguori | } |
143 | 274b6fcc | aliguori | } |
144 | 274b6fcc | aliguori | return 0; |
145 | 274b6fcc | aliguori | } |
146 | 274b6fcc | aliguori | |
147 | 274b6fcc | aliguori | static int protocol_client_vencrypt_init(VncState *vs, uint8_t *data, size_t len) |
148 | 274b6fcc | aliguori | { |
149 | 274b6fcc | aliguori | if (data[0] != 0 || |
150 | 274b6fcc | aliguori | data[1] != 2) { |
151 | 274b6fcc | aliguori | VNC_DEBUG("Unsupported VeNCrypt protocol %d.%d\n", (int)data[0], (int)data[1]); |
152 | 274b6fcc | aliguori | vnc_write_u8(vs, 1); /* Reject version */ |
153 | 274b6fcc | aliguori | vnc_flush(vs); |
154 | 274b6fcc | aliguori | vnc_client_error(vs); |
155 | 274b6fcc | aliguori | } else {
|
156 | 274b6fcc | aliguori | VNC_DEBUG("Sending allowed auth %d\n", vs->vd->subauth);
|
157 | 274b6fcc | aliguori | vnc_write_u8(vs, 0); /* Accept version */ |
158 | 274b6fcc | aliguori | vnc_write_u8(vs, 1); /* Number of sub-auths */ |
159 | 274b6fcc | aliguori | vnc_write_u32(vs, vs->vd->subauth); /* The supported auth */
|
160 | 274b6fcc | aliguori | vnc_flush(vs); |
161 | 274b6fcc | aliguori | vnc_read_when(vs, protocol_client_vencrypt_auth, 4);
|
162 | 274b6fcc | aliguori | } |
163 | 274b6fcc | aliguori | return 0; |
164 | 274b6fcc | aliguori | } |
165 | 274b6fcc | aliguori | |
166 | 274b6fcc | aliguori | |
167 | 274b6fcc | aliguori | void start_auth_vencrypt(VncState *vs)
|
168 | 274b6fcc | aliguori | { |
169 | 274b6fcc | aliguori | /* Send VeNCrypt version 0.2 */
|
170 | 274b6fcc | aliguori | vnc_write_u8(vs, 0);
|
171 | 274b6fcc | aliguori | vnc_write_u8(vs, 2);
|
172 | 274b6fcc | aliguori | |
173 | 274b6fcc | aliguori | vnc_read_when(vs, protocol_client_vencrypt_init, 2);
|
174 | 274b6fcc | aliguori | } |