On Wed, Oct 27, 2010 at 02:36:46PM +0200, Guillaume Destuynder wrote:
> Index: unix/vncviewer/CConn.cxx
> ===================================================================
> --- unix/vncviewer/CConn.cxx (revision 4175)
> +++ unix/vncviewer/CConn.cxx (working copy)
> +// getCertificateReply() is called by the CSecurity object when it needs to
> get
> +// a reply from the user (display/accept certificate dialog).
>
> +int CConn::getCertificateReply(char* cert)
> +{
> + TXMsgBox msgBox(dpy, cert, MB_YESNO, "VNC Viewer: Confirm certificate
> information");
> + if (msgBox.show())
> + return 0;
> + return 1;
> +}
Basic question: Wouldn't a generic messagebox (like in
http://e9925248.users.sourceforge.net/0005-client-side-TLS-tunnel.patch
File common/rfb/UserMsgBox.h) be more useful?
With this approch, each SecurityType need it's own callback function
to ask things.
> +int CConn::saveCertificate(char *data)
> +{
> + char *homeDir = getenv("HOME");
> + if (!homeDir) {
> + vlog.error("Could not find environement variable $HOME");
> + return 1;
> + }
> +
> + CharArray vncDir(strlen(homeDir)+6);
> + sprintf(vncDir.buf, "%s/.vnc", homeDir);
> + CharArray certFile(strlen(vncDir.buf)+12);
> + sprintf(certFile.buf, "%s/x509.certs", vncDir.buf);
> +
> + int result = mkdir(vncDir.buf, 0755);
> + if (result == -1 && errno != EEXIST) {
> + vlog.error("Could not create .vnc directory: %s.", strerror(errno));
> + return 1;
> + }
The vncDir mkdir code is the same as in main of vncviewer.cpp - maybe something
could be merged.
> + FILE *f = fopen(certFile.buf, "w+");
> +
> + if (!f) {
> + vlog.error("Couldnt open/create .vnc/x509.certs file: %s.",
> strerror(errno));
> + return 1;
> + }
> + fprintf(f, "%s", data);
> + fclose(f);
> + return 0;
> +}
So it only stores the last used certificate. Users with more than one
vnc server can take no advantage, as the certificate is overwritten
again and again.
> // CConnection callback methods
>
> Index: common/rfb/CSecurityTLS.cxx
> ===================================================================
> --- common/rfb/CSecurityTLS.cxx (revision 4175)
> +++ common/rfb/CSecurityTLS.cxx (working copy)
> @@ -2,6 +2,7 @@
> * Copyright (C) 2004 Red Hat Inc.
> * Copyright (C) 2005 Martin Koegler
> * Copyright (C) 2010 TigerVNC Team
> + * Copyright (C) 2010 m-privacy GmbH
> *
> * This is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License as published by
> @@ -27,6 +28,9 @@
> #error "This header should not be compiled without HAVE_GNUTLS defined"
> #endif
>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> #include <rfb/CSecurityTLS.h>
> #include <rfb/SSecurityVeNCrypt.h>
> #include <rfb/CConnection.h>
> @@ -34,6 +38,7 @@
> #include <rfb/Exception.h>
> #include <rdr/TLSInStream.h>
> #include <rdr/TLSOutStream.h>
> +#include <os/tilde.h>
>
> #include <gnutls/x509.h>
>
> @@ -41,7 +46,7 @@
>
> using namespace rfb;
>
> -StringParameter CSecurityTLS::x509ca("x509ca", "X509 CA certificate", "",
> ConfViewer);
> +StringParameter CSecurityTLS::x509ca("x509ca", "X509 CA certificate",
> "~/.vnc/x509.certs", ConfViewer);
If you intend to use the last saved certificate by default, why do you
use two different constructions patterns for this file name (with one being
fixed)?
> StringParameter CSecurityTLS::x509crl("x509crl", "X509 CRL file", "",
> ConfViewer);
>
> static LogWriter vlog("TLS");
> @@ -72,8 +77,12 @@
> CSecurityTLS::CSecurityTLS(bool _anon) : session(0), anon_cred(0),
> anon(_anon), fis(0), fos(0)
> {
> - cafile = x509ca.getData();
> - crlfile = x509crl.getData();
> + cafile = tilde_expand(x509ca.getData());
> + if (access(cafile, F_OK))
> + cafile = "";
> + crlfile = tilde_expand(x509crl.getData());
> + if (access(crlfile, F_OK))
> + crlfile = "";
> }
~ expansion in parameters passed via command line is not very common for unix
commands.
If you want ~ expansion in a shell script, you don't escape - if you
want, you pass the ~ as '~'. This would break this.
> void CSecurityTLS::shutdown()
> @@ -206,6 +215,7 @@
> const gnutls_datum *cert_list;
> unsigned int cert_list_size = 0;
> unsigned int i;
> + gnutls_datum_t info;
>
> if (anon)
> return;
> @@ -226,12 +236,18 @@
> throw AuthFailureException("certificate verification failed");
> }
>
> - if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
> - throw AuthFailureException("certificate issuer unknown");
> + if (status & GNUTLS_CERT_REVOKED) {
> + throw AuthFailureException("certificate has been revoked");
> + }
>
> - if (status & GNUTLS_CERT_INVALID)
> - throw AuthFailureException("certificate not trusted");
> + if (status & GNUTLS_CERT_EXPIRED) {
> + throw AuthFailureException("certificate has expired");
> + }
Wishlist: Being able to ignore expired certificates via yes/no question.
> + if (status & GNUTLS_CERT_NOT_ACTIVATED) {
> + throw AuthFailureException("certificate has not been activated");
> + }
> +
> for (i = 0; i < cert_list_size; i++) {
> gnutls_x509_crt crt;
> gnutls_x509_crt_init(&crt);
> @@ -239,12 +255,61 @@
> if (gnutls_x509_crt_import(crt, &cert_list[i],GNUTLS_X509_FMT_DER) < 0)
> throw AuthFailureException("Decoding of certificate failed");
>
> + if (gnutls_x509_crt_print(crt, GNUTLS_CRT_PRINT_ONELINE, &info)) {
> + gnutls_free(info.data);
> + throw AuthFailureException("Could not find certificate to display");
> + }
> +
> if (gnutls_x509_crt_check_hostname(crt, client->getServerName()) == 0) {
> -#if 0
> - throw AuthFailureException("Hostname mismatch"); /* Non-fatal for
> now... */
> -#endif
> + char buf[255];
> + sprintf(buf, "Hostname (%s) does not match any certificate, do you
> want to continue?", client->getServerName());
> + vlog.debug("hostname mistmatch");
> + if ((CSecurityTLS::ctd)->getCertificateReply(buf)) {
> + exit(1);
I would throw an AuthFailureException here.
> + }
> }
> +
> + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
> + size_t out_size;
> + char *out_buf;
> + char *certinfo;
> + int len = 0;
> +
> + 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 = (char*) malloc(len);
> + 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);
> +
> + for (int i=0;i<len-1;i++)
> + if (certinfo[i] == ',' && certinfo[i+1] == ' ')
> + certinfo[i] = '\n';
> +
> + if ((CSecurityTLS::ctd)->getCertificateReply(certinfo)) {
> + free(certinfo);
> + exit(1);
I would throw an AuthFailureException here.
> + }
> + free(certinfo);
> +
> + 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 = (char *) malloc(out_size);
> + if (gnutls_x509_crt_export(crt, GNUTLS_X509_FMT_PEM, out_buf,
> &out_size) < 0)
> + AuthFailureException("certificate issuer unknown, and certificate
> export failed");
> +
> + if ((CSecurityTLS::ctd)->saveCertificate(out_buf))
> + AuthFailureException("certificate save failed");
I wouldn't abort here. Failing to save the certificate is not fatal for all
users.
> + free(out_buf);
> + } else if (status & GNUTLS_CERT_INVALID)
> + throw AuthFailureException("certificate not trusted");
> gnutls_x509_crt_deinit(crt);
> + gnutls_free(info.data);
> }
> }
>
Regards,
Martin Kögler
------------------------------------------------------------------------------
Nokia and AT&T present the 2010 Calling All Innovators-North America contest
Create new apps & games for the Nokia N8 for consumers in U.S. and Canada
$10 million total in prizes - $4M cash, 500 devices, nearly $6M in marketing
Develop with Nokia Qt SDK, Web Runtime, or Java and Publish to Ovi Store
http://p.sf.net/sfu/nokia-dev2dev
_______________________________________________
Tigervnc-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tigervnc-devel