Hi,

> i think that the code you produced for 0.2.x branch could helped to
> add this feature in one of the next release.

ah ok, I believed 0.3 was written (almost) from scratch, so I wasn't sure
whether there would be any benefit. I've attached my patch, but there are
a few remarks:

* The gnutls init code is in weechat_init_vars(), where the config dir has
  probably not even been created. The certificate and key files ('x509.crt'
  and 'x509.key') are therefore opened in the current directory (just like
  the 'ca.pem' file already is).
* There is no support for passphrase-protected key files.
* I've already created the patch to use the certificate callback function
  so weechat could react to the offered algorithms and list of trusted
  CAs; it currently doesn't use that list, though, only one certificate
  is loaded and offered to all servers alike.


Regards,

Jan
SSL client certificate support for weechat. Very rudimentary and
currently not configurable, just a proof of concept. Nevertheless
it plays together nicely with OFTC Nickserv.
--- weechat-0.2.6.3.orig/src/irc/irc-server.c   2009-05-12 18:22:25.000000000 
+0200
+++ weechat-0.2.6.3/src/irc/irc-server.c        2009-06-15 01:52:18.486255908 
+0200
@@ -39,7 +39,8 @@
 #include <netdb.h>
 
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
 #endif
 
 #include "../common/weechat.h"
@@ -1881,6 +1882,18 @@
 #ifdef HAVE_GNUTLS
     if (server->ssl)
     {
+        if (gnutls_xcred_cert_retr_st.ncerts == 1)
+        {
+            char certdn[1024];
+            size_t certlen = 1024;
+            
(void)gnutls_x509_crt_get_dn(gnutls_xcred_cert_retr_st.cert.x509[0], certdn, 
&certlen);
+            gui_printf (NULL, "Using SSL client certificate %s%.*s%s.\n",
+                    GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+                    (1024<certlen)?1024:certlen, certdn,
+                    GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER)
+                   );
+        }
+
         if (gnutls_init (&server->gnutls_sess, GNUTLS_CLIENT) != 0)
         {
             irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
only in patch2:
unchanged:
--- weechat-0.2.6.3.orig/src/common/weechat.c
+++ weechat-0.2.6.3/src/common/weechat.c
@@ -42,12 +42,15 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <sys/stat.h>
 #include <time.h>
 #include <signal.h>
 
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
 #endif
 
 #ifdef HAVE_LANGINFO_CODESET
@@ -87,7 +90,13 @@
 int auto_load_plugins;        /* enabled by default (cmd option to disable) */
 
 #ifdef HAVE_GNUTLS
-gnutls_certificate_credentials gnutls_xcred;   /* gnutls client credentials */
+gnutls_certificate_credentials gnutls_xcred;   /* gnutls client credentials */
+
+gnutls_retr_st                 gnutls_xcred_cert_retr_st;      /** structure 
and callback prototype */
+gnutls_x509_crt_t              gnutls_xcred_certificate;       /*  for client 
certificate support  **/
+gnutls_x509_privkey_t          gnutls_xcred_certificate_key;
+
+int weechat_provide_gnutls_certificates(gnutls_session_t, const gnutls_datum_t 
*, int, const gnutls_pk_algorithm_t *, int, gnutls_retr_st *);
 #endif
 
 
@@ -573,9 +582,90 @@
     gnutls_global_init ();
     gnutls_certificate_allocate_credentials (&gnutls_xcred);
     gnutls_certificate_set_x509_trust_file (gnutls_xcred, "ca.pem", 
GNUTLS_X509_FMT_PEM);
+    gnutls_xcred_cert_retr_st.ncerts = 0;
+
+    do {
+      gnutls_datum_t filedatum;
+      struct stat filestat;
+      char *filebuffer;
+      off_t fileread;
+      int filefd;
+
+      filefd = open("x509.crt", O_RDONLY);
+      if (filefd < 0) break;
+      if (fstat(filefd, &filestat) < 0 || ((filebuffer = 
malloc(filestat.st_size)) == NULL) ) {
+        close(filefd);
+        break;
+      }
+      fileread = 0;
+      while (fileread < filestat.st_size) {
+        ssize_t R = read(filefd, filebuffer+fileread, 
filestat.st_size-fileread);
+        if (R < 0) {
+          free(filebuffer); close(filefd);
+          break;
+        }
+        fileread += R;
+      }
+      close(filefd);
+      filedatum.data = (unsigned char *)filebuffer;
+      filedatum.size = filestat.st_size;
+      gnutls_x509_crt_init(&gnutls_xcred_certificate);
+      gnutls_x509_crt_import(gnutls_xcred_certificate, &filedatum, 
GNUTLS_X509_FMT_PEM);
+      free(filebuffer);
+
+      filefd = open("x509.key", O_RDONLY);
+      if (filefd < 0) break;
+      if (fstat(filefd, &filestat) < 0 || ((filebuffer = 
malloc(filestat.st_size)) == NULL) ) {
+        close(filefd);
+        break;
+      }
+      fileread = 0;
+      while (fileread < filestat.st_size) {
+        ssize_t R = read(filefd, filebuffer+fileread, 
filestat.st_size-fileread);
+        if (R < 0) {
+          free(filebuffer); close(filefd);
+          break;
+        }
+        fileread += R;
+      }
+      close(filefd);
+      filedatum.data = (unsigned char *)filebuffer;
+      filedatum.size = filestat.st_size;
+      gnutls_x509_privkey_init(&gnutls_xcred_certificate_key);
+      gnutls_x509_privkey_import(gnutls_xcred_certificate_key, &filedatum, 
GNUTLS_X509_FMT_PEM);
+      free(filebuffer);
+
+      gnutls_xcred_cert_retr_st.type = GNUTLS_CRT_X509;
+      gnutls_xcred_cert_retr_st.ncerts = 1;
+      gnutls_xcred_cert_retr_st.deinit_all = 0;
+      gnutls_xcred_cert_retr_st.cert.x509 = &gnutls_xcred_certificate;
+      gnutls_xcred_cert_retr_st.key.x509 = gnutls_xcred_certificate_key;
+
+      gnutls_certificate_client_set_retrieve_function (gnutls_xcred, 
&weechat_provide_gnutls_certificates);
+    } while (0);
 #endif
 }
 
+#ifdef HAVE_GNUTLS
+/*
+ * weechat_provide_gnutls_certificate: gnutls callback to obtain the
+ * client certificate to use in the current handshake
+ * TODO: client might know about several certificates and could pick
+ * one depending on the CA list provided by the remote end...
+ * TODO: client should look at pk_algos...
+ */
+
+int weechat_provide_gnutls_certificates(gnutls_session_t tls_session,
+      const gnutls_datum_t *req_ca, int nreq,
+      const gnutls_pk_algorithm_t *pk_algos, int pk_algos_len,
+      gnutls_retr_st *answer) {
+
+  memcpy(answer, &gnutls_xcred_cert_retr_st, sizeof(gnutls_retr_st));
+
+  return 0;
+}
+#endif
+
 /*
  * weechat_config_read: read WeeChat config file
  */
--- weechat-0.2.6.3.orig/src/common/weechat.h   2009-05-12 18:22:25.000000000 
+0200
+++ weechat-0.2.6.3/src/common/weechat.h        2009-06-15 01:53:34.438006168 
+0200
@@ -113,6 +113,7 @@
 
 #ifdef HAVE_GNUTLS
 extern gnutls_certificate_credentials gnutls_xcred;
+extern gnutls_retr_st gnutls_xcred_cert_retr_st;
 #endif
 
 extern void weechat_dump (int);

Attachment: signature.asc
Description: Digital signature

Reply via email to