[Cleanup] Merge SSecurityTLS and SSecurityX509 classes into SSecurityTLSBase class.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4107 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/rfb/SSecurityTLSBase.cxx b/common/rfb/SSecurityTLSBase.cxx
index 6801210..8b9cae7 100644
--- a/common/rfb/SSecurityTLSBase.cxx
+++ b/common/rfb/SSecurityTLSBase.cxx
@@ -34,10 +34,17 @@
 #include <rdr/TLSInStream.h>
 #include <rdr/TLSOutStream.h>
 
+#define DH_BITS 1024 /* XXX This should be configurable! */
 #define TLS_DEBUG
 
 using namespace rfb;
 
+StringParameter SSecurityTLSBase::X509_CertFile
+("x509cert", "specifies path to the x509 certificate in PEM format", "", ConfServer);
+
+StringParameter SSecurityTLSBase::X509_KeyFile
+("x509key", "specifies path to the key of the x509 certificate in PEM format", "", ConfServer);
+
 static LogWriter vlog("TLS");
 
 #ifdef TLS_DEBUG
@@ -64,30 +71,58 @@
   }
 }
 
-SSecurityTLSBase::SSecurityTLSBase() : session(0)
+SSecurityTLSBase::SSecurityTLSBase(bool _anon) : session(0), dh_params(0),
+						 anon_cred(0), cert_cred(0),
+						 anon(_anon), fis(0), fos(0)
 {
-  fis=0;
-  fos=0;
+  certfile = X509_CertFile.getData();
+  keyfile = X509_KeyFile.getData();
 }
 
 void SSecurityTLSBase::shutdown()
 {
-  if(session)
-    ;//gnutls_bye(session, GNUTLS_SHUT_RDWR);
+  if (session) {
+    if (gnutls_bye(session, GNUTLS_SHUT_RDWR) != GNUTLS_E_SUCCESS) {
+      /* FIXME: Treat as non-fatal error */
+      vlog.error("TLS session wasn't terminated gracefully");
+    }
+  }
+
+  if (dh_params) {
+    gnutls_dh_params_deinit(dh_params);
+    dh_params = 0;
+  }
+
+  if (anon_cred) {
+    gnutls_anon_free_server_credentials(anon_cred);
+    anon_cred = 0;
+  }
+
+  if (cert_cred) {
+    gnutls_certificate_free_credentials(cert_cred);
+    cert_cred = 0;
+  }
+
+  if (session) {
+    gnutls_deinit(session);
+    session = 0;
+
+    gnutls_global_deinit();
+  }
 }
 
 
 SSecurityTLSBase::~SSecurityTLSBase()
 {
-  if (session) {
-    //gnutls_bye(session, GNUTLS_SHUT_RDWR);
-    gnutls_deinit(session);
-  }
-  if(fis)
+  shutdown();
+
+  if (fis)
     delete fis;
-  if(fos)
+  if (fos)
     delete fos;
-  /* FIXME: should be doing gnutls_global_deinit() at some point */
+
+  delete[] keyfile;
+  delete[] certfile;
 }
 
 bool SSecurityTLSBase::processMsg(SConnection *sc)
@@ -130,10 +165,7 @@
       return false;
     }
     vlog.error("TLS Handshake failed: %s", gnutls_strerror (err));
-    gnutls_bye(session, GNUTLS_SHUT_RDWR);
-    freeResources();
-    gnutls_deinit(session);
-    session = 0;
+    shutdown();
     throw AuthFailureException("TLS Handshake failed");
   }
 
@@ -145,3 +177,48 @@
   return true;
 }
 
+void SSecurityTLSBase::setParams(gnutls_session session)
+{
+  static const int kx_anon_priority[] = { GNUTLS_KX_ANON_DH, 0 };
+  static const int kx_priority[] = { GNUTLS_KX_DHE_DSS, GNUTLS_KX_RSA,
+				     GNUTLS_KX_DHE_RSA, GNUTLS_KX_SRP, 0 };
+
+  gnutls_kx_set_priority(session, anon ? kx_anon_priority : kx_priority);
+
+  if (gnutls_dh_params_init(&dh_params) != GNUTLS_E_SUCCESS)
+    throw AuthFailureException("gnutls_dh_params_init failed");
+
+  if (gnutls_dh_params_generate2(dh_params, DH_BITS) != GNUTLS_E_SUCCESS)
+    throw AuthFailureException("gnutls_dh_params_generate2 failed");
+
+  if (anon) {
+    if (gnutls_anon_allocate_server_credentials(&anon_cred) != GNUTLS_E_SUCCESS)
+      throw AuthFailureException("gnutls_anon_allocate_server_credentials failed");
+
+    gnutls_anon_set_server_dh_params(anon_cred, dh_params);
+
+    if (gnutls_credentials_set(session, GNUTLS_CRD_ANON, anon_cred)
+        != GNUTLS_E_SUCCESS)
+      throw AuthFailureException("gnutls_credentials_set failed");
+
+    vlog.debug("Anonymous session has been set");
+
+  } else {
+    if (gnutls_certificate_allocate_credentials(&cert_cred) != GNUTLS_E_SUCCESS)
+      throw AuthFailureException("gnutls_certificate_allocate_credentials failed");
+
+    gnutls_certificate_set_dh_params(cert_cred, dh_params);
+
+    if (gnutls_certificate_set_x509_key_file(cert_cred, certfile, keyfile,
+        GNUTLS_X509_FMT_PEM) != GNUTLS_E_SUCCESS)
+      throw AuthFailureException("load of key failed");
+
+    if (gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cert_cred)
+        != GNUTLS_E_SUCCESS)
+      throw AuthFailureException("gnutls_credentials_set failed");
+
+    vlog.debug("X509 session has been set");
+
+  }
+
+}