[Development] Implement VeNCrypt type support on client side. Currently only
TLSNone and TLSVnc VeNCrypt subtypes are implemented.
git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4046 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/CSecurityVeNCrypt.cxx b/common/rfb/CSecurityVeNCrypt.cxx
new file mode 100644
index 0000000..12eed8f
--- /dev/null
+++ b/common/rfb/CSecurityVeNCrypt.cxx
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2006 OCCAM Financial Technology
+ * Copyright (C) 2005-2006 Martin Koegler
+ * Copyright (C) 2010 TigerVNC Team
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ */
+//
+// CSecurityVeNCrypt
+//
+
+#include <rfb/Exception.h>
+#include <rdr/InStream.h>
+#include <rdr/OutStream.h>
+#include <rfb/CConnection.h>
+#include <rfb/CSecurityTLS.h>
+#include <rfb/CSecurityVeNCrypt.h>
+#include <rfb/CSecurityVncAuth.h>
+#include <rfb/SSecurityVeNCrypt.h>
+#include <list>
+
+using namespace rfb;
+using namespace rdr;
+using namespace std;
+
+CSecurityVeNCrypt::CSecurityVeNCrypt(void) : csecurityStack(NULL)
+{
+ haveRecvdMajorVersion = false;
+ haveRecvdMinorVersion = false;
+ haveSentVersion = false;
+ haveAgreedVersion = false;
+ haveListOfTypes = false;
+ haveNumberOfTypes = false;
+ haveChosenType = false;
+ majorVersion = 0;
+ minorVersion = 0;
+ chosenType = secTypeVeNCrypt;
+ nAvailableTypes = 0;
+ availableTypes = NULL;
+ iAvailableType = 0;
+}
+
+CSecurityVeNCrypt::~CSecurityVeNCrypt()
+{
+ if (availableTypes)
+ delete[] availableTypes;
+}
+
+bool CSecurityVeNCrypt::processMsg(CConnection* cc)
+{
+ InStream* is = cc->getInStream();
+ OutStream* os = cc->getOutStream();
+
+ /* get major, minor versions, send what we can support (or 0.0 for can't support it) */
+ if (!haveRecvdMajorVersion) {
+ majorVersion = is->readU8();
+ haveRecvdMajorVersion = true;
+
+ return false;
+ }
+
+ if (!haveRecvdMinorVersion) {
+ minorVersion = is->readU8();
+ haveRecvdMinorVersion = true;
+ }
+
+ /* major version in upper 8 bits and minor version in lower 8 bits */
+ U16 Version = (((U16) majorVersion) << 8) | ((U16) minorVersion);
+
+ if (!haveSentVersion) {
+ /* Currently we don't support former VeNCrypt 0.1 */
+ if (Version >= 0x0002) {
+ majorVersion = 0;
+ minorVersion = 2;
+ os->writeU8(majorVersion);
+ os->writeU8(minorVersion);
+ os->flush();
+ } else {
+ /* Send 0.0 to indicate no support */
+ majorVersion = 0;
+ minorVersion = 0;
+ os->writeU8(0);
+ os->writeU8(0);
+ os->flush();
+ throw AuthFailureException("The server reported an unsupported VeNCrypt version");
+ }
+
+ haveSentVersion = true;
+ return false;
+ }
+
+ /* Check that the server is OK */
+ if (!haveAgreedVersion) {
+ if (is->readU8())
+ throw AuthFailureException("The server reported it could not support the "
+ "VeNCrypt version");
+
+ haveAgreedVersion = true;
+ return false;
+ }
+
+ /* get a number of types */
+ if (!haveNumberOfTypes) {
+ nAvailableTypes = is->readU8();
+ iAvailableType = 0;
+
+ if (!nAvailableTypes)
+ throw AuthFailureException("The server reported no VeNCrypt sub-types");
+
+ availableTypes = new rdr::U32[nAvailableTypes];
+ haveNumberOfTypes = true;
+ return false;
+ }
+
+ if (nAvailableTypes) {
+ /* read in the types possible */
+ if (!haveListOfTypes) {
+ if (is->checkNoWait(4)) {
+ availableTypes[iAvailableType++] = is->readU32();
+ haveListOfTypes = (iAvailableType >= nAvailableTypes);
+
+ if (!haveListOfTypes)
+ return false;
+
+ } else
+ return false;
+ }
+
+ /* make a choice and send it to the server, meanwhile set up the stack */
+ if (!haveChosenType) {
+ chosenType = 0;
+ U8 i;
+ list<U32>::iterator j;
+ list<U32> preferredList;
+
+ /* Try preferred choice */
+ SSecurityVeNCrypt::getSecTypes(&preferredList);
+
+ for (j = preferredList.begin(); j != preferredList.end(); j++) {
+ for (i = 0; i < nAvailableTypes; i++) {
+ if (*j == availableTypes[i]) {
+ chosenType = *j;
+ break;
+ }
+ }
+
+ if (chosenType)
+ break;
+ }
+
+ /* Set up the stack according to the chosen type: */
+ switch (chosenType) {
+ case secTypeTLSNone:
+ case secTypeTLSVnc:
+ case secTypeTLSPlain:
+ case secTypeX509None:
+ case secTypeX509Vnc:
+ case secTypeX509Plain:
+ csecurityStack = CSecurityVeNCrypt::getCSecurityStack(chosenType);
+ break;
+
+ case secTypeInvalid:
+ case secTypeVeNCrypt: /* would cause looping */
+ default:
+ throw AuthFailureException("No valid VeNCrypt sub-type");
+ }
+
+ /* send chosen type to server */
+ os->writeU32(chosenType);
+ os->flush();
+
+ haveChosenType = true;
+ }
+ } else {
+ /*
+ * Server told us that there are 0 types it can support - this should not
+ * happen, since if the server supports 0 sub-types, it doesn't support
+ * this security type
+ */
+ throw AuthFailureException("The server reported 0 VeNCrypt sub-types");
+ }
+
+ return csecurityStack->processMsg(cc);
+}
+
+CSecurityStack* CSecurityVeNCrypt::getCSecurityStack(int secType)
+{
+ switch (secType) {
+ case secTypeTLSNone:
+ return new CSecurityStack(secTypeTLSNone, "TLS with no password",
+ new CSecurityTLS());
+ case secTypeTLSVnc:
+ return new CSecurityStack(secTypeTLSVnc, "TLS with VNCAuth",
+ new CSecurityTLS(), new CSecurityVncAuth());
+#if 0
+ /* Following subtypes are not implemented, yet */
+ case secTypeTLSPlain:
+ case secTypeX509None:
+ case secTypeX509Vnc:
+ case secTypeX509Plain:
+#endif
+ default:
+ throw Exception("Unsupported VeNCrypt subtype");
+ }
+
+ return NULL; /* not reached */
+}