Re: [gtk-vnc-devel] Time for new release ...



On Thu, Nov 27, 2008 at 12:46:52PM -0300, Jonh Wendell wrote:
> Em Qui, 2008-11-27 às 11:12 +0000, Daniel P. Berrange escreveu:
> > Jonh and I were talking on IRC the other day and think its time for a new
> > release so we can get people using the new Cairo based rendering code,
> > Windows portability, and (hopefully) fixed keyboard handling. Any
> > objections....
> > 
> > Daniel
> 
> How about the ms-logon patch? It could be added into this release.

I'm not entirely happy with the code license pedigree of the diffie-hellman
stuff in that patch. So here's a version that is re-written to be clean.

This is basically written based off the gnutls internal DH impl, in
lib/gnutls_dh.c which is explicitly LGPLv2+ licensed. It uses gcrypt
for its core functions.

NB, I don't have a windows server against which to test this code, so it
is quite possible I broke it when re-writing ....

Daniel

diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h
 libgtk_vnc_1_0_la_SOURCES = blt.h blt1.h \
 	coroutine.h \
 	d3des.h d3des.c \
+	dh.h dh.c \
 	gvnc.h gvnc.c \
 	vncdisplay.h vncdisplay.c \
         vncmarshal.h vncmarshal.c \
diff --git a/src/dh.c b/src/dh.c
new file mode 100644
--- /dev/null
+++ b/src/dh.c
@@ -0,0 +1,135 @@
+/*
+ * GTK VNC Widget, Diffie Hellman
+ *
+ * Copyright (C) 2008  Red Hat, Inc
+ *
+ * Derived from gnutls_dh.c, also under:
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <config.h>
+
+#include "dh.h"
+
+
+/*
+ * General plan, as per gnutls_dh.c
+ *
+ *
+ *  VNC server: X = g ^ x mod p;
+ *  VNC client: Y = g ^ y mod p;
+ *
+ *  Server key = Y ^ x mod p;
+ *  Client key = X ^ y mod p;
+ *
+ * Where
+ *   g == gen
+ *   p == mod
+ *
+ *   y == priv
+ *   Y == pub
+ *  Client key == key
+ *
+ *
+ */
+
+struct gvnc_dh {
+	gcry_mpi_t gen;  /* g */
+	gcry_mpi_t mod;  /* p */
+
+	gcry_mpi_t priv; /* y */
+	gcry_mpi_t pub;  /* Y = g ^ y mod p */
+
+	gcry_mpi_t key;  /*     X ^ y mod p */
+};
+
+#define GVNC_DH_MAX_BITS 31
+
+struct gvnc_dh *gvnc_dh_new(gcry_mpi_t gen, gcry_mpi_t mod)
+{
+	struct gvnc_dh *ret = g_new0(struct gvnc_dh, 1);
+
+	ret->gen = gcry_mpi_copy(gen);
+	ret->mod = gcry_mpi_copy(mod);
+
+	return ret;
+}
+
+
+gcry_mpi_t gvnc_dh_gen_secret(struct gvnc_dh *dh)
+{
+	if (!(dh->priv = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+		abort();
+
+	do {
+		gcry_mpi_randomize (dh->priv, (GVNC_DH_MAX_BITS / 8) * 8, GCRY_STRONG_RANDOM);
+	} while (gcry_mpi_cmp_ui (dh->priv, 0) == 0);
+
+	if (!(dh->pub = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+		abort();
+
+	gcry_mpi_powm(dh->pub, dh->gen, dh->priv, dh->mod);
+
+	return dh->pub;
+}
+
+gcry_mpi_t gvnc_dh_gen_key(struct gvnc_dh *dh, gcry_mpi_t inter)
+{
+	if (!(dh->key = gcry_mpi_new(GVNC_DH_MAX_BITS)))
+		abort();
+
+	gcry_mpi_powm(dh->key, inter, dh->priv, dh->mod);
+
+	return dh->key;
+}
+
+void gvnc_dh_free(struct gvnc_dh *dh)
+{
+	if (dh->key)
+		gcry_mpi_release(dh->key);
+	if (dh->pub)
+		gcry_mpi_release(dh->pub);
+	if (dh->priv)
+		gcry_mpi_release(dh->priv);
+	if (dh->mod)
+		gcry_mpi_release(dh->mod);
+	if (dh->gen)
+		gcry_mpi_release(dh->gen);
+	g_free(dh);
+}
+
+void gvnc_mpi_to_bytes(const gcry_mpi_t value, guchar* const bytes)
+{
+	gcry_mpi_print(GCRYMPI_FMT_STD, bytes, sizeof(gint64), NULL, value);
+}
+
+gcry_mpi_t gvnc_bytes_to_mpi(const guchar* const bytes)
+{
+	gcry_mpi_t ret;
+
+	gcry_mpi_scan(&ret, GCRYMPI_FMT_STD, bytes, sizeof(gint64), NULL);
+
+	return NULL;
+}
+
+
+/*
+ * Local variables:
+ *  c-indent-level: 8
+ *  c-basic-offset: 8
+ *  tab-width: 8
+ * End:
+ */
diff --git a/src/dh.h b/src/dh.h
new file mode 100644
--- /dev/null
+++ b/src/dh.h
@@ -0,0 +1,38 @@
+/*
+ * GTK VNC Widget, Diffie Hellman
+ *
+ * Copyright (C) 2008  Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.0 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef GTK_VNC_DH_H__
+#define GTK_VNC_DH_H__
+
+#include <glib.h>
+#include <gcrypt.h>
+
+struct gvnc_dh;
+
+struct gvnc_dh *gvnc_dh_new(gcry_mpi_t prime, gcry_mpi_t generator);
+
+gcry_mpi_t gvnc_dh_gen_secret(struct gvnc_dh *dh);
+gcry_mpi_t gvnc_dh_gen_key(struct gvnc_dh *dh, gcry_mpi_t inter);
+void gvnc_dh_free(struct gvnc_dh *dh);
+
+void gvnc_mpi_to_bytes(const gcry_mpi_t value, guchar* const bytes);
+gcry_mpi_t gvnc_bytes_to_mpi(const guchar* const bytes);
+
+#endif
diff --git a/src/gvnc.c b/src/gvnc.c
--- a/src/gvnc.c
+++ b/src/gvnc.c
@@ -36,6 +36,10 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <zlib.h>
+#include <gdk/gdkkeysyms.h>
 
 #include "coroutine.h"
 #include "d3des.h"
@@ -43,13 +47,7 @@
 #include "x_keymap.h"
 
 #include "utils.h"
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include <zlib.h>
-
-#include <gdk/gdkkeysyms.h>
-
+#include "dh.h"
 #include "getaddrinfo.h"
 
 /* AI_ADDRCONFIG is missing on some systems and gnulib won't provide it
@@ -2173,6 +2171,84 @@ static gboolean gvnc_perform_auth_vnc(st
 }
 
 
+/*
+ *   marscha 2006 - Martin Scharpf
+ *   Encrypt bytes[length] in memory using key.
+ *   Key has to be 8 bytes, length a multiple of 8 bytes.
+ */
+static void
+vncEncryptBytes2(unsigned char *where, const int length, unsigned char *key) {
+       int i, j;
+       deskey(key, EN0);
+       for (i = 0; i< 8; i++)
+               where[i] ^= key[i];
+       des(where, where);
+       for (i = 8; i < length; i += 8) {
+               for (j = 0; j < 8; j++)
+                       where[i + j] ^= where[i + j - 8];
+               des(where + i, where + i);
+       }
+}
+
+static gboolean gvnc_perform_auth_mslogon(struct gvnc *gvnc)
+{
+	struct gvnc_dh *dh;
+	guchar gen[8], mod[8], resp[8], pub[8], key[8];
+	gcry_mpi_t genmpi, modmpi, respmpi, pubmpi, keympi;
+
+	guchar username[256], password[64];
+	guint passwordLen, usernameLen;
+
+	GVNC_DEBUG("Do Challenge\n");
+	if (!gvnc->cred_username)
+		return FALSE;
+	if (!gvnc->cred_password)
+		return FALSE;
+
+	gvnc_read(gvnc, gen, sizeof(gen));
+	gvnc_read(gvnc, mod, sizeof(mod));
+	gvnc_read(gvnc, resp, sizeof(resp));
+
+	genmpi = gvnc_bytes_to_mpi(gen);
+	modmpi = gvnc_bytes_to_mpi(mod);
+	respmpi = gvnc_bytes_to_mpi(resp);
+
+	dh = gvnc_dh_new(genmpi, modmpi);
+
+	pubmpi = gvnc_dh_gen_secret(dh);
+	gvnc_mpi_to_bytes(pubmpi, pub);
+	gvnc_write(gvnc, pub, sizeof(pub));
+
+	keympi = gvnc_dh_gen_key(dh, respmpi);
+	gvnc_mpi_to_bytes(keympi, key);
+
+	passwordLen = strlen(gvnc->cred_password);
+	usernameLen = strlen(gvnc->cred_username);
+	if (passwordLen > sizeof(password))
+		passwordLen = sizeof(password);
+	if (usernameLen > sizeof(username))
+		usernameLen = sizeof(username);
+
+	memset(password, 0, sizeof password);
+	memset(username, 0, sizeof username);
+	memcpy(password, gvnc->cred_password, passwordLen);
+	memcpy(username, gvnc->cred_username, usernameLen);
+
+	vncEncryptBytes2(username, sizeof(username), key);
+	vncEncryptBytes2(password, sizeof(password), key);
+
+	gvnc_write(gvnc, username, sizeof(username));
+	gvnc_write(gvnc, password, sizeof(password));
+	gvnc_flush(gvnc);
+
+	gcry_mpi_release(genmpi);
+	gcry_mpi_release(modmpi);
+	gcry_mpi_release(respmpi);
+	gvnc_dh_free (dh);
+
+	return gvnc_check_auth_result(gvnc);
+}
+
 static gboolean gvnc_start_tls(struct gvnc *gvnc, int anonTLS)
 {
 	static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
@@ -2297,6 +2373,9 @@ gboolean gvnc_wants_credential_password(
                         return TRUE;
         }
 
+	if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+		return TRUE;
+
         return FALSE;
 }
 
@@ -2308,6 +2387,9 @@ gboolean gvnc_wants_credential_username(
                     gvnc->auth_subtype == GVNC_AUTH_VENCRYPT_X509PLAIN)
                         return TRUE;
         }
+
+	if (gvnc->auth_type == GVNC_AUTH_MSLOGON)
+		return TRUE;
 
         return FALSE;
 }
@@ -2626,6 +2708,9 @@ static gboolean gvnc_perform_auth(struct
 	case GVNC_AUTH_VENCRYPT:
 		return gvnc_perform_auth_vencrypt(gvnc);
 
+	case GVNC_AUTH_MSLOGON:
+		return gvnc_perform_auth_mslogon(gvnc);
+
 	default:
 		if (gvnc->ops.auth_unsupported)
 			gvnc->ops.auth_unsupported (gvnc->ops_data, gvnc->auth_type);
@@ -2994,6 +3079,7 @@ gboolean gvnc_set_auth_type(struct gvnc 
         }
         if (type != GVNC_AUTH_NONE &&
             type != GVNC_AUTH_VNC &&
+            type != GVNC_AUTH_MSLOGON &&
             type != GVNC_AUTH_TLS &&
             type != GVNC_AUTH_VENCRYPT) {
             	if (gvnc->ops.auth_unsupported)
diff --git a/src/gvnc.h b/src/gvnc.h
--- a/src/gvnc.h
+++ b/src/gvnc.h
@@ -128,7 +128,8 @@ typedef enum {
 	GVNC_AUTH_TIGHT = 16,
 	GVNC_AUTH_ULTRA = 17,
 	GVNC_AUTH_TLS = 18,  /* Used by VINO */
-	GVNC_AUTH_VENCRYPT = 19 /* Used by VeNCrypt and QEMU */
+	GVNC_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */
+	GVNC_AUTH_MSLOGON = 0xfffffffa, /* Used by UltraVNC */
 } gvnc_auth;
 
 typedef enum {
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -1861,6 +1861,7 @@ static void vnc_display_init(VncDisplay 
 
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VENCRYPT));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_TLS));
+	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_MSLOGON));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_VNC));
 	priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (GVNC_AUTH_NONE));
 



-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]