blob: 39a95f443dfd7391bf46e82fbde2542fad63bef1 [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 <list>
34
35using namespace rfb;
36using namespace rdr;
37using namespace std;
38
Adam Tkacdb062b62010-07-20 15:13:24 +000039static LogWriter vlog("CVeNCrypt");
40
Adam Tkaca0325932010-07-20 15:14:08 +000041CSecurityVeNCrypt::CSecurityVeNCrypt(Security* sec) : csecurity(NULL), security(sec)
Adam Tkacb10489b2010-04-23 14:16:04 +000042{
43 haveRecvdMajorVersion = false;
44 haveRecvdMinorVersion = false;
45 haveSentVersion = false;
46 haveAgreedVersion = false;
47 haveListOfTypes = false;
48 haveNumberOfTypes = false;
49 haveChosenType = false;
50 majorVersion = 0;
51 minorVersion = 0;
52 chosenType = secTypeVeNCrypt;
53 nAvailableTypes = 0;
54 availableTypes = NULL;
55 iAvailableType = 0;
56}
57
58CSecurityVeNCrypt::~CSecurityVeNCrypt()
59{
60 if (availableTypes)
61 delete[] availableTypes;
62}
63
64bool CSecurityVeNCrypt::processMsg(CConnection* cc)
65{
66 InStream* is = cc->getInStream();
67 OutStream* os = cc->getOutStream();
68
69 /* get major, minor versions, send what we can support (or 0.0 for can't support it) */
70 if (!haveRecvdMajorVersion) {
71 majorVersion = is->readU8();
72 haveRecvdMajorVersion = true;
73
74 return false;
75 }
76
77 if (!haveRecvdMinorVersion) {
78 minorVersion = is->readU8();
79 haveRecvdMinorVersion = true;
80 }
81
82 /* major version in upper 8 bits and minor version in lower 8 bits */
83 U16 Version = (((U16) majorVersion) << 8) | ((U16) minorVersion);
84
85 if (!haveSentVersion) {
86 /* Currently we don't support former VeNCrypt 0.1 */
87 if (Version >= 0x0002) {
88 majorVersion = 0;
89 minorVersion = 2;
90 os->writeU8(majorVersion);
91 os->writeU8(minorVersion);
92 os->flush();
93 } else {
94 /* Send 0.0 to indicate no support */
95 majorVersion = 0;
96 minorVersion = 0;
97 os->writeU8(0);
98 os->writeU8(0);
99 os->flush();
100 throw AuthFailureException("The server reported an unsupported VeNCrypt version");
101 }
102
103 haveSentVersion = true;
104 return false;
105 }
106
107 /* Check that the server is OK */
108 if (!haveAgreedVersion) {
109 if (is->readU8())
110 throw AuthFailureException("The server reported it could not support the "
111 "VeNCrypt version");
112
113 haveAgreedVersion = true;
114 return false;
115 }
116
117 /* get a number of types */
118 if (!haveNumberOfTypes) {
119 nAvailableTypes = is->readU8();
120 iAvailableType = 0;
121
122 if (!nAvailableTypes)
123 throw AuthFailureException("The server reported no VeNCrypt sub-types");
124
125 availableTypes = new rdr::U32[nAvailableTypes];
126 haveNumberOfTypes = true;
127 return false;
128 }
129
130 if (nAvailableTypes) {
131 /* read in the types possible */
132 if (!haveListOfTypes) {
133 if (is->checkNoWait(4)) {
134 availableTypes[iAvailableType++] = is->readU32();
135 haveListOfTypes = (iAvailableType >= nAvailableTypes);
Adam Tkacdb062b62010-07-20 15:13:24 +0000136 vlog.debug("Server offers security type %s (%d)",
137 secTypeName(availableTypes[iAvailableType - 1]),
138 availableTypes[iAvailableType - 1]);
Adam Tkacb10489b2010-04-23 14:16:04 +0000139
140 if (!haveListOfTypes)
141 return false;
142
143 } else
144 return false;
145 }
146
147 /* make a choice and send it to the server, meanwhile set up the stack */
148 if (!haveChosenType) {
Adam Tkac814fa892010-07-20 15:14:50 +0000149 chosenType = secTypeInvalid;
Adam Tkacb10489b2010-04-23 14:16:04 +0000150 U8 i;
151 list<U32>::iterator j;
152 list<U32> preferredList;
153
154 /* Try preferred choice */
Adam Tkac814fa892010-07-20 15:14:50 +0000155 preferredList = security->GetEnabledExtSecTypes();
156
Adam Tkacb10489b2010-04-23 14:16:04 +0000157 for (j = preferredList.begin(); j != preferredList.end(); j++) {
158 for (i = 0; i < nAvailableTypes; i++) {
159 if (*j == availableTypes[i]) {
160 chosenType = *j;
161 break;
162 }
163 }
164
Adam Tkac814fa892010-07-20 15:14:50 +0000165 if (chosenType != secTypeInvalid)
Adam Tkacb10489b2010-04-23 14:16:04 +0000166 break;
167 }
168
Adam Tkacdb062b62010-07-20 15:13:24 +0000169 vlog.debug("Choosing security type %s (%d)", secTypeName(chosenType),
170 chosenType);
Adam Tkacb10489b2010-04-23 14:16:04 +0000171
Adam Tkac814fa892010-07-20 15:14:50 +0000172 /* Set up the stack according to the chosen type: */
173 if (chosenType == secTypeInvalid || chosenType == secTypeVeNCrypt)
174 throw AuthFailureException("No valid VeNCrypt sub-type");
175
176 csecurity = CSecurityVeNCrypt::getCSecurityStack(chosenType);
177
Adam Tkacb10489b2010-04-23 14:16:04 +0000178 /* send chosen type to server */
179 os->writeU32(chosenType);
180 os->flush();
181
182 haveChosenType = true;
183 }
184 } else {
185 /*
186 * Server told us that there are 0 types it can support - this should not
187 * happen, since if the server supports 0 sub-types, it doesn't support
188 * this security type
189 */
190 throw AuthFailureException("The server reported 0 VeNCrypt sub-types");
191 }
192
Adam Tkacc86db212010-07-20 15:08:58 +0000193 return csecurity->processMsg(cc);
Adam Tkacb10489b2010-04-23 14:16:04 +0000194}
195
196CSecurityStack* CSecurityVeNCrypt::getCSecurityStack(int secType)
197{
198 switch (secType) {
199 case secTypeTLSNone:
200 return new CSecurityStack(secTypeTLSNone, "TLS with no password",
201 new CSecurityTLS());
202 case secTypeTLSVnc:
203 return new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
204 new CSecurityTLS(), new CSecurityVncAuth());
205#if 0
206 /* Following subtypes are not implemented, yet */
207 case secTypeTLSPlain:
208 case secTypeX509None:
209 case secTypeX509Vnc:
210 case secTypeX509Plain:
211#endif
212 default:
213 throw Exception("Unsupported VeNCrypt subtype");
214 }
215
216 return NULL; /* not reached */
217}