[gtk-vnc] Support Mac OS VNC authentication
- From: Jonh Wendell <jwendell src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk-vnc] Support Mac OS VNC authentication
- Date: Fri, 20 Aug 2010 18:13:56 +0000 (UTC)
commit 416a0dc3592e831409e6e8c18929b785094ef87c
Author: HÃ¥kon Enger <hakon enger gmail com>
Date: Fri Aug 20 15:12:27 2010 -0300
Support Mac OS VNC authentication
src/dh.c | 47 +++++++--------
src/dh.h | 4 +-
src/vncconnection.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++--
src/vncconnection.h | 1 +
src/vncdisplay.c | 1 +
5 files changed, 175 insertions(+), 32 deletions(-)
---
diff --git a/src/dh.c b/src/dh.c
index 3e9ee6f..3ab5e77 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -111,38 +111,35 @@ void vnc_dh_free(struct vnc_dh *dh)
g_free(dh);
}
-/* convert from big-endian to little-endian:
- 68 183 219 160 0 0 0 0 becomes
- 0 0 0 0 68 183 219 160 */
-static void convert (unsigned char *input, int size)
+void vnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result, size_t size)
{
- int i, count=0;
-
- for (i = size-1; i >= 0; i--)
- if (input[i] == 0)
- count++;
- else
- break;
-
- for (i = 0; i< size-count; i++)
- {
- input[i+count] = input[i];
- input[i] = 0;
- }
-}
-
-void vnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result)
-{
- gcry_mpi_print(GCRYMPI_FMT_STD, result, 8, NULL, value);
- convert (result, 8);
+ 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) {
+ VNC_DEBUG ("MPI error: %s", gcry_strerror (error));
+ abort();
+ }
+
+ /* right adjust the result
+ 68 183 219 160 0 0 0 0 becomes
+ 0 0 0 0 68 183 219 160 */
+ for(i=size-1;i>(int)size-1-(int)len;--i) {
+ result[i] = result[i-size+len];
+ }
+ for(;i>=0;--i) {
+ result[i] = 0;
+ }
}
-gcry_mpi_t vnc_bytes_to_mpi(const guchar* value)
+gcry_mpi_t vnc_bytes_to_mpi(const guchar* value, size_t size)
{
gcry_mpi_t ret;
gcry_error_t error;
- error = gcry_mpi_scan(&ret, GCRYMPI_FMT_STD, value, 8, NULL);
+ error = gcry_mpi_scan(&ret, GCRYMPI_FMT_USG, value, size, NULL);
if (gcry_err_code (error) != GPG_ERR_NO_ERROR)
VNC_DEBUG ("MPI error: %s", gcry_strerror (error));
diff --git a/src/dh.h b/src/dh.h
index 7585df1..ed4fe14 100644
--- a/src/dh.h
+++ b/src/dh.h
@@ -32,7 +32,7 @@ gcry_mpi_t vnc_dh_gen_secret(struct vnc_dh *dh);
gcry_mpi_t vnc_dh_gen_key(struct vnc_dh *dh, gcry_mpi_t inter);
void vnc_dh_free(struct vnc_dh *dh);
-void vnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result);
-gcry_mpi_t vnc_bytes_to_mpi(const guchar* value);
+void vnc_mpi_to_bytes(const gcry_mpi_t value, guchar* result, size_t size);
+gcry_mpi_t vnc_bytes_to_mpi(const guchar* value, size_t size);
#endif
diff --git a/src/vncconnection.c b/src/vncconnection.c
index 7525b8d..566f4da 100644
--- a/src/vncconnection.c
+++ b/src/vncconnection.c
@@ -2989,19 +2989,19 @@ static gboolean vnc_connection_perform_auth_mslogon(VncConnection *conn)
vnc_connection_read(conn, mod, sizeof(mod));
vnc_connection_read(conn, resp, sizeof(resp));
- genmpi = vnc_bytes_to_mpi(gen);
- modmpi = vnc_bytes_to_mpi(mod);
- respmpi = vnc_bytes_to_mpi(resp);
+ genmpi = vnc_bytes_to_mpi(gen,sizeof(gen));
+ modmpi = vnc_bytes_to_mpi(mod,sizeof(mod));
+ respmpi = vnc_bytes_to_mpi(resp,sizeof(resp));
dh = vnc_dh_new(genmpi, modmpi);
pubmpi = vnc_dh_gen_secret(dh);
- vnc_mpi_to_bytes(pubmpi, pub);
+ vnc_mpi_to_bytes(pubmpi, pub, sizeof(pub));
vnc_connection_write(conn, pub, sizeof(pub));
keympi = vnc_dh_gen_key(dh, respmpi);
- vnc_mpi_to_bytes(keympi, key);
+ vnc_mpi_to_bytes(keympi, key, sizeof(key));
passwordLen = strlen(priv->cred_password);
usernameLen = strlen(priv->cred_username);
@@ -3030,6 +3030,146 @@ static gboolean vnc_connection_perform_auth_mslogon(VncConnection *conn)
return vnc_connection_check_auth_result(conn);
}
+static gboolean vnc_connection_perform_auth_ard(VncConnection *conn)
+{
+ VncConnectionPrivate *priv = conn->priv;
+ struct vnc_dh *dh;
+ guchar gen[2], len[2];
+ size_t keylen;
+ guchar *mod, *resp, *pub, *key, *shared;
+ gcry_mpi_t genmpi, modmpi, respmpi, pubmpi, keympi;
+ guchar userpass[128], ciphertext[128];
+ guint passwordLen, usernameLen;
+ gcry_md_hd_t md5;
+ gcry_cipher_hd_t aes;
+ gcry_error_t error;
+
+ VNC_DEBUG("Do Challenge");
+ priv->want_cred_password = TRUE;
+ priv->want_cred_username = TRUE;
+ priv->want_cred_x509 = FALSE;
+ if (!vnc_connection_gather_credentials(conn))
+ return FALSE;
+
+ vnc_connection_read(conn, gen, sizeof(gen));
+ vnc_connection_read(conn, len, sizeof(len));
+
+ keylen = 256*len[0] + len[1];
+ mod = malloc(keylen);
+ if (mod == NULL) {
+ VNC_DEBUG("malloc failed\n");
+ return FALSE;
+ }
+ resp = malloc(keylen);
+ if (resp == NULL) {
+ free(mod);
+ VNC_DEBUG("malloc failed\n");
+ return FALSE;
+ }
+ pub = malloc(keylen);
+ if (pub == NULL) {
+ free(resp);
+ free(mod);
+ VNC_DEBUG("malloc failed\n");
+ return FALSE;
+ }
+ key = malloc(keylen);
+ if (key == NULL) {
+ free(pub);
+ free(resp);
+ free(mod);
+ VNC_DEBUG("malloc failed\n");
+ return FALSE;
+ }
+
+ vnc_connection_read(conn, mod, keylen);
+ vnc_connection_read(conn, resp, keylen);
+
+ genmpi = vnc_bytes_to_mpi(gen,sizeof(gen));
+ modmpi = vnc_bytes_to_mpi(mod,keylen);
+ respmpi = vnc_bytes_to_mpi(resp,keylen);
+
+ dh = vnc_dh_new(genmpi, modmpi);
+
+ pubmpi = vnc_dh_gen_secret(dh);
+ vnc_mpi_to_bytes(pubmpi, pub, keylen);
+
+ keympi = vnc_dh_gen_key(dh, respmpi);
+ vnc_mpi_to_bytes(keympi, key, keylen);
+
+ error=gcry_md_open(&md5, GCRY_MD_MD5, 0);
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR) {
+ VNC_DEBUG("gcry_md_open error: %s\n", gcry_strerror(error));
+ free(pub);
+ free(resp);
+ free(mod);
+ return FALSE;
+ }
+ gcry_md_write(md5, key, keylen);
+ error=gcry_md_final(md5);
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR) {
+ VNC_DEBUG("gcry_md_final error: %s\n", gcry_strerror(error));
+ free(pub);
+ free(resp);
+ free(mod);
+ return FALSE;
+ }
+ shared = gcry_md_read(md5, GCRY_MD_MD5);
+
+ passwordLen = strlen(priv->cred_password)+1;
+ usernameLen = strlen(priv->cred_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, priv->cred_username, usernameLen);
+ memcpy(userpass+sizeof(userpass)/2, priv->cred_password, passwordLen);
+
+ error=gcry_cipher_open(&aes, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB, 0);
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR) {
+ VNC_DEBUG("gcry_cipher_open error: %s\n", gcry_strerror(error));
+ free(pub);
+ free(resp);
+ free(mod);
+ return FALSE;
+ }
+ error=gcry_cipher_setkey(aes, shared, 16);
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR) {
+ VNC_DEBUG("gcry_cipher_setkey error: %s\n", gcry_strerror(error));
+ free(pub);
+ free(resp);
+ free(mod);
+ return FALSE;
+ }
+ error=gcry_cipher_encrypt(aes, ciphertext, sizeof(ciphertext), userpass, sizeof(userpass));
+ if (gcry_err_code (error) != GPG_ERR_NO_ERROR) {
+ VNC_DEBUG("gcry_cipher_encrypt error: %s\n", gcry_strerror(error));
+ free(pub);
+ free(resp);
+ free(mod);
+ return FALSE;
+ }
+
+ vnc_connection_write(conn, ciphertext, sizeof(ciphertext));
+ vnc_connection_write(conn, pub, keylen);
+ vnc_connection_flush(conn);
+
+ free(mod);
+ free(resp);
+ free(pub);
+ free(key);
+ gcry_md_close(md5);
+ gcry_mpi_release(genmpi);
+ gcry_mpi_release(modmpi);
+ gcry_mpi_release(respmpi);
+ vnc_dh_free (dh);
+
+ return vnc_connection_check_auth_result(conn);
+}
+
+
#if HAVE_SASL
/*
* NB, keep in sync with similar method in qemud/remote.c
@@ -3918,6 +4058,9 @@ static gboolean vnc_connection_perform_auth(VncConnection *conn)
case VNC_CONNECTION_AUTH_MSLOGON:
return vnc_connection_perform_auth_mslogon(conn);
+ case VNC_CONNECTION_AUTH_ARD:
+ return vnc_connection_perform_auth_ard(conn);
+
default:
{
struct signal_data sigdata;
@@ -4610,6 +4753,7 @@ gboolean vnc_connection_set_auth_type(VncConnection *conn, unsigned int type)
if (type != VNC_CONNECTION_AUTH_NONE &&
type != VNC_CONNECTION_AUTH_VNC &&
type != VNC_CONNECTION_AUTH_MSLOGON &&
+ type != VNC_CONNECTION_AUTH_ARD &&
type != VNC_CONNECTION_AUTH_TLS &&
type != VNC_CONNECTION_AUTH_VENCRYPT &&
type != VNC_CONNECTION_AUTH_SASL) {
diff --git a/src/vncconnection.h b/src/vncconnection.h
index 5023f80..e189351 100644
--- a/src/vncconnection.h
+++ b/src/vncconnection.h
@@ -124,6 +124,7 @@ typedef enum {
VNC_CONNECTION_AUTH_TLS = 18, /* Used by VINO */
VNC_CONNECTION_AUTH_VENCRYPT = 19, /* Used by VeNCrypt and QEMU */
VNC_CONNECTION_AUTH_SASL = 20, /* SASL type used by VINO and QEMU */
+ VNC_CONNECTION_AUTH_ARD = 30, /* Apple remote desktop (screen sharing) */
VNC_CONNECTION_AUTH_MSLOGON = 0xfffffffa, /* Used by UltraVNC */
} VncConnectionAuth;
diff --git a/src/vncdisplay.c b/src/vncdisplay.c
index 5c7845e..9ef9841 100644
--- a/src/vncdisplay.c
+++ b/src/vncdisplay.c
@@ -1857,6 +1857,7 @@ static void vnc_display_init(VncDisplay *display)
*/
priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (VNC_CONNECTION_AUTH_SASL));
priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (VNC_CONNECTION_AUTH_MSLOGON));
+ priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (VNC_CONNECTION_AUTH_ARD));
priv->preferable_auths = g_slist_append (priv->preferable_auths, GUINT_TO_POINTER (VNC_CONNECTION_AUTH_VNC));
/*
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]