diff options
author | Eric S. Raymond <esr@thyrsus.com> | 2001-05-14 06:54:37 +0000 |
---|---|---|
committer | Eric S. Raymond <esr@thyrsus.com> | 2001-05-14 06:54:37 +0000 |
commit | c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab (patch) | |
tree | 0bf23b7047e5dfb584f97a32db1e1714304fcaf4 | |
parent | c346e09c465f8365b8d91041f10f56f3c8227213 (diff) | |
download | fetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.tar.gz fetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.tar.bz2 fetchmail-c5a58c018e5a8207bd39a63aedcd8ef206c9d8ab.zip |
SSL certification handling.
svn path=/trunk/; revision=3314
-rw-r--r-- | Makefile.in | 6 | ||||
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | conf.c | 3 | ||||
-rw-r--r-- | driver.c | 3 | ||||
-rw-r--r-- | fetchmail.c | 13 | ||||
-rw-r--r-- | fetchmail.h | 3 | ||||
-rw-r--r-- | fetchmail.man | 28 | ||||
-rwxr-xr-x | fetchmailconf | 30 | ||||
-rw-r--r-- | options.c | 22 | ||||
-rw-r--r-- | rcfile_l.l | 3 | ||||
-rw-r--r-- | rcfile_y.y | 5 | ||||
-rw-r--r-- | socket.c | 172 | ||||
-rw-r--r-- | socket.h | 3 | ||||
-rw-r--r-- | todo.html | 8 |
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 \ @@ -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 @@ -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); @@ -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) @@ -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: @@ -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; } @@ -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;} @@ -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 @@ -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__ */ @@ -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"><esr@thyrsus.com></A></ADDRESS> |