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
Tigervnc-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/tigervnc-devel

Reply via email to