]> source.dussan.org Git - tigervnc.git/commitdiff
Add client-side support for the MSLogonII security type. 1566/head
authorDinglan Peng <pengdinglan@gmail.com>
Tue, 27 Dec 2022 09:06:08 +0000 (04:06 -0500)
committerDinglan Peng <pengdinglan@gmail.com>
Tue, 27 Dec 2022 09:06:08 +0000 (04:06 -0500)
common/rfb/CMakeLists.txt
common/rfb/CSecurityMSLogonII.cxx [new file with mode: 0644]
common/rfb/CSecurityMSLogonII.h [new file with mode: 0644]
common/rfb/Security.cxx
common/rfb/Security.h
common/rfb/SecurityClient.cxx
vncviewer/OptionsDialog.cxx

index 4a7a1b619ef32264f176cca1d0c5e51c30185ea6..b7ac1145c9c6c48962a07d6b7ff7929c4fa6ecb8 100644 (file)
@@ -103,7 +103,7 @@ if(GNUTLS_FOUND)
 endif()
 
 if (NETTLE_FOUND)
-  target_sources(rfb PRIVATE CSecurityDH.cxx
+  target_sources(rfb PRIVATE CSecurityDH.cxx CSecurityMSLogonII.cxx
                  CSecurityRSAAES.cxx SSecurityRSAAES.cxx)
   include_directories(${NETTLE_INCLUDE_DIRS} ${GMP_INCLUDE_DIRS})
   target_link_libraries(rfb ${HOGWEED_LIBRARIES}
diff --git a/common/rfb/CSecurityMSLogonII.cxx b/common/rfb/CSecurityMSLogonII.cxx
new file mode 100644 (file)
index 0000000..e9b7d62
--- /dev/null
@@ -0,0 +1,151 @@
+/* \r
+ * Copyright (C) 2022 Dinglan Peng\r
+ *    \r
+ * This is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This software is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this software; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,\r
+ * USA.\r
+ */\r
+\r
+#ifdef HAVE_CONFIG_H\r
+#include <config.h>\r
+#endif\r
+\r
+#ifndef HAVE_NETTLE\r
+#error "This header should not be compiled without HAVE_NETTLE defined"\r
+#endif\r
+\r
+#include <stdlib.h>\r
+#ifndef WIN32\r
+#include <unistd.h>\r
+#endif\r
+#include <assert.h>\r
+\r
+#include <nettle/des.h>\r
+#include <nettle/cbc.h>\r
+#include <nettle/bignum.h>\r
+#include <rfb/CSecurityMSLogonII.h>\r
+#include <rfb/CConnection.h>\r
+#include <rdr/InStream.h>\r
+#include <rdr/OutStream.h>\r
+#include <rdr/RandomStream.h>\r
+#include <rfb/Exception.h>\r
+#include <os/os.h>\r
+\r
+using namespace rfb;\r
+\r
+CSecurityMSLogonII::CSecurityMSLogonII(CConnection* cc)\r
+  : CSecurity(cc)\r
+{\r
+  mpz_init(g);\r
+  mpz_init(p);\r
+  mpz_init(A);\r
+  mpz_init(b);\r
+  mpz_init(B);\r
+  mpz_init(k);\r
+}\r
+\r
+CSecurityMSLogonII::~CSecurityMSLogonII()\r
+{\r
+  mpz_clear(g);\r
+  mpz_clear(p);\r
+  mpz_clear(A);\r
+  mpz_clear(b);\r
+  mpz_clear(B);\r
+  mpz_clear(k);\r
+}\r
+\r
+bool CSecurityMSLogonII::processMsg()\r
+{\r
+  if (readKey()) {\r
+    writeCredentials();\r
+    return true;\r
+  }\r
+  return false;\r
+}\r
+\r
+bool CSecurityMSLogonII::readKey()\r
+{\r
+  rdr::InStream* is = cc->getInStream();\r
+  if (!is->hasData(24))\r
+    return false;\r
+  rdr::U8 gBytes[8];\r
+  rdr::U8 pBytes[8];\r
+  rdr::U8 ABytes[8];\r
+  is->readBytes(gBytes, 8);\r
+  is->readBytes(pBytes, 8);\r
+  is->readBytes(ABytes, 8);\r
+  nettle_mpz_set_str_256_u(g, 8, gBytes);\r
+  nettle_mpz_set_str_256_u(p, 8, pBytes);\r
+  nettle_mpz_set_str_256_u(A, 8, ABytes);\r
+  return true;\r
+}\r
+\r
+void CSecurityMSLogonII::writeCredentials()\r
+{\r
+  CharArray username;\r
+  CharArray password;\r
+  rdr::RandomStream rs;\r
+\r
+  (CSecurity::upg)->getUserPasswd(isSecure(), &username.buf, &password.buf);\r
+  rdr::U8Array bBytes(8);\r
+  if (!rs.hasData(8))\r
+    throw ConnFailedException("failed to generate DH private key");\r
+  rs.readBytes(bBytes.buf, 8);\r
+  nettle_mpz_set_str_256_u(b, 8, bBytes.buf);\r
+  mpz_powm(k, A, b, p);\r
+  mpz_powm(B, g, b, p);\r
+\r
+  rdr::U8 key[8];\r
+  rdr::U8 reversedKey[8];\r
+  rdr::U8 BBytes[8];\r
+  rdr::U8 user[256];\r
+  rdr::U8 pass[64];\r
+  nettle_mpz_get_str_256(8, key, k);\r
+  nettle_mpz_get_str_256(8, BBytes, B);\r
+  for (int i = 0; i < 8; ++i) {\r
+    rdr::U8 x = 0;\r
+    for (int j = 0; j < 8; ++j) {\r
+      x |= ((key[i] >> j) & 1) << (7 - j);\r
+    }\r
+    reversedKey[i] = x;\r
+  }\r
+\r
+  if (!rs.hasData(256 + 64))\r
+    throw ConnFailedException("failed to generate random padding");\r
+  rs.readBytes(user, 256);\r
+  rs.readBytes(pass, 64);\r
+  size_t len = strlen(username.buf);\r
+  if (len >= 256)\r
+    throw AuthFailureException("username is too long");\r
+  memcpy(user, username.buf, len + 1);\r
+  len = strlen(password.buf);\r
+  if (len >= 64)\r
+    throw AuthFailureException("password is too long");\r
+  memcpy(pass, password.buf, len + 1);\r
+\r
+  // DES-CBC with the original key as IV, and the reversed one as the DES key\r
+  struct CBC_CTX(struct des_ctx, DES_BLOCK_SIZE) ctx;\r
+  des_fix_parity(8, reversedKey, reversedKey);\r
+  des_set_key(&ctx.ctx, reversedKey);\r
+  CBC_SET_IV(&ctx, key);\r
+  CBC_ENCRYPT(&ctx, des_encrypt, 256, user, user);\r
+  CBC_SET_IV(&ctx, key);\r
+  CBC_ENCRYPT(&ctx, des_encrypt, 64, pass, pass);\r
+\r
+  rdr::OutStream* os = cc->getOutStream();\r
+  os->writeBytes(BBytes, 8);\r
+  os->writeBytes(user, 256);\r
+  os->writeBytes(pass, 64);\r
+  os->flush();\r
+}\r
diff --git a/common/rfb/CSecurityMSLogonII.h b/common/rfb/CSecurityMSLogonII.h
new file mode 100644 (file)
index 0000000..28f0c75
--- /dev/null
@@ -0,0 +1,48 @@
+/* \r
+ * Copyright (C) 2022 Dinglan Peng\r
+ *    \r
+ * This is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ * \r
+ * This software is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this software; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,\r
+ * USA.\r
+ */\r
+\r
+#ifndef __C_SECURITY_MSLOGONII_H__\r
+#define __C_SECURITY_MSLOGONII_H__\r
+\r
+#ifndef HAVE_NETTLE\r
+#error "This header should not be compiled without HAVE_NETTLE defined"\r
+#endif\r
+\r
+#include <nettle/bignum.h>\r
+#include <rfb/CSecurity.h>\r
+#include <rfb/Security.h>\r
+\r
+namespace rfb {\r
+  class CSecurityMSLogonII : public CSecurity {\r
+  public:\r
+    CSecurityMSLogonII(CConnection* cc);\r
+    virtual ~CSecurityMSLogonII();\r
+    virtual bool processMsg();\r
+    virtual int getType() const { return secTypeMSLogonII; }\r
+    virtual bool isSecure() const { return false; }\r
+\r
+  private:\r
+    bool readKey();\r
+    void writeCredentials();\r
+\r
+    mpz_t g, p, A, b, B, k;\r
+  };\r
+}\r
+\r
+#endif\r
index 3a51be801109abaf753411966c6b464bcf0e8d46..efed0cd0299631119a50c59a09a012b2ce7692b1 100644 (file)
@@ -166,6 +166,7 @@ rdr::U32 rfb::secTypeNum(const char* name)
   if (strcasecmp(name, "SSPIne") == 0)     return secTypeSSPIne;
   if (strcasecmp(name, "VeNCrypt") == 0)   return secTypeVeNCrypt;
   if (strcasecmp(name, "DH") == 0)         return secTypeDH;
+  if (strcasecmp(name, "MSLogonII") == 0)  return secTypeMSLogonII;
 
   /* VeNCrypt subtypes */
   if (strcasecmp(name, "Plain") == 0)      return secTypePlain;
@@ -193,6 +194,7 @@ const char* rfb::secTypeName(rdr::U32 num)
   case secTypeSSPIne:     return "SSPIne";
   case secTypeVeNCrypt:   return "VeNCrypt";
   case secTypeDH:         return "DH";
+  case secTypeMSLogonII:  return "MSLogonII";
 
   /* VeNCrypt subtypes */
   case secTypePlain:      return "Plain";
index 860d9a58f900f89e08f002e5d97e49d3f108dec1..57800ffdfc3bcf8e9ec9b5866b827d3715ca83e0 100644 (file)
 #include <list>
 
 namespace rfb {
-  const rdr::U8 secTypeInvalid = 0;
-  const rdr::U8 secTypeNone    = 1;
-  const rdr::U8 secTypeVncAuth = 2;
+  const rdr::U8 secTypeInvalid    = 0;
+  const rdr::U8 secTypeNone       = 1;
+  const rdr::U8 secTypeVncAuth    = 2;
 
-  const rdr::U8 secTypeRA2     = 5;
-  const rdr::U8 secTypeRA2ne   = 6;
+  const rdr::U8 secTypeRA2        = 5;
+  const rdr::U8 secTypeRA2ne      = 6;
 
-  const rdr::U8 secTypeSSPI    = 7;
-  const rdr::U8 secTypeSSPIne  = 8;
+  const rdr::U8 secTypeSSPI       = 7;
+  const rdr::U8 secTypeSSPIne     = 8;
 
-  const rdr::U8 secTypeTight   = 16;
-  const rdr::U8 secTypeUltra   = 17;
-  const rdr::U8 secTypeTLS     = 18;
-  const rdr::U8 secTypeVeNCrypt= 19;
+  const rdr::U8 secTypeTight      = 16;
+  const rdr::U8 secTypeUltra      = 17;
+  const rdr::U8 secTypeTLS        = 18;
+  const rdr::U8 secTypeVeNCrypt   = 19;
 
-  const rdr::U8 secTypeDH      = 30;
+  const rdr::U8 secTypeDH         = 30;
 
-  const rdr::U8 secTypeRA256   = 129;
-  const rdr::U8 secTypeRAne256 = 130;
+  const rdr::U8 secTypeMSLogonII  = 113;
+
+  const rdr::U8 secTypeRA256      = 129;
+  const rdr::U8 secTypeRAne256    = 130;
 
   /* VeNCrypt subtypes */
-  const int secTypePlain       = 256;
-  const int secTypeTLSNone     = 257;
-  const int secTypeTLSVnc      = 258;
-  const int secTypeTLSPlain    = 259;
-  const int secTypeX509None    = 260;
-  const int secTypeX509Vnc     = 261;
-  const int secTypeX509Plain   = 262;
+  const int secTypePlain          = 256;
+  const int secTypeTLSNone        = 257;
+  const int secTypeTLSVnc         = 258;
+  const int secTypeTLSPlain       = 259;
+  const int secTypeX509None       = 260;
+  const int secTypeX509Vnc        = 261;
+  const int secTypeX509Plain      = 262;
 
   /* RSA-AES subtypes */
-  const int secTypeRA2UserPass = 1;
-  const int secTypeRA2Pass     = 2;
+  const int secTypeRA2UserPass    = 1;
+  const int secTypeRA2Pass        = 2;
 
   // result types
 
index 9c9218eec15ae308c3392188537485aaf30bf885..80165f57e9edb669a61883f44a6d65b0643bba91 100644 (file)
@@ -35,6 +35,7 @@
 #ifdef HAVE_NETTLE
 #include <rfb/CSecurityRSAAES.h>
 #include <rfb/CSecurityDH.h>
+#include <rfb/CSecurityMSLogonII.h>
 #endif
 
 using namespace rdr;
@@ -52,14 +53,14 @@ StringParameter SecurityClient::secTypes
  ", TLSNone, TLSVnc, TLSPlain, X509None, X509Vnc, X509Plain"
 #endif
 #ifdef HAVE_NETTLE
- ", RA2, RA2ne, RA2_256, RA2ne_256, DH"
+ ", RA2, RA2ne, RA2_256, RA2ne_256, DH, MSLogonII"
 #endif
  ")",
 #ifdef HAVE_GNUTLS
  "X509Plain,TLSPlain,X509Vnc,TLSVnc,X509None,TLSNone,"
 #endif
 #ifdef HAVE_NETTLE
- "RA2,RA2_256,RA2ne,RA2ne_256,DH"
+ "RA2,RA2_256,RA2ne,RA2ne_256,DH,MSLogonII"
 #endif
  "VncAuth,None",
 ConfViewer);
@@ -114,6 +115,8 @@ CSecurity* SecurityClient::GetCSecurity(CConnection* cc, U32 secType)
     return new CSecurityRSAAES(cc, secTypeRAne256, 256, false);
   case secTypeDH:
     return new CSecurityDH(cc);
+  case secTypeMSLogonII:
+    return new CSecurityMSLogonII(cc);
 #endif
   }
 
index 7a9cd6aeb4abd80c256b75f4388b4855ec2b0442..f4736a64a15ac0bb6d675f7fc2531a3d3013552c 100644 (file)
@@ -296,6 +296,7 @@ void OptionsDialog::loadOptions(void)
     case secTypeRAne256:
       authVncCheckbox->value(true);
     case secTypeDH:
+    case secTypeMSLogonII:
       encNoneCheckbox->value(true);
       authPlainCheckbox->value(true);
       break;
@@ -410,6 +411,7 @@ void OptionsDialog::storeOptions(void)
       security.EnableSecType(secTypeRA2ne);
       security.EnableSecType(secTypeRAne256);
       security.EnableSecType(secTypeDH);
+      security.EnableSecType(secTypeMSLogonII);
 #endif
     }
   }