<<< Date Index >>>     <<< Thread Index >>>

Re: [PATCH] SSL client certificate support



For your amusement, here's a repost of the SSL client certificate
patch against CVS HEAD.

On Sunday, 25 July 2004 at 00:42, Brendan Cully wrote:
> Here's a patch to allow mutt to use SSL client certificates to
> authenticate itself. To use, set ssl_client_cert to the path to your
> certificate file (containing both the certificate and the private
> key). It works with the SASL EXTERNAL authentication mechanism, so
> you'll need to have SASL enabled as well.
> 
> Someone on IRC asked about it, so I thought I'd whip it up. I tested
> it against Cyrus 2.1.
Index: globals.h
===================================================================
RCS file: /home/roessler/cvs/mutt/globals.h,v
retrieving revision 3.10
diff -u -p -r3.10 globals.h
--- globals.h   19 Jul 2004 21:44:23 -0000      3.10
+++ globals.h   28 Aug 2004 04:25:58 -0000
@@ -108,6 +108,7 @@ WHERE char *SpamSep;
 #if defined(USE_SSL) || defined(USE_NSS)
 WHERE char *SslCertFile INITVAL (NULL);
 WHERE char *SslEntropyFile INITVAL (NULL);
+WHERE char *SslClientCert INITVAL (NULL);
 #endif
 WHERE char *StChars;
 WHERE char *Status;
