summaryrefslogtreecommitdiffstats
path: root/libvncclient/rfbproto.c
diff options
context:
space:
mode:
Diffstat (limited to 'libvncclient/rfbproto.c')
-rw-r--r--libvncclient/rfbproto.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
index 010d08d..2de9891 100644
--- a/libvncclient/rfbproto.c
+++ b/libvncclient/rfbproto.c
@@ -51,6 +51,10 @@
#include <stdarg.h>
#include <time.h>
+#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
+#include <gcrypt.h>
+#endif
+
#include "minilzo.h"
#include "tls.h"
@@ -566,6 +570,7 @@ ReadSupportedSecurityType(rfbClient* client, uint32_t *result, rfbBool subAuth)
rfbClientLog("%d) Received security type %d\n", loop, tAuth[loop]);
if (flag) continue;
if (tAuth[loop]==rfbVncAuth || tAuth[loop]==rfbNoAuth || tAuth[loop]==rfbMSLogon ||
+ tAuth[loop]==rfbARD ||
(!subAuth && (tAuth[loop]==rfbTLS || tAuth[loop]==rfbVeNCrypt)))
{
if (!subAuth && client->clientAuthSchemes)
@@ -795,6 +800,208 @@ HandleMSLogonAuth(rfbClient *client)
return TRUE;
}
+#ifdef LIBVNCSERVER_WITH_CLIENT_GCRYPT
+static rfbBool
+rfbMpiToBytes(const gcry_mpi_t value, uint8_t *result, size_t size)
+{
+ gcry_error_t error;
+ size_t len;
+ int i;
+
+ error = gcry_mpi_print(GCRYMPI_FMT_USG, result, size, &len, value);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_mpi_print error: %s\n", gcry_strerror(error));
+ return FALSE;
+ }
+ for (i=size-1;i>(int)size-1-(int)len;--i)
+ result[i] = result[i-size+len];
+ for (;i>=0;--i)
+ result[i] = 0;
+ return TRUE;
+}
+
+static rfbBool
+HandleARDAuth(rfbClient *client)
+{
+ uint8_t gen[2], len[2];
+ size_t keylen;
+ uint8_t *mod = NULL, *resp, *pub, *key, *shared;
+ gcry_mpi_t genmpi = NULL, modmpi = NULL, respmpi = NULL;
+ gcry_mpi_t privmpi = NULL, pubmpi = NULL, keympi = NULL;
+ gcry_md_hd_t md5 = NULL;
+ gcry_cipher_hd_t aes = NULL;
+ gcry_error_t error;
+ uint8_t userpass[128], ciphertext[128];
+ int passwordLen, usernameLen;
+ rfbCredential *cred = NULL;
+ rfbBool result = FALSE;
+
+ while (1)
+ {
+ if (!ReadFromRFBServer(client, (char *)gen, 2))
+ break;
+ if (!ReadFromRFBServer(client, (char *)len, 2))
+ break;
+
+ if (!client->GetCredential)
+ {
+ rfbClientLog("GetCredential callback is not set.\n");
+ break;
+ }
+ cred = client->GetCredential(client, rfbCredentialTypeUser);
+ if (!cred)
+ {
+ rfbClientLog("Reading credential failed\n");
+ break;
+ }
+
+ keylen = 256*len[0]+len[1];
+ mod = (uint8_t*)malloc(keylen*4);
+ if (!mod)
+ {
+ rfbClientLog("malloc out of memory\n");
+ break;
+ }
+ resp = mod+keylen;
+ pub = resp+keylen;
+ key = pub+keylen;
+
+ if (!ReadFromRFBServer(client, (char *)mod, keylen))
+ break;
+ if (!ReadFromRFBServer(client, (char *)resp, keylen))
+ break;
+
+ error = gcry_mpi_scan(&genmpi, GCRYMPI_FMT_USG, gen, 2, NULL);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
+ break;
+ }
+ error = gcry_mpi_scan(&modmpi, GCRYMPI_FMT_USG, mod, keylen, NULL);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
+ break;
+ }
+ error = gcry_mpi_scan(&respmpi, GCRYMPI_FMT_USG, resp, keylen, NULL);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_mpi_scan error: %s\n", gcry_strerror(error));
+ break;
+ }
+
+ privmpi = gcry_mpi_new(keylen);
+ if (!privmpi)
+ {
+ rfbClientLog("gcry_mpi_new out of memory\n");
+ break;
+ }
+ gcry_mpi_randomize(privmpi, (keylen/8)*8, GCRY_STRONG_RANDOM);
+
+ pubmpi = gcry_mpi_new(keylen);
+ if (!pubmpi)
+ {
+ rfbClientLog("gcry_mpi_new out of memory\n");
+ break;
+ }
+ gcry_mpi_powm(pubmpi, genmpi, privmpi, modmpi);
+
+ keympi = gcry_mpi_new(keylen);
+ if (!keympi)
+ {
+ rfbClientLog("gcry_mpi_new out of memory\n");
+ break;
+ }
+ gcry_mpi_powm(keympi, respmpi, privmpi, modmpi);
+
+ if (!rfbMpiToBytes(pubmpi, pub, keylen))
+ break;
+ if (!rfbMpiToBytes(keympi, key, keylen))
+ break;
+
+ error = gcry_md_open(&md5, GCRY_MD_MD5, 0);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_md_open error: %s\n", gcry_strerror(error));
+ break;
+ }
+ gcry_md_write(md5, key, keylen);
+ error = gcry_md_final(md5);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_md_final error: %s\n", gcry_strerror(error));
+ break;
+ }
+ shared = gcry_md_read(md5, GCRY_MD_MD5);
+
+ passwordLen = strlen(cred->userCredential.password)+1;
+ usernameLen = strlen(cred->userCredential.username)+1;
+ if (passwordLen > sizeof(userpass)/2)
+ passwordLen = sizeof(userpass)/2;
+ if (usernameLen > sizeof(userpass)/2)
+ usernameLen = sizeof(userpass)/2;
+
+ gcry_randomize(userpass, sizeof(userpass), GCRY_STRONG_RANDOM);
+ memcpy(userpass, cred->userCredential.username, usernameLen);
+ memcpy(userpass+sizeof(userpass)/2, cred->userCredential.password, passwordLen);
+
+ error = gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_cipher_open error: %s\n", gcry_strerror(error));
+ break;
+ }
+ error = gcry_cipher_setkey(aes, shared, 16);
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_cipher_setkey error: %s\n", gcry_strerror(error));
+ break;
+ }
+ error = gcry_cipher_encrypt(aes, ciphertext, sizeof(ciphertext), userpass, sizeof(userpass));
+ if (gcry_err_code(error) != GPG_ERR_NO_ERROR)
+ {
+ rfbClientLog("gcry_cipher_encrypt error: %s\n", gcry_strerror(error));
+ break;
+ }
+
+ if (!WriteToRFBServer(client, (char *)ciphertext, sizeof(ciphertext)))
+ break;
+ if (!WriteToRFBServer(client, (char *)pub, keylen))
+ break;
+
+ /* Handle the SecurityResult message */
+ if (!rfbHandleAuthResult(client))
+ break;
+
+ result = TRUE;
+ break;
+ }
+
+ if (cred)
+ FreeUserCredential(cred);
+ if (mod)
+ free(mod);
+ if (genmpi)
+ gcry_mpi_release(genmpi);
+ if (modmpi)
+ gcry_mpi_release(modmpi);
+ if (respmpi)
+ gcry_mpi_release(respmpi);
+ if (privmpi)
+ gcry_mpi_release(privmpi);
+ if (pubmpi)
+ gcry_mpi_release(pubmpi);
+ if (keympi)
+ gcry_mpi_release(keympi);
+ if (md5)
+ gcry_md_close(md5);
+ if (aes)
+ gcry_cipher_close(aes);
+ return result;
+}
+#endif
+
/*
* SetClientAuthSchemes.
*/
@@ -928,6 +1135,15 @@ InitialiseRFBConnection(rfbClient* client)
if (!HandleMSLogonAuth(client)) return FALSE;
break;
+ case rfbARD:
+#ifndef LIBVNCSERVER_WITH_CLIENT_GCRYPT
+ rfbClientLog("GCrypt support was not compiled in\n");
+ return FALSE;
+#else
+ if (!HandleARDAuth(client)) return FALSE;
+#endif
+ break;
+
case rfbTLS:
#ifndef LIBVNCSERVER_WITH_CLIENT_TLS
rfbClientLog("TLS support was not compiled in\n");