Commit 95ae56c8 authored by Vic Lee's avatar Vic Lee Committed by Johannes Schindelin

Add VeNCrypt support in libvncclient

Signed-off-by: 's avatarVic Lee <llyzs@163.com>
parent 68964c29
......@@ -504,7 +504,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 ||
(!subAuth && tAuth[loop]==rfbTLS))
(!subAuth && (tAuth[loop]==rfbTLS || tAuth[loop]==rfbVeNCrypt)))
{
flag++;
authScheme=tAuth[loop];
......@@ -569,6 +569,50 @@ HandleVncAuth(rfbClient *client)
return TRUE;
}
static rfbBool
HandlePlainAuth(rfbClient *client)
{
uint32_t ulen, ulensw;
uint32_t plen, plensw;
rfbCredential *cred;
if (!client->GetCredential)
{
rfbClientLog("GetCredential callback is not set.\n");
return FALSE;
}
cred = client->GetCredential(client, rfbCredentialTypeUser);
if (!cred)
{
rfbClientLog("Reading credential failed\n");
return FALSE;
}
ulen = (cred->userCredential.username ? strlen(cred->userCredential.username) : 0);
ulensw = rfbClientSwap32IfLE(ulen);
plen = (cred->userCredential.password ? strlen(cred->userCredential.password) : 0);
plensw = rfbClientSwap32IfLE(plen);
if (!WriteToRFBServer(client, (char *)&ulensw, 4)) return FALSE;
if (!WriteToRFBServer(client, (char *)&plensw, 4)) return FALSE;
if (ulen > 0)
{
if (!WriteToRFBServer(client, cred->userCredential.username, ulen)) return FALSE;
}
if (plen > 0)
{
if (!WriteToRFBServer(client, cred->userCredential.password, plen)) return FALSE;
}
if (cred->userCredential.username) free(cred->userCredential.username);
if (cred->userCredential.password) free(cred->userCredential.password);
free(cred);
/* Handle the SecurityResult message */
if (!rfbHandleAuthResult(client)) return FALSE;
return TRUE;
}
/*
* InitialiseRFBConnection.
*/
......@@ -700,6 +744,35 @@ InitialiseRFBConnection(rfbClient* client)
break;
case rfbVeNCrypt:
if (!HandleVeNCryptAuth(client)) return FALSE;
switch (client->subAuthScheme) {
case rfbVeNCryptTLSNone:
case rfbVeNCryptX509None:
rfbClientLog("No sub authentication needed\n");
if (!rfbHandleAuthResult(client)) return FALSE;
break;
case rfbVeNCryptTLSVNC:
case rfbVeNCryptX509VNC:
if (!HandleVncAuth(client)) return FALSE;
break;
case rfbVeNCryptTLSPlain:
case rfbVeNCryptX509Plain:
if (!HandlePlainAuth(client)) return FALSE;
break;
default:
rfbClientLog("Unknown sub authentication scheme from VNC server: %d\n",
client->subAuthScheme);
return FALSE;
}
break;
default:
rfbClientLog("Unknown authentication scheme from VNC server: %d\n",
(int)authScheme);
......
......@@ -168,6 +168,136 @@ HandshakeTLS(rfbClient* client)
return TRUE;
}
/* VeNCrypt sub auth. 1 byte auth count, followed by count * 4 byte integers */
static rfbBool
ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result)
{
uint8_t count=0;
uint8_t loop=0;
uint8_t flag=0;
uint32_t tAuth[256], t;
char buf1[500],buf2[10];
uint32_t authScheme;
if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE;
if (count==0)
{
rfbClientLog("List of security types is ZERO. Giving up.\n");
return FALSE;
}
if (count>sizeof(tAuth))
{
rfbClientLog("%d security types are too many; maximum is %d\n", count, sizeof(tAuth));
return FALSE;
}
rfbClientLog("We have %d security types to read\n", count);
authScheme=0;
/* now, we have a list of available security types to read ( uint8_t[] ) */
for (loop=0;loop<count;loop++)
{
if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
t=rfbClientSwap32IfLE(tAuth[loop]);
rfbClientLog("%d) Received security type %d\n", loop, t);
if (flag) continue;
if (t==rfbVeNCryptTLSNone ||
t==rfbVeNCryptTLSVNC ||
t==rfbVeNCryptTLSPlain ||
t==rfbVeNCryptX509None ||
t==rfbVeNCryptX509VNC ||
t==rfbVeNCryptX509Plain)
{
flag++;
authScheme=t;
rfbClientLog("Selecting security type %d (%d/%d in the list)\n", authScheme, loop, count);
/* send back 4 bytes (in original byte order!) indicating which security type to use */
if (!WriteToRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
}
tAuth[loop]=t;
}
if (authScheme==0)
{
memset(buf1, 0, sizeof(buf1));
for (loop=0;loop<count;loop++)
{
if (strlen(buf1)>=sizeof(buf1)-1) break;
snprintf(buf2, sizeof(buf2), (loop>0 ? ", %d" : "%d"), (int)tAuth[loop]);
strncat(buf1, buf2, sizeof(buf1)-strlen(buf1)-1);
}
rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n",
buf1);
return FALSE;
}
*result = authScheme;
return TRUE;
}
static void
FreeX509Credential(rfbCredential *cred)
{
if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile);
if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile);
if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile);
if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile);
free(cred);
}
static gnutls_certificate_credentials_t
CreateX509CertCredential(rfbCredential *cred)
{
gnutls_certificate_credentials_t x509_cred;
int ret;
if (!cred->x509Credential.x509CACertFile)
{
rfbClientLog("No CA certificate provided.\n");
return NULL;
}
if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0)
{
rfbClientLog("Cannot allocate credentials: %s.\n", gnutls_strerror(ret));
return NULL;
}
if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
cred->x509Credential.x509CACertFile, GNUTLS_X509_FMT_PEM)) < 0)
{
rfbClientLog("Cannot load CA credentials: %s.\n", gnutls_strerror(ret));
gnutls_certificate_free_credentials (x509_cred);
return NULL;
}
if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile)
{
if ((ret = gnutls_certificate_set_x509_key_file(x509_cred,
cred->x509Credential.x509ClientCertFile, cred->x509Credential.x509ClientKeyFile,
GNUTLS_X509_FMT_PEM)) < 0)
{
rfbClientLog("Cannot load client certificate or key: %s.\n", gnutls_strerror(ret));
gnutls_certificate_free_credentials (x509_cred);
return NULL;
}
} else
{
rfbClientLog("No client certificate or key provided.\n");
}
if (cred->x509Credential.x509CACrlFile)
{
if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
cred->x509Credential.x509CACrlFile, GNUTLS_X509_FMT_PEM)) < 0)
{
rfbClientLog("Cannot load CRL: %s.\n", gnutls_strerror(ret));
gnutls_certificate_free_credentials (x509_cred);
return NULL;
}
} else
{
rfbClientLog("No CRL provided.\n");
}
gnutls_certificate_set_dh_params (x509_cred, rfbDHParams);
return x509_cred;
}
#endif
rfbBool
......@@ -193,17 +323,108 @@ rfbBool
HandleVeNCryptAuth(rfbClient* client)
{
#ifdef LIBVNCSERVER_WITH_CLIENT_TLS
uint8_t major, minor, status;
uint32_t authScheme;
rfbBool anonTLS;
gnutls_certificate_credentials_t x509_cred = NULL;
int ret;
if (!InitializeTLS() || !InitializeTLSSession(client, FALSE)) return FALSE;
if (!InitializeTLS()) return FALSE;
/* Read VeNCrypt version */
if (!ReadFromRFBServer(client, (char *)&major, 1) ||
!ReadFromRFBServer(client, (char *)&minor, 1))
{
return FALSE;
}
rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major, (int)minor);
if (major != 0 && minor != 2)
{
rfbClientLog("Unsupported VeNCrypt version.\n");
return FALSE;
}
if (!WriteToRFBServer(client, (char *)&major, 1) ||
!WriteToRFBServer(client, (char *)&minor, 1) ||
!ReadFromRFBServer(client, (char *)&status, 1))
{
return FALSE;
}
if (status != 0)
{
rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major, (int)minor);
return FALSE;
}
if (!ReadVeNCryptSecurityType(client, &authScheme)) return FALSE;
if (!ReadFromRFBServer(client, (char *)&status, 1) || status != 1)
{
rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme, (int)status);
return FALSE;
}
client->subAuthScheme = authScheme;
/* Some VeNCrypt security types are anonymous TLS, others are X509 */
switch (authScheme)
{
case rfbVeNCryptTLSNone:
case rfbVeNCryptTLSVNC:
case rfbVeNCryptTLSPlain:
anonTLS = TRUE;
break;
default:
anonTLS = FALSE;
break;
}
/* Get X509 Credentials if it's not anonymous */
if (!anonTLS)
{
rfbCredential *cred;
if (!client->GetCredential)
{
rfbClientLog("GetCredential callback is not set.\n");
return FALSE;
}
cred = client->GetCredential(client, rfbCredentialTypeX509);
if (!cred)
{
rfbClientLog("Reading credential failed\n");
return FALSE;
}
x509_cred = CreateX509CertCredential(cred);
FreeX509Credential(cred);
if (!x509_cred) return FALSE;
}
/* TODO: read VeNCrypt version, etc */
/* TODO: call GetCredential and set to TLS session */
/* Start up the TLS session */
if (!InitializeTLSSession(client, anonTLS)) return FALSE;
if (anonTLS)
{
if (!SetTLSAnonCredential(client)) return FALSE;
}
else
{
if ((ret = gnutls_credentials_set(client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
{
rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
FreeTLS(client);
return FALSE;
}
}
if (!HandshakeTLS(client)) return FALSE;
/* TODO: validate certificate */
/* We are done here. The caller should continue with client->subAuthScheme
* to do actual sub authentication.
*/
return TRUE;
#else
......
......@@ -104,7 +104,7 @@ typedef struct {
/* For GetCredentialProc callback function to return */
typedef union _rfbCredential
{
/* VeNCrypt */
/* X509 (VeNCrypt) */
struct
{
char *x509CACertFile;
......@@ -112,7 +112,7 @@ typedef union _rfbCredential
char *x509ClientCertFile;
char *x509ClientKeyFile;
} x509Credential;
/* MSLogon */
/* Plain (VeNCrypt), MSLogon (UltraVNC) */
struct
{
char *username;
......@@ -120,6 +120,9 @@ typedef union _rfbCredential
} userCredential;
} rfbCredential;
#define rfbCredentialTypeX509 1
#define rfbCredentialTypeUser 2
struct _rfbClient;
typedef void (*HandleTextChatProc)(struct _rfbClient* client, int value, char *text);
......@@ -129,7 +132,7 @@ typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y,
typedef void (*SoftCursorUnlockScreenProc)(struct _rfbClient* client);
typedef void (*GotFrameBufferUpdateProc)(struct _rfbClient* client, int x, int y, int w, int h);
typedef char* (*GetPasswordProc)(struct _rfbClient* client);
typedef rfbCredential* (*GetCredentialProc)(struct _rfbClient* client, uint8_t securityType);
typedef rfbCredential* (*GetCredentialProc)(struct _rfbClient* client, int credentialType);
typedef rfbBool (*MallocFrameBufferProc)(struct _rfbClient* client);
typedef void (*GotXCutTextProc)(struct _rfbClient* client, const char *text, int textlen);
typedef void (*BellProc)(struct _rfbClient* client);
......
......@@ -266,6 +266,16 @@ typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
#define rfbTLS 18
#define rfbVeNCrypt 19
#define rfbVeNCryptPlain 256
#define rfbVeNCryptTLSNone 257
#define rfbVeNCryptTLSVNC 258
#define rfbVeNCryptTLSPlain 259
#define rfbVeNCryptX509None 260
#define rfbVeNCryptX509VNC 261
#define rfbVeNCryptX509Plain 262
#define rfbVeNCryptX509SASL 263
#define rfbVeNCryptTLSSASL 264
/*
* rfbConnFailed: For some reason the connection failed (e.g. the server
* cannot support the desired protocol version). This is
......
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