Index: init.h
===================================================================
RCS file: /home/roessler/cvs/mutt/init.h,v
retrieving revision 3.55
diff -u -p -r3.55 init.h
--- init.h      19 Jul 2004 21:44:23 -0000      3.55
+++ init.h      28 Aug 2004 04:26:00 -0000
@@ -1849,6 +1849,12 @@ struct option_t MuttVars[] = {
   ** This variables specifies whether to attempt to use TLSv1 in the
   ** SSL authentication process.
   */
+  { "ssl_client_cert", DT_PATH, R_NONE, UL &SslClientCert, 0 },
+  /*
+  ** .pp
+  ** The file containing a client certificate and its associated private
+  ** key.
+  */
 #endif
 
   { "pipe_split",      DT_BOOL, R_NONE, OPTPIPESPLIT, 0 },
Index: mutt_sasl.c
===================================================================
RCS file: /home/roessler/cvs/mutt/mutt_sasl.c,v
retrieving revision 3.7
diff -u -p -r3.7 mutt_sasl.c
--- mutt_sasl.c 12 Apr 2004 19:20:13 -0000      3.7
+++ mutt_sasl.c 28 Aug 2004 04:26:01 -0000
@@ -294,8 +294,8 @@ dprint(1,(debugfile, "local ip: %s, remo
    * If someone does it'd probably be trivial to write mutt_nss_get_ssf().
    * I have a feeling more SSL code could be shared between those two files,
    * but I haven't looked into it yet, since I still don't know the APIs. */
-#if defined(USE_SSL) && !defined(USE_NSS)
-  if (conn->account.flags & M_ACCT_SSL)
+#if defined(USE_SSL)
+  if (conn->ssf)
   {
 #ifdef USE_SASL2 /* I'm not sure this actually has an effect, at least with 
SASLv2 */
     dprint (2, (debugfile, "External SSF: %d\n", conn->ssf));
@@ -311,8 +311,8 @@ dprint(1,(debugfile, "local ip: %s, remo
       return -1;
     }
 #ifdef USE_SASL2
-    dprint (2, (debugfile, "External authentication name: %s\n","NULL"));
-    if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, NULL) != SASL_OK)
+    dprint (2, (debugfile, "External authentication name: %s\n", 
conn->account.user));
+    if (sasl_setprop (*saslconn, SASL_AUTH_EXTERNAL, conn->account.user) != 
SASL_OK)
      {
       dprint (1, (debugfile, "mutt_sasl_client_new: Error setting external 
properties\n"));
       return -1;
Index: mutt_ssl.c
===================================================================
RCS file: /home/roessler/cvs/mutt/mutt_ssl.c,v
retrieving revision 3.3
diff -u -p -r3.3 mutt_ssl.c
--- mutt_ssl.c  3 Sep 2003 17:10:37 -0000       3.3
+++ mutt_ssl.c  28 Aug 2004 04:26:01 -0000
@@ -68,13 +68,15 @@ sslsockdata;
 /* local prototypes */
 int ssl_init (void);
 static int add_entropy (const char *file);
-static int ssl_check_certificate (sslsockdata * data);
 static int ssl_socket_read (CONNECTION* conn, char* buf, size_t len);
 static int ssl_socket_write (CONNECTION* conn, const char* buf, size_t len);
 static int ssl_socket_open (CONNECTION * conn);
 static int ssl_socket_close (CONNECTION * conn);
 static int tls_close (CONNECTION* conn);
-int ssl_negotiate (sslsockdata*);
+static int ssl_check_certificate (sslsockdata * data);
+static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn);
+static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata);
+static int ssl_negotiate (sslsockdata*);
 
 /* mutt_ssl_starttls: Negotiate TLS over an already opened connection.
  *   TODO: Merge this code better with ssl_socket_open. */
@@ -94,6 +96,8 @@ int mutt_ssl_starttls (CONNECTION* conn)
     goto bail_ssldata;
   }
 
+  ssl_get_client_cert(ssldata, conn);
+
   if (! (ssldata->ssl = SSL_new (ssldata->ctx)))
   {
     dprint (1, (debugfile, "mutt_ssl_starttls: Error allocating SSL\n"));
@@ -279,6 +283,8 @@ static int ssl_socket_open (CONNECTION *
     SSL_CTX_set_options(data->ctx, SSL_OP_NO_SSLv3);
   }
 
+  ssl_get_client_cert(data, conn);
+
   data->ssl = SSL_new (data->ctx);
   SSL_set_fd (data->ssl, conn->fd);
 
@@ -296,7 +302,7 @@ static int ssl_socket_open (CONNECTION *
 
 /* ssl_negotiate: After SSL state has been initialised, attempt to negotiate
  *   SSL over the wire, including certificate checks. */
-int ssl_negotiate (sslsockdata* ssldata)
+static int ssl_negotiate (sslsockdata* ssldata)
 {
   int err;
   const char* errmsg;
@@ -315,7 +321,7 @@ int ssl_negotiate (sslsockdata* ssldata)
       errmsg = _("I/O error");
       break;
     case SSL_ERROR_SSL:
-      errmsg = _("unspecified protocol error");
+      errmsg = ERR_error_string (ERR_get_error (), NULL);
       break;
     default:
       errmsg = _("unknown error");
@@ -666,4 +672,32 @@ static int ssl_check_certificate (sslsoc
   unset_option(OPTUNBUFFEREDINPUT);
   mutt_menuDestroy (&menu);
   return (done == 2);
+}
+
+static void ssl_get_client_cert(sslsockdata *ssldata, CONNECTION *conn)
+{
+  if (SslClientCert)
+  {
+    dprint (2, (debugfile, "Using client certificate %s\n", SslClientCert));
+    SSL_CTX_set_default_passwd_cb_userdata(ssldata->ctx, &conn->account);
+    SSL_CTX_set_default_passwd_cb(ssldata->ctx, ssl_passwd_cb);
+    SSL_CTX_use_certificate_file(ssldata->ctx, SslClientCert, 
SSL_FILETYPE_PEM);
+    SSL_CTX_use_PrivateKey_file(ssldata->ctx, SslClientCert, SSL_FILETYPE_PEM);
+  }
+}
+
+static int ssl_passwd_cb(char *buf, int size, int rwflag, void *userdata)
+{
+  ACCOUNT *account = (ACCOUNT*)userdata;
+
+  if (mutt_account_getuser (account))
+    return 0;
+
+  dprint (2, (debugfile, "ssl_passwd_cb: getting password for %s@%s:%u\n",
+             account->user, account->host, account->port));
+  
+  if (mutt_account_getpass (account))
+    return 0;
+
+  return snprintf(buf, size, "%s", account->pass);
 }

Attachment: pgp25rervFWVA.pgp
Description: PGP signature