1 /* 2 * Copyright (C) 2009 Vic Lee. 3 * 4 * This is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This software is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this software; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 17 * USA. 18 */ 19 20 #include <gnutls/gnutls.h> 21 #include <rfb/rfbclient.h> 22 #include <errno.h> 23 #ifdef WIN32 24 #undef SOCKET 25 #include <windows.h> /* for Sleep() */ 26 #define sleep(X) Sleep(1000*X) /* MinGW32 has no sleep() */ 27 #include <winsock2.h> 28 #define read(sock,buf,len) recv(sock,buf,len,0) 29 #define write(sock,buf,len) send(sock,buf,len,0) 30 #endif 31 #include "tls.h" 32 33 34 static const char *rfbTLSPriority = "NORMAL:+DHE-DSS:+RSA:+DHE-RSA:+SRP"; 35 static const char *rfbAnonTLSPriority= "NORMAL:+ANON-DH"; 36 37 #define DH_BITS 1024 38 static gnutls_dh_params_t rfbDHParams; 39 40 static rfbBool rfbTLSInitialized = FALSE; 41 42 static rfbBool 43 InitializeTLS(void) 44 { 45 int ret; 46 47 if (rfbTLSInitialized) return TRUE; 48 if ((ret = gnutls_global_init()) < 0 || 49 (ret = gnutls_dh_params_init(&rfbDHParams)) < 0 || 50 (ret = gnutls_dh_params_generate2(rfbDHParams, DH_BITS)) < 0) 51 { 52 rfbClientLog("Failed to initialized GnuTLS: %s.\n", gnutls_strerror(ret)); 53 return FALSE; 54 } 55 rfbClientLog("GnuTLS initialized.\n"); 56 rfbTLSInitialized = TRUE; 57 return TRUE; 58 } 59 60 /* 61 * On Windows, translate WSAGetLastError() to errno values as GNU TLS does it 62 * internally too. This is necessary because send() and recv() on Windows 63 * don't set errno when they fail but GNUTLS expects a proper errno value. 64 * 65 * Use gnutls_transport_set_global_errno() like the GNU TLS documentation 66 * suggests to avoid problems with different errno variables when GNU TLS and 67 * libvncclient are linked to different versions of msvcrt.dll. 68 */ 69 #ifdef WIN32 70 static void WSAtoTLSErrno() 71 { 72 switch(WSAGetLastError()) { 73 case WSAEWOULDBLOCK: 74 gnutls_transport_set_global_errno(EAGAIN); 75 break; 76 case WSAEINTR: 77 gnutls_transport_set_global_errno(EINTR); 78 break; 79 default: 80 gnutls_transport_set_global_errno(EIO); 81 break; 82 } 83 } 84 #endif 85 86 87 static ssize_t 88 PushTLS(gnutls_transport_ptr_t transport, const void *data, size_t len) 89 { 90 rfbClient *client = (rfbClient*)transport; 91 int ret; 92 93 while (1) 94 { 95 ret = write(client->sock, data, len); 96 if (ret < 0) 97 { 98 #ifdef WIN32 99 WSAtoTLSErrno(); 100 #endif 101 if (errno == EINTR) continue; 102 return -1; 103 } 104 return ret; 105 } 106 } 107 108 109 static ssize_t 110 PullTLS(gnutls_transport_ptr_t transport, void *data, size_t len) 111 { 112 rfbClient *client = (rfbClient*)transport; 113 int ret; 114 115 while (1) 116 { 117 ret = read(client->sock, data, len); 118 if (ret < 0) 119 { 120 #ifdef WIN32 121 WSAtoTLSErrno(); 122 #endif 123 if (errno == EINTR) continue; 124 return -1; 125 } 126 return ret; 127 } 128 } 129 130 static rfbBool 131 InitializeTLSSession(rfbClient* client, rfbBool anonTLS) 132 { 133 int ret; 134 const char *p; 135 136 if (client->tlsSession) return TRUE; 137 138 if ((ret = gnutls_init((gnutls_session_t*)&client->tlsSession, GNUTLS_CLIENT)) < 0) 139 { 140 rfbClientLog("Failed to initialized TLS session: %s.\n", gnutls_strerror(ret)); 141 return FALSE; 142 } 143 144 if ((ret = gnutls_priority_set_direct((gnutls_session_t)client->tlsSession, 145 anonTLS ? rfbAnonTLSPriority : rfbTLSPriority, &p)) < 0) 146 { 147 rfbClientLog("Warning: Failed to set TLS priority: %s (%s).\n", gnutls_strerror(ret), p); 148 } 149 150 gnutls_transport_set_ptr((gnutls_session_t)client->tlsSession, (gnutls_transport_ptr_t)client); 151 gnutls_transport_set_push_function((gnutls_session_t)client->tlsSession, PushTLS); 152 gnutls_transport_set_pull_function((gnutls_session_t)client->tlsSession, PullTLS); 153 154 rfbClientLog("TLS session initialized.\n"); 155 156 return TRUE; 157 } 158 159 static rfbBool 160 SetTLSAnonCredential(rfbClient* client) 161 { 162 gnutls_anon_client_credentials anonCred; 163 int ret; 164 165 if ((ret = gnutls_anon_allocate_client_credentials(&anonCred)) < 0 || 166 (ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_ANON, anonCred)) < 0) 167 { 168 FreeTLS(client); 169 rfbClientLog("Failed to create anonymous credentials: %s", gnutls_strerror(ret)); 170 return FALSE; 171 } 172 rfbClientLog("TLS anonymous credential created.\n"); 173 return TRUE; 174 } 175 176 static rfbBool 177 HandshakeTLS(rfbClient* client) 178 { 179 int timeout = 15; 180 int ret; 181 182 while (timeout > 0 && (ret = gnutls_handshake((gnutls_session_t)client->tlsSession)) < 0) 183 { 184 if (!gnutls_error_is_fatal(ret)) 185 { 186 rfbClientLog("TLS handshake blocking.\n"); 187 sleep(1); 188 timeout--; 189 continue; 190 } 191 rfbClientLog("TLS handshake failed: %s.\n", gnutls_strerror(ret)); 192 FreeTLS(client); 193 return FALSE; 194 } 195 196 if (timeout <= 0) 197 { 198 rfbClientLog("TLS handshake timeout.\n"); 199 FreeTLS(client); 200 return FALSE; 201 } 202 203 rfbClientLog("TLS handshake done.\n"); 204 return TRUE; 205 } 206 207 /* VeNCrypt sub auth. 1 byte auth count, followed by count * 4 byte integers */ 208 static rfbBool 209 ReadVeNCryptSecurityType(rfbClient* client, uint32_t *result) 210 { 211 uint8_t count=0; 212 uint8_t loop=0; 213 uint8_t flag=0; 214 uint32_t tAuth[256], t; 215 char buf1[500],buf2[10]; 216 uint32_t authScheme; 217 218 if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE; 219 220 if (count==0) 221 { 222 rfbClientLog("List of security types is ZERO. Giving up.\n"); 223 return FALSE; 224 } 225 226 if (count>sizeof(tAuth)) 227 { 228 rfbClientLog("%d security types are too many; maximum is %d\n", count, sizeof(tAuth)); 229 return FALSE; 230 } 231 232 rfbClientLog("We have %d security types to read\n", count); 233 authScheme=0; 234 /* now, we have a list of available security types to read ( uint8_t[] ) */ 235 for (loop=0;loop<count;loop++) 236 { 237 if (!ReadFromRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE; 238 t=rfbClientSwap32IfLE(tAuth[loop]); 239 rfbClientLog("%d) Received security type %d\n", loop, t); 240 if (flag) continue; 241 if (t==rfbVeNCryptTLSNone || 242 t==rfbVeNCryptTLSVNC || 243 t==rfbVeNCryptTLSPlain || 244 t==rfbVeNCryptX509None || 245 t==rfbVeNCryptX509VNC || 246 t==rfbVeNCryptX509Plain) 247 { 248 flag++; 249 authScheme=t; 250 rfbClientLog("Selecting security type %d (%d/%d in the list)\n", authScheme, loop, count); 251 /* send back 4 bytes (in original byte order!) indicating which security type to use */ 252 if (!WriteToRFBServer(client, (char *)&tAuth[loop], 4)) return FALSE; 253 } 254 tAuth[loop]=t; 255 } 256 if (authScheme==0) 257 { 258 memset(buf1, 0, sizeof(buf1)); 259 for (loop=0;loop<count;loop++) 260 { 261 if (strlen(buf1)>=sizeof(buf1)-1) break; 262 snprintf(buf2, sizeof(buf2), (loop>0 ? ", %d" : "%d"), (int)tAuth[loop]); 263 strncat(buf1, buf2, sizeof(buf1)-strlen(buf1)-1); 264 } 265 rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n", 266 buf1); 267 return FALSE; 268 } 269 *result = authScheme; 270 return TRUE; 271 } 272 273 static void 274 FreeX509Credential(rfbCredential *cred) 275 { 276 if (cred->x509Credential.x509CACertFile) free(cred->x509Credential.x509CACertFile); 277 if (cred->x509Credential.x509CACrlFile) free(cred->x509Credential.x509CACrlFile); 278 if (cred->x509Credential.x509ClientCertFile) free(cred->x509Credential.x509ClientCertFile); 279 if (cred->x509Credential.x509ClientKeyFile) free(cred->x509Credential.x509ClientKeyFile); 280 free(cred); 281 } 282 283 static gnutls_certificate_credentials_t 284 CreateX509CertCredential(rfbCredential *cred) 285 { 286 gnutls_certificate_credentials_t x509_cred; 287 int ret; 288 289 if (!cred->x509Credential.x509CACertFile) 290 { 291 rfbClientLog("No CA certificate provided.\n"); 292 return NULL; 293 } 294 295 if ((ret = gnutls_certificate_allocate_credentials(&x509_cred)) < 0) 296 { 297 rfbClientLog("Cannot allocate credentials: %s.\n", gnutls_strerror(ret)); 298 return NULL; 299 } 300 if ((ret = gnutls_certificate_set_x509_trust_file(x509_cred, 301 cred->x509Credential.x509CACertFile, GNUTLS_X509_FMT_PEM)) < 0) 302 { 303 rfbClientLog("Cannot load CA credentials: %s.\n", gnutls_strerror(ret)); 304 gnutls_certificate_free_credentials (x509_cred); 305 return NULL; 306 } 307 if (cred->x509Credential.x509ClientCertFile && cred->x509Credential.x509ClientKeyFile) 308 { 309 if ((ret = gnutls_certificate_set_x509_key_file(x509_cred, 310 cred->x509Credential.x509ClientCertFile, cred->x509Credential.x509ClientKeyFile, 311 GNUTLS_X509_FMT_PEM)) < 0) 312 { 313 rfbClientLog("Cannot load client certificate or key: %s.\n", gnutls_strerror(ret)); 314 gnutls_certificate_free_credentials (x509_cred); 315 return NULL; 316 } 317 } else 318 { 319 rfbClientLog("No client certificate or key provided.\n"); 320 } 321 if (cred->x509Credential.x509CACrlFile) 322 { 323 if ((ret = gnutls_certificate_set_x509_crl_file(x509_cred, 324 cred->x509Credential.x509CACrlFile, GNUTLS_X509_FMT_PEM)) < 0) 325 { 326 rfbClientLog("Cannot load CRL: %s.\n", gnutls_strerror(ret)); 327 gnutls_certificate_free_credentials (x509_cred); 328 return NULL; 329 } 330 } else 331 { 332 rfbClientLog("No CRL provided.\n"); 333 } 334 gnutls_certificate_set_dh_params (x509_cred, rfbDHParams); 335 return x509_cred; 336 } 337 338 339 rfbBool 340 HandleAnonTLSAuth(rfbClient* client) 341 { 342 if (!InitializeTLS() || !InitializeTLSSession(client, TRUE)) return FALSE; 343 344 if (!SetTLSAnonCredential(client)) return FALSE; 345 346 if (!HandshakeTLS(client)) return FALSE; 347 348 return TRUE; 349 } 350 351 rfbBool 352 HandleVeNCryptAuth(rfbClient* client) 353 { 354 uint8_t major, minor, status; 355 uint32_t authScheme; 356 rfbBool anonTLS; 357 gnutls_certificate_credentials_t x509_cred = NULL; 358 int ret; 359 360 if (!InitializeTLS()) return FALSE; 361 362 /* Read VeNCrypt version */ 363 if (!ReadFromRFBServer(client, (char *)&major, 1) || 364 !ReadFromRFBServer(client, (char *)&minor, 1)) 365 { 366 return FALSE; 367 } 368 rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major, (int)minor); 369 370 if (major != 0 && minor != 2) 371 { 372 rfbClientLog("Unsupported VeNCrypt version.\n"); 373 return FALSE; 374 } 375 376 if (!WriteToRFBServer(client, (char *)&major, 1) || 377 !WriteToRFBServer(client, (char *)&minor, 1) || 378 !ReadFromRFBServer(client, (char *)&status, 1)) 379 { 380 return FALSE; 381 } 382 383 if (status != 0) 384 { 385 rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major, (int)minor); 386 return FALSE; 387 } 388 389 if (!ReadVeNCryptSecurityType(client, &authScheme)) return FALSE; 390 if (!ReadFromRFBServer(client, (char *)&status, 1) || status != 1) 391 { 392 rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme, (int)status); 393 return FALSE; 394 } 395 client->subAuthScheme = authScheme; 396 397 /* Some VeNCrypt security types are anonymous TLS, others are X509 */ 398 switch (authScheme) 399 { 400 case rfbVeNCryptTLSNone: 401 case rfbVeNCryptTLSVNC: 402 case rfbVeNCryptTLSPlain: 403 anonTLS = TRUE; 404 break; 405 default: 406 anonTLS = FALSE; 407 break; 408 } 409 410 /* Get X509 Credentials if it's not anonymous */ 411 if (!anonTLS) 412 { 413 rfbCredential *cred; 414 415 if (!client->GetCredential) 416 { 417 rfbClientLog("GetCredential callback is not set.\n"); 418 return FALSE; 419 } 420 cred = client->GetCredential(client, rfbCredentialTypeX509); 421 if (!cred) 422 { 423 rfbClientLog("Reading credential failed\n"); 424 return FALSE; 425 } 426 427 x509_cred = CreateX509CertCredential(cred); 428 FreeX509Credential(cred); 429 if (!x509_cred) return FALSE; 430 } 431 432 /* Start up the TLS session */ 433 if (!InitializeTLSSession(client, anonTLS)) return FALSE; 434 435 if (anonTLS) 436 { 437 if (!SetTLSAnonCredential(client)) return FALSE; 438 } 439 else 440 { 441 if ((ret = gnutls_credentials_set((gnutls_session_t)client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0) 442 { 443 rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret)); 444 FreeTLS(client); 445 return FALSE; 446 } 447 } 448 449 if (!HandshakeTLS(client)) return FALSE; 450 451 /* TODO: validate certificate */ 452 453 /* We are done here. The caller should continue with client->subAuthScheme 454 * to do actual sub authentication. 455 */ 456 return TRUE; 457 } 458 459 int 460 ReadFromTLS(rfbClient* client, char *out, unsigned int n) 461 { 462 ssize_t ret; 463 464 ret = gnutls_record_recv((gnutls_session_t)client->tlsSession, out, n); 465 if (ret >= 0) return ret; 466 if (ret == GNUTLS_E_REHANDSHAKE || ret == GNUTLS_E_AGAIN) 467 { 468 errno = EAGAIN; 469 } else 470 { 471 rfbClientLog("Error reading from TLS: %s.\n", gnutls_strerror(ret)); 472 errno = EINTR; 473 } 474 return -1; 475 } 476 477 int 478 WriteToTLS(rfbClient* client, char *buf, unsigned int n) 479 { 480 unsigned int offset = 0; 481 ssize_t ret; 482 483 while (offset < n) 484 { 485 ret = gnutls_record_send((gnutls_session_t)client->tlsSession, buf+offset, (size_t)(n-offset)); 486 if (ret == 0) continue; 487 if (ret < 0) 488 { 489 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) continue; 490 rfbClientLog("Error writing to TLS: %s.\n", gnutls_strerror(ret)); 491 return -1; 492 } 493 offset += (unsigned int)ret; 494 } 495 return offset; 496 } 497 498 void FreeTLS(rfbClient* client) 499 { 500 if (client->tlsSession) 501 { 502 gnutls_deinit((gnutls_session_t)client->tlsSession); 503 client->tlsSession = NULL; 504 } 505 } 506