summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libvncclient/rfbproto.c75
-rw-r--r--libvncclient/tls.c227
-rw-r--r--rfb/rfbclient.h9
-rw-r--r--rfb/rfbproto.h10
4 files changed, 314 insertions, 7 deletions
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
index 1a71f4f..497facb 100644
--- a/libvncclient/rfbproto.c
+++ b/libvncclient/rfbproto.c
@@ -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);
diff --git a/libvncclient/tls.c b/libvncclient/tls.c
index b8d2d1f..206dbda 100644
--- a/libvncclient/tls.c
+++ b/libvncclient/tls.c
@@ -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
diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h
index b3a0d87..c32168c 100644
--- a/rfb/rfbclient.h
+++ b/rfb/rfbclient.h
@@ -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);
diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h
index fec6bf7..06ab579 100644
--- a/rfb/rfbproto.h
+++ b/rfb/rfbproto.h
@@ -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