blob: 94af48d558e34f351887508dbaeaaadefb366a70 [file] [log] [blame]
Adam Tkacb10489b2010-04-23 14:16:04 +00001/*
2 * Copyright (C) 2006 OCCAM Financial Technology
3 * Copyright (C) 2005-2006 Martin Koegler
4 * Copyright (C) 2010 TigerVNC Team
5 *
6 * This is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This software 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this software; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19 * USA.
20 */
21//
22// CSecurityVeNCrypt
23//
24
25#include <rfb/Exception.h>
26#include <rdr/InStream.h>
27#include <rdr/OutStream.h>
28#include <rfb/CConnection.h>
29#include <rfb/CSecurityTLS.h>
30#include <rfb/CSecurityVeNCrypt.h>
31#include <rfb/CSecurityVncAuth.h>
Adam Tkacdb062b62010-07-20 15:13:24 +000032#include <rfb/LogWriter.h>
Adam Tkacb10489b2010-04-23 14:16:04 +000033#include <rfb/SSecurityVeNCrypt.h>
34#include <list>
35
36using namespace rfb;
37using namespace rdr;
38using namespace std;
39
Adam Tkacdb062b62010-07-20 15:13:24 +000040static LogWriter vlog("CVeNCrypt");
41
Adam Tkaca0325932010-07-20 15:14:08 +000042CSecurityVeNCrypt::CSecurityVeNCrypt(Security* sec) : csecurity(NULL), security(sec)
Adam Tkacb10489b2010-04-23 14:16:04 +000043{
44 haveRecvdMajorVersion = false;
45 haveRecvdMinorVersion = false;
46 haveSentVersion = false;
47 haveAgreedVersion = false;
48 haveListOfTypes = false;
49 haveNumberOfTypes = false;
50 haveChosenType = false;
51 majorVersion = 0;
52 minorVersion = 0;
53 chosenType = secTypeVeNCrypt;
54 nAvailableTypes = 0;
55 availableTypes = NULL;
56 iAvailableType = 0;
57}
58
59CSecurityVeNCrypt::~CSecurityVeNCrypt()
60{
61 if (availableTypes)
62 delete[] availableTypes;
63}
64
65bool CSecurityVeNCrypt::processMsg(CConnection* cc)
66{
67 InStream* is = cc->getInStream();
68 OutStream* os = cc->getOutStream();
69
70 /* get major, minor versions, send what we can support (or 0.0 for can't support it) */
71 if (!haveRecvdMajorVersion) {
72 majorVersion = is->readU8();
73 haveRecvdMajorVersion = true;
74
75 return false;
76 }
77
78 if (!haveRecvdMinorVersion) {
79 minorVersion = is->readU8();
80 haveRecvdMinorVersion = true;
81 }
82
83 /* major version in upper 8 bits and minor version in lower 8 bits */
84 U16 Version = (((U16) majorVersion) << 8) | ((U16) minorVersion);
85
86 if (!haveSentVersion) {
87 /* Currently we don't support former VeNCrypt 0.1 */
88 if (Version >= 0x0002) {
89 majorVersion = 0;
90 minorVersion = 2;
91 os->writeU8(majorVersion);
92 os->writeU8(minorVersion);
93 os->flush();
94 } else {
95 /* Send 0.0 to indicate no support */
96 majorVersion = 0;
97 minorVersion = 0;
98 os->writeU8(0);
99 os->writeU8(0);
100 os->flush();
101 throw AuthFailureException("The server reported an unsupported VeNCrypt version");
102 }
103
104 haveSentVersion = true;
105 return false;
106 }
107
108 /* Check that the server is OK */
109 if (!haveAgreedVersion) {
110 if (is->readU8())
111 throw AuthFailureException("The server reported it could not support the "
112 "VeNCrypt version");
113
114 haveAgreedVersion = true;
115 return false;
116 }
117
118 /* get a number of types */
119 if (!haveNumberOfTypes) {
120 nAvailableTypes = is->readU8();
121 iAvailableType = 0;
122
123 if (!nAvailableTypes)
124 throw AuthFailureException("The server reported no VeNCrypt sub-types");
125
126 availableTypes = new rdr::U32[nAvailableTypes];
127 haveNumberOfTypes = true;
128 return false;
129 }
130
131 if (nAvailableTypes) {
132 /* read in the types possible */
133 if (!haveListOfTypes) {
134 if (is->checkNoWait(4)) {
135 availableTypes[iAvailableType++] = is->readU32();
136 haveListOfTypes = (iAvailableType >= nAvailableTypes);
Adam Tkacdb062b62010-07-20 15:13:24 +0000137 vlog.debug("Server offers security type %s (%d)",
138 secTypeName(availableTypes[iAvailableType - 1]),
139 availableTypes[iAvailableType - 1]);
Adam Tkacb10489b2010-04-23 14:16:04 +0000140
141 if (!haveListOfTypes)
142 return false;
143
144 } else
145 return false;
146 }
147
148 /* make a choice and send it to the server, meanwhile set up the stack */
149 if (!haveChosenType) {
150 chosenType = 0;
151 U8 i;
152 list<U32>::iterator j;
153 list<U32> preferredList;
154
155 /* Try preferred choice */
156 SSecurityVeNCrypt::getSecTypes(&preferredList);
157
158 for (j = preferredList.begin(); j != preferredList.end(); j++) {
159 for (i = 0; i < nAvailableTypes; i++) {
160 if (*j == availableTypes[i]) {
161 chosenType = *j;
162 break;
163 }
164 }
165
166 if (chosenType)
167 break;
168 }
169
Adam Tkacdb062b62010-07-20 15:13:24 +0000170 vlog.debug("Choosing security type %s (%d)", secTypeName(chosenType),
171 chosenType);
Adam Tkacb10489b2010-04-23 14:16:04 +0000172 /* Set up the stack according to the chosen type: */
173 switch (chosenType) {
174 case secTypeTLSNone:
175 case secTypeTLSVnc:
176 case secTypeTLSPlain:
177 case secTypeX509None:
178 case secTypeX509Vnc:
179 case secTypeX509Plain:
Adam Tkacc86db212010-07-20 15:08:58 +0000180 csecurity = CSecurityVeNCrypt::getCSecurityStack(chosenType);
Adam Tkacb10489b2010-04-23 14:16:04 +0000181 break;
182
183 case secTypeInvalid:
184 case secTypeVeNCrypt: /* would cause looping */
185 default:
186 throw AuthFailureException("No valid VeNCrypt sub-type");
187 }
188
189 /* send chosen type to server */
190 os->writeU32(chosenType);
191 os->flush();
192
193 haveChosenType = true;
194 }
195 } else {
196 /*
197 * Server told us that there are 0 types it can support - this should not
198 * happen, since if the server supports 0 sub-types, it doesn't support
199 * this security type
200 */
201 throw AuthFailureException("The server reported 0 VeNCrypt sub-types");
202 }
203
Adam Tkacc86db212010-07-20 15:08:58 +0000204 return csecurity->processMsg(cc);
Adam Tkacb10489b2010-04-23 14:16:04 +0000205}
206
207CSecurityStack* CSecurityVeNCrypt::getCSecurityStack(int secType)
208{
209 switch (secType) {
210 case secTypeTLSNone:
211 return new CSecurityStack(secTypeTLSNone, "TLS with no password",
212 new CSecurityTLS());
213 case secTypeTLSVnc:
214 return new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
215 new CSecurityTLS(), new CSecurityVncAuth());
216#if 0
217 /* Following subtypes are not implemented, yet */
218 case secTypeTLSPlain:
219 case secTypeX509None:
220 case secTypeX509Vnc:
221 case secTypeX509Plain:
222#endif
223 default:
224 throw Exception("Unsupported VeNCrypt subtype");
225 }
226
227 return NULL; /* not reached */
228}