2 * Copyright (C) 2012 Philip Van Hoof <philip@codeminded.be>
3 * Copyright (C) 2009 Vic Lee.
5 * This is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21 #include <rfb/rfbclient.h>
24 #include <openssl/err.h>
25 #include <openssl/ssl.h>
26 #include <openssl/x509.h>
27 #include <openssl/rand.h>
28 #include <openssl/x509.h>
34 static rfbBool rfbTLSInitialized
= FALSE
;
35 static pthread_mutex_t
*mutex_buf
= NULL
;
37 struct CRYPTO_dynlock_value
{
38 pthread_mutex_t mutex
;
41 static void locking_function(int mode
, int n
, const char *file
, int line
)
43 if (mode
& CRYPTO_LOCK
)
44 pthread_mutex_lock(&mutex_buf
[n
]);
46 pthread_mutex_unlock(&mutex_buf
[n
]);
49 static unsigned long id_function(void)
51 return ((unsigned long) pthread_self());
54 static struct CRYPTO_dynlock_value
*dyn_create_function(const char *file
, int line
)
56 struct CRYPTO_dynlock_value
*value
;
58 value
= (struct CRYPTO_dynlock_value
*)
59 malloc(sizeof(struct CRYPTO_dynlock_value
));
62 pthread_mutex_init(&value
->mutex
, NULL
);
70 static void dyn_lock_function (int mode
, struct CRYPTO_dynlock_value
*l
, const char *file
, int line
)
72 if (mode
& CRYPTO_LOCK
)
73 pthread_mutex_lock(&l
->mutex
);
75 pthread_mutex_unlock(&l
->mutex
);
80 dyn_destroy_function(struct CRYPTO_dynlock_value
*l
, const char *file
, int line
)
82 pthread_mutex_destroy(&l
->mutex
);
88 ssl_errno (SSL
*ssl
, int ret
)
90 switch (SSL_get_error (ssl
, ret
)) {
93 case SSL_ERROR_ZERO_RETURN
:
94 /* this one does not map well at all */
95 //d(printf ("ssl_errno: SSL_ERROR_ZERO_RETURN\n"));
97 case SSL_ERROR_WANT_READ
: /* non-fatal; retry */
98 case SSL_ERROR_WANT_WRITE
: /* non-fatal; retry */
99 //d(printf ("ssl_errno: SSL_ERROR_WANT_[READ,WRITE]\n"));
101 case SSL_ERROR_SYSCALL
:
102 //d(printf ("ssl_errno: SSL_ERROR_SYSCALL\n"));
105 //d(printf ("ssl_errno: SSL_ERROR_SSL <-- very useful error...riiiiight\n"));
108 //d(printf ("ssl_errno: default error\n"));
118 if (rfbTLSInitialized
) return TRUE
;
120 mutex_buf
= malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t
));
121 if (mutex_buf
== NULL
) {
122 rfbClientLog("Failed to initialized OpenSSL: memory.\n");
126 for (i
= 0; i
< CRYPTO_num_locks(); i
++)
127 pthread_mutex_init(&mutex_buf
[i
], NULL
);
129 CRYPTO_set_locking_callback(locking_function
);
130 CRYPTO_set_id_callback(id_function
);
131 CRYPTO_set_dynlock_create_callback(dyn_create_function
);
132 CRYPTO_set_dynlock_lock_callback(dyn_lock_function
);
133 CRYPTO_set_dynlock_destroy_callback(dyn_destroy_function
);
134 SSL_load_error_strings();
135 SSLeay_add_ssl_algorithms();
136 RAND_load_file("/dev/urandom", 1024);
138 rfbClientLog("OpenSSL initialized.\n");
139 rfbTLSInitialized
= TRUE
;
144 ssl_verify (int ok
, X509_STORE_CTX
*ctx
)
146 unsigned char md5sum
[16], fingerprint
[40], *f
;
148 char *prompt
, *cert_str
;
158 ssl
= X509_STORE_CTX_get_ex_data (ctx
, SSL_get_ex_data_X509_STORE_CTX_idx ());
160 client
= SSL_CTX_get_app_data (ssl
->ctx
);
162 cert
= X509_STORE_CTX_get_current_cert (ctx
);
163 err
= X509_STORE_CTX_get_error (ctx
);
165 /* calculate the MD5 hash of the raw certificate */
166 md5len
= sizeof (md5sum
);
167 X509_digest (cert
, EVP_md5 (), md5sum
, &md5len
);
168 for (i
= 0, f
= fingerprint
; i
< 16; i
++, f
+= 3)
169 sprintf ((char *) f
, "%.2x%c", md5sum
[i
], i
!= 15 ? ':' : '\0');
171 #define GET_STRING(name) X509_NAME_oneline (name, buf, 256)
173 /* TODO: Don't just ignore certificate checks
175 fingerprint = key to check in db
177 GET_STRING (X509_get_issuer_name (cert));
178 GET_STRING (X509_get_subject_name (cert));
179 cert->valid (bool: GOOD or BAD) */
186 static int sock_read_ready(SSL
*ssl
, uint32_t ms
)
194 FD_SET(SSL_get_fd(ssl
), &fds
);
196 tv
.tv_sec
= ms
/ 1000;
197 tv
.tv_usec
= (ms
% 1000) * 1000;
199 r
= select (SSL_get_fd(ssl
) + 1, &fds
, NULL
, NULL
, &tv
);
204 static int wait_for_data(SSL
*ssl
, int ret
, int timeout
)
211 err
= SSL_get_error(ssl
, ret
);
215 case SSL_ERROR_WANT_READ
:
216 case SSL_ERROR_WANT_WRITE
:
217 ret
= sock_read_ready(ssl
, timeout
*1000);
235 open_ssl_connection (rfbClient
*client
, int sockfd
, rfbBool anonTLS
)
237 SSL_CTX
*ssl_ctx
= NULL
;
242 ssl_ctx
= SSL_CTX_new (SSLv23_client_method ());
243 SSL_CTX_set_default_verify_paths (ssl_ctx
);
244 SSL_CTX_set_verify (ssl_ctx
, SSL_VERIFY_NONE
, &ssl_verify
);
245 ssl
= SSL_new (ssl_ctx
);
247 /* TODO: finetune this list, take into account anonTLS bool */
248 SSL_set_cipher_list(ssl
, "ALL");
250 SSL_set_fd (ssl
, sockfd
);
251 SSL_CTX_set_app_data (ssl_ctx
, client
);
255 n
= SSL_connect(ssl
);
259 if (wait_for_data(ssl
, n
, 1) != 1)
263 SSL_CTX_free (ssl
->ctx
);
270 } while( n
!= 1 && finished
!= 1 );
277 InitializeTLSSession(rfbClient
* client
, rfbBool anonTLS
)
281 if (client
->tlsSession
) return TRUE
;
283 client
->tlsSession
= open_ssl_connection (client
, client
->sock
, anonTLS
);
285 if (!client
->tlsSession
)
288 rfbClientLog("TLS session initialized.\n");
294 SetTLSAnonCredential(rfbClient
* client
)
296 rfbClientLog("TLS anonymous credential created.\n");
301 HandshakeTLS(rfbClient
* client
)
308 while (timeout
> 0 && (ret
= SSL_do_handshake(client
->tlsSession
)) < 0)
312 rfbClientLog("TLS handshake blocking.\n");
317 rfbClientLog("TLS handshake failed: -.\n");
324 rfbClientLog("TLS handshake timeout.\n");
329 rfbClientLog("TLS handshake done.\n");
333 /* VeNCrypt sub auth. 1 byte auth count, followed by count * 4 byte integers */
335 ReadVeNCryptSecurityType(rfbClient
* client
, uint32_t *result
)
340 uint32_t tAuth
[256], t
;
341 char buf1
[500],buf2
[10];
344 if (!ReadFromRFBServer(client
, (char *)&count
, 1)) return FALSE
;
348 rfbClientLog("List of security types is ZERO. Giving up.\n");
352 if (count
>sizeof(tAuth
))
354 rfbClientLog("%d security types are too many; maximum is %d\n", count
, sizeof(tAuth
));
358 rfbClientLog("We have %d security types to read\n", count
);
360 /* now, we have a list of available security types to read ( uint8_t[] ) */
361 for (loop
=0;loop
<count
;loop
++)
363 if (!ReadFromRFBServer(client
, (char *)&tAuth
[loop
], 4)) return FALSE
;
364 t
=rfbClientSwap32IfLE(tAuth
[loop
]);
365 rfbClientLog("%d) Received security type %d\n", loop
, t
);
367 if (t
==rfbVeNCryptTLSNone
||
368 t
==rfbVeNCryptTLSVNC
||
369 t
==rfbVeNCryptTLSPlain
||
370 t
==rfbVeNCryptX509None
||
371 t
==rfbVeNCryptX509VNC
||
372 t
==rfbVeNCryptX509Plain
)
376 rfbClientLog("Selecting security type %d (%d/%d in the list)\n", authScheme
, loop
, count
);
377 /* send back 4 bytes (in original byte order!) indicating which security type to use */
378 if (!WriteToRFBServer(client
, (char *)&tAuth
[loop
], 4)) return FALSE
;
384 memset(buf1
, 0, sizeof(buf1
));
385 for (loop
=0;loop
<count
;loop
++)
387 if (strlen(buf1
)>=sizeof(buf1
)-1) break;
388 snprintf(buf2
, sizeof(buf2
), (loop
>0 ? ", %d" : "%d"), (int)tAuth
[loop
]);
389 strncat(buf1
, buf2
, sizeof(buf1
)-strlen(buf1
)-1);
391 rfbClientLog("Unknown VeNCrypt authentication scheme from VNC server: %s\n",
395 *result
= authScheme
;
400 HandleAnonTLSAuth(rfbClient
* client
)
402 if (!InitializeTLS() || !InitializeTLSSession(client
, TRUE
)) return FALSE
;
404 if (!SetTLSAnonCredential(client
)) return FALSE
;
406 if (!HandshakeTLS(client
)) return FALSE
;
412 HandleVeNCryptAuth(rfbClient
* client
)
414 uint8_t major
, minor
, status
;
417 // gnutls_certificate_credentials_t x509_cred = NULL;
420 if (!InitializeTLS()) return FALSE
;
422 /* Read VeNCrypt version */
423 if (!ReadFromRFBServer(client
, (char *)&major
, 1) ||
424 !ReadFromRFBServer(client
, (char *)&minor
, 1))
428 rfbClientLog("Got VeNCrypt version %d.%d from server.\n", (int)major
, (int)minor
);
430 if (major
!= 0 && minor
!= 2)
432 rfbClientLog("Unsupported VeNCrypt version.\n");
436 if (!WriteToRFBServer(client
, (char *)&major
, 1) ||
437 !WriteToRFBServer(client
, (char *)&minor
, 1) ||
438 !ReadFromRFBServer(client
, (char *)&status
, 1))
445 rfbClientLog("Server refused VeNCrypt version %d.%d.\n", (int)major
, (int)minor
);
449 if (!ReadVeNCryptSecurityType(client
, &authScheme
)) return FALSE
;
450 if (!ReadFromRFBServer(client
, (char *)&status
, 1) || status
!= 1)
452 rfbClientLog("Server refused VeNCrypt authentication %d (%d).\n", authScheme
, (int)status
);
455 client
->subAuthScheme
= authScheme
;
457 /* Some VeNCrypt security types are anonymous TLS, others are X509 */
460 case rfbVeNCryptTLSNone
:
461 case rfbVeNCryptTLSVNC
:
462 case rfbVeNCryptTLSPlain
:
470 /* Get X509 Credentials if it's not anonymous */
475 if (!client
->GetCredential
)
477 rfbClientLog("GetCredential callback is not set.\n");
480 cred
= client
->GetCredential(client
, rfbCredentialTypeX509
);
483 rfbClientLog("Reading credential failed\n");
487 /* TODO: don't just ignore this
488 x509_cred = CreateX509CertCredential(cred);
489 FreeX509Credential(cred);
490 if (!x509_cred) return FALSE; */
493 /* Start up the TLS session */
494 if (!InitializeTLSSession(client
, anonTLS
)) return FALSE
;
498 if (!SetTLSAnonCredential(client
)) return FALSE
;
502 /* TODO: don't just ignore this
503 if ((ret = gnutls_credentials_set(client->tlsSession, GNUTLS_CRD_CERTIFICATE, x509_cred)) < 0)
505 rfbClientLog("Cannot set x509 credential: %s.\n", gnutls_strerror(ret));
511 if (!HandshakeTLS(client
)) return FALSE
;
513 /* TODO: validate certificate */
515 /* We are done here. The caller should continue with client->subAuthScheme
516 * to do actual sub authentication.
522 ReadFromTLS(rfbClient
* client
, char *out
, unsigned int n
)
526 ret
= SSL_read (client
->tlsSession
, out
, n
);
531 errno
= ssl_errno (client
->tlsSession
, ret
);
533 if (errno
!= EAGAIN
) {
534 rfbClientLog("Error reading from TLS: -.\n");
542 WriteToTLS(rfbClient
* client
, char *buf
, unsigned int n
)
544 unsigned int offset
= 0;
550 ret
= SSL_write (client
->tlsSession
, buf
+ offset
, (size_t)(n
-offset
));
553 errno
= ssl_errno (client
->tlsSession
, ret
);
555 if (ret
== 0) continue;
558 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) continue;
559 rfbClientLog("Error writing to TLS: -\n");
562 offset
+= (unsigned int)ret
;
567 void FreeTLS(rfbClient
* client
)
571 if (mutex_buf
!= NULL
) {
572 CRYPTO_set_dynlock_create_callback(NULL
);
573 CRYPTO_set_dynlock_lock_callback(NULL
);
574 CRYPTO_set_dynlock_destroy_callback(NULL
);
576 CRYPTO_set_locking_callback(NULL
);
577 CRYPTO_set_id_callback(NULL
);
579 for (i
= 0; i
< CRYPTO_num_locks(); i
++)
580 pthread_mutex_destroy(&mutex_buf
[i
]);
585 SSL_free(client
->tlsSession
);