summaryrefslogtreecommitdiffstats
path: root/x11vnc/sslhelper.c
diff options
context:
space:
mode:
authorrunge <runge>2008-11-22 18:36:33 +0000
committerrunge <runge>2008-11-22 18:36:33 +0000
commit6fbba525a924961083bf2e43bb841bd15671f526 (patch)
tree3ec0cf4b285fb0140294a151b801c91bc78a612e /x11vnc/sslhelper.c
parent63b98dba790fa9835e970b8502d93258862a9373 (diff)
downloadlibtdevnc-6fbba525a924961083bf2e43bb841bd15671f526.tar.gz
libtdevnc-6fbba525a924961083bf2e43bb841bd15671f526.zip
x11vnc: x11vnc.desktop file. -reopen, -dhparams, -sslCRL,
-setdefer options. -rfbport PROMPT VeNCrypt and TLSVNC SSL/TLS encryption support. Tweaks to choose_delay() algorithm. -ssl ANON anonymouse Diffie-Hellman mode. Fix bugs in certs management. Additions to tray=setpass naive user mode.
Diffstat (limited to 'x11vnc/sslhelper.c')
-rw-r--r--x11vnc/sslhelper.c1104
1 files changed, 1064 insertions, 40 deletions
diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c
index 7aad2c4..13e60a3 100644
--- a/x11vnc/sslhelper.c
+++ b/x11vnc/sslhelper.c
@@ -7,6 +7,7 @@
#include "scan.h"
#include "connections.h"
#include "sslcmds.h"
+#include "unixpw.h"
#define OPENSSL_INETD 1
#define OPENSSL_VNC 2
@@ -21,13 +22,6 @@
#endif
#endif
-#ifdef NO_SSL_OR_UNIXPW
-#undef FORK_OK
-#undef LIBVNCSERVER_HAVE_LIBSSL
-#define LIBVNCSERVER_HAVE_LIBSSL 0
-#endif
-
-
int openssl_sock = -1;
int openssl_port_num = 0;
int https_sock = -1;
@@ -39,6 +33,11 @@ static int certret_fd = -1;
static mode_t omode;
char *certret_str = NULL;
+static char *dhret = NULL;
+static int dhret_fd = -1;
+char *dhret_str = NULL;
+char *new_dh_params = NULL;
+
void raw_xfer(int csock, int s_in, int s_out);
#if !LIBVNCSERVER_HAVE_LIBSSL
@@ -85,6 +84,7 @@ static SSL_CTX *ctx = NULL;
static RSA *rsa_512 = NULL;
static RSA *rsa_1024 = NULL;
static SSL *ssl = NULL;
+static X509_STORE *revocation_store = NULL;
static void init_prng(void);
@@ -128,6 +128,9 @@ char *get_saved_pem(char *save, int create) {
if (strstr(save, "SAVE_PROMPT") == save) {
prompt = 1;
s = save + strlen("SAVE_PROMPT");
+ } else if (strstr(save, "SAVE_NOPROMPT") == save) {
+ set_env("GENCERT_NOPROMPT", "1");
+ s = save + strlen("SAVE_NOPROMPT");
} else if (strstr(save, "SAVE") == save) {
s = save + strlen("SAVE");
} else {
@@ -318,7 +321,7 @@ static char *create_tmp_pem(char *pathin, int prompt) {
}
rfbLog("\n");
- rfbLog("This will NOT prevent man-in-the-middle attacks UNLESS you\n");
+ rfbLog("This will NOT prevent Man-In-The-Middle attacks UNLESS you\n");
rfbLog("get the certificate information to the VNC viewers SSL\n");
rfbLog("tunnel configuration or you take the extra steps to sign it\n");
rfbLog("with a CA key. However, it will prevent passive network\n");
@@ -486,6 +489,9 @@ static char *create_tmp_pem(char *pathin, int prompt) {
fprintf(out, "%s", line);
if (on) {
fprintf(crt, "%s", line);
+ if (!quiet) {
+ fprintf(stderr, "%s", line);
+ }
}
if (strstr(line, "END CERTIFICATE")) {
on = 0;
@@ -585,7 +591,7 @@ static char *get_ssl_verify_file(char *str_in) {
char *tfile, *tfile2;
FILE *file;
struct stat sbuf;
- int count = 0;
+ int count = 0, fd;
if (! str_in) {
rfbLog("get_ssl_verify_file: no filename\n");
@@ -606,7 +612,15 @@ static char *get_ssl_verify_file(char *str_in) {
tfile = (char *) malloc(strlen(tmp) + 1024);
tfile2 = (char *) malloc(strlen(tmp) + 1024);
- sprintf(tfile, "%s/sslverify-load-%d.crts", tmp, getpid());
+ sprintf(tfile, "%s/sslverify-load-%d.crts.XXXXXX", tmp, getpid());
+
+ fd = mkstemp(tfile);
+ if (fd < 0) {
+ rfbLog("get_ssl_verify_file: %s\n", tfile);
+ rfbLogPerror("mkstemp");
+ exit(1);
+ }
+ close(fd);
file = fopen(tfile, "w");
chmod(tfile, 0600);
@@ -626,7 +640,7 @@ static char *get_ssl_verify_file(char *str_in) {
unlink(tfile);
exit(1);
}
- fprintf(stderr, "sslverify: loaded %s\n", tfile2);
+ rfbLog("sslverify: loaded %s\n", tfile2);
count++;
} else if (!strcmp(p, "clients")) {
@@ -657,7 +671,7 @@ static char *get_ssl_verify_file(char *str_in) {
unlink(tfile);
exit(1);
}
- fprintf(stderr, "sslverify: loaded %s\n",
+ rfbLog("sslverify: loaded %s\n",
tfile2);
count++;
}
@@ -676,7 +690,7 @@ static char *get_ssl_verify_file(char *str_in) {
unlink(tfile);
exit(1);
}
- fprintf(stderr, "sslverify: loaded %s\n", tfile2);
+ rfbLog("sslverify: loaded %s\n", tfile2);
count++;
}
p = strtok(NULL, ",");
@@ -685,14 +699,167 @@ static char *get_ssl_verify_file(char *str_in) {
free(tfile2);
free(str);
- fprintf(stderr, "sslverify: using %d client certs in %s\n", count,
- tfile);
+ rfbLog("sslverify: using %d client certs in\n", count);
+ rfbLog("sslverify: %s\n", tfile);
return tfile;
}
+/* based on mod_ssl */
+static int crl_callback(X509_STORE_CTX *callback_ctx) {
+ X509_STORE_CTX store_ctx;
+ X509_OBJECT obj;
+ X509_NAME *subject;
+ X509_NAME *issuer;
+ X509 *xs;
+ X509_CRL *crl;
+ X509_REVOKED *revoked;
+ EVP_PKEY *pubkey;
+ long serial;
+ BIO *bio;
+ int i, n, rc;
+ char *cp, *cp2;
+ ASN1_TIME *t;
+
+ /* Determine certificate ingredients in advance */
+ xs = X509_STORE_CTX_get_current_cert(callback_ctx);
+ subject = X509_get_subject_name(xs);
+ issuer = X509_get_issuer_name(xs);
+
+ /* Try to retrieve a CRL corresponding to the _subject_ of
+ * the current certificate in order to verify it's integrity. */
+ memset((char *)&obj, 0, sizeof(obj));
+ X509_STORE_CTX_init(&store_ctx, revocation_store, NULL, NULL);
+ rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, subject, &obj);
+ X509_STORE_CTX_cleanup(&store_ctx);
+ crl=obj.data.crl;
+
+ if(rc>0 && crl) {
+ /* Log information about CRL
+ * (A little bit complicated because of ASN.1 and BIOs...) */
+ bio=BIO_new(BIO_s_mem());
+ BIO_printf(bio, "lastUpdate: ");
+ ASN1_UTCTIME_print(bio, X509_CRL_get_lastUpdate(crl));
+ BIO_printf(bio, ", nextUpdate: ");
+ ASN1_UTCTIME_print(bio, X509_CRL_get_nextUpdate(crl));
+ n=BIO_pending(bio);
+ cp=malloc(n+1);
+ n=BIO_read(bio, cp, n);
+ cp[n]='\0';
+ BIO_free(bio);
+ cp2=X509_NAME_oneline(subject, NULL, 0);
+ rfbLog("CA CRL: Issuer: %s, %s\n", cp2, cp);
+ OPENSSL_free(cp2);
+ free(cp);
+
+ /* Verify the signature on this CRL */
+ pubkey=X509_get_pubkey(xs);
+ if(X509_CRL_verify(crl, pubkey)<=0) {
+ rfbLog("Invalid signature on CRL\n");
+ X509_STORE_CTX_set_error(callback_ctx,
+ X509_V_ERR_CRL_SIGNATURE_FAILURE);
+ X509_OBJECT_free_contents(&obj);
+ if(pubkey)
+ EVP_PKEY_free(pubkey);
+ return 0; /* Reject connection */
+ }
+ if(pubkey)
+ EVP_PKEY_free(pubkey);
+
+ /* Check date of CRL to make sure it's not expired */
+ t=X509_CRL_get_nextUpdate(crl);
+ if(!t) {
+ rfbLog("Found CRL has invalid nextUpdate field\n");
+ X509_STORE_CTX_set_error(callback_ctx,
+ X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+ X509_OBJECT_free_contents(&obj);
+ return 0; /* Reject connection */
+ }
+ if(X509_cmp_current_time(t)<0) {
+ rfbLog("Found CRL is expired - "
+ "revoking all certificates until you get updated CRL\n");
+ X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+ X509_OBJECT_free_contents(&obj);
+ return 0; /* Reject connection */
+ }
+ X509_OBJECT_free_contents(&obj);
+ }
+
+ /* Try to retrieve a CRL corresponding to the _issuer_ of
+ * the current certificate in order to check for revocation. */
+ memset((char *)&obj, 0, sizeof(obj));
+ X509_STORE_CTX_init(&store_ctx, revocation_store, NULL, NULL);
+ rc=X509_STORE_get_by_subject(&store_ctx, X509_LU_CRL, issuer, &obj);
+ X509_STORE_CTX_cleanup(&store_ctx);
+ crl=obj.data.crl;
+
+ if(rc>0 && crl) {
+ /* Check if the current certificate is revoked by this CRL */
+ n=sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+ for(i=0; i<n; i++) {
+ revoked=sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+ if(ASN1_INTEGER_cmp(revoked->serialNumber,
+ X509_get_serialNumber(xs)) == 0) {
+ serial=ASN1_INTEGER_get(revoked->serialNumber);
+ cp=X509_NAME_oneline(issuer, NULL, 0);
+ rfbLog("Certificate with serial %ld (0x%lX) "
+ "revoked per CRL from issuer %s\n", serial, serial, cp);
+ OPENSSL_free(cp);
+ X509_STORE_CTX_set_error(callback_ctx, X509_V_ERR_CERT_REVOKED);
+ X509_OBJECT_free_contents(&obj);
+ return 0; /* Reject connection */
+ }
+ }
+ X509_OBJECT_free_contents(&obj);
+ }
+
+ return 1; /* Accept connection */
+}
+
+static int verify_callback(int ok, X509_STORE_CTX *callback_ctx) {
+ if (!ssl_verify) {
+ rfbLog("CRL_check: skipped.\n");
+ return ok;
+ }
+ if (!ssl_crl) {
+ rfbLog("CRL_check: skipped.\n");
+ return ok;
+ }
+ if (!ok) {
+ rfbLog("CRL_check: client cert is already rejected.\n");
+ return ok;
+ }
+ if (revocation_store) {
+ if (crl_callback(callback_ctx)) {
+ rfbLog("CRL_check: succeeded.\n");
+ return 1;
+ } else {
+ rfbLog("CRL_check: did not pass.\n");
+ return 0;
+ }
+ }
+ /* NOTREACHED */
+ return 1;
+}
+
+#define rfbSecTypeTlsVnc 18
+#define rfbSecTypeVencrypt 19
+
+#define rfbVencryptPlain 256
+#define rfbVencryptTlsNone 257
+#define rfbVencryptTlsVnc 258
+#define rfbVencryptTlsPlain 259
+#define rfbVencryptX509None 260
+#define rfbVencryptX509Vnc 261
+#define rfbVencryptX509Plain 262
+
+static int vencrypt_selected = 0;
+static int tlsvnc_selected = 0;
+
static int ssl_client_mode = 0;
+static int switch_to_anon_dh(void);
+
void openssl_init(int isclient) {
int db = 0, tmp_pem = 0, do_dh;
FILE *in;
@@ -792,11 +959,27 @@ void openssl_init(int isclient) {
}
tmp_pem = 1;
+ } else if (!strcmp(openssl_pem, "ANON")) {
+ if (ssl_verify) {
+ rfbLog("openssl_init: Anonymous Diffie-Hellman cannot"
+ " be used in -sslverify mode.\n");
+ clean_up_exit(1);
+ }
+ if (ssl_crl) {
+ rfbLog("openssl_init: Anonymous Diffie-Hellman cannot"
+ " be used in -sslCRL mode.\n");
+ clean_up_exit(1);
+ }
+ if (!switch_to_anon_dh()) {
+ rfbLog("openssl_init: Anonymous Diffie-Hellman setup"
+ " failed.\n");
+ clean_up_exit(1);
+ }
} else if (strstr(openssl_pem, "SAVE") == openssl_pem) {
openssl_pem = get_saved_pem(openssl_pem, 1);
if (! openssl_pem) {
rfbLog("openssl_init: could not create or open"
- " saved PEM:\n", openssl_pem);
+ " saved PEM: %s\n", openssl_pem);
clean_up_exit(1);
}
tmp_pem = 0;
@@ -834,18 +1017,20 @@ void openssl_init(int isclient) {
DH_free(dh);
}
- if (! SSL_CTX_use_certificate_chain_file(ctx, openssl_pem)) {
- rfbLog("openssl_init: SSL_CTX_use_certificate_chain_file() failed.\n");
- sslerrexit();
- }
- if (! SSL_CTX_use_RSAPrivateKey_file(ctx, openssl_pem,
- SSL_FILETYPE_PEM)) {
- rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");
- sslerrexit();
- }
- if (! SSL_CTX_check_private_key(ctx)) {
- rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");
- sslerrexit();
+ if (strcmp(openssl_pem, "ANON")) {
+ if (! SSL_CTX_use_certificate_chain_file(ctx, openssl_pem)) {
+ rfbLog("openssl_init: SSL_CTX_use_certificate_chain_file() failed.\n");
+ sslerrexit();
+ }
+ if (! SSL_CTX_use_RSAPrivateKey_file(ctx, openssl_pem,
+ SSL_FILETYPE_PEM)) {
+ rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");
+ sslerrexit();
+ }
+ if (! SSL_CTX_check_private_key(ctx)) {
+ rfbLog("openssl_init: SSL_CTX_set_tmp_rsa(1024) failed.\n");
+ sslerrexit();
+ }
}
if (tmp_pem && ! getenv("X11VNC_KEEP_TMP_PEM")) {
@@ -866,6 +1051,46 @@ void openssl_init(int isclient) {
openssl_pem = NULL;
}
+ if (ssl_crl) {
+ struct stat sbuf;
+ X509_LOOKUP *lookup;
+
+ if (stat(ssl_crl, &sbuf) != 0) {
+ rfbLog("openssl_init: -sslCRL does not exist %s.\n",
+ ssl_crl ? ssl_crl : "null");
+ rfbLogPerror("stat");
+ clean_up_exit(1);
+ }
+
+ revocation_store = X509_STORE_new();
+ if (!revocation_store) {
+ rfbLog("openssl_init: X509_STORE_new failed.\n");
+ sslerrexit();
+ }
+ if (! S_ISDIR(sbuf.st_mode)) {
+ lookup = X509_STORE_add_lookup(revocation_store, X509_LOOKUP_file());
+ if (!lookup) {
+ rfbLog("openssl_init: X509_STORE_add_lookup failed.\n");
+ sslerrexit();
+ }
+ if (!X509_LOOKUP_load_file(lookup, ssl_crl, X509_FILETYPE_PEM)) {
+ rfbLog("openssl_init: X509_LOOKUP_load_file failed.\n");
+ sslerrexit();
+ }
+ } else {
+ lookup = X509_STORE_add_lookup(revocation_store, X509_LOOKUP_hash_dir());
+ if (!lookup) {
+ rfbLog("openssl_init: X509_STORE_add_lookup failed.\n");
+ sslerrexit();
+ }
+ if (!X509_LOOKUP_add_dir(lookup, ssl_crl, X509_FILETYPE_PEM)) {
+ rfbLog("openssl_init: X509_LOOKUP_add_dir failed.\n");
+ sslerrexit();
+ }
+ }
+ rfbLog("loaded CRL file: %s\n", ssl_crl);
+ }
+
if (ssl_verify) {
struct stat sbuf;
char *file;
@@ -874,7 +1099,7 @@ void openssl_init(int isclient) {
file = get_ssl_verify_file(ssl_verify);
if (!file || stat(file, &sbuf) != 0) {
- rfbLog("openssl_init: -sslverify does not exists %s.\n",
+ rfbLog("openssl_init: -sslverify does not exist %s.\n",
file ? file : "null");
rfbLogPerror("stat");
clean_up_exit(1);
@@ -894,7 +1119,11 @@ void openssl_init(int isclient) {
}
lvl = SSL_VERIFY_FAIL_IF_NO_PEER_CERT|SSL_VERIFY_PEER;
- SSL_CTX_set_verify(ctx, lvl, NULL);
+ if (ssl_crl == NULL) {
+ SSL_CTX_set_verify(ctx, lvl, NULL);
+ } else {
+ SSL_CTX_set_verify(ctx, lvl, verify_callback);
+ }
if (strstr(file, "tmp/sslverify-load-")) {
/* temporary file */
unlink(file);
@@ -1371,6 +1600,106 @@ static int check_ssl_access(char *addr) {
return check_access(addr);
}
+static int write_exact(int sock, char *buf, int len);
+static int read_exact(int sock, char *buf, int len);
+
+static int finish_auth(rfbClientPtr client, char *type) {
+ int security_result, ret;
+
+ ret = 0;
+
+if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "finish_auth type=%s\n", type);
+
+ if (!strcmp(type, "None")) {
+ security_result = 0; /* success */
+ if (write_exact(client->sock, (char *) &security_result, 4)) {
+ ret = 1;
+ }
+ rfbLog("finish_auth: using auth 'None'\n");
+ client->state = RFB_INITIALISATION;
+
+ } else if (!strcmp(type, "Vnc")) {
+ RAND_bytes(client->authChallenge, CHALLENGESIZE);
+ if (write_exact(client->sock, (char *) &client->authChallenge, CHALLENGESIZE)) {
+ ret = 1;
+ }
+ rfbLog("finish_auth: using auth 'Vnc', sent challenge.\n");
+ client->state = RFB_AUTHENTICATION;
+
+ } else if (!strcmp(type, "Plain")) {
+ if (!unixpw) {
+ rfbLog("finish_auth: *Plain not allowed outside unixpw mode.\n");
+ ret = 0;
+ } else {
+ char *un, *pw;
+ int unlen, pwlen;
+
+if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "*Plain begin: onHold=%d client=%p unixpw_client=%p\n", client->onHold, (void *) client, (void *) unixpw_client);
+
+ if (!read_exact(client->sock, (char *)&unlen, 4)) goto fail;
+ unlen = Swap32IfLE(unlen);
+
+if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "unlen: %d\n", unlen);
+
+ if (!read_exact(client->sock, (char *)&pwlen, 4)) goto fail;
+ pwlen = Swap32IfLE(pwlen);
+
+if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "pwlen: %d\n", pwlen);
+
+ un = (char *) malloc(unlen+1);
+ memset(un, 0, unlen+1);
+
+ pw = (char *) malloc(pwlen+2);
+ memset(pw, 0, pwlen+2);
+
+ if (!read_exact(client->sock, un, unlen)) goto fail;
+ if (!read_exact(client->sock, pw, pwlen)) goto fail;
+
+if (getenv("X11VNC_DEBUG_TLSPLAIN")) fprintf(stderr, "*Plain: %d %d '%s' ... \n", unlen, pwlen, un);
+ strcat(pw, "\n");
+
+ if (unixpw_verify(un, pw)) {
+ security_result = 0; /* success */
+ if (write_exact(client->sock, (char *) &security_result, 4)) {
+ ret = 1;
+ unixpw_verify_screen(un, pw);
+ }
+ client->onHold = FALSE;
+ client->state = RFB_INITIALISATION;
+ }
+ if (ret == 0) {
+ rfbClientSendString(client, "unixpw failed");
+ }
+
+ memset(un, 0, unlen+1);
+ memset(pw, 0, pwlen+2);
+ free(un);
+ free(pw);
+ }
+ } else {
+ rfbLog("finish_auth: unknown sub-type: %s\n", type);
+ ret = 0;
+ }
+
+ fail:
+ return ret;
+}
+
+static int finish_vencrypt_auth(rfbClientPtr client, int subtype) {
+
+ if (subtype == rfbVencryptTlsNone || subtype == rfbVencryptX509None) {
+ return finish_auth(client, "None");
+ } else if (subtype == rfbVencryptTlsVnc || subtype == rfbVencryptX509Vnc) {
+ return finish_auth(client, "Vnc");
+ } else if (subtype == rfbVencryptTlsPlain || subtype == rfbVencryptX509Plain) {
+ return finish_auth(client, "Plain");
+ } else {
+ rfbLog("finish_vencrypt_auth: unknown sub-type: %d\n", subtype);
+ return 0;
+ }
+}
+
+
void accept_openssl(int mode, int presock) {
int sock = -1, listen = -1, cport, csock, vsock;
int peerport = 0;
@@ -1384,15 +1713,18 @@ void accept_openssl(int mode, int presock) {
rfbClientPtr client;
pid_t pid;
char uniq[] = "_evilrats_";
- char cookie[128], rcookie[128], *name = NULL;
+ char cookie[256], rcookie[256], *name = NULL;
+ int vencrypt_sel = 0;
+ int tlsvnc_sel = 0;
static time_t last_https = 0;
- static char last_get[128];
+ static char last_get[256];
static int first = 1;
+ unsigned char *rb;
openssl_last_helper_pid = 0;
/* zero buffers for use below. */
- for (i=0; i<128; i++) {
+ for (i=0; i<256; i++) {
if (first) {
last_get[i] = '\0';
}
@@ -1500,7 +1832,11 @@ void accept_openssl(int mode, int presock) {
* but hard to guess exactly (just worrying about local lusers
* here, since we use INADDR_LOOPBACK).
*/
- sprintf(cookie, "%f/%f", dnow(), x11vnc_start);
+ rb = (unsigned char *) malloc(6);
+ RAND_bytes((char *)rb, 6);
+ sprintf(cookie, "RB=%d%d%d%d%d%d/%f%f/0x%x",
+ rb[0], rb[1], rb[2], rb[3], rb[4], rb[5],
+ dnow() - x11vnc_start, x11vnc_start, rb);
if (mode != OPENSSL_INETD) {
name = get_remote_host(sock);
@@ -1543,6 +1879,23 @@ void accept_openssl(int mode, int presock) {
certret_fd = -1;
}
+ if (dhret) {
+ free(dhret);
+ }
+ if (dhret_str) {
+ free(dhret_str);
+ dhret_str = NULL;
+ }
+ dhret = strdup("/tmp/x11vnc-dhret.XXXXXX");
+ omode = umask(077);
+ dhret_fd = mkstemp(dhret);
+ umask(omode);
+ if (dhret_fd < 0) {
+ free(dhret);
+ dhret = NULL;
+ dhret_fd = -1;
+ }
+
/* now fork the child to handle the SSL: */
pid = fork();
@@ -1614,6 +1967,20 @@ void accept_openssl(int mode, int presock) {
exit(1);
}
+ if (vencrypt_selected != 0) {
+ char *tbuf;
+ tbuf = (char *) malloc(strlen(cookie) + 100);
+ sprintf(tbuf, "%s,VENCRYPT=%d,%s", uniq, vencrypt_selected, cookie);
+ write(vncsock, tbuf, strlen(cookie));
+ goto wrote_cookie;
+ } else if (tlsvnc_selected != 0) {
+ char *tbuf;
+ tbuf = (char *) malloc(strlen(cookie) + 100);
+ sprintf(tbuf, "%s,TLSVNC=%d,%s", uniq, tlsvnc_selected, cookie);
+ write(vncsock, tbuf, strlen(cookie));
+ goto wrote_cookie;
+ }
+
/*
* things get messy below since we are trying to do
* *both* VNC and Java applet httpd through the same
@@ -1907,6 +2274,13 @@ void accept_openssl(int mode, int presock) {
if (certret) {
unlink(certret);
}
+ if (dhret_fd >= 0) {
+ close(dhret_fd);
+ dhret_fd = -1;
+ }
+ if (dhret) {
+ unlink(dhret);
+ }
return;
}
if (db) fprintf(stderr, "accept_openssl: vsock: %d\n", vsock);
@@ -1920,7 +2294,7 @@ void accept_openssl(int mode, int presock) {
struct stat sbuf;
sbuf.st_size = 0;
if (certret_fd >= 0 && stat(certret, &sbuf) == 0 && sbuf.st_size > 0) {
- certret_str = (char *) malloc(sbuf.st_size+1);
+ certret_str = (char *) calloc(sbuf.st_size+1, 1);
read(certret_fd, certret_str, sbuf.st_size);
close(certret_fd);
certret_fd = -1;
@@ -1939,6 +2313,59 @@ void accept_openssl(int mode, int presock) {
}
}
+ if (dhret) {
+ struct stat sbuf;
+ sbuf.st_size = 0;
+ if (dhret_fd >= 0 && stat(dhret, &sbuf) == 0 && sbuf.st_size > 0) {
+ dhret_str = (char *) calloc(sbuf.st_size+1, 1);
+ read(dhret_fd, dhret_str, sbuf.st_size);
+ close(dhret_fd);
+ dhret_fd = -1;
+ }
+ if (dhret_fd >= 0) {
+ close(dhret_fd);
+ dhret_fd = -1;
+ }
+ unlink(dhret);
+ if (dhret_str && strstr(dhret_str, "NOCERT") == dhret_str) {
+ free(dhret_str);
+ dhret_str = NULL;
+ }
+ if (dhret_str) {
+ if (new_dh_params == NULL) {
+ fprintf(stderr, "dhret_str[%d]:\n%s\n", (int) sbuf.st_size, dhret_str);
+ new_dh_params = strdup(dhret_str);
+ }
+ }
+ }
+
+ if (0) {
+ fprintf(stderr, "rcookie: %s\n", rcookie);
+ fprintf(stderr, "cookie: %s\n", cookie);
+ }
+
+ if (strstr(rcookie, uniq) == rcookie) {
+ char *q = strstr(rcookie, "RB=");
+ if (q && strstr(cookie, q) == cookie) {
+ vencrypt_sel = 0;
+ tlsvnc_sel = 0;
+ q = strstr(rcookie, "VENCRYPT=");
+ if (q && sscanf(q, "VENCRYPT=%d,", &vencrypt_sel) == 1) {
+ if (vencrypt_sel != 0) {
+ rfbLog("SSL: VENCRYPT mode=%d accepted.\n", vencrypt_sel);
+ goto accept_client;
+ }
+ }
+ q = strstr(rcookie, "TLSVNC=");
+ if (q && sscanf(q, "TLSVNC=%d,", &tlsvnc_sel) == 1) {
+ if (tlsvnc_sel != 0) {
+ rfbLog("SSL: TLSVNC mode=%d accepted.\n", tlsvnc_sel);
+ goto accept_client;
+ }
+ }
+ }
+ }
+
if (n != (int) strlen(cookie) || strncmp(cookie, rcookie, n)) {
rfbLog("SSL: accept_openssl: cookie from ssl_helper FAILED. %d\n", n);
if (db) fprintf(stderr, "'%s'\n'%s'\n", cookie, rcookie);
@@ -1949,7 +2376,7 @@ void accept_openssl(int mode, int presock) {
rfbLog("SSL: BUT WAIT! HTTPS for helper process succeeded. Good.\n");
if (mode != OPENSSL_HTTPS) {
last_https = time(NULL);
- for (i=0; i<128; i++) {
+ for (i=0; i<256; i++) {
last_get[i] = '\0';
}
strncpy(last_get, rcookie, 100);
@@ -2044,6 +2471,9 @@ void accept_openssl(int mode, int presock) {
}
return;
}
+
+ accept_client:
+
if (db) fprintf(stderr, "accept_openssl: cookie good: %s\n", cookie);
rfbLog("SSL: handshake with helper process succeeded.\n");
@@ -2072,6 +2502,17 @@ void accept_openssl(int mode, int presock) {
strpbrk(openssl_last_ip, "0123456789") == openssl_last_ip) {
client->host = strdup(openssl_last_ip);
}
+ if (vencrypt_sel != 0) {
+ client->protocolMajorVersion = 3;
+ client->protocolMinorVersion = 8;
+ if (!finish_vencrypt_auth(client, vencrypt_sel)) {
+ rfbCloseClient(client);
+ }
+ } else if (tlsvnc_sel != 0) {
+ client->protocolMajorVersion = 3;
+ client->protocolMinorVersion = 8;
+ rfbAuthNewClient(client);
+ }
} else {
rfbLog("SSL: accept_openssl: rfbNewClient failed.\n");
close(vsock);
@@ -2085,6 +2526,567 @@ void accept_openssl(int mode, int presock) {
}
}
+static int read_exact(int sock, char *buf, int len) {
+ int n, fail = 0;
+ if (sock < 0) {
+ return 0;
+ }
+ while (len > 0) {
+ n = read(sock, buf, len);
+ if (n > 0) {
+ buf += n;
+ len -= n;
+ } else if (n == 0) {
+ fail = 1;
+ break;
+ } else if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ usleep(10*1000);
+ } else if (n < 0 && errno != EINTR) {
+ fail = 1;
+ break;
+ }
+ }
+ if (fail) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int write_exact(int sock, char *buf, int len) {
+ int n, fail = 0;
+ if (sock < 0) {
+ return 0;
+ }
+ while (len > 0) {
+ n = write(sock, buf, len);
+ if (n > 0) {
+ buf += n;
+ len -= n;
+ } else if (n == 0) {
+ fail = 1;
+ break;
+ } else if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ usleep(10*1000);
+ } else if (n < 0 && errno != EINTR) {
+ fail = 1;
+ break;
+ }
+ }
+ if (fail) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int add_anon_dh(void) {
+ pid_t pid, pidw;
+ char cnf[] = "/tmp/x11vnc-dh.XXXXXX";
+ char *infile = NULL;
+ int status, cnf_fd;
+ DH *dh;
+ BIO *bio;
+ FILE *in;
+ double ds;
+ /*
+ * These are dh parameters (prime, generator), not dh keys.
+ * Evidently it is ok for them to be publicly known.
+ * openssl dhparam -out dh.out 1024
+ */
+ char *fixed_dh_params =
+"-----BEGIN DH PARAMETERS-----\n"
+"MIGHAoGBAL28w69ZnLYBvp8R2OeqtAIms+oatY19iBL4WhGI/7H1OMmkJjIe+OHs\n"
+"PXoJfe5ucrnvno7Xm+HJZYa1jnPGQuWoa/VJKXdVjYdJVNzazJKM2daKKcQA4GDc\n"
+"msFS5DxLbzUR5jy1n12K3EcbvpyFqDYVTJJXm7NuNuiWRfz3wTozAgEC\n"
+"-----END DH PARAMETERS-----\n";
+
+ if (dhparams_file != NULL) {
+ infile = dhparams_file;
+ rfbLog("add_anon_dh: using %s\n", dhparams_file);
+ goto readin;
+ }
+
+ cnf_fd = mkstemp(cnf);
+ if (cnf_fd < 0) {
+ return 0;
+ }
+ infile = cnf;
+
+ if (create_fresh_dhparams) {
+
+ if (new_dh_params != NULL) {
+ write(cnf_fd, new_dh_params, strlen(new_dh_params));
+ close(cnf_fd);
+ } else {
+ char *exe = find_openssl_bin();
+ struct stat sbuf;
+
+ if (no_external_cmds || !cmd_ok("ssl")) {
+ rfbLog("add_anon_dh: cannot run external commands.\n");
+ return 0;
+ }
+
+ close(cnf_fd);
+ if (exe == NULL) {
+ return 0;
+ }
+ ds = dnow();
+ pid = fork();
+ if (pid < 0) {
+ return 0;
+ } else if (pid == 0) {
+ int i;
+ for (i=0; i<256; i++) {
+ if (i == 2) continue;
+ close(i);
+ }
+ /* rather slow at 1024 */
+ execlp(exe, exe, "dhparam", "-out", cnf, "1024", (char *)0);
+ exit(1);
+ }
+ pidw = waitpid(pid, &status, 0);
+ if (pidw != pid) {
+ return 0;
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ ;
+ } else {
+ return 0;
+ }
+ rfbLog("add_anon_dh: created new DH params in %.3f secs\n", dnow() - ds);
+
+ if (stat(cnf, &sbuf) == 0 && sbuf.st_size > 0) {
+ /* save it to reuse during our process's lifetime: */
+ int d = open(cnf, O_RDONLY);
+ if (d >= 0) {
+ int n, len = sbuf.st_size;
+ new_dh_params = (char *) calloc(len+1, 1);
+ n = read(d, new_dh_params, len);
+ close(d);
+ if (n != len) {
+ free(new_dh_params);
+ new_dh_params = NULL;
+ } else if (dhret != NULL) {
+ d = open(dhret, O_WRONLY);
+ if (d >= 0) {
+ write(d, new_dh_params, strlen(new_dh_params));
+ close(d);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ write(cnf_fd, fixed_dh_params, strlen(fixed_dh_params));
+ close(cnf_fd);
+ }
+
+ readin:
+
+ ds = dnow();
+ in = fopen(infile, "r");
+
+ if (in == NULL) {
+ rfbLogPerror("fopen");
+ unlink(cnf);
+ return 0;
+ }
+ bio = BIO_new_fp(in, BIO_CLOSE|BIO_FP_TEXT);
+ if (! bio) {
+ rfbLog("openssl_init: BIO_new_fp() failed.\n");
+ unlink(cnf);
+ return 0;
+ }
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ if (dh == NULL) {
+ rfbLog("openssl_init: PEM_read_bio_DHparams() failed.\n");
+ unlink(cnf);
+ BIO_free(bio);
+ return 0;
+ }
+ BIO_free(bio);
+ SSL_CTX_set_tmp_dh(ctx, dh);
+ rfbLog("loaded Diffie Hellman %d bits, %.3fs\n", 8*DH_size(dh), dnow()-ds);
+ DH_free(dh);
+
+ unlink(cnf);
+ return 1;
+}
+
+static int switch_to_anon_dh(void) {
+ long mode;
+
+ rfbLog("Using Anonymous Diffie-Hellman mode.\n");
+ rfbLog("WARNING: Anonymous Diffie-Hellman uses encryption but is\n");
+ rfbLog("WARNING: susceptible to a Man-In-The-Middle attack.\n");
+ ctx = SSL_CTX_new( SSLv23_server_method() );
+ if (ctx == NULL) {
+ return 0;
+ }
+ if (!SSL_CTX_set_cipher_list(ctx, "ADH:@STRENGTH")) {
+ return 0;
+ }
+ if (!add_anon_dh()) {
+ return 0;
+ }
+
+ mode = 0;
+ mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
+ mode |= SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
+ SSL_CTX_set_mode(ctx, mode);
+
+ SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_BOTH);
+ SSL_CTX_set_timeout(ctx, 300);
+ SSL_CTX_set_default_passwd_cb(ctx, pem_passwd_callback);
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+
+ return 1;
+}
+
+static int tlsvnc_dialog(int s_in, int s_out) {
+
+ tlsvnc_selected = 1;
+
+ if (!switch_to_anon_dh()) {
+ rfbLog("tlsvnc: Anonymous Diffie-Hellman failed.\n");
+ return 0;
+ }
+
+ /* continue with SSL/TLS */
+ return 1;
+}
+
+/*
+ * Using spec:
+ * http://www.mail-archive.com/qemu-devel@nongnu.org/msg08681.html
+ */
+static int vencrypt_dialog(int s_in, int s_out) {
+ char buf[256], buf2[256];
+ int subtypes[16];
+ int n, i, ival, ok, db = 1, nsubtypes = 0;
+
+ vencrypt_selected = 0;
+
+ /* send version 0.2 */
+ buf[0] = 0;
+ buf[1] = 2;
+
+ if (!write_exact(s_out, buf, 2)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ /* read client version 0.2 */
+ memset(buf, 0, sizeof(buf));
+ if (!read_exact(s_in, buf, 2)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+ rfbLog("vencrypt: received %d.%d client version.\n", (int) buf[0], (int) buf[1]);
+
+ /* close 0.0 */
+ if (buf[0] == 0 && buf[1] == 0) {
+ rfbLog("vencrypt: received 0.0 version, closing connection.\n");
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ /* accept only 0.2 */
+ if (buf[0] != 0 || buf[1] != 2) {
+ rfbLog("vencrypt: unsupported VeNCrypt version, closing connection.\n");
+ buf[0] = 255;
+ write_exact(s_out, buf, 1);
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ /* tell them OK */
+ buf[0] = 0;
+ if (!write_exact(s_out, buf, 1)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ if (getenv("X11VNC_ENABLE_VENCRYPT_PLAIN_LOGIN")) {
+ vencrypt_enable_plain_login = atoi(getenv("X11VNC_ENABLE_VENCRYPT_PLAIN_LOGIN"));
+ }
+
+ /* load our list of sub-types: */
+ n = 0;
+ if (!ssl_verify && vencrypt_kx != VENCRYPT_NODH) {
+ if (screen->authPasswdData != NULL) {
+ subtypes[n++] = rfbVencryptTlsVnc;
+ } else {
+ if (vencrypt_enable_plain_login && unixpw) {
+ subtypes[n++] = rfbVencryptTlsPlain;
+ } else {
+ subtypes[n++] = rfbVencryptTlsNone;
+ }
+ }
+ }
+ if (vencrypt_kx != VENCRYPT_NOX509) {
+ if (screen->authPasswdData != NULL) {
+ subtypes[n++] = rfbVencryptX509Vnc;
+ } else {
+ if (vencrypt_enable_plain_login && unixpw) {
+ subtypes[n++] = rfbVencryptX509Plain;
+ } else {
+ subtypes[n++] = rfbVencryptX509None;
+ }
+ }
+ }
+
+ nsubtypes = n;
+ for (i = 0; i < nsubtypes; i++) {
+ ((uint32_t *)buf)[i] = Swap32IfLE(subtypes[i]);
+ }
+
+ /* send number first: */
+ buf2[0] = (char) nsubtypes;
+ if (!write_exact(s_out, buf2, 1)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+ /* and now the list: */
+ if (!write_exact(s_out, buf, 4*n)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ /* read client's selection: */
+ if (!read_exact(s_in, (char *)&ival, 4)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+ ival = Swap32IfLE(ival);
+
+ /* zero means no dice: */
+ if (ival == 0) {
+ rfbLog("vencrypt: client selected no sub-type, closing connection.\n");
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ /* check if he selected a valid one: */
+ ok = 0;
+ for (i = 0; i < nsubtypes; i++) {
+ if (ival == subtypes[i]) {
+ ok = 1;
+ }
+ }
+
+ if (!ok) {
+ rfbLog("vencrypt: client selected invalid sub-type: %d\n", ival);
+ close(s_in); close(s_out);
+ return 0;
+ } else {
+ char *st = "unknown!!";
+ if (ival == rfbVencryptTlsNone) st = "rfbVencryptTlsNone";
+ if (ival == rfbVencryptTlsVnc) st = "rfbVencryptTlsVnc";
+ if (ival == rfbVencryptTlsPlain) st = "rfbVencryptTlsPlain";
+ if (ival == rfbVencryptX509None) st = "rfbVencryptX509None";
+ if (ival == rfbVencryptX509Vnc) st = "rfbVencryptX509Vnc";
+ if (ival == rfbVencryptX509Plain) st = "rfbVencryptX509Plain";
+ rfbLog("vencrypt: client selected sub-type: %d (%s)\n", ival, st);
+ }
+
+ vencrypt_selected = ival;
+
+ /* not documented in spec, send OK: */
+ buf[0] = 1;
+ if (!write_exact(s_out, buf, 1)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ if (vencrypt_selected == rfbVencryptTlsNone ||
+ vencrypt_selected == rfbVencryptTlsVnc ||
+ vencrypt_selected == rfbVencryptTlsPlain) {
+ /* these modes are Anonymous Diffie-Hellman */
+ if (!switch_to_anon_dh()) {
+ rfbLog("vencrypt: Anonymous Diffie-Hellman failed.\n");
+ return 0;
+ }
+ }
+
+ /* continue with SSL/TLS */
+ return 1;
+}
+
+static int check_vnc_tls_mode(int s_in, int s_out) {
+ double waited = 0.0, dt = 0.01, start = dnow();
+ struct timeval tv;
+ int input = 0, i, n, ok;
+ int major, minor, sectype = -1;
+ char *proto = "RFB 003.008\n";
+ char *stype = "unknown";
+ char buf[256];
+
+ vencrypt_selected = 0;
+ tlsvnc_selected = 0;
+
+ if (vencrypt_mode == VENCRYPT_NONE && tlsvnc_mode == TLSVNC_NONE) {
+ /* only normal SSL */
+ return 1;
+ }
+ if (ssl_client_mode) {
+ /* XXX check if this can be done in SSL client mode. */
+ if (vencrypt_mode == VENCRYPT_FORCE || tlsvnc_mode == TLSVNC_FORCE) {
+ rfbLog("check_vnc_tls_mode: VENCRYPT_FORCE/TLSVNC_FORCE prevents normal SSL\n");
+ return 0;
+ }
+ return 1;
+ }
+ if (ssl_verify && vencrypt_mode != VENCRYPT_FORCE && tlsvnc_mode == TLSVNC_FORCE) {
+ rfbLog("check_vnc_tls_mode: Cannot use TLSVNC_FORCE with -sslverify (Anon DH only)\n");
+ /* fallback to normal SSL */
+ return 1;
+ }
+
+ while (waited < 0.7) {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(s_in, &rfds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ select(s_in+1, &rfds, NULL, NULL, &tv);
+ if (FD_ISSET(s_in, &rfds)) {
+ input = 1;
+ break;
+ }
+ usleep((int) (1000 * 1000 * dt));
+ waited += dt;
+ }
+ rfbLog("check_vnc_tls_mode: waited: %f input: %s\n", dnow() - start, input ? "SSL Handshake" : "(future) RFB Handshake");
+
+ if (input) {
+ /* got SSL client hello, can only assume normal SSL */
+ if (vencrypt_mode == VENCRYPT_FORCE || tlsvnc_mode == TLSVNC_FORCE) {
+ rfbLog("check_vnc_tls_mode: VENCRYPT_FORCE/TLSVNC_FORCE prevents normal SSL\n");
+ return 0;
+ }
+ return 1;
+ }
+
+ /* send RFB 003.008 -- there is no turning back from this point... */
+ if (!write_exact(s_out, proto, strlen(proto))) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ memset(buf, 0, sizeof(buf));
+ if (!read_exact(s_in, buf, 12)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ if (sscanf(buf, "RFB %03d.%03d\n", &major, &minor) != 2) {
+ rfbLog("check_vnc_tls_mode: abnormal handshake: '%s'\n", buf);
+ close(s_in); close(s_out);
+ return 0;
+ }
+ rfbLog("check_vnc_tls_mode: version: %d.%d\n", major, minor);
+ if (major != 3 || minor < 8) {
+ rfbLog("check_vnc_tls_mode: invalid version: '%s'\n", buf);
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ n = 1;
+ if (vencrypt_mode == VENCRYPT_FORCE) {
+ buf[n++] = rfbSecTypeVencrypt;
+ } else if (tlsvnc_mode == TLSVNC_FORCE && !ssl_verify) {
+ buf[n++] = rfbSecTypeTlsVnc;
+ } else if (vencrypt_mode == VENCRYPT_SOLE) {
+ buf[n++] = rfbSecTypeVencrypt;
+ } else if (tlsvnc_mode == TLSVNC_SOLE && !ssl_verify) {
+ buf[n++] = rfbSecTypeTlsVnc;
+ } else {
+ if (vencrypt_mode == VENCRYPT_SUPPORT) {
+ buf[n++] = rfbSecTypeVencrypt;
+ }
+ if (tlsvnc_mode == TLSVNC_SUPPORT && !ssl_verify) {
+ buf[n++] = rfbSecTypeTlsVnc;
+ }
+ }
+
+ n--;
+ buf[0] = (char) n;
+ if (!write_exact(s_out, buf, n+1)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+ if (0) fprintf(stderr, "wrote[%d] %d %d %d\n", n, buf[0], buf[1], buf[2]);
+
+ buf[0] = 0;
+ if (!read_exact(s_in, buf, 1)) {
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ if (buf[0] == rfbSecTypeVencrypt) stype = "VeNCrypt";
+ if (buf[0] == rfbSecTypeTlsVnc) stype = "TLSVNC";
+
+ rfbLog("check_vnc_tls_mode: reply: %d (%s)\n", (int) buf[0], stype);
+
+ ok = 0;
+ for (i=1; i < n+1; i++) {
+ if (buf[0] == buf[i]) {
+ ok = 1;
+ }
+ }
+ if (!ok) {
+ char *msg = "check_vnc_tls_mode: invalid security-type";
+ int len = strlen(msg);
+ rfbLog("%s: %d\n", msg, (int) buf[0]);
+ ((uint32_t *)buf)[0] = Swap32IfLE(len);
+ write_exact(s_out, buf, 4);
+ write_exact(s_out, msg, strlen(msg));
+ close(s_in); close(s_out);
+ return 0;
+ }
+
+ sectype = (int) buf[0];
+
+ if (sectype == rfbSecTypeVencrypt) {
+ return vencrypt_dialog(s_in, s_out);
+ } else if (sectype == rfbSecTypeTlsVnc) {
+ return tlsvnc_dialog(s_in, s_out);
+ } else {
+ return 0;
+ }
+}
+
+static void pr_ssl_info(int verb) {
+ SSL_CIPHER *c;
+ SSL_SESSION *s;
+ char *proto = "unknown";
+
+ if (ssl == NULL) {
+ return;
+ }
+ c = SSL_get_current_cipher(ssl);
+ s = SSL_get_session(ssl);
+
+ if (s == NULL) {
+ proto = "nosession";
+ } else if (s->ssl_version == SSL2_VERSION) {
+ proto = "SSLv2";
+ } else if (s->ssl_version == SSL3_VERSION) {
+ proto = "SSLv3";
+ } else if (s->ssl_version == TLS1_VERSION) {
+ proto = "TLSv1";
+ }
+ if (c != NULL) {
+ rfbLog("SSL: ssl_helper[%d]: Cipher: %s %s Proto: %s\n", getpid(),
+ SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c), proto);
+ } else {
+ rfbLog("SSL: ssl_helper[%d]: Proto: %s\n", getpid(),
+ proto);
+ }
+}
+
static void ssl_timeout (int sig) {
rfbLog("sig: %d, ssl_init timed out.\n", sig);
exit(1);
@@ -2110,12 +3112,16 @@ static int ssl_init(int s_in, int s_out) {
}
if (db) fprintf(stderr, "ssl_init: %d/%d\n", s_in, s_out);
+ if (!check_vnc_tls_mode(s_in, s_out)) {
+ return 0;
+ }
+
ssl = SSL_new(ctx);
if (ssl == NULL) {
fprintf(stderr, "SSL_new failed\n");
return 0;
}
-if (db > 1) fprintf(stderr, "ssl_init: 1\n");
+ if (db > 1) fprintf(stderr, "ssl_init: 1\n");
SSL_set_session_id_context(ssl, sid, strlen((char *)sid));
@@ -2134,7 +3140,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 1\n");
return 0;
}
}
-if (db > 1) fprintf(stderr, "ssl_init: 2\n");
+ if (db > 1) fprintf(stderr, "ssl_init: 2\n");
if (ssl_client_mode) {
SSL_set_connect_state(ssl);
@@ -2142,12 +3148,12 @@ if (db > 1) fprintf(stderr, "ssl_init: 2\n");
SSL_set_accept_state(ssl);
}
-if (db > 1) fprintf(stderr, "ssl_init: 3\n");
+ if (db > 1) fprintf(stderr, "ssl_init: 3\n");
name = get_remote_host(ssock);
peerport = get_remote_port(ssock);
-if (db > 1) fprintf(stderr, "ssl_init: 4\n");
+ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
while (1) {
if (db) fprintf(stderr, "calling SSL_accept...\n");
@@ -2173,6 +3179,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
if (db) fprintf(stderr, "got SSL_ERROR_WANT_READ\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",
getpid(), name, peerport);
+ pr_ssl_info(1);
return 0;
} else if (err == SSL_ERROR_WANT_WRITE) {
@@ -2180,6 +3187,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
if (db) fprintf(stderr, "got SSL_ERROR_WANT_WRITE\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",
getpid(), name, peerport);
+ pr_ssl_info(1);
return 0;
} else if (err == SSL_ERROR_SYSCALL) {
@@ -2187,6 +3195,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
if (db) fprintf(stderr, "got SSL_ERROR_SYSCALL\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",
getpid(), name, peerport);
+ pr_ssl_info(1);
return 0;
} else if (err == SSL_ERROR_ZERO_RETURN) {
@@ -2194,6 +3203,7 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
if (db) fprintf(stderr, "got SSL_ERROR_ZERO_RETURN\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n",
getpid(), name, peerport);
+ pr_ssl_info(1);
return 0;
} else if (rc < 0) {
@@ -2207,12 +3217,14 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
break;
}
}
+ pr_ssl_info(1);
return 0;
} else if (dnow() > start + 3.0) {
rfbLog("SSL: ssl_helper[%d]: timeout looping SSL_accept() "
"fatal.\n", getpid());
+ pr_ssl_info(1);
return 0;
} else {
@@ -2220,11 +3232,13 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
if (bio == NULL) {
rfbLog("SSL: ssl_helper[%d]: ssl BIO is null. "
"fatal.\n", getpid());
+ pr_ssl_info(1);
return 0;
}
if (BIO_eof(bio)) {
rfbLog("SSL: ssl_helper[%d]: ssl BIO is EOF. "
"fatal.\n", getpid());
+ pr_ssl_info(1);
return 0;
}
}
@@ -2233,6 +3247,8 @@ if (db > 1) fprintf(stderr, "ssl_init: 4\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() succeeded for: %s:%d\n", getpid(), name, peerport);
+ pr_ssl_info(0);
+
if (SSL_get_verify_result(ssl) == X509_V_OK) {
X509 *x;
FILE *cr = NULL;
@@ -2358,6 +3374,14 @@ static void ssl_xfer(int csock, int s_in, int s_out, int is_https) {
cptr = 0; /* offsets into ABSIZE buffers */
sptr = 0;
+ if (vencrypt_selected > 0 || tlsvnc_selected > 0) {
+ char tmp[16];
+ /* read and discard the extra RFB version */
+ memset(tmp, 0, sizeof(tmp));
+ read(csock, tmp, 12);
+ if (0) fprintf(stderr, "extra: %s\n", tmp);
+ }
+
while (1) {
int c_to_s, s_to_c, closing;