diff options
author | Vic Lee <llyzs@163.com> | 2011-01-21 13:03:40 +0800 |
---|---|---|
committer | Christian Beier <dontmind@freeshell.org> | 2011-01-31 17:47:44 +0100 |
commit | 030ccf673d96016733ffb3bef3feede20dba19a7 (patch) | |
tree | c1f9fbb7c509244881ff4a7b8b33f8981d7b9fe2 /libvncclient | |
parent | ffe30366d63fd318f0ee3b55dd9a60642bfb5d88 (diff) | |
download | libtdevnc-030ccf673d96016733ffb3bef3feede20dba19a7.tar.gz libtdevnc-030ccf673d96016733ffb3bef3feede20dba19a7.zip |
Add ARD (Apple Remote Desktop) security type support
Signed-off-by: Vic Lee <llyzs@163.com>
Signed-off-by: Christian Beier <dontmind@freeshell.org>
Diffstat (limited to 'libvncclient')
-rw-r--r-- | libvncclient/rfbproto.c | 216 |
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"); |