00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <gnutls/gnutls.h>
00021 #include <rfb/rfbclient.h>
00022 #include <errno.h>
00023 #ifdef WIN32
00024 #undef SOCKET
00025 #include <windows.h>
00026 #define sleep(X) Sleep(1000*X)
00027 #include <winsock2.h>
00028 #define read(sock,buf,len) recv(sock,buf,len,0)
00029 #define write(sock,buf,len) send(sock,buf,len,0)
00030 #endif
00031 #include "tls.h"
00032
00033
00034 static const char *rfbTLSPriority = "NORMAL:+DHE-DSS:+RSA:+DHE-RSA:+SRP";
00035 static const char *rfbAnonTLSPriority= "NORMAL:+ANON-DH";
00036
00037 #define DH_BITS 1024
00038 static gnutls_dh_params_t rfbDHParams;
00039
00040 static rfbBool rfbTLSInitialized = FALSE;
00041
00042 static rfbBool
00043 InitializeTLS(void)
00044 {
00045 int ret;
00046
00047 if (rfbTLSInitialized) return TRUE;
00048 if ((ret = gnutls_global_init()) < 0 ||
00049 (ret = gnutls_dh_params_init(&rfbDHParams)) < 0 ||
00050 (ret = gnutls_dh_params_generate2(rfbDHParams, DH_BITS)) < 0)
00051 {
00052 rfbClientLog("Failed to initialized GnuTLS: %s.\n", gnutls_strerror(ret));
00053 return FALSE;
00054 }
00055 rfbClientLog("GnuTLS initialized.\n");
00056 rfbTLSInitialized = TRUE;
00057 return TRUE;
00058 }
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 #ifdef WIN32
00070 static void WSAtoTLSErrno()
00071 {
00072 switch(WSAGetLastError()) {
00073 case WSAEWOULDBLOCK:
00074 gnutls_transport_set_global_errno(EAGAIN);
00075 break;
00076 case WSAEINTR:
00077 gnutls_transport_set_global_errno(EINTR);
00078 break;
00079 default:
00080 gnutls_transport_set_global_errno(EIO);
00081 break;
00082 }
00083 }
00084 #endif
00085
00086
00087 static ssize_t
00088 PushTLS(gnutls_transport_ptr_t transport, const void *data, size_t len)
00089 {
00090 rfbClient *client = (rfbClient*)transport;
00091 int ret;
00092
00093 while (1)
00094 {
00095 ret = write(client->sock, data, len);
00096 if (ret < 0)
00097 {
00098 #ifdef WIN32
00099 WSAtoTLSErrno();
00100 #endif
00101 if (errno == EINTR) continue;
00102 return -1;
00103 }
00104 return ret;
00105 }
00106 }
00107
00108
00109 static ssize_t
00110 PullTLS(gnutls_transport_ptr_t transport, void *data, size_t len)
00111 {
00112 rfbClient *client = (rfbClient*)transport;
00113 int ret;
00114
00115 while (1)
00116 {
00117 ret = read(client->sock, data, len);
00118 if (ret < 0)
00119 {
00120 #ifdef WIN32
00121 WSAtoTLSErrno();
00122 #endif
00123 if (errno == EINTR) continue;
00124 return -1;
00125 }
00126 return ret;
00127 }
00128 }
00129
00130 static rfbBool
00131 InitializeTLSSession(rfbClient* client, rfbBool anonTLS)
00132 {
00133 int ret;
00134 const char *p;
00135
00136 if (client->tlsSession) return TRUE;
00137
00138 if ((ret = gnutls_init((gnutls_session_t*)&client->tlsSession, GNUTLS_CLIENT)) < 0)
00139 {
00140 rfbClientLog("Failed to initialized TLS session: %s.\n", gnutls_strerror(ret));
00141 return FALSE;
00142 }
00143
00144 if ((ret = gnutls_priority_set_direct((gnutls_session_t)client->tlsSession,
00145 anonTLS ? rfbAnonTLSPriority : rfbTLSPriority, &p)) < 0)
00146 {
00147 rfbClientLog("Warning: Failed to set TLS priority: %s (%s).\n", gnutls_strerror(ret), p);
00148 }
00149
00150 gnutls_transport_set_ptr((gnutls_session_t)client->tlsSession, (gnutls_transport_ptr_t)client);
00151 gnutls_transport_set_push_function((gnutls_session_t)client->tlsSession, PushTLS);
00152 gnutls_transport_set_pull_function((gnutls_session_t)client->tlsSession, PullTLS);
00153
00154 rfbClientLog("TLS session initialized.\n");
00155
00156 return TRUE;
00157 }
00158
00159 static rfbBool
00160 SetTLSAnonCredential(rfbClient* client)
00161 {
00162 gnutls_anon_client_credentials anonCred;
00163 int ret;
00164
00165 if ((ret = gnutls_anon_allocate_client_credentials(&anonCred)) < 0 ||
00166 (ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_ANON, anonCred)) < 0)
00167 {
00168 FreeTLS(client);
00169 rfbClientLog("Failed to create anonymous credentials: %s", gnutls_strerror(ret));
00170 return FALSE;
00171 }
00172 rfbClientLog("TLS anonymous credential created.\n");
00173 return TRUE;
00174 }
00175
00176 static rfbBool
00177 HandshakeTLS(rfbClient* client)
00178 {
00179 int timeout = 15;
00180 int ret;
00181
00182 while (timeout > 0 && (ret = gnutls_handshake((gnutls_session_t)client->tlsSession)) < 0)
00183 {
00184 if (!gnutls_error_is_fatal(ret))
00185 {
00186 rfbClientLog("TLS handshake blocking.\n");
00187 sleep(1);
00188 timeout--;
00189 continue;
00190 }
00191 rfbClientLog("TLS handshake failed: %s.\n", gnutls_strerror(ret));
00192 FreeTLS(client);
00193 return FALSE;
00194 }
00195
00196 if (timeout <= 0)
00197 {
00198 rfbClientLog("TLS handshake timeout.\n");
00199 FreeTLS(client);
00200 return FALSE;
00201 }
00202
00203 rfbClientLog("TLS handshake done.\n");
00204 return TRUE;
00205 }
00206
00207
00208 static rfbBool
00209 ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result)
00210 {
00211 uint8_t count=0;
00212 uint8_t loop=0;
00213 uint8_t flag=0;
00214 uint32_t tAuth[256], t;
00215 char buf1[500],buf2[10];
00216 uint32_t authScheme;
00217
00218 if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE;
00219
00220 if (count==0)
00221 {
00222 rfbClientLog("List of security types is ZERO. Giving up.\n");
00223 return FALSE;
00224 }
00225
00226 if (count>sizeof(tAuth))
00227 {
00228 rfbClientLog("%d security types are too many; maximum is %d\n", count, sizeof(tAuth));
00229 return FALSE;
00230 }
00231
00232 rfbClientLog("We have %d security types to read\n", count);
00233 authScheme=0;
00234
00235 for (loop=0;loop<count;loop++)
00236 {
00237 if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
00238 t=rfbClientSwap32IfLE(tAuth[loop]);
00239 rfbClientLog("%d) Received security type %d\n", loop, t);
00240 if (flag) continue;
00241 if (t==rfbVeNCryptTLSNone ||
00242 t==rfbVeNCryptTLSVNC ||
00243 t==rfbVeNCryptTLSPlain ||
00244 t==rfbVeNCryptX509None ||
00245 t==rfbVeNCryptX509VNC ||
00246 t==rfbVeNCryptX509Plain)
00247 {
00248 flag++;
00249 authScheme=t;
00250 rfbClientLog("Selecting security type %d (%d/%d in the list)\n", authScheme, loop, count);
00251
00252 if (!WriteToRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE;
00253 }
00254 tAuth[loop]=t;
00255 }
00256 if (authScheme==0)
00257 {
00258 memset(buf1, 0, sizeof(buf1));
00259 for (loop=0;loop<count;loop++)
00260 {
00261 if (strlen(buf1)>=sizeof(buf1)-1) break;
00262 snprintf(buf2, sizeof(buf2), (loop>0 ? ", %d" : "%d"), (int)tAuth[loop]);
00263 strncat(buf1, buf2, sizeof(buf1)-strlen(buf1)-1);
00264 }
00265 rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n",
00266 buf1);
00267 return FALSE;
00268 }
00269 *result = authScheme;
00270 return TRUE;
00271 }
00272
00273 static void
00274 FreeX509Credential(rfbCredential *cred)
00275 {
00276 if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile);
00277 if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile);
00278 if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile);
00279 if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile);
00280 free(cred);
00281 }
00282
00283 static gnutls_certificate_credentials_t
00284 CreateX509CertCredential(rfbCredential *cred)
00285 {
00286 gnutls_certificate_credentials_t x509_cred;
00287 int ret;
00288
00289 if (!cred->x509Credential.x509CACertFile)
00290 {
00291 rfbClientLog("No CA certificate provided.\n");
00292 return NULL;
00293 }
00294
00295 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0)
00296 {
00297 rfbClientLog("Cannot allocate credentials: %s.\n", gnutls_strerror(ret));
00298 return NULL;
00299 }
00300 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred,
00301 cred->x509Credential.x509CACertFile, GNUTLS_X509_FMT_PEM)) < 0)
00302 {
00303 rfbClientLog("Cannot load CA credentials: %s.\n", gnutls_strerror(ret));
00304 gnutls_certificate_free_credentials (x509_cred);
00305 return NULL;
00306 }
00307 if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile)
00308 {
00309 if ((ret = gnutls_certificate_set_x509_key_file(x509_cred,
00310 cred->x509Credential.x509ClientCertFile, cred->x509Credential.x509ClientKeyFile,
00311 GNUTLS_X509_FMT_PEM)) < 0)
00312 {
00313 rfbClientLog("Cannot load client certificate or key: %s.\n", gnutls_strerror(ret));
00314 gnutls_certificate_free_credentials (x509_cred);
00315 return NULL;
00316 }
00317 } else
00318 {
00319 rfbClientLog("No client certificate or key provided.\n");
00320 }
00321 if (cred->x509Credential.x509CACrlFile)
00322 {
00323 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred,
00324 cred->x509Credential.x509CACrlFile, GNUTLS_X509_FMT_PEM)) < 0)
00325 {
00326 rfbClientLog("Cannot load CRL: %s.\n", gnutls_strerror(ret));
00327 gnutls_certificate_free_credentials (x509_cred);
00328 return NULL;
00329 }
00330 } else
00331 {
00332 rfbClientLog("No CRL provided.\n");
00333 }
00334 gnutls_certificate_set_dh_params (x509_cred, rfbDHParams);
00335 return x509_cred;
00336 }
00337
00338
00339 rfbBool
00340 HandleAnonTLSAuth(rfbClient* client)
00341 {
00342 if (!InitializeTLS() || !InitializeTLSSession(client, TRUE)) return FALSE;
00343
00344 if (!SetTLSAnonCredential(client)) return FALSE;
00345
00346 if (!HandshakeTLS(client)) return FALSE;
00347
00348 return TRUE;
00349 }
00350
00351 rfbBool
00352 HandleVeNCryptAuth(rfbClient* client)
00353 {
00354 uint8_t major, minor, status;
00355 uint32_t authScheme;
00356 rfbBool anonTLS;
00357 gnutls_certificate_credentials_t x509_cred = NULL;
00358 int ret;
00359
00360 if (!InitializeTLS()) return FALSE;
00361
00362
00363 if (!ReadFromRFBServer(client, (char *)&major, 1) ||
00364 !ReadFromRFBServer(client, (char *)&minor, 1))
00365 {
00366 return FALSE;
00367 }
00368 rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major, (int)minor);
00369
00370 if (major != 0 && minor != 2)
00371 {
00372 rfbClientLog("Unsupported VeNCrypt version.\n");
00373 return FALSE;
00374 }
00375
00376 if (!WriteToRFBServer(client, (char *)&major, 1) ||
00377 !WriteToRFBServer(client, (char *)&minor, 1) ||
00378 !ReadFromRFBServer(client, (char *)&status, 1))
00379 {
00380 return FALSE;
00381 }
00382
00383 if (status != 0)
00384 {
00385 rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major, (int)minor);
00386 return FALSE;
00387 }
00388
00389 if (!ReadVeNCryptSecurityType(client, &authScheme)) return FALSE;
00390 if (!ReadFromRFBServer(client, (char *)&status, 1) || status != 1)
00391 {
00392 rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme, (int)status);
00393 return FALSE;
00394 }
00395 client->subAuthScheme = authScheme;
00396
00397
00398 switch (authScheme)
00399 {
00400 case rfbVeNCryptTLSNone:
00401 case rfbVeNCryptTLSVNC:
00402 case rfbVeNCryptTLSPlain:
00403 anonTLS = TRUE;
00404 break;
00405 default:
00406 anonTLS = FALSE;
00407 break;
00408 }
00409
00410
00411 if (!anonTLS)
00412 {
00413 rfbCredential *cred;
00414
00415 if (!client->GetCredential)
00416 {
00417 rfbClientLog("GetCredential callback is not set.\n");
00418 return FALSE;
00419 }
00420 cred = client->GetCredential(client, rfbCredentialTypeX509);
00421 if (!cred)
00422 {
00423 rfbClientLog("Reading credential failed\n");
00424 return FALSE;
00425 }
00426
00427 x509_cred = CreateX509CertCredential(cred);
00428 FreeX509Credential(cred);
00429 if (!x509_cred) return FALSE;
00430 }
00431
00432
00433 if (!InitializeTLSSession(client, anonTLS)) return FALSE;
00434
00435 if (anonTLS)
00436 {
00437 if (!SetTLSAnonCredential(client)) return FALSE;
00438 }
00439 else
00440 {
00441 if ((ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
00442 {
00443 rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
00444 FreeTLS(client);
00445 return FALSE;
00446 }
00447 }
00448
00449 if (!HandshakeTLS(client)) return FALSE;
00450
00451
00452
00453
00454
00455
00456 return TRUE;
00457 }
00458
00459 int
00460 ReadFromTLS(rfbClient* client, char *out, unsigned int n)
00461 {
00462 ssize_t ret;
00463
00464 ret = gnutls_record_recv((gnutls_session_t)client->tlsSession, out, n);
00465 if (ret >= 0) return ret;
00466 if (ret == GNUTLS_E_REHANDSHAKE || ret == GNUTLS_E_AGAIN)
00467 {
00468 errno = EAGAIN;
00469 } else
00470 {
00471 rfbClientLog("Error reading from TLS: %s.\n", gnutls_strerror(ret));
00472 errno = EINTR;
00473 }
00474 return -1;
00475 }
00476
00477 int
00478 WriteToTLS(rfbClient* client, char *buf, unsigned int n)
00479 {
00480 unsigned int offset = 0;
00481 ssize_t ret;
00482
00483 while (offset < n)
00484 {
00485 ret = gnutls_record_send((gnutls_session_t)client->tlsSession, buf+offset, (size_t)(n-offset));
00486 if (ret == 0) continue;
00487 if (ret < 0)
00488 {
00489 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) continue;
00490 rfbClientLog("Error writing to TLS: %s.\n", gnutls_strerror(ret));
00491 return -1;
00492 }
00493 offset += (unsigned int)ret;
00494 }
00495 return offset;
00496 }
00497
00498 void FreeTLS(rfbClient* client)
00499 {
00500 if (client->tlsSession)
00501 {
00502 gnutls_deinit((gnutls_session_t)client->tlsSession);
00503 client->tlsSession = NULL;
00504 }
00505 }