aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric S. Raymond <esr@thyrsus.com>2001-05-14 06:54:37 +0000
committerEric S. Raymond <esr@thyrsus.com>2001-05-14 06:54:37 +0000
commitc5a58c018e5a8207bd39a63aedcd8ef206c9d8ab (patch)
tree0bf23b7047e5dfb584f97a32db1e1714304fcaf4
parentc346e09c465f8365b8d91041f10f56f3c8227213 (diff)
downloadfetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.tar.gz
fetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.tar.bz2
fetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.zip
SSL certification handling.
svn path=/trunk/; revision=3314
-rw-r--r--Makefile.in6
-rw-r--r--NEWS2
-rw-r--r--conf.c3
-rw-r--r--driver.c3
-rw-r--r--fetchmail.c13
-rw-r--r--fetchmail.h3
-rw-r--r--fetchmail.man28
-rwxr-xr-xfetchmailconf30
-rw-r--r--options.c22
-rw-r--r--rcfile_l.l3
-rw-r--r--rcfile_y.y5
-rw-r--r--socket.c172
-rw-r--r--socket.h3
-rw-r--r--todo.html8
14 files changed, 240 insertions, 61 deletions
diff --git a/Makefile.in b/Makefile.in
index 40d1b83f..339bd2a9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -4,7 +4,7 @@
# So just uncomment all the lines marked QNX.
PACKAGE = fetchmail
-VERSION = 5.8.3
+VERSION = 5.8.4
# Ultrix 2.2 make doesn't expand the value of VPATH.
srcdir = @srcdir@
@@ -266,8 +266,8 @@ extra = $(srcdir)/alloca.c $(srcdir)/getopt.[ch] $(srcdir)/getopt1.c \
docs = $(srcdir)/COPYING $(srcdir)/FEATURES $(srcdir)/fetchmail-features.html \
$(srcdir)/design-notes.html $(srcdir)/NOTES \
$(srcdir)/todo.html $(srcdir)/TODO \
- $(srcdir)/INSTALL $(srcdir)/NEWS $(srcdir)/README \
- $(srcdir)/README.NTLM $(srcdir)/fetchmail.lsm \
+ $(srcdir)/INSTALL $(srcdir)/README $(srcdir)/README.SSL \
+ $(srcdir)/README.NTLM $(srcdir)/fetchmail.lsm $(srcdir)/NEWS \
$(srcdir)/*.man $(srcdir)/FAQ $(srcdir)/fetchmail-FAQ.html
config = $(srcdir)/Makefile.in $(srcdir)/configure.in $(srcdir)/configure \
$(srcdir)/config.guess $(srcdir)/config.h.in $(srcdir)/config.sub \
diff --git a/NEWS b/NEWS
index fea0542a..b51cf8b5 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@
(The `lines' figures total .c, .h, .l, and .y files under version control.)
+* SSL certificate options from Thomas Moestl <tmoestl@gmx.net>.
+
fetchmail-5.8.3 (Sat May 12 04:07:12 EDT 2001), 20502 lines:
* The `localhost' special case of `via' is gone. Use `plugin %h' for talking
diff --git a/conf.c b/conf.c
index ac88c513..2daa8225 100644
--- a/conf.c
+++ b/conf.c
@@ -375,6 +375,9 @@ void dump_config(struct runctl *runp, struct query *querylist)
stringdump("sslkey", ctl->sslkey);
stringdump("sslcert", ctl->sslcert);
stringdump("sslproto", ctl->sslproto);
+ booldump("sslcertck", ctl->sslcertck);
+ stringdump("sslcertpath", ctl->sslcertpath);
+ stringdump("sslfingerprint", ctl->sslfingerprint);
#endif /* SSL_ENABLE */
numdump("expunge", ctl->expunge);
stringdump("properties", ctl->properties);
diff --git a/driver.c b/driver.c
index 11338f77..42dcac8f 100644
--- a/driver.c
+++ b/driver.c
@@ -1766,7 +1766,8 @@ const int maxfetch; /* maximum number of messages to fetch */
/* perform initial SSL handshake on open connection */
/* Note: We pass the realhost name over for certificate
verification. We may want to make this configurable */
- if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,ctl->sslproto,realhost) == -1)
+ if (ctl->use_ssl && SSLOpen(mailserver_socket,ctl->sslkey,ctl->sslcert,ctl->sslproto,ctl->sslcertck,
+ ctl->sslcertpath,ctl->sslfingerprint,realhost,ctl->server.pollname) == -1)
{
report(stderr, _("SSL connection failed.\n"));
goto closeUp;
diff --git a/fetchmail.c b/fetchmail.c
index 621a69f6..a2343614 100644
--- a/fetchmail.c
+++ b/fetchmail.c
@@ -843,6 +843,9 @@ static void optmerge(struct query *h2, struct query *h1, int force)
FLAG_MERGE(sslkey);
FLAG_MERGE(sslcert);
FLAG_MERGE(sslproto);
+ FLAG_MERGE(sslcertck);
+ FLAG_MERGE(sslcertpath);
+ FLAG_MERGE(sslfingerprint);
#endif
FLAG_MERGE(expunge);
@@ -1035,6 +1038,7 @@ static int load_params(int argc, char **argv, int optind)
DEFAULT(ctl->server.uidl, FALSE);
#ifdef SSL_ENABLE
DEFAULT(ctl->use_ssl, FALSE);
+ DEFAULT(ctl->sslcertck, FALSE);
#endif
DEFAULT(ctl->server.checkalias, FALSE);
#undef DEFAULT
@@ -1559,7 +1563,14 @@ static void dump_params (struct runctl *runp,
printf(_(" Mail service principal is: %s\n"), ctl->server.principal);
#ifdef SSL_ENABLE
if (ctl->use_ssl)
- printf(" SSL encrypted sessions enabled.\n");
+ printf(_(" SSL encrypted sessions enabled.\n"));
+ if (ctl->sslcertck) {
+ printf(_(" SSL server certificate checking enabled.\n"));
+ if (ctl->sslcertpath != NULL)
+ printf(_(" SSL trusted certificate directory: %s\n"), ctl->sslcertpath);
+ }
+ if (ctl->sslfingerprint != NULL)
+ printf(_(" SSL key fingerprint (checked against the server key): %s\n"), ctl->sslfingerprint);
#endif
if (ctl->server.timeout > 0)
printf(_(" Server nonresponse timeout is %d seconds"), ctl->server.timeout);
diff --git a/fetchmail.h b/fetchmail.h
index f3181da6..29aa7015 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -287,6 +287,9 @@ struct query
char *sslkey; /* optional SSL private key file */
char *sslcert; /* optional SSL certificate file */
char *sslproto; /* force usage of protocol (ssl2|ssl3|tls1) - defaults to ssl23 */
+ char *sslcertpath; /* Trusted certificate directory for checking the server cert */
+ flag sslcertck; /* Strictly check the server cert. */
+ char *sslfingerprint; /* Fingerprint to check against */
char *properties; /* passthrough properties for extensions */
/* internal use -- per-poll state */
diff --git a/fetchmail.man b/fetchmail.man
index cc7e46a2..030da083 100644
--- a/fetchmail.man
+++ b/fetchmail.man
@@ -310,6 +310,34 @@ server. This can cause some complications in daemon mode.
(Keyword: sslproto)
Forces an ssl protocol. Possible values are \&`\fBssl2\fR', `\fBssl3\fR' and
`\fBtls1\fR'. Try this if the default handshake does not work for your server.
+.TP
+.B \--sslcertck
+(Keyword: sslcertck)
+Causes fetchmail to strictly check the server certificate against a set of
+local trusted certificates (see the \fBsslcertpath\fR option). If the server
+certificate is not signed by one of the trusted ones (directly or indirectly),
+the SSL connection will fail. This checking should prevent man-in-the-middle
+attacks against the SSL connection. Note that CRLs are seemingly not currently
+supported by OpenSSL in certificate verification! Your system clock should
+be reasonably accurate when using this option!
+.TP
+.B \--sslcertpath <directory>
+(Keyword: sslcertpath)
+Sets the directory fetchmail uses to look up local certificates. The default
+is your OpenSSL default one. The directory must be hashed as OpenSSL expects
+it - every time you add or modify a certificate in the directory, you need
+to use the \fBc_rehash\fR tool (which comes with OpenSSL in the tools/
+subdirectory).
+.TP
+.B \--sslfingerprint
+(Keyword: sslfingerprint)
+Specify the fingerprint of the server key (an MD5 hash of the key) in
+hexadecimal notation with colons separating groups of two digits. The letter
+hex digits must be in upper case. This is the default format OpenSSL uses,
+and the one fetchmail uses to report the fingerprint when an SSL connection
+is established. When this is specified, fetchmail will compare the server key
+fingerprint with the given one, and the connection will fail if they do not
+match. This can be used to prevent man-in-the-middle attacks.
.SS Delivery Control Options
.TP
.B \-S <hosts>, --smtphost <hosts>
diff --git a/fetchmailconf b/fetchmailconf
index 8ec65603..ab4aa9de 100755
--- a/fetchmailconf
+++ b/fetchmailconf
@@ -238,6 +238,9 @@ class User:
self.sslkey = None # SSL key filename
self.sslcert = None # SSL certificate filename
self.sslproto = None # Force SSL?
+ self.sslcertck = 0 # Enable strict SSL cert checking
+ self.sslcertpath = None # Path to trusted certificates
+ self.sslfingerprint = None # SSL key fingerprint to check
self.properties = None # Extension properties
User.typemap = (
('remote', 'String'),
@@ -271,6 +274,9 @@ class User:
('ssl', 'Boolean'),
('sslkey', 'String'),
('sslcert', 'String'),
+ ('sslcertck', 'Boolean'),
+ ('sslcertpath', 'String'),
+ ('sslfingerprint', 'String'),
('properties', 'String'))
def __repr__(self):
@@ -331,8 +337,14 @@ class User:
res = res + " sslkey " + `self.sslkey`
if self.sslcert and self.sslcert != UserDefaults.sslcert:
res = res + " sslcert " + `self.sslcert`
- if self.sslproto and self.sslcert != UserDefaults.sslproto:
- res = res + " sslproto " + `self.sslcert`
+ if self.sslproto and self.sslproto != UserDefaults.sslproto:
+ res = res + " sslproto " + `self.sslproto`
+ if self.sslcertck and self.sslcertck != UserDefaults.sslcertck:
+ res = res + flag2str(self.sslcertck, 'sslcertck')
+ if self.sslcertpath and self.sslcertpath != UserDefaults.sslcertpath:
+ res = res + " sslcertpath " + `self.sslcertpath`
+ if self.sslfingerprint and self.sslfingerprint != UserDefaults.sslfingerprint:
+ res = res + " sslfingerprint " + `self.sslfingerprint`
if self.expunge != UserDefaults.expunge:
res = res + " expunge " + `self.expunge`
res = res + "\n"
@@ -925,6 +937,10 @@ manual page for details on these.
The ssl option enables SSL communication with a mailserver
supporting Secure Sockets Layer. The sslkey and sslcert options
declare key and certificate files for use with SSL.
+The sslcertck option enables strict checking of SSL server
+certificates (and sslcertpath gives trusted certificate
+directory). With sslfingerprint, you can specify a finger-
+print the server's key is checked against.
The `netsec' option will be configurable only if fetchmail
was compiled with IPV6 support. If you need to use it,
@@ -1535,6 +1551,12 @@ class UserEdit(Frame, MyWidget):
self.sslkey, '14').pack(side=TOP, fill=X)
LabeledEntry(sslwin, 'SSL certificate:',
self.sslcert, '14').pack(side=TOP, fill=X)
+ Checkbutton(sslwin, text="Check server SSL certificate?",
+ variable=self.sslcertck).pack(side=TOP, fill=X)
+ LabeledEntry(sslwin, 'SSL trusted certificate directory:',
+ self.sslcertpath, '14').pack(side=TOP, fill=X)
+ LabeledEntry(sslwin, 'SSL key fingerprint:',
+ self.sslfingerprint, '14').pack(side=TOP, fill=X)
sslwin.pack(fill=X, anchor=N)
names = Frame(leftwin, relief=RAISED, bd=5)
@@ -1813,8 +1835,8 @@ def copy_instance(toclass, fromdict):
# present in the dictionary.
optional = ('interface', 'monitor',
'netsec',
- 'ssl', 'sslkey', 'sslcert', 'sslproto',
- 'showdots')
+ 'ssl', 'sslkey', 'sslcert', 'sslproto', 'sslcertck',
+ 'sslcertpath', 'sslfingerprint', 'showdots')
class_sig = setdiff(toclass.__dict__.keys(), optional)
class_sig.sort()
dict_keys = setdiff(fromdict.keys(), optional)
diff --git a/options.c b/options.c
index 71003d21..7b7c4799 100644
--- a/options.c
+++ b/options.c
@@ -77,10 +77,13 @@
#define LA_SSLKEY 51
#define LA_SSLCERT 52
#define LA_SSLPROTO 53
+#define LA_SSLCERTCK 54
+#define LA_SSLCERTPATH 55
+#define LA_SSLFINGERPRINT 56
#endif
-#define LA_SHOWDOTS 54
-#define LA_PRINCIPAL 55
+#define LA_SHOWDOTS 57
+#define LA_PRINCIPAL 58
/* options still left: CDgGhHjJoORwWxXYz */
static const char *shortoptions =
@@ -148,6 +151,9 @@ static const struct option longoptions[] = {
{"sslkey", required_argument, (int *) 0, LA_SSLKEY },
{"sslcert", required_argument, (int *) 0, LA_SSLCERT },
{"sslproto", required_argument, (int *) 0, LA_SSLPROTO },
+ {"sslcertck", no_argument, (int *) 0, LA_SSLCERTCK },
+ {"sslcertpath", required_argument, (int *) 0, LA_SSLCERTPATH },
+ {"sslfingerprint", required_argument, (int *) 0, LA_SSLFINGERPRINT },
#endif
{"principal", required_argument, (int *) 0, LA_PRINCIPAL },
@@ -568,6 +574,18 @@ struct query *ctl; /* option record to be initialized */
case LA_SSLPROTO:
ctl->sslproto = xstrdup(optarg);
break;
+
+ case LA_SSLCERTCK:
+ ctl->sslcertck = FLAG_TRUE;
+ break;
+
+ case LA_SSLCERTPATH:
+ ctl->sslcertpath = xstrdup(optarg);
+ break;
+
+ case LA_SSLFINGERPRINT:
+ ctl->sslfingerprint = xstrdup(optarg);
+ break;
#endif
case LA_PRINCIPAL:
diff --git a/rcfile_l.l b/rcfile_l.l
index 3d4040d5..18ac7278 100644
--- a/rcfile_l.l
+++ b/rcfile_l.l
@@ -166,6 +166,9 @@ ssl { return SSL; }
sslkey { return SSLKEY; }
sslcert { return SSLCERT; }
sslproto { return SSLPROTO; }
+sslcertck { return SSLCERTCK; }
+sslcertpath { return SSLCERTPATH; }
+sslfingerprint { return SSLFINGERPRINT; }
checkalias { return CHECKALIAS; }
limit { return LIMIT; }
diff --git a/rcfile_y.y b/rcfile_y.y
index dfe8ec87..ba17b9b9 100644
--- a/rcfile_y.y
+++ b/rcfile_y.y
@@ -73,7 +73,7 @@ extern char * yytext;
%token NO KEEP FLUSH FETCHALL REWRITE FORCECR STRIPCR PASS8BITS
%token DROPSTATUS DROPDELIVERED
%token DNS SERVICE PORT UIDL INTERVAL MIMEDECODE IDLE CHECKALIAS
-%token SSL SSLKEY SSLCERT SSLPROTO
+%token SSL SSLKEY SSLCERT SSLPROTO SSLCERTCK SSLCERTPATH SSLFINGERPRINT
%token PRINCIPAL
%%
@@ -331,6 +331,9 @@ user_option : TO localnames HERE
| SSLKEY STRING {current.sslkey = xstrdup($2);}
| SSLCERT STRING {current.sslcert = xstrdup($2);}
| SSLPROTO STRING {current.sslproto = xstrdup($2);}
+ | SSLCERTCK {current.sslcertck = FLAG_TRUE;}
+ | SSLCERTPATH STRING {current.sslcertpath = xstrdup($2);}
+ | SSLFINGERPRINT STRING {current.sslfingerprint = xstrdup($2);}
| NO KEEP {current.keep = FLAG_FALSE;}
| NO FLUSH {current.flush = FLAG_FALSE;}
diff --git a/socket.c b/socket.c
index d96743c8..e84211d8 100644
--- a/socket.c
+++ b/socket.c
@@ -638,6 +638,10 @@ int SockPeek(int sock)
#ifdef SSL_ENABLE
static char *_ssl_server_cname = NULL;
+static int _check_fp;
+static char *_check_digest;
+static char *_server_label;
+static int _depth0ck;
SSL *SSLGetContext( int sock )
{
@@ -651,7 +655,7 @@ SSL *SSLGetContext( int sock )
}
-int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx )
+int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict )
{
char buf[260];
char cbuf[260];
@@ -659,19 +663,24 @@ int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx )
char *str_ptr;
X509 *x509_cert;
int err, depth;
+ unsigned char digest[EVP_MAX_MD_SIZE];
+ char text[EVP_MAX_MD_SIZE * 3 + 1], *tp, *te;
+ EVP_MD *digest_tp;
+ unsigned int dsz, i, esz;
x509_cert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
- X509_NAME_oneline(X509_get_subject_name(x509_cert), buf, 256);
- X509_NAME_oneline(X509_get_issuer_name(x509_cert), ibuf, 256);
-
- /* Just to be sure those buffers are terminated... I think the
- X509 libraries do, but... */
- buf[256] = ibuf[256] = '\0';
-
if (depth == 0) {
+ _depth0ck = 1;
+
+ X509_NAME_oneline(X509_get_subject_name(x509_cert), buf, 256);
+ X509_NAME_oneline(X509_get_issuer_name(x509_cert), ibuf, 256);
+
+ /* Just to be sure those buffers are terminated... I think the
+ X509 libraries do, but... */
+ buf[256] = ibuf[256] = '\0';
if( ( str_ptr = strstr( ibuf, "/O=" ) ) ) {
str_ptr += 3;
strcpy( cbuf, str_ptr );
@@ -705,57 +714,110 @@ int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx )
if (outlevel == O_VERBOSE)
report(stdout, _("Server CommonName: %s\n"), cbuf);
- if (_ssl_server_cname != NULL)
- {
- char *p1 = cbuf;
- char *p2 = _ssl_server_cname;
- int n;
-
- if (*p1 == '*')
- {
- ++p1;
- n = strlen(p2) - strlen(p1);
- if (n >= 0)
- p2 += n;
- }
- if ( 0 != strcasecmp( p1, p2 ) )
- report(stdout,
- "Server CommonName mismatch: %s != %s\n",
- cbuf, _ssl_server_cname );
+ if (_ssl_server_cname != NULL)
+ {
+ char *p1 = cbuf;
+ char *p2 = _ssl_server_cname;
+ int n;
+
+ if (*p1 == '*')
+ {
+ ++p1;
+ n = strlen(p2) - strlen(p1);
+ if (n >= 0)
+ p2 += n;
+ }
+ if ( 0 != strcasecmp( p1, p2 ) ) {
+ report(stderr,
+ _("Server CommonName mismatch: %s != %s\n"),
+ cbuf, _ssl_server_cname );
+ if (ok_return && strict)
+ return( 0 );
+ }
+ } else if (ok_return && strict) {
+ report(stderr, _("Canonical server name not set, could not verify certificate!\n"));
+ return( 0 );
}
} else {
if (outlevel == O_VERBOSE)
report(stdout, _("Unknown Server CommonName\n"));
+ if (ok_return && strict) {
+ report(stderr, _("Server name not specified in certificate!\n"));
+ return( 0 );
+ }
+ }
+ /* Print the finger print. Note that on errors, we might print it more than once
+ * normally; we kluge around that by using a global variable. */
+ if (_check_fp) {
+ _check_fp = 0;
+ digest_tp = EVP_md5();
+ if (digest_tp == NULL) {
+ report(stderr, _("EVP_md5() failed!\n"));
+ return( 0 );
+ }
+ if (!X509_digest(x509_cert, digest_tp, digest, &dsz)) {
+ report(stderr, _("out of memory!\n"));
+ return( 0 );
+ }
+ tp = text;
+ te = text + sizeof(text);
+ for (i = 0; i < dsz; i++) {
+ esz = snprintf(tp, te - tp, i > 0 ? ":%02X" : "%02X", digest[i]);
+ if (esz >= te - tp) {
+ report(stderr, _("Digest text buffer too small!\n"));
+ return( 0 );
+ }
+ tp += esz;
+ }
+ report(stdout, _("%s key fingerprint: %s\n"), _server_label, text);
+ if (_check_digest != NULL) {
+ if (strcmp(text, _check_digest) == 0)
+ report(stdout, _("%s fingerprints match.\n"), _server_label);
+ else {
+ report(stderr, _("%s fingerprints do not match!\n"), _server_label);
+ return( 0 );
+ }
+ }
}
}
- switch (ctx->error) {
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
- report(stdout, _("unknown issuer= %s"), buf);
- break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- report(stderr, _("Server Certificate not yet valid"));
- break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- report(stderr, _("Server Certificate expired"));
- break;
+ if (err != X509_V_OK && (strict || outlevel == O_VERBOSE)) {
+ report(strict ? stderr : stdout, _("Warning: server certificate verification: %s\n"), X509_verify_cert_error_string(err));
+ /* We gave the error code, but maybe we can add some more details for debugging */
+ switch (ctx->error) {
+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
+ buf[256] = '\0';
+ report(stdout, _("unknown issuer= %s\n"), buf);
+ break;
+ }
}
/* We are not requiring or validating server or issuer id's as yet */
/* Always return OK from here */
- ok_return = 1;
+ if (!strict)
+ ok_return = 1;
return( ok_return );
}
+int SSL_nock_verify_callback( int ok_return, X509_STORE_CTX *ctx )
+{
+ return SSL_verify_callback(ok_return, ctx, 0);
+}
+
+int SSL_ck_verify_callback( int ok_return, X509_STORE_CTX *ctx )
+{
+ return SSL_verify_callback(ok_return, ctx, 1);
+}
/* performs initial SSL handshake over the connected socket
* uses SSL *ssl global variable, which is currently defined
* in this file
*/
-int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, char *servercname )
+int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, int certck, char *certpath,
+ char *fingerprint, char *servercname, char *label)
{
+ SSL *ssl;
+
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
@@ -787,6 +849,16 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, char *servercnam
return(-1);
}
}
+
+ if (certck) {
+ SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, SSL_ck_verify_callback);
+ if (certpath)
+ SSL_CTX_load_verify_locations(_ctx, NULL, certpath);
+ } else {
+ /* In this case, we do not fail if verification fails. However,
+ * we provide the callback for output and possible fingerprint checks. */
+ SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, SSL_nock_verify_callback);
+ }
_ssl_context[sock] = SSL_new(_ctx);
@@ -797,8 +869,10 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, char *servercnam
/* This static is for the verify callback */
_ssl_server_cname = servercname;
-
- SSL_CTX_set_verify(_ctx, SSL_VERIFY_PEER, SSL_verify_callback);
+ _server_label = label;
+ _check_fp = 1;
+ _check_digest = fingerprint;
+ _depth0ck = 0;
if( mycert || mykey ) {
@@ -820,7 +894,19 @@ int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, char *servercnam
ERR_print_errors_fp(stderr);
return(-1);
}
-
+
+ /* Paranoia: was the callback not called as we expected? */
+ if ((fingerprint != NULL || certck) && !_depth0ck) {
+ report(stderr, _("Certificate/fingerprint verification was somehow skipped!\n"));
+
+ if( NULL != ( ssl = SSLGetContext( sock ) ) ) {
+ /* Clean up the SSL stack */
+ SSL_free( _ssl_context[sock] );
+ _ssl_context[sock] = NULL;
+ }
+ return(-1);
+ }
+
return(0);
}
#endif
diff --git a/socket.h b/socket.h
index 230345de..c530a8e4 100644
--- a/socket.h
+++ b/socket.h
@@ -59,7 +59,8 @@ additional clean-up if necessary.
int SockClose(int sock);
#if SSL_ENABLE
-int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, char *servercname);
+int SSLOpen(int sock, char *mycert, char *mykey, char *myproto, int certck, char *certpath,
+ char *fingerprint, char *servercname, char *label);
#endif /* SSL_ENABLE */
#endif /* SOCKET__ */
diff --git a/todo.html b/todo.html
index 6e13b8c4..13f30a7c 100644
--- a/todo.html
+++ b/todo.html
@@ -10,7 +10,7 @@
<table width="100%" cellpadding=0><tr>
<td width="30%">Back to <a href="/~esr">Eric's Home Page</a>
<td width="30%" align=center>Up to <a href="/~esr/sitemap.html">Site Map</a>
-<td width="30%" align=right>$Date: 2001/02/19 17:32:34 $
+<td width="30%" align=right>$Date: 2001/05/14 06:54:37 $
</table>
<HR>
<H1 ALIGN=CENTER>Fetchmail Bugs and To-Do Items</H1>
@@ -41,9 +41,7 @@ some kind of character sign-extension problem. Trouble is, it's very
likely in the BIND libraries. Someone should go in with a debugger
and check this.<p>
-In the SSL support, we need to add server certificate validation (In
-other words, does the certificate match the system we are trying to
-contact?). Also, add authentication of Certifying Authority (Is this
+In the SSL support, add authentication of Certifying Authority (Is this
a Certifying Authority we recognize?).<p>
Laszlo Vecsey writes: "I believe qmail uses a technique of writing
@@ -65,7 +63,7 @@ bug-tracking page for fetchmail</a> lists other bug reports.<p>
<table width="100%" cellpadding=0><tr>
<td width="30%">Back to <a href="/~esr">Eric's Home Page</a>
<td width="30%" align=center>Up to <a href="/~esr/sitemap.html">Site Map</a>
-<td width="30%" align=right>$Date: 2001/02/19 17:32:34 $
+<td width="30%" align=right>$Date: 2001/05/14 06:54:37 $
</table>
<P><ADDRESS>Eric S. Raymond <A HREF="mailto:esr@thyrsus.com">&lt;esr@thyrsus.com&gt;</A></ADDRESS>