src/tls/tls.h, src/tls/tls_client.c, src/tls/tls_fprint.c,
src/tls/tls_level.c, src/tls/tls_misc.c, src/tls/tls_server.c,
src/tls/tls_verify.c, src/tlsproxy/tlsproxy.c.
+
+20130327
+
+ Cleanup: final polish for MacOSX workarounds; replaced
+ #ifdef MacOSX by feature test as required by PORTING
+ document. Files: util/poll_fd.c, util/open_limit.c.
+
+ Export tls_fprint() and tls_digest_encode() for use in DANE.
+ Viktor Dukhovni. Files: src/tls/tls.h, src/tls/tls_fprint.c.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20130326"
+#define MAIL_RELEASE_DATE "20130327"
#define MAIL_VERSION_NUMBER "2.11"
#ifdef SNAPSHOT
/*
* tls_fprint.c
*/
+extern char *tls_digest_encode(const unsigned char *, int);
+extern char *tls_fprint(const char *, int, const char *);
extern char *tls_fingerprint(X509 *, const char *);
extern char *tls_pkey_fprint(X509 *, const char *);
extern char *tls_serverid_digest(const TLS_CLIENT_START_PROPS *, long,
/* SYNOPSIS
/* #include <tls.h>
/*
-/* char *tls_serverid_digest(props, protomask, ciphers);
+/* char *tls_serverid_digest(props, protomask, ciphers)
/* const TLS_CLIENT_START_PROPS *props;
/* long protomask;
/* const char *ciphers;
/*
+/* char *tls_digest_encode(md_buf, md_len)
+/* const unsigned char *md_buf;
+/* const char *md_len;
+/*
+/* char *tls_fprint(buf, len, mdalg)
+/* const char *buf;
+/* int len;
+/* const char *mdalg;
+/*
/* char *tls_fingerprint(peercert, mdalg)
/* X509 *peercert;
/* const char *mdalg;
/* X509 *peercert;
/* const char *mdalg;
/* DESCRIPTION
+/* tls_digest_encode() converts a binary message digest to a hex ASCII
+/* format with ':' separators between each pair of hex digits.
+/* The return value is dynamically allocated with mymalloc(),
+/* and the caller must eventually free it with myfree().
+/*
+/* tls_fprint() digests unstructured data, and encodes the digested
+/* result via tls_digest_encode().
+/* The return value is dynamically allocated with mymalloc(),
+/* and the caller must eventually free it with myfree().
+/*
/* tls_fingerprint() returns a fingerprint of the the given
-/* certificate using the requested message digest. Panics if the
+/* certificate using the requested message digest, formatted
+/* with tls_digest_encode(). Panics if the
/* (previously verified) digest algorithm is not found. The return
/* value is dynamically allocated with mymalloc(), and the caller
/* must eventually free it with myfree().
/* other respects the function behaves as tls_fingerprint().
/* The var_tls_bc_pkey_fprint variable enables an incorrect
/* algorithm that was used in Postfix versions 2.9.[0-5].
+/* The return value is dynamically allocated with mymalloc(),
+/* and the caller must eventually free it with myfree().
/*
/* tls_serverid_digest() suffixes props->serverid computed by the SMTP
-/* client with a digest of additional parameters needed to ensure
-/* that re-used sessions are more likely to be reused and will satisfy
-/* all protocol and security requirements. The caller should pass
-/* the result to myfree().
+/* client with ":" plus a digest of additional parameters
+/* needed to ensure that re-used sessions are more likely to
+/* be reused and that they will satisfy all protocol and
+/* security requirements.
+/* The return value is dynamically allocated with mymalloc(),
+/* and the caller must eventually free it with myfree().
/*
/* Arguments:
/* .IP peercert
/* Server or client X.509 certificate.
+/* .IP md_buf
+/* The raw binary digest.
+/* .IP md_len
+/* The digest length in bytes.
/* .IP mdalg
/* Name of a message digest algorithm suitable for computing secure
/* (1st pre-image resistant) message digests of certificates. For now,
/* md5, sha1, or member of SHA-2 family if supported by OpenSSL.
+/* .IP buf
+/* Input data for the message digest algorithm mdalg.
+/* .IP len
+/* The length of the input data.
/* .IP props
/* The client start properties for the session, which include the
/* initial serverid from the SMTP client.
return (vstring_export(result));
}
+/* tls_digest_encode - encode message digest binary blob as xx:xx:... */
+
+char *tls_digest_encode(const unsigned char *md_buf, int md_len)
+{
+ int i;
+ char *result = mymalloc(md_len * 3);
+
+ /* Check for contract violation */
+ if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
+ msg_panic("unexpectedly large message digest size: %u", md_len);
+
+ /* No risk of overrunes, len is bounded by OpenSSL digest length */
+ for (i = 0; i < md_len; i++) {
+ result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
+ result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
+ result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
+ }
+ return (result);
+}
+
/* tls_fprint - compute and encode digest of DER-encoded object */
-static char *tls_fprint(const char *buf, int len, const char *mdalg)
+char *tls_fprint(const char *buf, int len, const char *mdalg)
{
EVP_MD_CTX *mdctx;
const EVP_MD *md;
if (!ok)
msg_fatal("error computing %s message digest", mdalg);
- /* Check for OpenSSL contract violation */
- if (md_len > EVP_MAX_MD_SIZE || md_len >= INT_MAX / 3)
- msg_panic("unexpectedly large %s digest size: %u", mdalg, md_len);
-
- result = mymalloc(md_len * 3);
- for (i = 0; i < md_len; i++) {
- result[i * 3] = hexcodes[(md_buf[i] & 0xf0) >> 4U];
- result[(i * 3) + 1] = hexcodes[(md_buf[i] & 0x0f)];
- result[(i * 3) + 2] = (i + 1 != md_len) ? ':' : '\0';
- }
- return (result);
+ return (tls_digest_encode(md_buf, md_len));
}
/* tls_fingerprint - extract certificate fingerprint */
#include <sys/resource.h>
#include <errno.h>
-#ifdef MACOSX
+#ifdef USE_MAX_FILES_PER_PROC
#include <sys/sysctl.h>
#define MAX_FILES_PER_PROC "kern.maxfilesperproc"
#endif
* MacOSX incorrectly reports rlim_max as RLIM_INFINITY. The true
* hard limit is finite and equals the kern.maxfilesperproc value.
*/
-#ifdef MACOSX
+#ifdef USE_MAX_FILES_PER_PROC
int max_files_per_proc;
size_t len = sizeof(max_files_per_proc);
/* int writable(fd)
/* int fd;
/*
-/* int read_wait(fd, timeout)
+/* int read_wait(fd, time_limit)
/* int fd;
-/* int timeout
+/* int time_limit;
/*
-/* int write_wait(fd, timeout)
+/* int write_wait(fd, time_limit)
/* int fd;
-/* int timeout
+/* int time_limit;
/*
/* int poll_fd(fd, request, time_limit, success_val)
/* int fd;
#include <unistd.h>
#include <string.h>
-#ifdef USE_SYSV_POLL
-#include <poll.h>
-#endif
-
-#ifdef USE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-/* Utility library. */
-
-#include <msg.h>
-#include <iostuff.h>
+ /*
+ * Use poll() with fall-back to select(). MacOSX needs this for devices.
+ */
+#if defined(USE_SYSV_POLL_THEN_SELECT)
+#define poll_fd_sysv poll_fd
+#define USE_SYSV_POLL
+#define USE_BSD_SELECT
+int poll_fd_bsd(int, int, int, int);
/*
* Use select() only.
*/
-#ifdef USE_BSD_SELECT
+#elif defined(USE_BSD_SELECT)
#define poll_fd_bsd poll_fd
#undef USE_SYSV_POLL
-#undef USE_SYSV_POLL_WITH_SELECT
-#endif
/*
* Use poll() only.
*/
-#ifdef USE_SYSV_POLL
+#elif defined(USE_SYSV_POLL)
#define poll_fd_sysv poll_fd
-#undef USE_SYSV_POLL_WITH_SELECT
-#endif
/*
- * Use poll() with fall-back to select(). MacOSX needs this for devices.
+ * Sanity check.
*/
-#ifdef USE_SYSV_POLL_WITH_SELECT
-#define poll_fd_sysv poll_fd
-#define USE_SYSV_POLL
-#define USE_BSD_SELECT
-int poll_fd_bsd(int, int, int, int);
+#else
+#error "specify USE_SYSV_POLL, USE_BSD_SELECT or USE_SYSV_POLL_THEN_SELECT"
+#endif
+#ifdef USE_SYSV_POLL
+#include <poll.h>
#endif
- /*
- * Sanity check.
- */
-#if !defined(USE_BSD_SELECT) && !defined(USE_SYSV_POLL)
-#error "specify USE_BSD_SELECT, USE_SYSV_POLL or USE_SYSV_POLL_WITH_SELECT"
+#ifdef USE_SYS_SELECT_H
+#include <sys/select.h>
#endif
+/* Utility library. */
+
+#include <msg.h>
+#include <iostuff.h>
+
#ifdef USE_BSD_SELECT
/* poll_fd_bsd - block with time_limit until file descriptor is ready */
/*
* Use select() so we do not depend on alarm() and on signal() handlers.
- * Restart the select when interrupted by some signal. Some select()
+ * Restart select() when interrupted by some signal. Some select()
* implementations reduce the time to wait when interrupted, which is
* exactly what we want.
*/
#ifdef USE_SYSV_POLL
+#ifdef USE_SYSV_POLL_THEN_SELECT
+#define HANDLE_SYSV_POLL_ERROR(fd, request, time_limit, success_val) \
+ return (poll_fd_bsd((fd), (request), (time_limit), (success_val)))
+#else
+#define HANDLE_SYSV_POLL_ERROR(fd, request, time_limit, success_val) \
+ msg_fatal("poll: %m")
+#endif
+
/* poll_fd_sysv - block with time_limit until file descriptor is ready */
int poll_fd_sysv(int fd, int request, int time_limit, int success_val)
#define WAIT_FOR_EVENT (-1)
pollfd.fd = fd;
- if (request == POLL_FD_READ)
+ if (request == POLL_FD_READ) {
pollfd.events = POLLIN;
- else if (request == POLL_FD_WRITE)
+ } else if (request == POLL_FD_WRITE) {
pollfd.events = POLLOUT;
- else
+ } else {
msg_panic("poll_fd: bad request %d", request);
+ }
for (;;) {
switch (poll(&pollfd, 1, time_limit < 0 ?
WAIT_FOR_EVENT : time_limit * 1000)) {
case -1:
if (errno != EINTR)
-#ifdef USE_SYSV_POLL_WITH_SELECT
- return (poll_fd_bsd(fd, request, time_limit, success_val));
-#else
- msg_fatal("poll: %m");
-#endif
+ HANDLE_SYSV_POLL_ERROR(fd, request, time_limit, success_val);
continue;
case 0:
if (time_limit == 0) {
}
default:
if (pollfd.revents & POLLNVAL)
- msg_fatal("poll: %m");
+ HANDLE_SYSV_POLL_ERROR(fd, request, time_limit, success_val);
return (success_val);
}
}
#define SOCKOPT_SIZE socklen_t
#ifndef NO_KQUEUE
# define EVENTS_STYLE EVENTS_STYLE_KQUEUE
-# define USE_SYSV_POLL_WITH_SELECT
+# define USE_SYSV_POLL_THEN_SELECT
#endif
+#define USE_MAX_FILES_PER_PROC
#ifndef NO_POSIX_GETPW_R
# define HAVE_POSIX_GETPW_R
#endif
#if !defined(EVENTS_STYLE)
#define EVENTS_STYLE EVENTS_STYLE_SELECT
#endif
-#if !defined(USE_SYSV_POLL) && !defined(USE_SYSV_POLL_WITH_SELECT)
-#define USE_BSD_SELECT
-#endif
#define EVENTS_STYLE_SELECT 1 /* Traditional BSD select */
#define EVENTS_STYLE_KQUEUE 2 /* FreeBSD kqueue */
#define EVENTS_STYLE_DEVPOLL 3 /* Solaris /dev/poll */
#define EVENTS_STYLE_EPOLL 4 /* Linux epoll */
+ /*
+ * We use poll() for read/write time limit enforcement on modern systems. We
+ * use select() on historical systems without poll() support. And on systems
+ * where poll() is not implemented for some file handle types, we try to use
+ * select() as a fall-back solution (MacOS X needs this).
+ */
+#if !defined(USE_SYSV_POLL) && !defined(USE_SYSV_POLL_THEN_SELECT)
+#define USE_BSD_SELECT
+#endif
+
/*
* The Postfix 2.9 post-install workaround assumes that the inet_protocols
* default value is "ipv4" when Postfix is compiled without IPv6 support.