Commit 416a0dc3 authored by Håkon Enger's avatar Håkon Enger Committed by Jonh Wendell
Browse files

Support Mac OS VNC authentication

parent e9ceaf0e
......@@ -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));
......
......@@ -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
......@@ -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) {
......
......@@ -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;
......
......@@ -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));
/*
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment