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