Revision: 4276
http://tigervnc.svn.sourceforge.net/tigervnc/?rev=4276&view=rev
Author: atkac
Date: 2011-02-09 14:13:41 +0000 (Wed, 09 Feb 2011)
Log Message:
-----------
[Bugfix] client: improve server certificate verification code.
Modified Paths:
--------------
trunk/common/rfb/CSecurityTLS.cxx
Modified: trunk/common/rfb/CSecurityTLS.cxx
===================================================================
--- trunk/common/rfb/CSecurityTLS.cxx 2011-02-09 14:09:10 UTC (rev 4275)
+++ trunk/common/rfb/CSecurityTLS.cxx 2011-02-09 14:13:41 UTC (rev 4276)
@@ -65,9 +65,11 @@
static LogWriter vlog("TLS");
#ifdef TLS_DEBUG
+static LogWriter vlog_raw("Raw TLS");
+
static void debug_log(int level, const char* str)
{
- vlog.debug(str);
+ vlog_raw.debug(str);
}
#endif
@@ -230,6 +232,22 @@
if (*cafile &&
gnutls_certificate_set_x509_trust_file(cert_cred,cafile,GNUTLS_X509_FMT_PEM) <
0)
throw AuthFailureException("load of CA cert failed");
+ /* Load previously saved certs */
+ char *homeDir = NULL;
+ int err;
+ if (getvnchomedir(&homeDir) == -1)
+ vlog.error("Could not obtain VNC home directory path");
+ else {
+ CharArray caSave(strlen(homeDir) + 19 + 1);
+ sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir);
+ delete [] homeDir;
+
+ err = gnutls_certificate_set_x509_trust_file(cert_cred, caSave.buf,
+ GNUTLS_X509_FMT_PEM);
+ if (err < 0)
+ vlog.debug("Failed to load saved server certificates from %s",
caSave.buf);
+ }
+
if (*crlfile &&
gnutls_certificate_set_x509_crl_file(cert_cred,crlfile,GNUTLS_X509_FMT_PEM) < 0)
throw AuthFailureException("load of CRL failed");
@@ -242,10 +260,13 @@
void CSecurityTLS::checkSession()
{
- int status;
+ const unsigned allowed_errors = GNUTLS_CERT_INVALID |
+ GNUTLS_CERT_SIGNER_NOT_FOUND |
+ GNUTLS_CERT_SIGNER_NOT_CA;
+ unsigned int status;
const gnutls_datum *cert_list;
unsigned int cert_list_size = 0;
- unsigned int i;
+ int err;
gnutls_datum info;
if (anon)
@@ -254,141 +275,163 @@
if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509)
throw AuthFailureException("unsupported certificate type");
+ err = gnutls_certificate_verify_peers2(session, &status);
+ if (err != 0) {
+ vlog.error("server certificate verification failed: %s",
gnutls_strerror(err));
+ throw AuthFailureException("server certificate verification failed");
+ }
+
+ if (status & GNUTLS_CERT_REVOKED)
+ throw AuthFailureException("server certificate has been revoked");
+
+ if (status & GNUTLS_CERT_NOT_ACTIVATED)
+ throw AuthFailureException("server certificate has not been activated");
+
+ if (status & GNUTLS_CERT_EXPIRED) {
+ vlog.debug("server certificate has expired");
+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate has expired",
+ "The certificate of the server has expired, "
+ "do you want to continue?"))
+ throw AuthFailureException("server certificate has expired");
+ }
+ /* Process other errors later */
+
cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
if (!cert_list_size)
- throw AuthFailureException("unsupported certificate type");
+ throw AuthFailureException("empty certificate chain");
- status = gnutls_certificate_verify_peers(session);
- if (status == GNUTLS_E_NO_CERTIFICATE_FOUND)
- throw AuthFailureException("no certificate sent");
+ /* Process only server's certificate, not issuer's certificate */
+ gnutls_x509_crt crt;
+ gnutls_x509_crt_init(&crt);
- if (status < 0) {
- vlog.error("X509 verify failed: %s\n", gnutls_strerror (status));
- throw AuthFailureException("certificate verification failed");
+ if (gnutls_x509_crt_import(crt, &cert_list[0], GNUTLS_X509_FMT_DER) < 0)
+ throw AuthFailureException("decoding of certificate failed");
+
+ if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
+ char buf[255];
+ vlog.debug("hostname mismatch");
+ snprintf(buf, sizeof(buf), "Hostname (%s) does not match any certificate, "
+ "do you want to continue?",
client->getServerName());
+ buf[sizeof(buf) - 1] = '\0';
+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf))
+ throw AuthFailureException("hostname mismatch");
}
- if (status & GNUTLS_CERT_REVOKED) {
- throw AuthFailureException("certificate has been revoked");
+ if (status == 0) {
+ /* Everything is fine (hostname + verification) */
+ gnutls_x509_crt_deinit(crt);
+ return;
}
+
+ if (status & GNUTLS_CERT_INVALID)
+ vlog.debug("server certificate invalid");
+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
+ vlog.debug("server cert signer not found");
+ if (status & GNUTLS_CERT_SIGNER_NOT_CA)
+ vlog.debug("server cert signer not CA");
- if (status & GNUTLS_CERT_NOT_ACTIVATED) {
- throw AuthFailureException("certificate has not been activated");
+ if ((status & (~allowed_errors)) != 0) {
+ /* No other errors are allowed */
+ vlog.debug("GNUTLS status of certificate verification: %u", status);
+ throw AuthFailureException("Invalid status of server certificate
verification");
}
- for (i = 0; i < cert_list_size; i++) {
- gnutls_x509_crt crt;
- gnutls_x509_crt_init(&crt);
+ vlog.debug("Saved server certificates don't match");
- if (gnutls_x509_crt_import(crt, &cert_list[i],GNUTLS_X509_FMT_DER) < 0)
- throw AuthFailureException("decoding of certificate failed");
-
- #if defined(GNUTLS_VERSION_NUMBER) && (GNUTLS_VERSION_NUMBER >= 0x010706)
- if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) {
- /*
- * GNUTLS doesn't correctly export gnutls_free symbol which is
- * a function pointer. Linking with Visual Studio 2008 Express will
- * fail when you call gnutls_free().
- */
+ #if defined(GNUTLS_VERSION_NUMBER) && (GNUTLS_VERSION_NUMBER >= 0x010706)
+ if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) {
+ /*
+ * GNUTLS doesn't correctly export gnutls_free symbol which is
+ * a function pointer. Linking with Visual Studio 2008 Express will
+ * fail when you call gnutls_free().
+ */
#if WIN32
- free(info.data);
+ free(info.data);
#else
- gnutls_free(info.data);
+ gnutls_free(info.data);
#endif
- throw AuthFailureException("Could not find certificate to display");
- }
- #endif
+ throw AuthFailureException("Could not find certificate to display");
+ }
+ #endif
- if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
- char buf[255];
- sprintf(buf, "Hostname (%s) does not match any certificate, do you want
to continue?", client->getServerName());
- vlog.debug("hostname mismatch");
- if(!msg->showMsgBox(UserMsgBox::M_YESNO, "hostname mismatch", buf))
- throw AuthFailureException("hostname mismatch");
- }
+ size_t out_size;
+ char *out_buf = NULL;
+ char *certinfo = NULL;
+ int len = 0;
- if (status & GNUTLS_CERT_EXPIRED) {
- vlog.debug("certificate has expired");
- if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certficate has expired", "The
certificate of the server has expired, do you want to continue?"))
- throw AuthFailureException("certificate has expired");
- }
+ vlog.debug("certificate issuer unknown");
- if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
- size_t out_size;
- char *homeDir = NULL;
- char *out_buf = NULL;
- char *certinfo = NULL;
- int len = 0;
+ len = snprintf(NULL, 0, "This certificate has been signed by an unknown "
+ "authority:\n\n%s\n\nDo you want to save it and "
+ "continue?\n ", info.data);
+ if (len < 0)
+ AuthFailureException("certificate decoding error");
- vlog.debug("certificate issuer unknown");
+ vlog.debug("%s", info.data);
- len = snprintf(NULL, 0, "This certificate has been signed by an unknown
authority:\n\n%s\n\nDo you want to save it and continue?\n ", info.data);
- if (len < 0)
- AuthFailureException("certificate decoding error");
+ certinfo = new char[len];
+ if (certinfo == NULL)
+ throw AuthFailureException("Out of memory");
- vlog.debug("%s", info.data);
+ snprintf(certinfo, len, "This certificate has been signed by an unknown "
+ "authority:\n\n%s\n\nDo you want to save it and "
+ "continue? ", info.data);
- certinfo = new char[len];
- if (certinfo == NULL)
- throw AuthFailureException("Out of memory");
+ for (int i = 0; i < len - 1; i++)
+ if (certinfo[i] == ',' && certinfo[i + 1] == ' ')
+ certinfo[i] = '\n';
- snprintf(certinfo, len, "This certificate has been signed by an unknown
authority:\n\n%s\n\nDo you want to save it and continue? ", info.data);
+ if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown",
+ certinfo)) {
+ delete [] certinfo;
+ throw AuthFailureException("certificate issuer unknown");
+ }
- for (int i = 0; i < len - 1; i++)
- if (certinfo[i] == ',' && certinfo[i + 1] == ' ')
- certinfo[i] = '\n';
+ delete [] certinfo;
- if (!msg->showMsgBox(UserMsgBox::M_YESNO, "certificate issuer unknown",
- certinfo)) {
- delete [] certinfo;
- throw AuthFailureException("certificate issuer unknown");
- }
- delete [] certinfo;
+ if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size)
+ == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ AuthFailureException("Out of memory");
- if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, NULL, &out_size)
- == GNUTLS_E_SHORT_MEMORY_BUFFER)
- AuthFailureException("Out of memory");
+ // Save cert
+ out_buf = new char[out_size];
+ if (out_buf == NULL)
+ AuthFailureException("Out of memory");
- // Save cert
- out_buf = new char[out_size];
- if (out_buf == NULL)
- AuthFailureException("Out of memory");
+ if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size) < 0)
+ AuthFailureException("certificate issuer unknown, and certificate "
+ "export failed");
- if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf, &out_size)
- < 0)
- AuthFailureException("certificate issuer unknown, and certificate "
- "export failed");
+ char *homeDir = NULL;
+ if (getvnchomedir(&homeDir) == -1)
+ vlog.error("Could not obtain VNC home directory path");
+ else {
+ FILE *f;
+ CharArray caSave(strlen(homeDir) + 1 + 19);
+ sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir);
+ delete [] homeDir;
+ f = fopen(caSave.buf, "a+");
+ if (!f)
+ msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed",
+ "Could not save the certificate");
+ else {
+ fprintf(f, "%s\n", out_buf);
+ fclose(f);
+ }
+ }
- if (getvnchomedir(&homeDir) == -1)
- vlog.error("Could not obtain VNC home directory path");
- else {
- FILE *f;
- CharArray caSave(strlen(homeDir) + 1 + 19);
- sprintf(caSave.buf, "%sx509_savedcerts.pem", homeDir);
- delete [] homeDir;
- f = fopen(caSave.buf, "a+");
- if (!f)
- msg->showMsgBox(UserMsgBox::M_OK, "certificate save failed",
- "Could not save the certificate");
- else {
- fprintf(f, "%s\n", out_buf);
- fclose(f);
- }
- }
- delete [] out_buf;
- } else if (status & GNUTLS_CERT_INVALID)
- throw AuthFailureException("certificate not trusted");
+ delete [] out_buf;
- gnutls_x509_crt_deinit(crt);
- /*
- * GNUTLS doesn't correctly export gnutls_free symbol which is
- * a function pointer. Linking with Visual Studio 2008 Express will
- * fail when you call gnutls_free().
- */
+ gnutls_x509_crt_deinit(crt);
+ /*
+ * GNUTLS doesn't correctly export gnutls_free symbol which is
+ * a function pointer. Linking with Visual Studio 2008 Express will
+ * fail when you call gnutls_free().
+ */
#if WIN32
- free(info.data);
+ free(info.data);
#else
- gnutls_free(info.data);
+ gnutls_free(info.data);
#endif
- }
}
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
The ultimate all-in-one performance toolkit: Intel(R) Parallel Studio XE:
Pinpoint memory and threading errors before they happen.
Find and fix more than 250 security defects in the development cycle.
Locate bottlenecks in serial and parallel code that limit performance.
http://p.sf.net/sfu/intel-dev2devfeb
_______________________________________________
Tigervnc-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tigervnc-commits