]> git.pld-linux.org Git - packages/postfix.git/commitdiff
- obsolete
authorTomek Orzechowski <orzech@pld-linux.org>
Mon, 13 Jan 2003 10:08:34 +0000 (10:08 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    postfix-IPv6.patch -> 1.2
    postfix-glibc.patch -> 1.2
    postfix-ldap2.patch -> 1.2
    postfix-script.patch -> 1.2
    postfix-ssl.patch -> 1.2
    postfix-virtual.patch -> 1.2

postfix-IPv6.patch [deleted file]
postfix-glibc.patch [deleted file]
postfix-ldap2.patch [deleted file]
postfix-script.patch [deleted file]
postfix-ssl.patch [deleted file]
postfix-virtual.patch [deleted file]

diff --git a/postfix-IPv6.patch b/postfix-IPv6.patch
deleted file mode 100644 (file)
index 5d04a52..0000000
+++ /dev/null
@@ -1,738 +0,0 @@
---- postfix-19990906-pl08/global/mynetworks.c.wiget    Fri Dec 11 19:55:22 1998
-+++ postfix-19990906-pl08/global/mynetworks.c  Wed Dec  1 13:01:35 1999
-@@ -43,12 +43,20 @@
- #include <msg.h>
- #include <vstring.h>
- #include <inet_addr_list.h>
-+#ifdef INET6
-+#include <sys/socket.h>
-+#include <netinet/in.h>
-+#endif
- /* Global library. */
- #include <own_inet_addr.h>
- #include <mynetworks.h>
-+#ifdef INET6
-+char ntop_buf[INET6_ADDRSTRLEN];
-+#endif
-+
- /* mynetworks - return patterns that match my own networks */
- const char *mynetworks(void)
-@@ -63,12 +71,24 @@
-       struct in_addr net;
-       int     shift;
-       int     i;
-+#ifdef INET6
-+      struct sockaddr_storage *sa;
-+#endif
-       result = vstring_alloc(20);
-       my_addr_list = own_inet_addr_list();
-       for (i = 0; i < my_addr_list->used; i++) {
-+#ifdef INET6
-+          if (my_addr_list->addrs[i].__ss_family!=AF_INET) {
-+              vstring_sprintf_append(result, "XAATODOmynetworks ");
-+              continue;
-+          }
-+          sa = my_addr_list->addrs+i;
-+          addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
-+#else
-           addr = ntohl(my_addr_list->addrs[i].s_addr);
-+#endif
-           if (IN_CLASSA(addr)) {
-               mask = IN_CLASSA_NET;
-               shift = IN_CLASSA_NSHIFT;
-@@ -82,8 +102,15 @@
-               mask = IN_CLASSD_NET;
-               shift = IN_CLASSD_NSHIFT;
-           } else {
-+#ifdef INET6
-+              if (inet_ntop(sa->__ss_family, sa, ntop_buf, sizeof(ntop_buf)))
-+                  msg_fatal("%s: bad address class: %s", myname, ntop_buf);
-+              else
-+                  msg_fatal("%s: bad address class: ???", myname);
-+#else
-               msg_fatal("%s: bad address class: %s",
-                         myname, inet_ntoa(my_addr_list->addrs[i]));
-+#endif
-           }
-           net.s_addr = htonl(addr & mask);
-           vstring_sprintf_append(result, "%s/%d ",
---- postfix-19990906-pl08/global/own_inet_addr.c.wiget Tue Dec 15 01:37:31 1998
-+++ postfix-19990906-pl08/global/own_inet_addr.c       Wed Dec  1 13:01:35 1999
-@@ -99,6 +99,23 @@
- /* own_inet_addr - is this my own internet address */
-+#ifdef INET6
-+int     own_inet_addr(struct sockaddr_storage * addr)
-+{
-+    int     i;
-+
-+    if (addr_list.used == 0)
-+      own_inet_addr_init(&addr_list);
-+
-+    for (i = 0; i < addr_list.used; i++)
-+      if (addr->__ss_family == addr_list.addrs[i].__ss_family) {
-+          if (!bcmp(addr->__ss_pad1, addr_list.addrs[i].__ss_pad1,
-+                    addr->__ss_len))
-+              return (1);
-+      }
-+    return (0);
-+}
-+#else
- int     own_inet_addr(struct in_addr * addr)
- {
-     int     i;
-@@ -111,6 +128,7 @@
-           return (1);
-     return (0);
- }
-+#endif
- /* own_inet_addr_list - return list of addresses */
---- postfix-19990906-pl08/global/own_inet_addr.h.wiget Fri Dec 11 19:55:26 1998
-+++ postfix-19990906-pl08/global/own_inet_addr.h       Wed Dec  1 13:01:35 1999
-@@ -15,11 +15,18 @@
-   * System library.
-   */
- #include <netinet/in.h>
-+#ifdef INET6
-+#include <sys/socket.h>
-+#endif
-  /*
-   * External interface.
-   */
-+#ifdef INET6
-+extern int own_inet_addr(struct sockaddr_storage *);
-+#else
- extern int own_inet_addr(struct in_addr *);
-+#endif
- extern struct INET_ADDR_LIST *own_inet_addr_list(void);
- /* LICENSE
---- postfix-19990906-pl08/global/peer_name.c.wiget     Fri Dec 11 19:55:38 1998
-+++ postfix-19990906-pl08/global/peer_name.c   Wed Dec  1 13:01:35 1999
-@@ -54,6 +54,11 @@
- #include <sys/param.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-+#ifdef INET6
-+#if (! __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 )
-+#include <netinet6/in6.h>
-+#endif
-+#endif
- #include <arpa/inet.h>
- #include <errno.h>
- #include <netdb.h>
-@@ -69,20 +74,46 @@
- PEER_NAME *peer_name(int sock)
- {
-     static PEER_NAME peer;
--    struct sockaddr_in sin;
--    SOCKADDR_SIZE len = sizeof(sin);
-+    union sockunion {
-+      struct {
-+          u_char si_len;
-+          u_char si_family;
-+          u_short si_port;
-+      } su_si;
-+      struct sockaddr peer_un;
-+      struct sockaddr_in peer_un4;
-+#ifdef INET6
-+      struct sockaddr_in6 peer_un6;
-+#endif
-+    } p_un;
-+#define sin  p_un.peer_un
-+#define sin4 p_un.peer_un4
-+#ifdef INET6
-+#define sin6 p_un.peer_un6
-+    char ntop_buf[INET6_ADDRSTRLEN];
-+#endif
-+    SOCKADDR_SIZE len = sizeof(p_un);
-     struct hostent *hp;
--    if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) {
--      switch (sin.sin_family) {
-+    if (getpeername(sock, (struct sockaddr *)& p_un, &len) == 0) {
-+      switch (p_un.peer_un.sa_family) {
-       case AF_INET:
-           peer.type = PEER_TYPE_INET;
--          hp = gethostbyaddr((char *) &(sin.sin_addr),
--                             sizeof(sin.sin_addr), AF_INET);
-+          hp = gethostbyaddr((char *) &(sin4.sin_addr),
-+                             sizeof(sin4.sin_addr), AF_INET);
-           peer.name = (hp && valid_hostname(hp->h_name) ?
-                        hp->h_name : "unknown");
--          peer.addr = inet_ntoa(sin.sin_addr);
-+          peer.addr = inet_ntoa(sin4.sin_addr);
-           return (&peer);
-+#ifdef INET6
-+      case AF_INET6:
-+          peer.type = PEER_TYPE_INET6;
-+          hp = gethostbyaddr((char *) &(sin6.sin6_addr),
-+                              sizeof(sin6.sin6_addr), AF_INET6);
-+          peer.name = (hp ? hp->h_name : "unknown");
-+          peer.addr = (char *)strdup(inet_ntop(AF_INET6, &sin6.sin6_addr, ntop_buf, sizeof(ntop_buf)));
-+          return (&peer);
-+#endif
-       case AF_UNSPEC:
-       case AF_UNIX:
-           peer.type = PEER_TYPE_LOCAL;
---- postfix-19990906-pl08/global/peer_name.h.wiget     Fri Dec 11 19:55:32 1998
-+++ postfix-19990906-pl08/global/peer_name.h   Wed Dec  1 13:01:35 1999
-@@ -22,6 +22,9 @@
- #define PEER_TYPE_UNKNOWN     0
- #define PEER_TYPE_INET                1
- #define PEER_TYPE_LOCAL               2
-+#ifdef INET6
-+#define PEER_TYPE_INET6               3
-+#endif
- extern PEER_NAME *peer_name(int);
---- postfix-19990906-pl08/smtpd/smtpd_check.c.wiget    Wed Dec  1 13:01:35 1999
-+++ postfix-19990906-pl08/smtpd/smtpd_check.c  Wed Dec  1 13:01:35 1999
-@@ -604,7 +604,11 @@
-       msg_info("%s: %s", myname, name);
-     dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
--                                (VSTRING *) 0, T_A, T_MX, 0);
-+                                (VSTRING *) 0, T_A, T_MX,
-+#ifdef INET6
-+                                T_AAAA,
-+#endif
-+                                0);
-     if (dns_status != DNS_OK)
-       return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
-                                  "%d <%s>: %s rejected: Host not found",
-@@ -626,7 +630,11 @@
-       msg_info("%s: %s", myname, name);
-     dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0,
--                                (VSTRING *) 0, T_A, T_MX, 0);
-+                                (VSTRING *) 0, T_A, T_MX,
-+#ifdef INET6
-+                                T_AAAA,
-+#endif
-+                                0);
-     if (dns_status != DNS_OK)
-       return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
-                                  "%d <%s>: %s rejected: Domain not found",
---- postfix-19990906-pl08/util/inet_addr_list.c.wiget  Fri Dec 11 19:55:36 1998
-+++ postfix-19990906-pl08/util/inet_addr_list.c        Wed Dec  1 13:01:35 1999
-@@ -44,24 +44,58 @@
- #include <netinet/in.h>
- #include <arpa/inet.h>
-+#ifdef INET6
-+#include <sys/socket.h>
-+#endif
-+
- /* Utility library. */
- #include <msg.h>
- #include <mymalloc.h>
- #include <inet_addr_list.h>
-+#ifdef INET6
-+    char ntop_buf[INET6_ADDRSTRLEN];
-+#endif
-+
- /* inet_addr_list_init - initialize internet address list */
- void    inet_addr_list_init(INET_ADDR_LIST *list)
- {
-     list->used = 0;
-     list->size = 2;
-+#ifdef INET6
-+    list->addrs = (struct sockaddr_storage *)
-+#else
-     list->addrs = (struct in_addr *)
-+#endif
-       mymalloc(sizeof(*list->addrs) * list->size);
- }
- /* inet_addr_list_append - append address to internet address list */
-+#ifdef INET6
-+void    inet_addr_list_append(INET_ADDR_LIST *list, 
-+                              struct sockaddr_storage * addr)
-+{
-+    char   *myname = "inet_addr_list_append";
-+
-+    if (msg_verbose > 1) {
-+        if (inet_ntop(addr->__ss_family,(struct sockaddr *)addr, 
-+                    ntop_buf, sizeof(ntop_buf)))
-+          msg_info("%s: %s", myname, ntop_buf);
-+      else
-+          msg_info("%s: ??????", myname);
-+    }
-+
-+    if (list->used >= list->size)
-+      list->size *= 2;
-+    list->addrs = (struct sockaddr_storage *)
-+      myrealloc((char *) list->addrs,
-+                sizeof(*list->addrs) * list->size);
-+    list->addrs[list->used++] = *addr;
-+}
-+#else
- void    inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr)
- {
-     char   *myname = "inet_addr_list_append";
-@@ -76,6 +110,7 @@
-                 sizeof(*list->addrs) * list->size);
-     list->addrs[list->used++] = *addr;
- }
-+#endif
- /* inet_addr_list_free - destroy internet address list */
---- postfix-19990906-pl08/util/inet_addr_list.h.wiget  Fri Dec 11 19:55:35 1998
-+++ postfix-19990906-pl08/util/inet_addr_list.h        Wed Dec  1 13:01:35 1999
-@@ -22,12 +22,20 @@
- typedef struct INET_ADDR_LIST {
-     int     used;                     /* nr of elements in use */
-     int     size;                     /* actual list size */
-+#ifdef INET6
-+    struct sockaddr_storage *addrs;   /* payload */
-+#else
-     struct in_addr *addrs;            /* payload */
-+#endif
- } INET_ADDR_LIST;
- extern void inet_addr_list_init(INET_ADDR_LIST *);
- extern void inet_addr_list_free(INET_ADDR_LIST *);
-+#ifdef INET6
-+extern void inet_addr_list_append(INET_ADDR_LIST *, struct sockaddr_storage *);
-+#else
- extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *);
-+#endif
- /* LICENSE
- /* .ad
---- postfix-19990906-pl08/util/inet_addr_local.c.wiget Fri Nov  5 15:05:26 1999
-+++ postfix-19990906-pl08/util/inet_addr_local.c       Wed Dec  1 13:01:35 1999
-@@ -138,6 +138,9 @@
- {
-     INET_ADDR_LIST addr_list;
-     int     i;
-+#ifdef INET6
-+    char buf[INET6_ADDRSTRLEN];
-+#endif
-     msg_vstream_init(argv[0], VSTREAM_ERR);
-@@ -151,7 +154,11 @@
-       msg_warn("found only one active network interface");
-     for (i = 0; i < addr_list.used; i++)
-+#ifdef #INET6
-+      vstream_printf("%s\n", net_ntop(AF_INET, addr_list.addrs[i]));
-+#else
-       vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i]));
-+#endif
-     vstream_fflush(VSTREAM_OUT);
-     inet_addr_list_free(&addr_list);
- }
---- postfix-19990906-pl08/util/inet_listen.c.wiget     Mon Mar 22 02:26:26 1999
-+++ postfix-19990906-pl08/util/inet_listen.c   Wed Dec  1 13:01:35 1999
-@@ -51,6 +51,11 @@
- #include <sys_defs.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-+#ifdef INET6
-+#if (! __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 )
-+#include <netinet6/in6.h>
-+#endif
-+#endif
- #include <arpa/inet.h>
- #include <netdb.h>
- #ifndef MAXHOSTNAMELEN
-@@ -79,7 +84,13 @@
- int     inet_listen(const char *addr, int backlog, int block_mode)
- {
-+#ifdef INET6
-+    struct sockaddr_in6 sin;
-+    struct addrinfo *ai,hints;
-+    int res;
-+#else
-     struct sockaddr_in sin;
-+#endif
-     int     sock;
-     int     t = 1;
-     char   *buf;
-@@ -90,22 +101,55 @@
-      * Translate address information to internal form.
-      */
-     buf = inet_parse(addr, &host, &port);
-+#ifdef INET6
-+    bzero((void *)&hints, sizeof(hints));
-+    hints.ai_flags = AI_PASSIVE;
-+    hints.ai_family = PF_INET6;
-+    hints.ai_socktype = SOCK_STREAM;
-+    if (res = getaddrinfo(NULL, "smtp", &hints, &ai)) {
-+      msg_fatal("Error getaddrinfo: %s", gai_strerror(res));
-+    }
-+/*
-+    sin.sin6_family = AF_INET6;
-+    sin.sin6_port = find_inet_port(port, "tcp");
-+    XAA:not yet....
-+    sin.sin6_addr.s6_addr = (*host ? find_inet_addr(host) : in6addr_any);
-+    sin.sin6_addr = in6addr_any;
-+*/
-+#else
-     memset((char *) &sin, 0, sizeof(sin));
-     sin.sin_family = AF_INET;
-     sin.sin_port = find_inet_port(port, "tcp");
-     sin.sin_addr.s_addr = (*host ? find_inet_addr(host) : INADDR_ANY);
-+#endif
-     myfree(buf);
-     /*
-      * Create a listener socket.
-      */
-+#ifdef INET6
-+    if ((sock = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
-+#else
-     if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
-+#endif
-       msg_fatal("socket: %m");
-     if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0)
-       msg_fatal("setsockopt: %m");
-+#ifdef INET6
-+    if (bind(sock, (struct sockaddr *) ai->ai_addr, ai->ai_addrlen) < 0)
-+    /* not yet XAA
-+      msg_fatal("bind %s port %d: %m", ai->ai_flags&AI_PASSIVE ?
-+             "IN6ADDR_ANY" : ai->ai_canonname, 
-+             ntohs(((struct sockaddr *)ai->ai_addr)->sin_port));
-+    */
-+      msg_fatal("bind %s: %m", ai->ai_flags&AI_PASSIVE ?
-+             "IN6ADDR_ANY" : ai->ai_canonname);
-+    freeaddrinfo(ai);
-+#else
-     if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
-       msg_fatal("bind %s port %d: %m", sin.sin_addr.s_addr == INADDR_ANY ?
-              "INADDR_ANY" : inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
-+#endif
-     non_blocking(sock, block_mode);
-     if (listen(sock, backlog) < 0)
-       msg_fatal("listen: %m");
---- postfix-19990906-pl08/smtp/smtp_addr.c.wiget       Mon Sep  6 05:11:07 1999
-+++ postfix-19990906-pl08/smtp/smtp_addr.c     Wed Dec  1 13:01:35 1999
-@@ -141,6 +141,7 @@
-     /*
-      * Interpret a numerical name as an address.
-      */
-+/* XAA TODO: check for numerical ipv6 address? */
-     if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
-       memset((char *) &fixed, 0, sizeof(fixed));
-       return (dns_rr_append(addr_list,
-@@ -153,6 +154,7 @@
-      */
-     if (var_disable_dns) {
-       memset((char *) &fixed, 0, sizeof(fixed));
-+/* TODO XAA, rewrite */
-       if ((hp = gethostbyname(host)) == 0) {
-           vstring_sprintf(why, "%s: host not found", host);
-           smtp_errno = SMTP_FAIL;
-@@ -176,7 +178,11 @@
-     /*
-      * Append the addresses for this host to the address list.
-      */
-+#ifdef INET6
-+    switch (dns_lookup_types(host, 0, &addr, (VSTRING *) 0, why, T_A, T_AAAA)) {/* XAA TODO: currently IPv6 and IPv4 are mixed in no order, ok? */
-+#else
-     switch (dns_lookup(host, T_A, 0, &addr, (VSTRING *) 0, why)) {
-+#endif
-     case DNS_OK:
-       for (rr = addr; rr; rr = rr->next)
-           rr->pref = pref;
-@@ -297,6 +303,9 @@
-     INET_ADDR_LIST *self;
-     DNS_RR *addr;
-     int     i;
-+#ifdef INET6
-+    struct sockaddr_storage *sa;
-+#endif
-     /*
-      * Find the first address that lists any address that this mail system is
-@@ -307,11 +316,30 @@
-     self = own_inet_addr_list();
-     for (addr = addr_list; addr; addr = addr->next) {
-       for (i = 0; i < self->used; i++)
-+#ifdef INET6
-+          switch(addr->type) {
-+              case T_A:
-+                  if (self->addrs[i].__ss_family==AF_INET) {
-+                      if (!bcmp(self->addrs[i].__ss_pad1, addr->data,
-+                                sizeof(struct in_addr)))
-+                          return(addr);
-+                  }
-+                  break;
-+              case T_AAAA:
-+                  if (self->addrs[i].__ss_family==AF_INET6) {
-+                      if (!bcmp(self->addrs[i].__ss_pad1, addr->data,
-+                                sizeof(struct in6_addr)))
-+                          return(addr);
-+                  }
-+                  break;
-+          }
-+#else
-           if (INADDRP(addr->data)->s_addr == self->addrs[i].s_addr) {
-               if (msg_verbose)
-                   msg_info("%s: found at pref %d", myname, addr->pref);
-               return (addr);
-           }
-+#endif
-     }
-     /*
---- postfix-19990906-pl08/smtp/smtp_connect.c.wiget    Wed Dec  1 13:01:35 1999
-+++ postfix-19990906-pl08/smtp/smtp_connect.c  Wed Dec  1 13:38:56 1999
-@@ -124,6 +124,10 @@
- {
-     char   *myname = "smtp_connect_addr";
-     struct sockaddr_in sin;
-+#ifdef INET6
-+    struct sockaddr_in6 sin6;
-+    char ntop_buf[INET6_ADDRSTRLEN];
-+#endif
-     int     sock;
-     INET_ADDR_LIST *addr_list;
-     int     conn_stat;
-@@ -135,7 +139,12 @@
-     /*
-      * Sanity checks.
-      */
-+#ifdef INET6
-+    if (((addr->type==T_A) && (addr->data_len > sizeof(sin.sin_addr))) ||
-+      ((addr->type==T_AAAA) && (addr->data_len >sizeof(sin6.sin6_addr)))) {
-+#else
-     if (addr->data_len > sizeof(sin.sin_addr)) {
-+#endif
-       msg_warn("%s: skip address with length %d", myname, addr->data_len);
-       smtp_errno = SMTP_RETRY;
-       return (0);
-@@ -144,11 +153,23 @@
-     /*
-      * Initialize.
-      */
--    memset((char *) &sin, 0, sizeof(sin));
--    sin.sin_family = AF_INET;
-+    switch(addr->type) {
-+      case T_A:
-+            memset((char *) &sin, 0, sizeof(sin));
-+            sin.sin_family = AF_INET;
-+            if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
-+              msg_fatal("%s: socket: %m", myname);
-+          break;
-+#ifdef INET6
-+      case T_AAAA:
-+          memset((char *) &sin6, 0, sizeof(sin6));
-+          sin6.sin6_family = AF_INET6;
-+          if ((sock = socket(sin6.sin6_family, SOCK_STREAM, 0)) < 0)
-+              msg_fatal("%s: socket: %m", myname);
-+          break;
-+#endif
-+    }
--    if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
--      msg_fatal("%s: socket: %m", myname);
-     /*
-      * When running as a virtual host, bind to the virtual interface so that
-@@ -171,21 +192,52 @@
-     /*
-      * Connect to the SMTP server.
-      */
--    sin.sin_port = port;
--    memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
-+    switch(addr->type) {
-+      case T_A:
-+            sin.sin_port = port;
-+          memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
-+          break;
-+#ifdef INET6
-+        case T_AAAA:
-+            sin6.sin6_port = port;
-+          memcpy((char *) &sin6.sin6_addr, addr->data, sizeof(sin6.sin6_addr));
-+          break;
-+#endif
-+    }
-     if (msg_verbose)
-       msg_info("%s: trying: %s/%s port %d...",
-                myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
-     if (var_smtp_conn_tmout > 0) {
-       non_blocking(sock, NON_BLOCKING);
--      conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
--                                sizeof(sin), var_smtp_conn_tmout);
-+      switch(addr->type) {
-+          case T_A:
-+              conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
-+                                        sizeof(sin), var_smtp_conn_tmout);
-+              break;
-+#ifdef INET6
-+          case T_AAAA:
-+              conn_stat = timed_connect(sock, (struct sockaddr *) & sin6,
-+                                        sizeof(sin6), var_smtp_conn_tmout);
-+              break;
-+#endif
-+      }
-       saved_errno = errno;
-       non_blocking(sock, BLOCKING);
-       errno = saved_errno;
-     } else {
--      conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin));
-+      switch (addr->type) {
-+          case T_A:
-+              conn_stat = connect(sock, (struct sockaddr *) & sin, 
-+                                  sizeof(sin));
-+              break;
-+#ifdef INET6
-+          case T_AAAA:
-+              conn_stat = connect(sock, (struct sockaddr *) & sin6, 
-+                                  sizeof(sin6));
-+              break;
-+#endif
-+      }
-     }
-     if (conn_stat < 0) {
-       vstring_sprintf(why, "connect to %s: %m", addr->name);
-@@ -227,10 +279,28 @@
-       return (0);
-     }
- #ifdef HAS_SSL
--    pfixtls_setfd(sock);
-+switch (addr->type) {
-+      case T_A:
-+              pfixtls_setfd(sock);
-+              break;
-+#ifdef INET6
-+/* FIXME no IPv6 support in TLS ? */          
-+      case T_AAAA:
-+              break;
-+#endif        
-+}
- #endif
-     vstream_ungetc(stream, ch);
--    return (smtp_session_alloc(dest, stream, addr->name, inet_ntoa(sin.sin_addr)));
-+    switch(addr->type) {
-+          case T_A:
-+                  return (smtp_session_alloc(dest, stream, addr->name,
-+                                          inet_ntoa(sin.sin_addr)));
-+#ifdef INET6              
-+          case T_AAAA:
-+              inet_ntop(AF_INET6, &sin6.sin6_addr, ntop_buf, sizeof(ntop_buf));
-+              return (smtp_session_alloc(dest, stream, addr->name,
-+                                      strdup(ntop_buf)));
-+#endif                
- }
- /* smtp_connect_host - direct connection to host */
---- postfix-19990906-pl08/smtp/smtp_unalias.c.wiget    Mon Jan 18 21:11:49 1999
-+++ postfix-19990906-pl08/smtp/smtp_unalias.c  Wed Dec  1 13:01:35 1999
-@@ -83,7 +83,11 @@
-     if ((result = htable_find(cache, name)) == 0) {
-       fqdn = vstring_alloc(10);
-       if (dns_lookup_types(name, smtp_unalias_flags, (DNS_RR **) 0,
--                           fqdn, (VSTRING *) 0, T_MX, T_A, 0) != DNS_OK)
-+                           fqdn, (VSTRING *) 0, T_MX, T_A,
-+#ifdef INET6
-+                           T_AAAA,
-+#endif
-+                           0) != DNS_OK)
-           vstring_strcpy(fqdn, name);
-       htable_enter(cache, name, result = vstring_export(fqdn));
-     }
---- postfix-19990906-pl08/dns/dns_lookup.c.wiget       Sun Dec 20 02:38:29 1998
-+++ postfix-19990906-pl08/dns/dns_lookup.c     Wed Dec  1 13:01:35 1999
-@@ -129,6 +129,9 @@
- } DNS_REPLY;
- #define INET_ADDR_LEN 4               /* XXX */
-+#ifdef INET6
-+#define INET6_ADDR_LEN        16
-+#endif
- /* dns_query - query name server and pre-parse the reply */
-@@ -285,6 +288,19 @@
-       memcpy(temp, pos, fixed->length);
-       data_len = fixed->length;
-       break;
-+#ifdef INET6
-+    case T_AAAA:
-+      if (fixed->length != INET6_ADDR_LEN) {
-+          msg_warn("extract_answer: bad IPv6 address length: %d", fixed->length);
-+          return (0);
-+      }
-+      if (fixed->length > sizeof(temp))
-+          msg_panic("dns_get_rr: length %d > DNS_NAME_LEN",
-+                    fixed->length);
-+      memcpy(temp, pos, fixed->length);
-+      data_len = fixed->length;
-+      break;
-+#endif
-     }
-     return (dns_rr_create(rr_name, fixed, pref, temp, data_len));
- }
---- postfix-19990906-pl08/master/master_listen.c.wiget Mon Mar 22 02:32:59 1999
-+++ postfix-19990906-pl08/master/master_listen.c       Wed Dec  1 13:01:35 1999
-@@ -63,6 +63,10 @@
- #include "master.h"
-+#ifdef INET6
-+char ntop_buf[INET6_ADDRSTRLEN];
-+#endif 
-+
- /* master_listen_init - enable connection requests */
- void    master_listen_init(MASTER_SERV *serv)
-@@ -113,8 +117,17 @@
-           close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC);
-       } else {                                /* virtual */
-           for (n = 0; n < serv->listen_fd_count; n++) {
-+#ifdef INET6
-+              if (!inet_ntop(serv->addr_list.inet->addrs[n].__ss_family,
-+                             serv->addr_list.inet->addrs+n,
-+                             ntop_buf, sizeof(ntop_buf))) {
-+                  sprintf(ntop_buf, "?????");
-+              }
-+              end_point = concatenate(ntop_buf, ":", serv->name, (char *) 0);
-+#else
-               end_point = concatenate(inet_ntoa(serv->addr_list.inet->addrs[n]),
-                                       ":", serv->name, (char *) 0);
-+#endif
-               serv->listen_fd[n]
-                   = inet_listen(end_point, serv->max_proc > var_proc_limit ?
-                            serv->max_proc : var_proc_limit, NON_BLOCKING);
---- postfix-19990906-pl08/makedefs.wiget       Tue Aug 31 22:38:12 1999
-+++ postfix-19990906-pl08/makedefs     Wed Dec  1 13:01:35 1999
-@@ -72,6 +72,7 @@
-   FreeBSD.2*) SYSTYPE=FREEBSD2
-               ;;
-   FreeBSD.3*) SYSTYPE=FREEBSD3
-+              SYSLIBS="-L/usr/local/v6/lib -linet6"
-               ;;
-   FreeBSD.4*) SYSTYPE=FREEBSD4
-               ;;
-@@ -240,7 +241,7 @@
- ARFL  = $ARFL
- RANLIB        = $RANLIB
- SYSLIBS       = $AUXLIBS $SYSLIBS
--CC    = $CC $CCARGS
-+CC    = $CC $CCARGS -DINET6
- OPT   = $OPT
- DEBUG = $DEBUG
- AWK   = $AWK
diff --git a/postfix-glibc.patch b/postfix-glibc.patch
deleted file mode 100644 (file)
index 8407f60..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-diff -ur postfix-19990906-pl05/global/own_inet_addr.c postfix-19990906-pl05.old/global/own_inet_addr.c
---- postfix-19990906-pl05/global/own_inet_addr.c       Tue Oct 12 21:00:22 1999
-+++ postfix-19990906-pl05.old/global/own_inet_addr.c   Tue Oct 12 18:58:55 1999
-@@ -109,8 +109,8 @@
-     for (i = 0; i < addr_list.used; i++)
-       if (addr->__ss_family == addr_list.addrs[i].__ss_family) {
--          if (!bcmp(addr->__ss_pad1, addr_list.addrs[i].__ss_pad1,
--                    addr->__ss_len))
-+          if (!bcmp(addr->__ss_padding, addr_list.addrs[i].__ss_padding,
-+                    SA_LEN((struct sockaddr *)&addr)))
-               return (1);
-       }
-     return (0);
-diff -ur postfix-19990906-pl05/smtp/smtp_addr.c postfix-19990906-pl05.old/smtp/smtp_addr.c
---- postfix-19990906-pl05/smtp/smtp_addr.c     Tue Oct 12 21:00:23 1999
-+++ postfix-19990906-pl05.old/smtp/smtp_addr.c Tue Oct 12 19:10:21 1999
-@@ -320,14 +320,14 @@
-           switch(addr->type) {
-               case T_A:
-                   if (self->addrs[i].__ss_family==AF_INET) {
--                      if (!bcmp(self->addrs[i].__ss_pad1, addr->data,
-+                      if (!bcmp(self->addrs[i].__ss_padding, addr->data,
-                                 sizeof(struct in_addr)))
-                           return(addr);
-                   }
-                   break;
-               case T_AAAA:
-                   if (self->addrs[i].__ss_family==AF_INET6) {
--                      if (!bcmp(self->addrs[i].__ss_pad1, addr->data,
-+                      if (!bcmp(self->addrs[i].__ss_padding, addr->data,
-                                 sizeof(struct in6_addr)))
-                           return(addr);
-                   }
diff --git a/postfix-ldap2.patch b/postfix-ldap2.patch
deleted file mode 100644 (file)
index 2f17fbc..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
---- snapshot-20000924/src/util/dict_ldap.c.wiget       Sun May  7 23:59:29 2000
-+++ snapshot-20000924/src/util/dict_ldap.c     Mon Oct  2 17:34:39 2000
-@@ -136,6 +136,9 @@
-     char   *myname = "dict_ldap_connect";
-     void    (*saved_alarm) (int);
-     int     rc = 0;
-+#ifdef NSLDAP 
-+    LDAPMemCache *dircache;
-+#endif
-     dict_errno = 0;
-@@ -172,7 +175,16 @@
-      * Configure alias dereferencing for this connection. Thanks to Mike
-      * Mattice for this.
-      */
-+#if ( defined NSLDAP ) || ( defined LDAP_API_VERSION && LDAP_API_VERSION >= 2004 ) 
-+    rc = ldap_set_option(dict_ldap->ld, LDAP_OPT_DEREF,
-+                       (void*)&dict_ldap->dereference);
-+    if (rc != LDAP_SUCCESS) {
-+      msg_warn("%s: Unable to set LDAP_OPT_DEREF to %d: %d (%s)",
-+               myname, dict_ldap->dereference, rc, ldap_err2string(rc));
-+    }
-+#else
-     dict_ldap->ld->ld_deref = dict_ldap->dereference;
-+#endif
-     /*
-      * If this server requires a bind, do so. Thanks to Sam Tardieu for
-@@ -207,7 +219,26 @@
-               ("%s: Enabling %ld-byte cache for %s with %ld-second expiry",
-                myname, dict_ldap->cache_size, dict_ldap->ldapsource,
-                dict_ldap->cache_expiry);
--
-+#ifdef NSLDAP 
-+      rc = ldap_memcache_init(dict_ldap->cache_expiry, dict_ldap->cache_size,
-+                              NULL, NULL, &dircache);
-+      if (rc != LDAP_SUCCESS) {
-+          msg_warn
-+              ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
-+               myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
-+      } else {
-+          rc = ldap_memcache_set(dict_ldap->ld, dircache);
-+          if (rc != LDAP_SUCCESS) {
-+              msg_warn
-+                  ("%s: Unable to configure cache for %s: %d (%s) -- continuing",
-+                   myname, dict_ldap->ldapsource, rc, ldap_err2string(rc));
-+          } else {
-+              if (msg_verbose)
-+                  msg_info("%s: Caching enabled for %s",
-+                           myname, dict_ldap->ldapsource);
-+          }
-+      }
-+#else
-       rc = ldap_enable_cache(dict_ldap->ld, dict_ldap->cache_expiry,
-                              dict_ldap->cache_size);
-       if (rc != LDAP_SUCCESS) {
-@@ -219,6 +250,7 @@
-               msg_info("%s: Caching enabled for %s",
-                        myname, dict_ldap->ldapsource);
-       }
-+#endif
-     }
-     if (msg_verbose)
-       msg_info("%s: Cached connection handle for LDAP source %s",
-@@ -417,10 +449,24 @@
-           }
-           ldap_value_free(attr_values);
-       }
-+#ifdef NSLDAP
-+      rc = ldap_get_lderrno(dict_ldap->ld, NULL, NULL);
-+      if (rc != LDAP_SUCCESS)
-+          msg_warn
-+              ("%s: Had some trouble with entries returned by search: %s",
-+               myname, ldap_err2string(rc));
-+#elif ( defined LDAP_API_VERSION && LDAP_API_VERSION >= 2004 ) 
-+      ldap_get_option(dict_ldap->ld, LDAP_OPT_ERROR_NUMBER, &rc);
-+      if (rc != LDAP_SUCCESS)
-+              msg_warn
-+              ("%s: Had some trouble with entries returned by search: %s",
-+              myname, ldap_err2string(rc));
-+#else
-       if (dict_ldap->ld->ld_errno != LDAP_SUCCESS)
-           msg_warn
-               ("%s: Had some trouble with entries returned by search: %s",
-                myname, ldap_err2string(dict_ldap->ld->ld_errno));
-+#endif
-       if (msg_verbose)
-           msg_info("%s: Search returned %s", myname,
-                    VSTRING_LEN(result) >
diff --git a/postfix-script.patch b/postfix-script.patch
deleted file mode 100644 (file)
index 8318910..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
---- snapshot-20010329/conf/postfix-script-sgid.orig    Wed Apr 25 15:23:06 2001
-+++ snapshot-20010329/conf/postfix-script-sgid Wed Apr 25 15:24:08 2001
-@@ -171,7 +171,7 @@
-               -exec $WARN not owned by root: {} \;
-       find $daemon_directory/. $config_directory/. \
--              \( -perm -020 -o -perm -002 \) \
-+              \( -perm +020 -o -perm +002 \) \
-               -exec $WARN group or other writable: {} \;
-       find $queue_directory/* $config_directory/* -name '*core' \
---- snapshot-20010329/conf/postfix-script-nosgid.orig  Wed Apr 25 15:22:53 2001
-+++ snapshot-20010329/conf/postfix-script-nosgid       Wed Apr 25 15:23:46 2001
-@@ -171,7 +171,7 @@
-               -exec $WARN not owned by root: {} \;
-       find $daemon_directory/. $config_directory/. \
--              \( -perm -020 -o -perm -002 \) \
-+              \( -perm +020 -o -perm +002 \) \
-               -exec $WARN group or other writable: {} \;
-       find $queue_directory/* $config_directory/* -name '*core' \
diff --git a/postfix-ssl.patch b/postfix-ssl.patch
deleted file mode 100644 (file)
index e7316fe..0000000
+++ /dev/null
@@ -1,14158 +0,0 @@
-diff -Nur snapshot-20010228-orig/Makefile.in snapshot-20010228/Makefile.in
---- snapshot-20010228-orig/Makefile.in Wed Mar 21 13:26:27 2001
-+++ snapshot-20010228/Makefile.in      Wed Mar 21 13:35:29 2001
-@@ -6,7 +6,7 @@
-       src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
-       src/showq src/postalias src/postcat src/postconf src/postdrop \
-       src/postkick src/postlock src/postlog src/postmap src/postsuper \
--      src/nqmgr src/spawn src/flush src/virtual # proto man html
-+      src/nqmgr src/spawn src/flush src/virtual src/tlsmgr # proto man html
- default: update
-diff -Nur snapshot-20010228-orig/conf/master.cf snapshot-20010228/conf/master.cf
---- snapshot-20010228-orig/conf/master.cf      Wed Mar 21 13:26:22 2001
-+++ snapshot-20010228/conf/master.cf   Wed Mar 21 13:32:23 2001
-@@ -68,10 +68,13 @@
- #             (yes)   (yes)   (yes)   (never) (50)
- # ==========================================================================
- smtp    inet  n       -       n       -       -       smtpd
-+#smtps     inet  n       -       y       -       -       smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
-+#submission inet n       -       y       -       -       smtpd -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes
- pickup          fifo  n       n       n       60      1       pickup
- cleanup         unix  -       -       n       -       0       cleanup
- qmgr    fifo  n       -       n       300     1       qmgr
- #qmgr   fifo  n       -       n       300     1       nqmgr
-+tlsmgr          fifo  -       -       n       300     1       tlsmgr
- rewrite         unix  -       -       n       -       -       trivial-rewrite
- bounce          unix  -       -       n       -       0       bounce
- defer   unix  -       -       n       -       0       bounce
-diff -Nur snapshot-20010228-orig/conf/sample-smtp.cf snapshot-20010228/conf/sample-smtp.cf
---- snapshot-20010228-orig/conf/sample-smtp.cf Wed Mar 21 13:26:23 2001
-+++ snapshot-20010228/conf/sample-smtp.cf      Wed Mar 21 13:32:23 2001
-@@ -145,6 +145,14 @@
- #
- smtp_helo_timeout = 300s
-+# The smtp_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# In case of problems the client does NOT try the next address on
-+# the mail exchanger list.
-+#
-+# smtp_starttls_timeout = 300s
-+
- # The smtp_mail_timeout parameter specifies the SMTP client timeout
- # for sending the SMTP MAIL FROM command, and for receiving the server
- # response.
-diff -Nur snapshot-20010228-orig/conf/sample-smtpd.cf snapshot-20010228/conf/sample-smtpd.cf
---- snapshot-20010228-orig/conf/sample-smtpd.cf        Wed Mar 21 13:26:23 2001
-+++ snapshot-20010228/conf/sample-smtpd.cf     Wed Mar 21 13:32:23 2001
-@@ -73,6 +73,11 @@
- # 
- strict_rfc821_envelopes = no
-+# The smtpd_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# smtpd_starttls_timeout = 300s
-+
- #
- # TARPIT CONTROLS
- #
-diff -Nur snapshot-20010228-orig/conf/sample-tls.cf snapshot-20010228/conf/sample-tls.cf
---- snapshot-20010228-orig/conf/sample-tls.cf  Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/conf/sample-tls.cf       Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,483 @@
-+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF
-+# HERE JUST SERVES AS AN EXAMPLE.
-+#
-+# This file contains example settings of Postfix configuration
-+# parameters that control the behaviour of the TLS extensions.
-+#
-+# We strictly seperate between server side TLS (smtpd_) and client side
-+# TLS (smtp_), as for practical reasons we might choose differently.
-+
-+# Section with SMTPD specific settings
-+
-+# To use TLS we do need a certificate and a private key. Both must be in
-+# "pem" format, the private key must not be encrypted, that does mean:
-+# it must be accessable without password. Both parts (certificate and
-+# private key) may be in the same file.
-+#
-+# Both RSA and DSA are certificates are supported. Typically you will only
-+# have RSA certificates issued by a commercial CA, also the tools supplied
-+# with OpenSSL will by default issue RSA certificates.
-+# You can have both at the same time, in this case the cipher used decides,
-+# which certificate is presented. For Netscape and OpenSSL clients without
-+# special cipher choices, the RSA certificate is preferred.
-+#
-+# In order to check the certificates, the CA-certificate (in case of a
-+# certificate chain, all CA-certificates) must be available.
-+# You should add these certificates to the server certificate, the server
-+# certificate first, then the issuing CA(s).
-+#
-+# Example: the certificate for "server.dom.ain" was issued by "intermediate CA"
-+# which itself has a certificate of "root CA". Create the server.pem file by
-+# 'cat server_cert.pem intemediate_CA.pem root_CA.pem > server.pem'
-+#
-+# If you want to accept certificates issued by these CAs yourself, you can
-+# also add the CA-certificates to the smtpd_tls_CAfile, in which case it is
-+# not necessary to have them in the smtpd_tls_[d]cert_file.
-+#
-+# A certificate supplied here must be useable as SSL server certificate and
-+# hence pass the "openssl verify -purpose sslserver ..." test.
-+#
-+smtpd_tls_cert_file = /etc/postfix/server.pem
-+smtpd_tls_key_file = $smtpd_tls_cert_file
-+#
-+# Its DSA counterparts:
-+smtpd_tls_dcert_file = /etc/postfix/server-dsa.pem
-+smtpd_tls_dkey_file = $smtpd_tls_dcert_file
-+
-+# The certificate was issued by a certification authority (CA), the CA-cert
-+# of which must be available, if not in the certificate file.
-+# This file may also contain the the CA certificates of other trusted CAs.
-+# You must use this file for the list of trusted CAs if you want to use
-+# chroot-mode. No default is supplied for this value as of now.
-+#
-+# smtpd_tls_CAfile = /etc/postfix/CAcert.pem
-+
-+# To verify the peer certificate, we need to know the certificates of
-+# certification authorities. These certificates in "pem" format are
-+# collected in a directory. The same CAs are offered to clients for
-+# client verification. Don't forget to create the necessary "hash"
-+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical
-+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is
-+# no default and you explicitly have to set the value here!
-+#
-+# To use this option in chroot mode, this directory itself or a copy of it
-+# must be inside the chroot jail. Please note also, that the CAs in this
-+# directory are not listed to the client, so that e.g. Netscape might not
-+# offer certificates issued by them.
-+#
-+# I therefore discourage the use of this option.
-+#
-+smtpd_tls_CApath = /etc/postfix/certs
-+
-+# To get additional information during the TLS setup and negotiations
-+# you can increase the loglevel from 0..4:
-+# 0: No output about the TLS subsystem
-+# 1: Printout startup and certificate information
-+# 2: 1 + Printout of levels during negotiation
-+# 3: 2 + Hex and ASCII dump of negotiation process
-+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS
-+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly
-+# discouraged.
-+#
-+# smtpd_tls_loglevel = 0
-+
-+# To include information about the protocol and cipher used as well as the
-+# client and issuer CommonName into the "Received:" header, set the
-+# smtpd_tls_received_header variable to true. The default is no, as the
-+# information is not necessarily authentic. Only the final destination
-+# is reliable, since the headers might have been changed in between.
-+#
-+#smtpd_tls_received_header = yes
-+
-+# By default TLS is disabled, so no difference to plain postfix is visible.
-+# Explicitely switch it on here:
-+#
-+smtpd_use_tls = yes
-+
-+# You can ENFORCE the use of TLS, so that no commands (except QUIT of course)
-+# are allowed without TLS. According to RFC2487 this MUST NOT be applied
-+# in case of a publicly-referenced SMTP server. So this option is off
-+# by default and should only seldom be used. Using this option implies
-+# smtpd_use_tls = yes
-+#
-+# smtpd_enforce_tls = no
-+
-+# Besides RFC2487 some clients, namely Outlook [Express] prefer to run the
-+# non-standard "wrapper" mode, not the STARTTLS enhancement to SMTP.
-+# This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run on a port!=25
-+# and OE (5.01 Mac on all ports).
-+# It is strictly discouraged to use this mode from main.cf. If you want to
-+# support this service, enable a special port in master.cf. Port 465 (smtps)
-+# was once chosen for this feature.
-+#
-+# smtpd_tls_wrappermode = no
-+
-+# To receive a client certificate, the server must explicitly ask for one.
-+# Hence netscape will either complain if no certificate is available (for
-+# the list of CAs in /etc/postfix/certs) or will offer you client certificates
-+# to choose from. This might be annoying, so this option is "off" by default.
-+# You will however need the certificate if you want to to e.g. certificate
-+# based relaying.
-+#
-+# smtpd_tls_ask_ccert = no
-+
-+# You may also decide to REQUIRE a client certificate to allow TLS connections.
-+# I don't think it will be necessary often, it is however included here for
-+# completeness. This option implies smtpd_tls_ask_ccert = yes
-+#
-+# Please be aware, that this will inhibit TLS connections without a proper
-+# certificate and only makes sense, when normal submission is disabled and
-+# TLS is enforced (smtpd_enforce_tls). Otherwise clients may bypass by simply
-+# not using STARTTLS at all. When TLS is not enforced, the connection will be
-+# handled, as if only smtpd_tls_ask_ccert = yes would be set and an information
-+# is logged.
-+#
-+# smtpd_tls_req_ccert = no
-+
-+# The verification depth for client certificates. A depth of 1 is sufficient,
-+# if the certificate ist directly issued by a CA listed in the CA locations.
-+# The default value (5) should also suffice for longer chains (root CA issues
-+# special CA which then issues the actual certificate...)
-+#
-+# smtpd_tls_ccert_verifydepth = 5
-+
-+# The server and client negotiate a session, which takes some computer time
-+# and network bandwidth. The session is cached only in the smtpd process
-+# actually using this session and is lost when the process dies.
-+# To share the session information between the smtpd processes, a disc based
-+# session cache can be used based on the SDBM databases (routines included
-+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM
-+# can be used.
-+#
-+smtpd_tls_session_cache_database = sdbm:/etc/postfix/smtpd_scache
-+
-+# The cached sessions time out after a certain amount of time. For Postfix/TLS
-+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec
-+# (=1 hour). RFC2246 recommends a maximum of 24 hours.
-+#
-+# smtpd_tls_session_cache_timeout = 3600s
-+
-+# Two additional options has been added for relay control to the UCE rules:
-+#   permit_tls_clientcerts    (a)
-+# and
-+#   permit_tls_all_clientcerts. (b)
-+#
-+# If one of these options is added to
-+#   smtpd_recipient_restrictions,
-+# postfix will relay if 
-+# (a) a valid (it passed the verification) client certificate is presented
-+#     and its fingerprint is listed in the list of client certs
-+#     (relay_clientcerts),
-+# (b) any valid (it passed the verification) client certificate is presented.
-+#
-+# Option (b) must only be used, if a special CA issues the certificates and
-+# only this CA is listed as trusted CA. If other CAs are trusted, any owner
-+# of a valid (SSL client)-certificate can relay. Option (b) can be practical
-+# for a specically created email relay. It is however recommended to stay with
-+# option (a) and list all certificates, as (b) does not permit any control
-+# when a certificate must no longer be used (e.g. an employee leaving).
-+#
-+# smtpd_recipient_restrictions = ... permit_tls_clientcerts ...
-+
-+# The list of client certificates for which relaying will be allowed.
-+# Unfortunately the routines for lists in postfix use whitespaces as
-+# seperators and choke on special chars. So using the certificate
-+# X509ONELINES is quite impractical. We will use the fingerprints at
-+# this point, as they are difficult to fake but easy to use for lookup.
-+# As postmap (when using e.g. db) insists of having a pair of key and value,
-+# but we only need the key, the value can be chosen freely, e.g. the name
-+# of the user or host:
-+# D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home
-+#
-+# relay_clientcerts = hash:/etc/postfix/relay_clientcerts
-+
-+# To influence the cipher selection scheme, you can give cipherlist-string.
-+# A detailed description would go to far here, please refer to the openssl
-+# documentation.
-+# If you don't know what to do with it, simply don't touch it and leave the
-+# (openssl-)compiled in default!
-+#
-+# DO NOT USE " to enclose the string, just the string!!!
-+#
-+# smtpd_tls_cipherlist = DEFAULT
-+
-+# If you want to take advantage of ciphers with EDH, DH parameters are needed.
-+# There are built in DH parameters for both 1025bit and 512bit available. It
-+# is however better to have "own" parameters, since otherwise it would "pay"
-+# for a possible attacker to start a brute force attack against these
-+# parameters commonly used by everybody. For this reason, the parameters
-+# chosen are already different from those distributed with other TLS packages.
-+#
-+# To generate your own set of parameters, use
-+# openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
-+# openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512
-+# (your source for "entropy" might vary; on Linux there is /dev/random, on
-+# other system, you might consider the "Entropy Gathering Daemon EGD", 
-+# available at http://www.lothar.com/tech/crypto/.
-+#
-+smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem
-+smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem
-+
-+# The smtpd_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# smtpd_starttls_timeout = 300s
-+
-+# Section with SMTP specific settings
-+
-+# During the startup negotiation we might present a certificate to the server.
-+# Netscape is rather clever here and lets the user select between only those
-+# certs that will match the CAs accepted from the server. As I simply use
-+# the integrated "SSL_connect()" from the OpenSSL package, this is not
-+# possible by now and we have to chose just one cert.
-+# So for now the default is to use _no_ cert and key unless explictly
-+# set here. It is possible to use the same key/cert pair as for the server.
-+# If a cert is to be presented, it must be in "pem" format, the private key
-+# must not be encrypted, that does mean: it must be accessable without
-+# password. Both parts (certificate and private key) may be in the
-+# same file.
-+#
-+# In order to check the certificates, the CA-certificate (in case of a
-+# certificate chain, all CA-certificates) must be available.
-+# You should add these certificates to the server certificate, the server
-+# certificate first, then the issuing CA(s).
-+#
-+# Example: the certificate for "client.dom.ain" was issued by "intermediate CA"
-+# which itself has a certificate of "root CA". Create the client.pem file by
-+# 'cat client_cert.pem intemediate_CA.pem root_CA.pem > client.pem'
-+#
-+# If you want to accept certificates issued by these CAs yourself, you can
-+# also add the CA-certificates to the smtp_tls_CAfile, in which case it is
-+# not necessary to have them in the smtp_tls_[d]cert_file.
-+#
-+# A certificate supplied here must be useable as SSL client certificate and
-+# hence pass the "openssl verify -purpose sslclient ..." test.
-+#
-+smtp_tls_cert_file = /etc/postfix/client.pem
-+smtp_tls_key_file = $smtp_tls_cert_file
-+
-+# The certificate was issued by a certification authority (CA), the CA-cert
-+# of which must be available, if not in the certificate file.
-+# This file may also contain the the CA certificates of other trusted CAs.
-+# You must use this file for the list of trusted CAs if you want to use
-+# chroot-mode. No default is supplied for this value as of now.
-+#
-+smtp_tls_CAfile = /etc/postfix/CAcert.pem
-+
-+# To verify the peer certificate, we need to know the certificates of
-+# certification authorities. These certificates in "pem" format are
-+# collected in a directory. Don't forget to create the necessary "hash"
-+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical
-+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is
-+# no default and you explicitly have to set the value here!
-+#
-+# To use this option in chroot mode, this directory itself or a copy of it
-+# must be inside the chroot jail.
-+#
-+smtp_tls_CApath = /etc/postfix/certs
-+
-+# To get additional information during the TLS setup and negotiations
-+# you can increase the loglevel from 0..4:
-+# 0: No output about the TLS subsystem
-+# 1: Printout startup and certificate information
-+# 2: 1 + Printout of levels during negotiation
-+# 3: 2 + Hex and ASCII dump of negotiation process
-+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS
-+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly
-+# discouraged.
-+#
-+smtp_tls_loglevel = 0
-+
-+# The server and client negotiate a session, which takes some computer time
-+# and network bandwidth. The session is cached only in the smtpd process
-+# actually using this session and is lost when the process dies.
-+# To share the session information between the smtp processes, a disc based
-+# session cache can be used based on the SDBM databases (routines included
-+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM
-+# can be used.
-+#
-+smtp_tls_session_cache_database = sdbm:/etc/postfix/smtp_scache
-+
-+# The cached sessions time out after a certain amount of time. For Postfix/TLS
-+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec
-+# (=1 hour). RFC2246 recommends a maximum of 24 hours.
-+#
-+# smtp_tls_session_cache_timeout = 3600s
-+
-+# By default TLS is disabled, so no difference to plain postfix is visible.
-+# If you enable TLS it will be used when offered by the server.
-+# WARNING: I didn't have access to other software (except those explicitely
-+# listed) to test the interaction. On corresponding mailing list
-+# there was a discussion going on about MS exchange servers offering
-+# STARTTLS even if it is not configured, so it might be wise to not
-+# use this option on your central mail hub, as you don't know in advance
-+# whether you are going to hit such host. Use the recipient/site specific
-+# options instead.
-+# HINT: I have it switched on on my mailservers and did experience one
-+# single failure since client side TLS is implemented. (There was one
-+# misconfired MS Exchange server; I contacted ths admin.) Hence, I am happy
-+# with it running all the time, but I am interested in testing anyway.
-+# You have been warned, however :-)
-+#
-+# In case of failure, a "4xx" code is issued and the mail stays in the queue.
-+#
-+# Explicitely switch it on here, if you want it.
-+#
-+smtp_use_tls = yes
-+
-+# You can ENFORCE the use of TLS, so that only connections with TLS will
-+# be accepted. Additionally, the hostname of the receiving host is matched
-+# against the CommonName in the certificate. Also, the certificate must
-+# be verified "Ok", so that a CA trusted by the client must have issued
-+# the certificate. If the certificate doesn't verify or the hostname doesn't
-+# match, a "4xx" will be issued and the mail stays in the queue.
-+# The hostname used in the check is beyond question, as it must be the
-+# principle hostname (no CNAME allowed here).
-+# The behaviour may be changed with the smtp_tls_enforce_peername option
-+#
-+# This option is useful only if you are definitely sure that you will only
-+# connect to servers supporting RFC2487 _and_ with valid certificates.
-+# I use it for my clients which will only send email to one mailhub, which
-+# does offer the necessary STARTTLS support.
-+#
-+# smtp_enforce_tls = no
-+
-+# As of RFC2487 the requirements for hostname checking for MTA clients are
-+# not set. When in smtp_enforce_tls mode, the option smtp_tls_enforce_peername
-+# can be set to "no" to disable strict peername checking. In this case, the
-+# mail delivery will be continued, if a TLS connection was established
-+# _and_ the peer certificate passed verification _but_ regardless of the
-+# CommonName listed in the certificate. This option only applies to the
-+# default setting smtp_enforce_tls_mode, special settings in the
-+# smtp_tls_per_site table override smtp_tls_enforce_peername.
-+#
-+# This can make sense in closed environment where special CAs are created.
-+# If not used carefully, this option opens the danger of a "man-in-the-middle"
-+# attack (the CommonName of this attacker is logged).
-+#
-+# smtp_tls_enforce_peername = yes
-+
-+# As generally trying TLS can be a bad idea (some hosts offer STARTTLS but
-+# the negotiation will fail leading to unexplainable failures, it may be
-+# a good idea to decide based on the recipient or the mailhub to which you are
-+# connecting.
-+#
-+# Deciding per recipient may be difficult, since a singe email can have
-+# several recipients. We use the "nexthop" mechanism inside postfix.
-+# When an email is to be delivered, the "nexthop" is obtained. If it matches
-+# an entry in the smtp_tls_per_site list, appropriate action is taken.
-+# Since entries in the transport table or the use of a relay_host override
-+# the nexthop setting, in these cases the relay_host etc must be listed
-+# in the table. In any case, the hostname of the peer to be contacted is
-+# looked up (that is: the MX or the name of the host, if no MX is given).
-+#
-+# Special hint for enforcement mode:
-+# Since there is no secure mechanism for DNS lookups available, the
-+# recommended setup is: put the sensible domains with their mailhost
-+# into the transport table (since you can asure security of this table
-+# unlike DNS), then set MUST mode for this mailhost.
-+#
-+# Format of the table:
-+# The keys entries are on the left hand side, no wildcards allowed. On the
-+# right hand side the keywords NONE (don't use TLS at all), MAY (try to use
-+# STARTTLS if offered, no problem if not), MUST (enforce usage of STARTTLS,
-+# check server certificate CommonName against server FQDN), MUST_NOPEERMATCH
-+# (enforce usage of STARTTLS and verify certificate, but ignore differences
-+# between CommonName and server FQDN).
-+# dom.ain             NONE
-+# host.dom.ain                MAY
-+# important.host      MUST
-+# some.host.dom.ain   MUST_NOPEERMATCH
-+#
-+# If an entry is not matched, the default policy is applied; if the default
-+# policy is "enforce", NONE explicitely switches it off, otherwise the
-+# "enforce" mode is used even for MAY entries.
-+#
-+smtp_tls_per_site = hash:/etc/postfix/tls_per_site
-+
-+# The verification depth for server certificates. A depth of 1 is sufficient,
-+# if the certificate ist directly issued by a CA listed in the CA locations.
-+# The default value (5) should also suffice for longer chains (root CA issues
-+# special CA which then issues the actual certificate...)
-+#
-+# smtp_tls_scert_verifydepth = 5
-+
-+# As we decide on a "per site" basis, wether to use TLS or not, it would be
-+# good to have a list of sites, that offered "STARTTLS'. We can collect it
-+# ourselves with this option.
-+#
-+# If activated and TLS is not already enabled for this host, a line is added
-+# to the logfile:
-+# postfix/smtp[pid]: Host offered STARTTLS: [name.of.host]
-+#
-+smtp_tls_note_starttls_offer = yes
-+
-+# To influence the cipher selection scheme, you can give cipherlist-string.
-+# A detailed description would go to far here, please refer to the openssl
-+# documentation.
-+# If you don't know what to do with it, simply don't touch it and leave the
-+# (openssl-)compiled in default!
-+#
-+# DO NOT USE " to enclose the string, just the string!!!
-+#
-+# smtp_tls_cipherlist = DEFAULT
-+
-+# The smtp_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# In case of problems the client does NOT try the next address on
-+# the mail exchanger list.
-+#
-+# smtp_starttls_timeout = 300s
-+
-+# In order to seed the PRNG Pseude Random Number Generator, random data is
-+# needed. The PRNG pool is maintained by the "tlsmgr" daemon and is used
-+# (read) by the smtp[d] processes after adding some more entropy by stirring
-+# in time and process id.
-+# The file, which is from time to time rewritten by the tlsmgr, is created
-+# if not existant. A default value is given; the default should probably
-+# be on the /var partition but _not_ inside chroot jail.
-+#
-+# tls_random_exchange_name = /etc/postfix/prng_exch
-+
-+# To feed the PRNG pool, entropy is being read from an external source,
-+# both at startup and during run.
-+# Specify a good entropy source here, like EGD or /dev/urandom; make sure
-+# to only use non-blocking sources.
-+# In both cases, 32 bytes are read at each re-seeding event (which is an
-+# amount of 256bits and hence good enough for 128bit symmetric keys).
-+# You must specify the type of source: "dev:" for a device special file
-+# or "egd:" for a source with EGD compatible socket interface. A maximum
-+# 255 bytes is read from these sources in each step.
-+# If you specify a normal file, a larger amount of data can be read.
-+#
-+# The entropy source is queried again after a certain amount of time. The
-+# time is calculated using the PRNG, it is between 0 and the time specified,
-+# default is a maximum of 1 hour.
-+#
-+# tls_random_source = dev:/dev/urandom
-+tls_random_source = egd:/var/run/egd-pool
-+# tls_random_bytes = 32
-+# tls_random_reseed_period = 3600s
-+
-+# The PRNG pool inside tlsmgr is used to re-generate the 1024 byte file
-+# being read by smtp[d]. The time, after which the exchange file is
-+# rewritten is calculated using the PRNG, it is between 0 and the time
-+# specified, default is a maximum of 60 seconds.
-+#
-+# tls_random_upd_period = 60s
-+
-+# If you have a entropy source available, that is not easily drained (like
-+# /dev/urandom), the daemons can also load additional entropy on startup from
-+# the source specified. By default an amount of 32 bytes is read, the
-+# equivalent to 256 bits. This is more than enough to generate a 128bit
-+# (or 168bit) session key, but we may have to generate more than one.
-+# Usage of this option may drain EGD (consider the case of 50 smtp starting
-+# up with a full queue and "postfix start", which will request 1600bytes
-+# of entropy). This is however not fatal, as long as "entropy" data could
-+# be read from the exchange file.
-+#
-+# tls_daemon_random_source = dev:/dev/urandom
-+tls_daemon_random_source = egd:/var/run/egd-pool
-+# tls_daemon_random_bytes = 32
-+
-diff -Nur snapshot-20010228-orig/html/ssl/conf.html snapshot-20010228/html/ssl/conf.html
---- snapshot-20010228-orig/html/ssl/conf.html  Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/conf.html       Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,537 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Configuring main.cf and master.cf</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Configuring main.cf and master.cf</h1>
-+
-+To use the TLS extension you need to feed some information to
-+postfix. Please see also the <code>conf/sample-tls.cf</code> file. 
-+
-+<h2>main.cf: smtpd (server) specific variables</h2>
-+
-+<pre>
-+# To use TLS we do need a certificate and a private key. Both must be in
-+# "pem" format, the private key must not be encrypted, that does mean:
-+# it must be accessable without password. Both parts (certificate and
-+# private key) may be in the same file.
-+#
-+# Both RSA and DSA are certificates are supported. Typically you will only
-+# have RSA certificates issued by a commercial CA, also the tools supplied
-+# with OpenSSL will by default issue RSA certificates.
-+# You can have both at the same time, in this case the cipher used decides,
-+# which certificate is presented. For Netscape and OpenSSL clients without
-+# special cipher choices, the RSA certificate is preferred.
-+#
-+# In order to check the certificates, the CA-certificate (in case of a
-+# certificate chain, all CA-certificates) must be available.
-+# You should add these certificates to the server certificate, the server
-+# certificate first, then the issuing CA(s).
-+#
-+# Example: the certificate for "server.dom.ain" was issued by "intermediate CA"
-+# which itself has a certificate of "root CA". Create the server.pem file by
-+# 'cat server_cert.pem intemediate_CA.pem root_CA.pem > server.pem'
-+#
-+# If you want to accept certificates issued by these CAs yourself, you can
-+# also add the CA-certificates to the smtpd_tls_CAfile, in which case it is
-+# not necessary to have them in the smtpd_tls_[d]cert_file.
-+#
-+# A certificate supplied here must be useable as SSL server certificate and
-+# hence pass the "openssl verify -purpose sslserver ..." test.
-+#
-+smtpd_tls_cert_file = /etc/postfix/server.pem
-+smtpd_tls_key_file = $smtpd_tls_cert_file
-+#
-+# Its DSA counterparts:
-+smtpd_tls_dcert_file = /etc/postfix/server-dsa.pem
-+smtpd_tls_dkey_file = $smtpd_tls_dcert_file
-+
-+# The certificate was issued by a certification authority (CA), the CA-cert
-+# of which must be available, if not in the certificate file.
-+# This file may also contain the the CA certificates of other trusted CAs.
-+# You must use this file for the list of trusted CAs if you want to use
-+# chroot-mode. No default is supplied for this value as of now.
-+#
-+# smtpd_tls_CAfile = /etc/postfix/CAcert.pem
-+
-+# To verify the peer certificate, we need to know the certificates of
-+# certification authorities. These certificates in "pem" format are
-+# collected in a directory. The same CAs are offered to clients for
-+# client verification. Don't forget to create the necessary "hash"
-+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical
-+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is
-+# no default and you explicitly have to set the value here!
-+#
-+# To use this option in chroot mode, this directory itself or a copy of it
-+# must be inside the chroot jail. Please note also, that the CAs in this
-+# directory are not listed to the client, so that e.g. Netscape might not
-+# offer certificates issued by them.
-+#
-+# I therefore discourage the use of this option.
-+#
-+smtpd_tls_CApath = /etc/postfix/certs
-+
-+# To get additional information during the TLS setup and negotiations
-+# you can increase the loglevel from 0..4:
-+# 0: No output about the TLS subsystem
-+# 1: Printout startup and certificate information
-+# 2: 1 + Printout of levels during negotiation
-+# 3: 2 + Hex and ASCII dump of negotiation process
-+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS
-+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly
-+# discouraged.
-+#
-+# smtpd_tls_loglevel = 0
-+
-+# To include information about the protocol and cipher used as well as the
-+# client and issuer CommonName into the "Received:" header, set the
-+# smtpd_tls_received_header variable to true. The default is no, as the
-+# information is not necessarily authentic. Only the final destination
-+# is reliable, since the headers might have been changed in between.
-+#
-+#smtpd_tls_received_header = yes
-+
-+# By default TLS is disabled, so no difference to plain postfix is visible.
-+# Explicitely switch it on here:
-+#
-+smtpd_use_tls = yes
-+
-+# You can ENFORCE the use of TLS, so that no commands (except QUIT of course)
-+# are allowed without TLS. According to RFC2487 this MUST NOT be applied
-+# in case of a publicly-referenced SMTP server. So this option is off
-+# by default and should only seldom be used. Using this option implies
-+# smtpd_use_tls = yes
-+#
-+# smtpd_enforce_tls = no
-+
-+# Besides RFC2487 some clients, namely Outlook [Express] prefer to run the
-+# non-standard "wrapper" mode, not the STARTTLS enhancement to SMTP.
-+# This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run on a port!=25
-+# and OE (5.01 Mac on all ports).
-+# It is strictly discouraged to use this mode from main.cf. If you want to
-+# support this service, enable a special port in master.cf. Port 465 (smtps)
-+# was once chosen for this feature.
-+#
-+# smtpd_tls_wrappermode = no
-+
-+# To receive a client certificate, the server must explicitly ask for one.
-+# Hence netscape will either complain if no certificate is available (for
-+# the list of CAs in /etc/postfix/certs) or will offer you client certificates
-+# to choose from. This might be annoying, so this option is "off" by default.
-+# You will however need the certificate if you want to to e.g. certificate
-+# based relaying.
-+#
-+# smtpd_tls_ask_ccert = no
-+
-+# You may also decide to REQUIRE a client certificate to allow TLS connections.
-+# I don't think it will be necessary often, it is however included here for
-+# completeness. This option implies smtpd_tls_ask_ccert = yes
-+#
-+# Please be aware, that this will inhibit TLS connections without a proper
-+# certificate and only makes sense, when normal submission is disabled and
-+# TLS is enforced (smtpd_enforce_tls). Otherwise clients may bypass by simply
-+# not using STARTTLS at all. When TLS is not enforced, the connection will be
-+# handled, as if only smtpd_tls_ask_ccert = yes would be set and an information
-+# is logged.
-+#
-+# smtpd_tls_req_ccert = no
-+
-+# The verification depth for client certificates. A depth of 1 is sufficient,
-+# if the certificate ist directly issued by a CA listed in the CA locations.
-+# The default value (5) should also suffice for longer chains (root CA issues
-+# special CA which then issues the actual certificate...)
-+#
-+# smtpd_tls_ccert_verifydepth = 5
-+
-+# The server and client negotiate a session, which takes some computer time
-+# and network bandwidth. The session is cached only in the smtpd process
-+# actually using this session and is lost when the process dies.
-+# To share the session information between the smtpd processes, a disc based
-+# session cache can be used based on the SDBM databases (routines included
-+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM
-+# can be used.
-+#
-+smtpd_tls_session_cache_database = sdbm:/etc/postfix/smtpd_scache
-+
-+# The cached sessions time out after a certain amount of time. For Postfix/TLS
-+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec
-+# (=1 hour). RFC2246 recommends a maximum of 24 hours.
-+#
-+# smtpd_tls_session_cache_timeout = 3600s
-+
-+# Two additional options has been added for relay control to the UCE rules:
-+#   permit_tls_clientcerts    (a)
-+# and
-+#   permit_tls_all_clientcerts. (b)
-+#
-+# If one of these options is added to
-+#   smtpd_recipient_restrictions,
-+# postfix will relay if 
-+# (a) a valid (it passed the verification) client certificate is presented
-+#     and its fingerprint is listed in the list of client certs
-+#     (relay_clientcerts),
-+# (b) any valid (it passed the verification) client certificate is presented.
-+#
-+# Option (b) must only be used, if a special CA issues the certificates and
-+# only this CA is listed as trusted CA. If other CAs are trusted, any owner
-+# of a valid (SSL client)-certificate can relay. Option (b) can be practical
-+# for a specically created email relay. It is however recommended to stay with
-+# option (a) and list all certificates, as (b) does not permit any control
-+# when a certificate must no longer be used (e.g. an employee leaving).
-+#
-+# smtpd_recipient_restrictions = ... permit_tls_clientcerts ...
-+
-+# The list of client certificates for which relaying will be allowed.
-+# Unfortunately the routines for lists in postfix use whitespaces as
-+# seperators and choke on special chars. So using the certificate
-+# X509ONELINES is quite impractical. We will use the fingerprints at
-+# this point, as they are difficult to fake but easy to use for lookup.
-+# As postmap (when using e.g. db) insists of having a pair of key and value,
-+# but we only need the key, the value can be chosen freely, e.g. the name
-+# of the user or host:
-+# D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home
-+#
-+# relay_clientcerts = hash:/etc/postfix/relay_clientcerts
-+
-+# To influence the cipher selection scheme, you can give cipherlist-string.
-+# A detailed description would go to far here, please refer to the openssl
-+# documentation.
-+# If you don't know what to do with it, simply don't touch it and leave the
-+# (openssl-)compiled in default!
-+#
-+# DO NOT USE " to enclose the string, just the string!!!
-+#
-+# smtpd_tls_cipherlist = DEFAULT
-+
-+# If you want to take advantage of ciphers with EDH, DH parameters are needed.
-+# There are built in DH parameters for both 1025bit and 512bit available. It
-+# is however better to have "own" parameters, since otherwise it would "pay"
-+# for a possible attacker to start a brute force attack against these
-+# parameters commonly used by everybody. For this reason, the parameters
-+# chosen are already different from those distributed with other TLS packages.
-+#
-+# To generate your own set of parameters, use
-+# openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024
-+# openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512
-+# (your source for "entropy" might vary; on Linux there is /dev/random, on
-+# other system, you might consider the "Entropy Gathering Daemon EGD", 
-+# available at http://www.lothar.com/tech/crypto/.
-+#
-+smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem
-+smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem
-+
-+# The smtpd_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# smtpd_starttls_timeout = 300s
-+</pre>
-+
-+<h2>main.cf: smtp (client) specific variables</h2>
-+
-+<pre>
-+# During the startup negotiation we might present a certificate to the server.
-+# Netscape is rather clever here and lets the user select between only those
-+# certs that will match the CAs accepted from the server. As I simply use
-+# the integrated "SSL_connect()" from the OpenSSL package, this is not
-+# possible by now and we have to chose just one cert.
-+# So for now the default is to use _no_ cert and key unless explictly
-+# set here. It is possible to use the same key/cert pair as for the server.
-+# If a cert is to be presented, it must be in "pem" format, the private key
-+# must not be encrypted, that does mean: it must be accessable without
-+# password. Both parts (certificate and private key) may be in the
-+# same file.
-+#
-+# In order to check the certificates, the CA-certificate (in case of a
-+# certificate chain, all CA-certificates) must be available.
-+# You should add these certificates to the server certificate, the server
-+# certificate first, then the issuing CA(s).
-+#
-+# Example: the certificate for "client.dom.ain" was issued by "intermediate CA"
-+# which itself has a certificate of "root CA". Create the client.pem file by
-+# 'cat client_cert.pem intemediate_CA.pem root_CA.pem > client.pem'
-+#
-+# If you want to accept certificates issued by these CAs yourself, you can
-+# also add the CA-certificates to the smtp_tls_CAfile, in which case it is
-+# not necessary to have them in the smtp_tls_[d]cert_file.
-+#
-+# A certificate supplied here must be useable as SSL client certificate and
-+# hence pass the "openssl verify -purpose sslclient ..." test.
-+#
-+smtp_tls_cert_file = /etc/postfix/client.pem
-+smtp_tls_key_file = $smtp_tls_cert_file
-+
-+# The certificate was issued by a certification authority (CA), the CA-cert
-+# of which must be available, if not in the certificate file.
-+# This file may also contain the the CA certificates of other trusted CAs.
-+# You must use this file for the list of trusted CAs if you want to use
-+# chroot-mode. No default is supplied for this value as of now.
-+#
-+smtp_tls_CAfile = /etc/postfix/CAcert.pem
-+
-+# To verify the peer certificate, we need to know the certificates of
-+# certification authorities. These certificates in "pem" format are
-+# collected in a directory. Don't forget to create the necessary "hash"
-+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical
-+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is
-+# no default and you explicitly have to set the value here!
-+#
-+# To use this option in chroot mode, this directory itself or a copy of it
-+# must be inside the chroot jail.
-+#
-+smtp_tls_CApath = /etc/postfix/certs
-+
-+# To get additional information during the TLS setup and negotiations
-+# you can increase the loglevel from 0..4:
-+# 0: No output about the TLS subsystem
-+# 1: Printout startup and certificate information
-+# 2: 1 + Printout of levels during negotiation
-+# 3: 2 + Hex and ASCII dump of negotiation process
-+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS
-+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly
-+# discouraged.
-+#
-+smtp_tls_loglevel = 0
-+
-+# The server and client negotiate a session, which takes some computer time
-+# and network bandwidth. The session is cached only in the smtpd process
-+# actually using this session and is lost when the process dies.
-+# To share the session information between the smtp processes, a disc based
-+# session cache can be used based on the SDBM databases (routines included
-+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM
-+# can be used.
-+#
-+smtp_tls_session_cache_database = sdbm:/etc/postfix/smtp_scache
-+
-+# The cached sessions time out after a certain amount of time. For Postfix/TLS
-+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec
-+# (=1 hour). RFC2246 recommends a maximum of 24 hours.
-+#
-+# smtp_tls_session_cache_timeout = 3600s
-+
-+# By default TLS is disabled, so no difference to plain postfix is visible.
-+# If you enable TLS it will be used when offered by the server.
-+# WARNING: I didn't have access to other software (except those explicitely
-+# listed) to test the interaction. On corresponding mailing list
-+# there was a discussion going on about MS exchange servers offering
-+# STARTTLS even if it is not configured, so it might be wise to not
-+# use this option on your central mail hub, as you don't know in advance
-+# whether you are going to hit such host. Use the recipient/site specific
-+# options instead.
-+# HINT: I have it switched on on my mailservers and did experience one
-+# single failure since client side TLS is implemented. (There was one
-+# misconfired MS Exchange server; I contacted ths admin.) Hence, I am happy
-+# with it running all the time, but I am interested in testing anyway.
-+# You have been warned, however :-)
-+#
-+# In case of failure, a "4xx" code is issued and the mail stays in the queue.
-+#
-+# Explicitely switch it on here, if you want it.
-+#
-+smtp_use_tls = yes
-+
-+# You can ENFORCE the use of TLS, so that only connections with TLS will
-+# be accepted. Additionally, the hostname of the receiving host is matched
-+# against the CommonName in the certificate. Also, the certificate must
-+# be verified "Ok", so that a CA trusted by the client must have issued
-+# the certificate. If the certificate doesn't verify or the hostname doesn't
-+# match, a "4xx" will be issued and the mail stays in the queue.
-+# The hostname used in the check is beyond question, as it must be the
-+# principle hostname (no CNAME allowed here).
-+# The behaviour may be changed with the smtp_tls_enforce_peername option
-+#
-+# This option is useful only if you are definitely sure that you will only
-+# connect to servers supporting RFC2487 _and_ with valid certificates.
-+# I use it for my clients which will only send email to one mailhub, which
-+# does offer the necessary STARTTLS support.
-+#
-+# smtp_enforce_tls = no
-+
-+# As of RFC2487 the requirements for hostname checking for MTA clients are
-+# not set. When in smtp_enforce_tls mode, the option smtp_tls_enforce_peername
-+# can be set to "no" to disable strict peername checking. In this case, the
-+# mail delivery will be continued, if a TLS connection was established
-+# _and_ the peer certificate passed verification _but_ regardless of the
-+# CommonName listed in the certificate. This option only applies to the
-+# default setting smtp_enforce_tls_mode, special settings in the
-+# smtp_tls_per_site table override smtp_tls_enforce_peername.
-+#
-+# This can make sense in closed environment where special CAs are created.
-+# If not used carefully, this option opens the danger of a "man-in-the-middle"
-+# attack (the CommonName of this attacker is logged).
-+#
-+# smtp_tls_enforce_peername = yes
-+
-+# As generally trying TLS can be a bad idea (some hosts offer STARTTLS but
-+# the negotiation will fail leading to unexplainable failures, it may be
-+# a good idea to decide based on the recipient or the mailhub to which you are
-+# connecting.
-+#
-+# Deciding per recipient may be difficult, since a singe email can have
-+# several recipients. We use the "nexthop" mechanism inside postfix.
-+# When an email is to be delivered, the "nexthop" is obtained. If it matches
-+# an entry in the smtp_tls_per_site list, appropriate action is taken.
-+# Since entries in the transport table or the use of a relay_host override
-+# the nexthop setting, in these cases the relay_host etc must be listed
-+# in the table. In any case, the hostname of the peer to be contacted is
-+# looked up (that is: the MX or the name of the host, if no MX is given).
-+#
-+# Special hint for enforcement mode:
-+# Since there is no secure mechanism for DNS lookups available, the
-+# recommended setup is: put the sensible domains with their mailhost
-+# into the transport table (since you can asure security of this table
-+# unlike DNS), then set MUST mode for this mailhost.
-+#
-+# Format of the table:
-+# The keys entries are on the left hand side, no wildcards allowed. On the
-+# right hand side the keywords NONE (don't use TLS at all), MAY (try to use
-+# STARTTLS if offered, no problem if not), MUST (enforce usage of STARTTLS,
-+# check server certificate CommonName against server FQDN), MUST_NOPEERMATCH
-+# (enforce usage of STARTTLS and verify certificate, but ignore differences
-+# between CommonName and server FQDN).
-+# dom.ain             NONE
-+# host.dom.ain                MAY
-+# important.host      MUST
-+# some.host.dom.ain   MUST_NOPEERMATCH
-+#
-+# If an entry is not matched, the default policy is applied; if the default
-+# policy is "enforce", NONE explicitely switches it off, otherwise the
-+# "enforce" mode is used even for MAY entries.
-+#
-+smtp_tls_per_site = hash:/etc/postfix/tls_per_site
-+
-+# The verification depth for server certificates. A depth of 1 is sufficient,
-+# if the certificate ist directly issued by a CA listed in the CA locations.
-+# The default value (5) should also suffice for longer chains (root CA issues
-+# special CA which then issues the actual certificate...)
-+#
-+# smtp_tls_scert_verifydepth = 5
-+
-+# As we decide on a "per site" basis, wether to use TLS or not, it would be
-+# good to have a list of sites, that offered "STARTTLS'. We can collect it
-+# ourselves with this option.
-+#
-+# If activated and TLS is not already enabled for this host, a line is added
-+# to the logfile:
-+# postfix/smtp[pid]: Host offered STARTTLS: [name.of.host]
-+#
-+smtp_tls_note_starttls_offer = yes
-+
-+# To influence the cipher selection scheme, you can give cipherlist-string.
-+# A detailed description would go to far here, please refer to the openssl
-+# documentation.
-+# If you don't know what to do with it, simply don't touch it and leave the
-+# (openssl-)compiled in default!
-+#
-+# DO NOT USE " to enclose the string, just the string!!!
-+#
-+# smtp_tls_cipherlist = DEFAULT
-+
-+# The smtp_starttls_timeout parameter limits the time in seconds to write and
-+# read operations during TLS start and stop handhake procedures.
-+#
-+# In case of problems the client does NOT try the next address on
-+# the mail exchanger list.
-+#
-+# smtp_starttls_timeout = 300s
-+</pre>
-+
-+<h2>main.cf: general variables</h2>
-+
-+<pre>
-+# In order to seed the PRNG Pseude Random Number Generator, random data is
-+# needed. The PRNG pool is maintained by the "tlsmgr" daemon and is used
-+# (read) by the smtp[d] processes after adding some more entropy by stirring
-+# in time and process id.
-+# The file, which is from time to time rewritten by the tlsmgr, is created
-+# if not existant. A default value is given; the default should probably
-+# be on the /var partition but _not_ inside chroot jail.
-+#
-+# tls_random_exchange_name = /etc/postfix/prng_exch
-+
-+# To feed the PRNG pool, entropy is being read from an external source,
-+# both at startup and during run.
-+# Specify a good entropy source here, like EGD or /dev/urandom; make sure
-+# to only use non-blocking sources.
-+# In both cases, 32 bytes are read at each re-seeding event (which is an
-+# amount of 256bits and hence good enough for 128bit symmetric keys).
-+# You must specify the type of source: "dev:" for a device special file
-+# or "egd:" for a source with EGD compatible socket interface. A maximum
-+# 255 bytes is read from these sources in each step.
-+# If you specify a normal file, a larger amount of data can be read.
-+#
-+# The entropy source is queried again after a certain amount of time. The
-+# time is calculated using the PRNG, it is between 0 and the time specified,
-+# default is a maximum of 1 hour.
-+#
-+# tls_random_source = dev:/dev/urandom
-+tls_random_source = egd:/var/run/egd-pool
-+# tls_random_bytes = 32
-+# tls_random_reseed_period = 3600s
-+
-+# The PRNG pool inside tlsmgr is used to re-generate the 1024 byte file
-+# being read by smtp[d]. The time, after which the exchange file is
-+# rewritten is calculated using the PRNG, it is between 0 and the time
-+# specified, default is a maximum of 60 seconds.
-+#
-+# tls_random_upd_period = 60s
-+
-+# If you have a entropy source available, that is not easily drained (like
-+# /dev/urandom), the daemons can also load additional entropy on startup from
-+# the source specified. By default an amount of 32 bytes is read, the
-+# equivalent to 256 bits. This is more than enough to generate a 128bit
-+# (or 168bit) session key, but we may have to generate more than one.
-+# Usage of this option may drain EGD (consider the case of 50 smtp starting
-+# up with a full queue and "postfix start", which will request 1600bytes
-+# of entropy). This is however not fatal, as long as "entropy" data could
-+# be read from the exchange file.
-+#
-+# tls_daemon_random_source = dev:/dev/urandom
-+tls_daemon_random_source = egd:/var/run/egd-pool
-+# tls_daemon_random_bytes = 32
-+</pre>
-+
-+<h2>master.cf: tlsmgr daemon</h2>
-+
-+If you don't have a /dev/urandom device and/or use session caching,
-+you must run the "tlsmgr" daemon (see conf/master.cf). The tlsmgr
-+needs to access entropy sources and can (currently) not be
-+chrooted. It can drop its privileges, if the entropy sources (e.g.
-+/dev/urandom or an EGD socket) don't have access restrictions. 
-+
-+<pre>
-+# ==========================================================================
-+# service type  private unpriv  chroot  wakeup  maxproc command + args
-+#               (yes)   (yes)   (yes)   (never) (50)
-+# ==========================================================================
-+tlsmgr    fifo  -       -       n       300     1       tlsmgr
-+</pre>
-+
-+<h2>master.cf: additional services</h2>
-+
-+It can be useful to have postfix listen on additional ports, namely
-+"submission"=587 for email submission as defined in RFC2476; this
-+is especially useful if you want to allow AUTH with plaintext
-+passwords (PLAIN, LOGIN) and hence run on a port with encryption
-+enforcement. Another useful port may be "smtps"=465 which was
-+intended with TLS-wrapping and is still used by Outlook (Express). 
-+
-+<p>Both example entries already contain the flags to enable SASL
-+authentication (which may be disabled on the normal port). Since
-+the actual service names are used, smtps and submission must be
-+defined in /etc/services (and probably also in
-+/var/spool/postfix/etc/services if chrooted)!!! (Use the port
-+numbers otherwise.)</p>
-+
-+<pre>
-+# ==========================================================================
-+# service type  private unpriv  chroot  wakeup  maxproc command + args
-+#               (yes)   (yes)   (yes)   (never) (50)
-+# ==========================================================================
-+smtps     inet  n       -       y       -       -       smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
-+submission inet n       -       y       -       -       smtpd -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes
-+</pre>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/index.html snapshot-20010228/html/ssl/index.html
---- snapshot-20010228-orig/html/ssl/index.html Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/index.html      Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,50 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - A TLS extension for POSTFIX</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - A TLS extension for POSTFIX</h1>
-+
-+<h2>Contents</h2>
-+
-+<ul>
-+<li><a href="intro.html">Introduction</a></li>
-+
-+<li><a href="install.html">Installating the patchkit</a></li>
-+
-+<li><a href="setup.html">Setting up the certificates</a></li>
-+
-+<li><a href="conf.html">Configuring main.cf</a></li>
-+
-+<li><a href="security.html">Security considerations</a></li>
-+
-+<li><a href="test.html">Testing</a></li>
-+
-+<li><a href="prng.html">PRNG - Pseudo Random Number
-+Generator</a></li>
-+
-+<li><a href="references.html">References</a></li>
-+</ul>
-+
-+<pre>
-+PLEASE REMEMBER THAT EXPORT/IMPORT AND/OR USE OF STRONG
-+CRYPTOGRAPHY SOFTWARE, PROVIDING CRYPTOGRAPHY HOOKS OR EVEN JUST
-+COMMUNICATING TECHNICAL DETAILS ABOUT CRYPTOGRAPHY SOFTWARE IS
-+ILLEGAL IN SOME PARTS OF THE WORLD. SO, WHEN YOU IMPORT THIS PACKAGE
-+TO YOUR COUNTRY, RE-DISTRIBUTE IT FROM THERE OR EVEN JUST EMAIL
-+TECHNICAL SUGGESTIONS OR EVEN SOURCE PATCHES TO THE AUTHOR OR
-+OTHER PEOPLE YOU ARE STRONGLY ADVICED TO PAY CLOSE ATTENTION TO ANY
-+EXPORT/IMPORT AND/OR USE LAWS WHICH APPLY TO YOU. THE AUTHOR OF
-+POSTFIX/TLS IS NOT LIABLE FOR ANY VIOLATIONS YOU MAKE HERE. SO BE
-+CAREFULLY YOURSELF, IT IS YOUR RESPONSIBILITY.
-+</pre>
-+
-+Lutz J&auml;nicke, <a href=
-+"http://www.aet.tu-cottbus.de/personen/jaenicke/">Homepage</a>,
-+Email: <a href="mailto:Lutz.Jaenicke@aet.TU-Cottbus.DE"><em>
-+Lutz.Jaenicke@aet.TU-Cottbus.DE</em></a>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/install.html snapshot-20010228/html/ssl/install.html
---- snapshot-20010228-orig/html/ssl/install.html       Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/install.html    Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,90 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Installation</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Installing the patchkit</h1>
-+
-+<h2>Prerequisits</h2>
-+
-+This patchkit is prepared for 
-+
-+<ul>
-+<li>Postfix Version release-20010228<br>
-+ <a href="http://www.postfix.org/">http://www.postfix.org/</a> [<a
-+href="references.html#postfix">POSTFIX</a>]<br>
-+ The use of other versions might lead to patch conflicts or silent
-+failures, as we directly change the source code.</li>
-+
-+<li>OpenSSL Version 0.9.5 or later (recommended: 0.9.6)<br>
-+ <a href="http://www.openssl.org/">http://www.openssl.org/</a> [<a
-+href="references.html#openssl">OPENSSL</a>]<br>
-+We use OpenSSL as library (and some command line tools to create
-+the certificates, if necessary). OpenSSL is the successor of
-+SSLeay.
-+<p>Postfix/TLS uses properties that are only available starting with
-+version 0.9.5 of the OpenSSL library. 0.9.5a has proven stability
-+over several months. The latest release 0.9.6 contains several improvements
-+and has proven stability so far.
-+</li>
-+</ul>
-+
-+You may also need to update your "patch" utility (see below). 
-+
-+<h2>Patching</h2>
-+
-+The changes to the postfix source code as well as the additional
-+files are included in the "<code>pfixtls.diff</code>" in the main
-+directory of the patch kit. It is a unified diff. 
-+
-+<p>To apply the patches, go to the directory one level below the
-+original postfix source tree (you should see
-+"<code>postfix-xxxxxxx</code>" or "<code>snapshot-xxxxxxx</code>"
-+when doing an "<code>ls -al</code>"
-+at this point. The patch is then applied with:</p>
-+
-+<pre>
-+patch -p0 &lt; path-to/pfixtls.diff
-+</pre>
-+
-+If you experience problems during the patch process (e.g. with the
-+HP-UX 10.20 included patch), you might need to update your patch
-+program, e.g. to an actual GNU-patch. 
-+
-+<p>If you need to apply the patchkit to a different version of
-+patchlevel of postfix, you might try the following:</p>
-+
-+<pre>
-+cd postfix-directory ; patch -p1 &lt; path-to/pfixtls.diff
-+</pre>
-+
-+Since the patch is in unified form, it might also apply to a mildly
-+changed source, as long as no conflicts appear. 
-+
-+<h2>Compiling</h2>
-+
-+After patching postfix will configure and compile as before. In
-+order to enable the TLS functions, you must specify the path to the
-+OpenSSL header files as well as the appropriate libraries, and you
-+must define <code>HAS_SSL</code>. Your command for configuration
-+might then be: 
-+
-+<pre>
-+make makefiles CCARGS="-DHAS_SSL -I/usr/local/ssl/include" AUXLIBS="-L/usr/local/ssl/lib -lssl -lcrypto"
-+</pre>
-+
-+You might need additional customization e.g. for using Berkeley-DB
-+as listed in the postfix INSTALL instructions. You can then
-+continue in the usual way with: 
-+
-+<pre>
-+make
-+</pre>
-+
-+and then follow the instructions in the postfix INSTALL file. 
-+
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/intro.html snapshot-20010228/html/ssl/intro.html
---- snapshot-20010228-orig/html/ssl/intro.html Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/intro.html      Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,184 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Introduction</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Introduction</h1>
-+
-+Postfix/TLS is an extension of the Postfix [<a href=
-+"references.html#postfix">POSTFIX</a>] MTA software to support the
-+TLS protocol. 
-+
-+<h2>A note about the start of the project</h2>
-+
-+When I started writing this software, I had a sophisticated way to
-+allow <a href="relaycert.html">relaying for roaming users</a> in
-+mind. In the meantime, this project is living on its own. 
-+
-+<h2>RFC2246: The TLS (former SSL) protocol</h2>
-+
-+By default all communication on the Internet is done without
-+encryption and without strong authentication. That does mean that
-+everybody with physical access to the communication line along
-+which a network packet will travel can eavesdrop on your
-+communication. Even worse, it might be possible to redirect or
-+alter your communication so that information, that you want to send
-+to a party can be lost or changed without your notice. 
-+
-+<p>In order to solve these security issues, the SSL protocol
-+(Secure Socket Layers) was introduced by Netscape, Inc., which now
-+has evolved into the standardised TLS protocol (Transportation
-+Layer Security) as <a href="rfc2246.txt">RFC2246</a>. It offers
-+both encryption of the communication (stopping eavesdropping) and
-+strong authentication (making sure that both parties of a
-+communication are correctly identified and that the communication
-+cannot be altered).</p>
-+
-+<p>Postfix/TLS does not realize the TLS protocol itself; it rather
-+uses the OpenSSL package [<a href=
-+"references.html#openssl">OPENSSL</a>] for this task. At the
-+OpenSSL WWW-site you can also find links to in-depth documentation
-+of the protocol and its features, so that it is not necessary to
-+included them here. (And, of course, there is no use of re-writing
-+what other people already wrote down, it just introduces additional
-+errors.)</p>
-+
-+<h2>RFC2487: Introducing TLS to SMTP</h2>
-+
-+The integration of the TLS protocol to Internet mail, SMTP (Simple
-+Mail Transport Protocol) is described in <a href="rfc2487.txt">
-+RFC2487</a>. 
-+
-+<p>Unlike the first incarnations of SSL as a <em>wrapper</em>
-+around normal network communications [<a href=
-+"references.html#stunnel">STUNNEL</a>] [<a href=
-+"references.html#jonama">JONAMA</a>], the TLS protocol is now
-+completely <em>integrated</em> into the ESMTP: during the startup
-+negotiation (EHLO) the server offers the support of TLS by
-+advertising the <strong>STARTTLS</strong> feature. The client can
-+now send the <strong>STARTTLS</strong> command to do authentication
-+and switch to encrypted communication.</p>
-+
-+<h2>Postfix/TLS: what can it do for you</h2>
-+
-+The list of features presented here should be understood as a list
-+of ideas. Not all of them are realized yet, please see the notes at
-+each feature. 
-+
-+<ul>
-+<li>Encrypted email transfer from one host to another.<br>
-+Status: realized.<br>
-+Comment: Once the STARTTLS negotiation is finished, the
-+communication between both parties is encrypted.
-+This also includes the MAIL FROM: and RCPT TO: envelop sender
-+and recipient negotiation, so that an eavesdropper will not be able
-+to get these informations.</li>
-+
-+<li>Authentication of the receiving host to prevent
-+interception.<br>
-+Status: realized.<br>
-+Comment: This is a quite important feature that is not difficult to
-+implement. The problem lies in the fact, that not all hosts (read
-+this: by now nearly no one) support this protocol. The sender must
-+hence maintain a list of receivers which must identify by TLS,
-+otherwise one could just intercept the communication and not offer
-+STARTTLS, so that no authentication is done. One must also be
-+careful to use the correct name of the host (see CNAMEs), but this
-+problem is the same for http-servers.</li>
-+
-+<li>Authentication of the sending host to prevent forgery.<br>
-+Status: Difficult to do.<br>
-+Comment: The transmission of emails is just a connection to the
-+SMTP port (25) of the receiving host. This is done by either
-+another MTA (Mail Transport Agent) or a MUA (Mail User Agent). In
-+the first case, the sending MTA should present a client certificate
-+issued on the name of the sending host. In the latter case however,
-+the user has no access to the host's certificate and will (or not)
-+present his own personal certificate. At this point I think that a
-+satisfying <em>and</em> reliable solution is hardly possible (do
-+you want your users' email bounce without reason?), so it has least
-+priority.</li>
-+
-+<li>Authentication of the sending host to allow relaying.<br>
-+Status: realized.<br>
-+Comment: This was the intention I had in mind when starting this
-+project, so it was realized first. Based on the certificate the
-+client MTA or MUA presents to the server, relaying can be
-+allowed.</li>
-+
-+<li>Any more ideas???<br>
-+Status: Send me an email.</li>
-+</ul>
-+
-+<h2>Postfix/TLS: what it cannot do for you</h2>
-+
-+There is one thing that I explicitly want to point out: 
-+
-+<ul>
-+<li>Securing the privacy of your email.<br>
-+Status: Cannot be done.<br>
-+Comment: RFC2487 only takes care of the transportation between mail
-+servers. To assure that nobody can eavesdrop on your private email
-+communication, it would be necessary that 
-+
-+<ul>
-+<li>all of the mailhubs in between are enforcing TLS.</li>
-+
-+<li>all mailhubs themselves are trustworthy, as the email is only
-+encrypted during transport, not when queued or spooled.</li>
-+
-+<li>the destination is trustworthy, as the mail is spooled in clear
-+and everybody who can access your mailbox (read this: at least the
-+superuser) can read your mail!</li>
-+</ul>
-+
-+Hence, if you want privacy, you have to <em>send out</em> your
-+email encrypted, e.g. using S/MIME or the traditional PGP
-+package.</li>
-+
-+<li>Authenticate the sender of an email.<br>
-+Status: Cannot be done.<br>
-+Comment: A lot of MUAs send out emails by just connecting the SMTP
-+port of the sending host or nearest mailhub. There is no way to
-+assure that the sender listed in the email is the real sender of
-+the email. And even if it would be possible to identify the sender,
-+the contents of the email might have been altered in between.<br>
-+To ensure the identity of the sender and the integrity of the
-+email, you can again use S/MIME or PGP.</li>
-+</ul>
-+
-+<h2>Other OpenSource packages</h2>
-+
-+As of version sendmail-8.11, sendmail includes RFC2487 support [<a
-+href="references.html#sendmail">SENDMAIL</a>]. 
-+
-+<p>Frederik Vermeulen has realized an RFC2487 extension [<a href=
-+"references.html#qmailtls">QMAILTLS</a>] for the Qmail [<a href=
-+"references.html#qmail">QMAIL</a>] MTA.</p>
-+
-+<p>Matti Aarnio has integrated RFC2487 into ZMailer [<a href=
-+"references.html#zmailer">ZMAILER</a>].</p>
-+
-+<p>Michal Trojnara is currently integrating basic SMTP support into
-+his stunnel software, starting with stunnel-3.3 [<a href=
-+"references.html#stunnel">STUNNEL</a>].</p>
-+
-+<p>Trey Childs is also working on a "wrapper" solution [<a href=
-+"references.html#smtps">SMTPS</a>].</p>
-+
-+<h2>Commercial implementations</h2>
-+
-+The commercial version of sendmail includes RFC2487 support [<a
-+href="references.html#sendmail.inc">SENDMAIL.INC</a>]. 
-+
-+<p>Netscape Enterprise Server and Microsoft Exchange Server do offer
-+RFC2487 functionality.</p>
-+
-+<p>The CommunigatePro mailserver software also supports RFC2487
-+[<a href="references.html#communigate">COMMUNIGATE</a>].</p>
-+
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/loadCAcert.pl snapshot-20010228/html/ssl/loadCAcert.pl
---- snapshot-20010228-orig/html/ssl/loadCAcert.pl      Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/loadCAcert.pl   Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,23 @@
-+#!/usr/local/bin/perl -T
-+
-+require 5.003;
-+use strict;
-+use CGI;
-+
-+my $cert_dir = "/usr/local/ssl/certs";
-+my $cert_file = "CAcert.pem";
-+
-+my $query = new CGI;
-+
-+my $kind = $query->param('FORMAT');
-+if($kind eq 'DER') { $cert_file = "CAcert.der"; }
-+
-+my $cert_path = "$cert_dir/$cert_file";
-+
-+open(CERT, "<$cert_path");
-+my $data = join '', <CERT>;
-+close(CERT);
-+print "Content-Type: application/x-x509-ca-cert\n";
-+print "Content-Length: ", length($data), "\n\n$data";
-+
-+1;
-diff -Nur snapshot-20010228-orig/html/ssl/myownca.html snapshot-20010228/html/ssl/myownca.html
---- snapshot-20010228-orig/html/ssl/myownca.html       Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/myownca.html    Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,175 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Being your on CA</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Lutz's very short course on being your own
-+CA</h1>
-+
-+This section is kept quite short as there are already a lot of
-+pages explaining these things (e.g. [<a href=
-+"references.html#introcert">INTROCERT</a>]). There are also
-+projects under way to make this task easier [<a href=
-+"references.html#openca">OPENCA</a>], so I wont't waste your time
-+(and mine) by writing a book about it. 
-+
-+<h2>Be your own CA</h2>
-+
-+If you want to do relaying based on client certificates you may
-+want to issue your own client certificates; hence you want to be
-+your own certificate authority (CA). Of course nobody else will
-+accept your certificates, so the damage you do is not so high (the
-+requirements for a good "professional" CA are very high, as you
-+should have the CA key on a private host without network for
-+security, be strict about checking the identity of requesters etc).
-+
-+
-+<p>For laziness, we also don't care about the (worthful)
-+possibility to generate certificates for specific purposes (e.g.
-+for servers, clients, email-signing) and simply generate "unlimited
-+general purpose" certificates. So a certificate issued for the
-+person "John Doe" is also valid for the "John Doe"-server.</p>
-+
-+<p>Using OpenSSL it is quite simple to become your own CA. Just
-+run</p>
-+
-+<pre>
-+CA.pl -newca
-+</pre>
-+
-+and you are done. Just make sure, that you select a useful CN
-+(Common Name)! By just using your name, you might create a lot of
-+confusion, as the CA certificate for "Lutz Jaenicke" looks quite
-+the same as the personal client certificate for "Lutz Jaenicke" (I
-+can tell you). Of course you can further improve this private CA by
-+editing the <code>openssl.cnf</code> file, especially the comment. 
-+
-+<p>If you want the full comfort of being your own CA, you must
-+import your CA certificate to Netscape. Unfortunately Netscape does
-+not offer an explicit function to perform this task (unlike for
-+client certificates). If you have an http-server available (and I
-+think you do), you can add the <a href="loadCAcert.pl">
-+loadCAcert.pl</a> script to your <code>cgi-bin</code> directory. If
-+you call it from Netscape (or Internet Explorer), you can load the
-+certificate! (Taken from [<a href=
-+"references.html/#introcert">6</a>])</p>
-+
-+<h2>Create your site certificate</h2>
-+
-+Ok, you now must create a site certificate for your postfix server.
-+As your clients will use it for verification, it must contain the
-+name of your host as common name (CN): host.in.domain. 
-+
-+<p>You want your postfix system to start up at boot time without
-+trouble? Then your server private key must not be encrypted. So
-+when you create the key you must add the <code>-nodes</code> option
-+in <code>CA.pl</code> to the line with the <code>-newcert</code>
-+and/or <code>-newreq</code> command:</p>
-+
-+<pre>
-+*** CA.pl   Wed Mar 24 10:30:38 1999
-+--- CA1.pl  Sat Mar 27 19:36:47 1999
-+***************
-+*** 56,67 ****
-+        exit 0;
-+    } elsif (/^-newcert$/) {
-+        # create a certificate
-+!       system ("$REQ -new -x509 -keyout newreq.pem -out newreq.pem $DAYS");
-+        $RET=$?;
-+        print "Certificate (and private key) is in newreq.pem\n"
-+    } elsif (/^-newreq$/) {
-+        # create a certificate request
-+!       system ("$REQ -new -keyout newreq.pem -out newreq.pem $DAYS");
-+        $RET=$?;
-+        print "Request (and private key) is in newreq.pem\n";
-+    } elsif (/^-newca$/) {
-+--- 56,67 ----
-+        exit 0;
-+    } elsif (/^-newcert$/) {
-+        # create a certificate
-+!       system ("$REQ -new -x509 -nodes -keyout newreq.pem -out newreq.pem $DAYS");
-+        $RET=$?;
-+        print "Certificate (and private key) is in newreq.pem\n"
-+    } elsif (/^-newreq$/) {
-+        # create a certificate request
-+!       system ("$REQ -new -nodes -keyout newreq.pem -out newreq.pem $DAYS");
-+        $RET=$?;
-+        print "Request (and private key) is in newreq.pem\n";
-+    } elsif (/^-newca$/) {
-+</pre>
-+
-+For sslwrap or stunnel the authors propose to use self signed certs
-+created with <code>-newcert</code>. I rather propose to create an
-+ordinary certificate request with 
-+
-+<pre>
-+CA.pl -newreq
-+</pre>
-+
-+and then sign it with your CA: 
-+
-+<pre>
-+CA.pl -sign
-+</pre>
-+
-+Now you can install the cert from <code>cacert.pem</code> to <code>
-+/etc/postfix/CAcert.pem</code>, the created certificate from <code>
-+newcert.pem</code> to <code>/etc/postfix/cert.pem</code> and the
-+key part form <code>newreq.pem</code> to <code>
-+/etc/postfix/key.pem</code>. Please be aware, that the <code>
-+key.pem</code> is not protected by password, so you have to protect
-+it by file access privileges. As the information is read before
-+smtpd changes to chroot jail, it still has root privileges, so you
-+should 
-+
-+<pre>
-+chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
-+</pre>
-+
-+<h2>Create a client certificate</h2>
-+
-+Creating a client certificate is as easy as a site certificate. At
-+least, if you are doing it as a CA. First you create and sign a
-+pair of key and certificate. Be sure to add the correct common name
-+(CN) for the client: 
-+
-+<pre>
-+CA.pl -newreq
-+CA.pl -sign
-+</pre>
-+
-+If you want to do client certificate based relaying, you do need
-+the fingerprint of the certificate, which can be obtained with 
-+
-+<pre>
-+openssl x509 -fingerprint -in newcert.pem
-+</pre>
-+
-+Now this certificate must be imported into netscape. Therefore the
-+data you just created must be converted to a ".p12" file in PKCS#12
-+format. You do need the <code>pkcs12</code> utility [<a href=
-+"references.html#pkcs12">PKCS12</a>], which is included in the
-+OpenSSL package as of version 0.9.3. The necessary command is: 
-+
-+<pre>
-+pkcs12 -export -in newcert.pem -inkey newreq.pem \
-+  -certfile /usr/local/ssl/CAcert.pem -name "Name" -out newcert.p12
-+</pre>
-+
-+Of course your filenames may vary. Please take special care to
-+supply a good name to your certificate. First: The name will be
-+listed every time when a client certificate is to be send by
-+netcape. As a person may have several certificates, the name might
-+include a hint on the CA (e.g. "Lutz Jaenicke (Lutz CA)"). <strong>
-+If you want to have a lot of fun, you can just omit the name.
-+Netscape will happily import the certificate, but you won't see it
-+in the list of user certificates. And as you don't see it, you
-+cannot select it. And as Netscape will not overwrite it, if you
-+offer the same (corrected) certificate with a name, you want to
-+delete it, but as you cannot select it, you cannot delete it. You
-+got the point?</strong>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/prng.html snapshot-20010228/html/ssl/prng.html
---- snapshot-20010228-orig/html/ssl/prng.html  Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/prng.html       Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,97 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - PRNG Pseudo Random Number Generator</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - PRNG Pseudo Random Number Generator</h1>
-+
-+One of the crucial points of encryption is the generation of the
-+keys, for which random numbers are required. As of OpenSSL 0.9.5,
-+the seeding of the included PRNG Pseudo Random Number Generator is
-+checked. Starting with Postfix/TLS 0.5.4, an architecture to
-+collect entropy is included. 
-+
-+<h2>Included PRNG</h2>
-+
-+OpenSSL features a quite sophisticated PRNG. In order to generate
-+random numbers of lengths of more then 1024bit, a 8192bit (=1kB)
-+pool is kept and used to generate these random numbers. To achieve
-+full complexity for an attacker, it is necessary to have the full
-+range of random numbers available and not restrict the search space
-+used for searching keys, hence an according amount of entropy is
-+necessary. 
-+
-+<h2>Obtaining Entropy</h2>
-+
-+To get entropy, unpredictable events are needed. Unfortunately,
-+computers and software tend to be very predictable, so that a lot
-+of effort is necessary to collect unpredictable events. The
-+mathematical techniques are discussed in the excellent book of
-+Schneier "Applied Cryptography". 
-+
-+<p>We use at least one feature: if you have collected a pool of
-+data with entropy in it, you can add up more data without losing
-+the entropy already there, so that we can mix external sources and
-+internal bits to only increase the entropy.</p>
-+
-+<h2>External sources</h2>
-+
-+Only few operating systems provide good entropy collection. 
-+
-+<h3>/dev/random and /dev/urandom</h3>
-+
-+Linux offers the <tt>/dev/random</tt> and <tt>/dev/urandom</tt>
-+devices, some BSD derivatives as well. 
-+
-+<p><tt>/dev/random</tt> will provide high quality random data, but
-+it will block until enough entropy is available, if too much random
-+data is requested to fast. <tt>/dev/urandom</tt> will fill up the
-+real entropy data with data from an internal PRNG and will never
-+block. For a system with automated startup /dev/urandom should be
-+used. Reading from /dev/urandom will however trigger kernel
-+activity to satisfy the demands. Imagine starting up postfix with a
-+large number of emails in the queue. 50 (default) smtp processes
-+want to start at the same time and access <tt>
-+/dev/urandom</tt>.</p>
-+
-+<h3>Entropy Gathering Daemon</h3>
-+
-+A replacement for operating systems without good random number
-+collection is the <a href="references.html#egd">EGD</a> Entropy
-+Gathering Daemon. It will also extract entropy from a lot of
-+sources. 
-+
-+<p>EGD has a command driven interface, there is a command for
-+blocking and one for non-blocking read. Unlike <tt>
-+/dev/urandom</tt> the non-blocking command will not trigger an
-+internal PRNG to fill up, but will simply return a smaller number
-+of bytes than requested, even 0 if totally drained.</p>
-+
-+<p>EGD should hence not be used for direct feeding of smtp[d]
-+processes. Again, imagine 50 smtp processes starting delivery at
-+the same time.</p>
-+
-+<p><em>To circumvent this problem, I have witten my own daemon,
-+that has a EGD compatible interface but can never run dry, just
-+like <tt>/dev/urandom</tt>. Check out <a href=
-+"references.html#prngd">PRNGD</a> for details.</em></p>
-+
-+<h3>Intermediate File</h3>
-+
-+Hence, Postfix/TLS maintains its own pool of entropy by means
-+of the <em>tlsmgr</em> daemon. It will collect entropy from an
-+external source at startup and periodically during runtime to ever
-+increase the entropy in the pool. The smtp[d] processes are fed
-+from an PRNG exchange file that is updated in short periods. Upon
-+restart, tlsmgr will also read entropy from this file, so that the
-+large entropy pool is fully utilized.
-+
-+<p>The single smtp[d] daemons can also access an external source. Their
-+collected entropy is also stirred into the intermediate file, so that
-+a significant amount of entropy is available alltogether.
-+
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/references.html snapshot-20010228/html/ssl/references.html
---- snapshot-20010228-orig/html/ssl/references.html    Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/references.html Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,101 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - References</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - References</h1>
-+
-+<ol>
-+<li>[<a name="postfix">POSTFIX] The Postfix (formerly VMailer) Home
-+Page: <a href="http://www.postfix.org/">
-+http://www.postfix.org/</a>.</a></li>
-+
-+<li>[<a name="openssl">OPENSSL</a>] OpenSSL: The Open Source
-+toolkit for SSL/TLS: <a href="http://www.openssl.org/">
-+http://www.openssl.org/</a>.</li>
-+
-+<li>[<a name="pkcs12">PKCS12</a>]OpenSSL PKCS#12 Program FAQ: <a
-+href="http://www.drh-consultancy.demon.co.uk/pkcs12faq.html">
-+http://www.drh-consultancy.demon.co.uk/pkcs12faq.html</a>.</li>
-+
-+<li>[<a name="sslwrap">SSLWRAP</a>] SSLwrap Homepage: <a href=
-+"http://www.rickk.com/sslwrap/">
-+http://www.rickk.com/sslwrap/</a>.</li>
-+
-+<li>[<a name="stunnel">STUNNEL</a>] Stunnel Homepage: <a href=
-+"http://mike.daewoo.com.pl/computer/stunnel/">
-+http://mike.daewoo.com.pl/computer/stunnel/</a>.</li>
-+
-+<li>[<a name="introcert">INTROCERT</a>] Introducing SSL and
-+Certificates using SSLeay: <a href=
-+"http://www.camb.opengroup.org/RI/www/prism/wwwj/index.html">
-+http://www.camb.opengroup.org/RI/www/prism/wwwj/index.html</a>.</li>
-+
-+<li>[<a name="imcorg">IMC</a>] Internet Mail Consortium: <a href=
-+"http://www.imc.org/">http://www.imc.org/</a>.</li>
-+
-+<li>[<a name="imcorgappstls">IETF-APPS-TLS</a>] ietf-apps-tls
-+mailing list: <a href="http://www.imc.org/ietf-apps-tls/">
-+http://www.imc.org/ietf-apps-tls/</a></li>
-+
-+<li>[<a name="openca">OPENCA</a>] The OpenCA Project: <a href=
-+"http://www.openca.org/">http://www.openca.org/</a>.</li>
-+
-+<li>[<a name="dfncert">DFNCERT</a>] DFN-CERT: <a href=
-+"http://www.cert.dfn.de/">http://www.cert.dfn.de/</a>.</li>
-+
-+<li>[<a name="sendmail">SENDMAIL</a>] Sendmail: <a href=
-+"http://www.sendmail.org/">http://www.sendmail.org/</a>.</li>
-+
-+<li>[<a name="sendmail.inc">SENDMAIL.INC</a>] Sendmail Inc: <a
-+href="http://www.sendmail.com/">http://www.sendmail.com/</a>.</li>
-+
-+<li>[<a name="qmail">QMAIL</a>] Qmail: <a href=
-+"http://www.qmail.org/">http://www.qmail.org/</a>.</li>
-+
-+<li>[<a name="qmailtls">QMAILTLS</a>] Qmail/TLS: <a href=
-+"http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch">
-+http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch</a>.</li>
-+
-+<li>[<a name="zmailer">ZMAILER</a>] ZMailer: <a href=
-+"http://www.zmailer.org/">http://www.zmailer.org/</a>.</li>
-+
-+<li>[<a name="jonama">JONAMA</a>] Jonama: <a href=
-+"http://www.multimania.com/jonama/">
-+http://www.multimania.com/jonama/</a>.</li>
-+
-+<li>[<a name="smtps">SMTPS</a>] Trey Child's STARTTLS wrapper: <a
-+href="http://sites.netscape.net/tc15163/homepage">
-+http://sites.netscape.net/tc15163/homepage</a>.</li>
-+
-+<li>[<a name="safegossip">SAFEGOSSIP</a>] Safegossip universal
-+TLS-wrapper: <a href="http://www.skygate.co.uk/safegossip/">
-+http://www.skygate.co.uk/safegossip/</a>.</li>
-+
-+<li>[<a name="sendmailtls">SENDMAIL-TLS</a>] Jeremy Beker's
-+sendmail-tls wrapper: <a href="http://opensource.3gi.com/">
-+http://opensource.3gi.com/</a>.</li>
-+
-+<li>[<a name="sendmailtls">COMMUNIGATE</a>] Stalker Software's
-+CommunigatePro mailserver product: <a href="http://www.stalker.com/">
-+http://www.stalker.com/</a>.</li>
-+
-+<li>[<a name="egd">EGD</a>] Entropy Gathering Daemon: <a href=
-+"http://www.lothar.com/tech/crypto/">
-+http://www.lothar.com/tech/crypto/</a>.</li>
-+
-+<li>[<a name="prngd">PRNGD</a>] Pseudo Random Number Generator
-+Daemon: <a href=
-+"http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html">
-+http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html</a>.</li>
-+
-+<li>[<a name="oe_ssl">Outlook/SSL</a>] Outlook (Express) and
-+STARTTLS info: <a href=
-+"http://support.microsoft.com/support/kb/articles/Q218/4/30.ASP">
-+http://support.microsoft.com/support/kb/articles/Q218/4/30.ASP</a>.</li>
-+</ol>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/relaycert.html snapshot-20010228/html/ssl/relaycert.html
---- snapshot-20010228-orig/html/ssl/relaycert.html     Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/relaycert.html  Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,124 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Initial Motivation</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Initial Motivation</h1>
-+
-+This introduction shall point out the motivation, why I spend my
-+time writing this TLS extension for postfix. 
-+
-+<h2>Roaming users problem</h2>
-+
-+It quite often happens that my users want to access their mailboxes
-+and to send emails from hosts outside our network. The main reasons
-+are the access from home via Internet service providers (ISP) or
-+from abroad during business trips (in our case typically to other
-+universities around the world). Sending and accessing leads to two
-+loosely coupled problems. 
-+
-+<h2>UCE control</h2>
-+
-+One problem is sending emails, because from abroad it is seldom
-+possible to predict the sending hostname we will have and when
-+using an ISP the assigned hostname is typically random. As we of
-+course must have UCE control in effect, I either must open up
-+relaying complete ISP domains on my users request (Arrgghh!) or
-+must introduce an authentication beside the hostname or IP address.
-+
-+
-+<h2>Passwords and insecure networks</h2>
-+
-+This directly leads to the second problem. Recent versions of
-+Netscape do offer password based authentication. This solves the
-+UCE problem but introduces another one, which I consider far more
-+severe: The users have to send a password in plain text over the
-+network. Of course I could solve this problem by issuing special
-+passwords just for this reasons, but some of my users don't have a
-+clue of what is going on between the keyboard and the screen, so
-+they would happily try their real password. 
-+
-+<p>The same problem of course also applies to the POP and IMAP
-+services. I tackled them first, because they are typically attacked
-+by port scanners, so I closed them down by tcpwrappers (Hi Wietse!)
-+to only allow my local hosts to access them.</p>
-+
-+<h2>Encryption via SSL</h2>
-+
-+The solution to the plain text password problem was easily found
-+with the use of SSL. You just tunnel the POP or IMAP connection
-+through SSL, using either <strong>SSLwrap</strong> [<a href=
-+"references.html#sslwrap">SSLWRAP</a>] or <strong>stunnel</strong>
-+[<a href="references.html#stunnel">STUNNEL</a>]. 
-+
-+<p>Netscape supports IMAP with SSL tunneling since version 4, I
-+have one user with Outlook Express, who uses POP3 with SSL
-+tunneling, so this solves the plain text password problem by
-+encryption.</p>
-+
-+<h2>Netscape 4.5</h2>
-+
-+Starting with Netscape 4.5, also sending with SSL encryption is
-+supported. As Netscape also supports client certificates, this
-+seemed to be an easy solution for the UCE control problem. So I
-+happily added an "smtps" service with SSL wrapper and client
-+certificate verification. Unfortunately it didn't work and the
-+connection just hung! After some digging around I found out, that
-+Netscape 4.5 seems to realize the protocol described in <a href=
-+"rfc2487.txt">RFC 2487</a> [<a href=
-+"references.html#imcorg">IMC</a>]. 
-+
-+<h2>RFC 2487 - SMTP Service Extension for Secure SMTP over TLS</h2>
-+
-+RFC 2487 describes how to include TLS (the successor of SSL) into
-+the normal Extended SMTP protocol. During the normal EHLO start
-+negotiation the server offers the STARTTLS option to the client,
-+which then issues the STARTTLS command. After the server accepts
-+the command (220), the normal SSL handshake will start. 
-+
-+<p>Unfortunately it is impossible to handle this situation with a
-+normal tunneling software, as they are not prepared to do clear
-+text negotiation before running SSL and don't have the slightest
-+idea on the SMTP protocol. Therefore the way to go was to extend a
-+given mail server software. The first candidate was sendmail-8.9.3,
-+as I was a long term sendmail user. After digging around some I
-+came to the conclusion, that even though possible, the source code
-+was quite difficult to understand and adding the necessary
-+configuration options didn't look inviting.</p>
-+
-+<h2>Postfix</h2>
-+
-+At this point (February 1999) I checked other mail servers and was
-+immedideately fascinated by postfix source. It was very good to
-+read and understand, so I decided that if I would take the time,
-+then postfix would be the way to go. 
-+
-+<p>I then started to first change our site to postfix. It took some
-+hours to do this, because our mail system is running on a common
-+network I administrate for several chairs, each of them with its
-+own mail server and domain, but a common user base, so a lot of
-+rewriting takes place, we need virtual services for symbolic names
-+like "webmaster" etc.</p>
-+
-+<h2>Postfix/TLS</h2>
-+
-+Some time after having done this I finally found the time to write
-+my TLS extensions for postfix. I took the source of the <code>
-+s_server</code> of the OpenSSL package and added a simplified
-+version of it to postfix, so that by now we can run the SMTP
-+protocol encrypted on the server side. This would also allow us to
-+use plain text password authentication, but as it is available
-+without cost, I rather decided to go with client certificates. If
-+you can offer a client certificate to our server, that is included
-+in a list on our server, you can relay your emails through our
-+server! 
-+
-+<h2>Summary</h2>
-+
-+Postfix/TLS is an addition to the smtpd server, which implements the RFC 2487
-+ TLS Service Extension and allows UCE control based on client certificates.
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/rfc2246.txt snapshot-20010228/html/ssl/rfc2246.txt
---- snapshot-20010228-orig/html/ssl/rfc2246.txt        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/rfc2246.txt     Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,4483 @@
-+
-+
-+
-+
-+
-+
-+Network Working Group                                         T. Dierks
-+Request for Comments: 2246                                     Certicom
-+Category: Standards Track                                      C. Allen
-+                                                               Certicom
-+                                                           January 1999
-+
-+
-+                            The TLS Protocol
-+                              Version 1.0
-+
-+Status of this Memo
-+
-+   This document specifies an Internet standards track protocol for the
-+   Internet community, and requests discussion and suggestions for
-+   improvements.  Please refer to the current edition of the "Internet
-+   Official Protocol Standards" (STD 1) for the standardization state
-+   and status of this protocol.  Distribution of this memo is unlimited.
-+
-+Copyright Notice
-+
-+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
-+
-+Abstract
-+
-+   This document specifies Version 1.0 of the Transport Layer Security
-+   (TLS) protocol. The TLS protocol provides communications privacy over
-+   the Internet. The protocol allows client/server applications to
-+   communicate in a way that is designed to prevent eavesdropping,
-+   tampering, or message forgery.
-+
-+Table of Contents
-+
-+   1.       Introduction                                              3
-+   2.       Goals                                                     4
-+   3.       Goals of this document                                    5
-+   4.       Presentation language                                     5
-+   4.1.     Basic block size                                          6
-+   4.2.     Miscellaneous                                             6
-+   4.3.     Vectors                                                   6
-+   4.4.     Numbers                                                   7
-+   4.5.     Enumerateds                                               7
-+   4.6.     Constructed types                                         8
-+   4.6.1.   Variants                                                  9
-+   4.7.     Cryptographic attributes                                 10
-+   4.8.     Constants                                                11
-+   5.       HMAC and the pseudorandom function                       11
-+   6.       The TLS Record Protocol                                  13
-+   6.1.     Connection states                                        14
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 1]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   6.2.     Record layer                                             16
-+   6.2.1.   Fragmentation                                            16
-+   6.2.2.   Record compression and decompression                     17
-+   6.2.3.   Record payload protection                                18
-+   6.2.3.1. Null or standard stream cipher                           19
-+   6.2.3.2. CBC block cipher                                         19
-+   6.3.     Key calculation                                          21
-+   6.3.1.   Export key generation example                            22
-+   7.       The TLS Handshake Protocol                               23
-+   7.1.     Change cipher spec protocol                              24
-+   7.2.     Alert protocol                                           24
-+   7.2.1.   Closure alerts                                           25
-+   7.2.2.   Error alerts                                             26
-+   7.3.     Handshake Protocol overview                              29
-+   7.4.     Handshake protocol                                       32
-+   7.4.1.   Hello messages                                           33
-+   7.4.1.1. Hello request                                            33
-+   7.4.1.2. Client hello                                             34
-+   7.4.1.3. Server hello                                             36
-+   7.4.2.   Server certificate                                       37
-+   7.4.3.   Server key exchange message                              39
-+   7.4.4.   Certificate request                                      41
-+   7.4.5.   Server hello done                                        42
-+   7.4.6.   Client certificate                                       43
-+   7.4.7.   Client key exchange message                              43
-+   7.4.7.1. RSA encrypted premaster secret message                   44
-+   7.4.7.2. Client Diffie-Hellman public value                       45
-+   7.4.8.   Certificate verify                                       45
-+   7.4.9.   Finished                                                 46
-+   8.       Cryptographic computations                               47
-+   8.1.     Computing the master secret                              47
-+   8.1.1.   RSA                                                      48
-+   8.1.2.   Diffie-Hellman                                           48
-+   9.       Mandatory Cipher Suites                                  48
-+   10.      Application data protocol                                48
-+   A.       Protocol constant values                                 49
-+   A.1.     Record layer                                             49
-+   A.2.     Change cipher specs message                              50
-+   A.3.     Alert messages                                           50
-+   A.4.     Handshake protocol                                       51
-+   A.4.1.   Hello messages                                           51
-+   A.4.2.   Server authentication and key exchange messages          52
-+   A.4.3.   Client authentication and key exchange messages          53
-+   A.4.4.   Handshake finalization message                           54
-+   A.5.     The CipherSuite                                          54
-+   A.6.     The Security Parameters                                  56
-+   B.       Glossary                                                 57
-+   C.       CipherSuite definitions                                  61
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 2]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   D.       Implementation Notes                                     64
-+   D.1.     Temporary RSA keys                                       64
-+   D.2.     Random Number Generation and Seeding                     64
-+   D.3.     Certificates and authentication                          65
-+   D.4.     CipherSuites                                             65
-+   E.       Backward Compatibility With SSL                          66
-+   E.1.     Version 2 client hello                                   67
-+   E.2.     Avoiding man-in-the-middle version rollback              68
-+   F.       Security analysis                                        69
-+   F.1.     Handshake protocol                                       69
-+   F.1.1.   Authentication and key exchange                          69
-+   F.1.1.1. Anonymous key exchange                                   69
-+   F.1.1.2. RSA key exchange and authentication                      70
-+   F.1.1.3. Diffie-Hellman key exchange with authentication          71
-+   F.1.2.   Version rollback attacks                                 71
-+   F.1.3.   Detecting attacks against the handshake protocol         72
-+   F.1.4.   Resuming sessions                                        72
-+   F.1.5.   MD5 and SHA                                              72
-+   F.2.     Protecting application data                              72
-+   F.3.     Final notes                                              73
-+   G.       Patent Statement                                         74
-+            Security Considerations                                  75
-+            References                                               75
-+            Credits                                                  77
-+            Comments                                                 78
-+            Full Copyright Statement                                 80
-+
-+1. Introduction
-+
-+   The primary goal of the TLS Protocol is to provide privacy and data
-+   integrity between two communicating applications. The protocol is
-+   composed of two layers: the TLS Record Protocol and the TLS Handshake
-+   Protocol. At the lowest level, layered on top of some reliable
-+   transport protocol (e.g., TCP[TCP]), is the TLS Record Protocol. The
-+   TLS Record Protocol provides connection security that has two basic
-+   properties:
-+
-+     - The connection is private. Symmetric cryptography is used for
-+       data encryption (e.g., DES [DES], RC4 [RC4], etc.) The keys for
-+       this symmetric encryption are generated uniquely for each
-+       connection and are based on a secret negotiated by another
-+       protocol (such as the TLS Handshake Protocol). The Record
-+       Protocol can also be used without encryption.
-+
-+     - The connection is reliable. Message transport includes a message
-+       integrity check using a keyed MAC. Secure hash functions (e.g.,
-+       SHA, MD5, etc.) are used for MAC computations. The Record
-+       Protocol can operate without a MAC, but is generally only used in
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 3]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       this mode while another protocol is using the Record Protocol as
-+       a transport for negotiating security parameters.
-+
-+   The TLS Record Protocol is used for encapsulation of various higher
-+   level protocols. One such encapsulated protocol, the TLS Handshake
-+   Protocol, allows the server and client to authenticate each other and
-+   to negotiate an encryption algorithm and cryptographic keys before
-+   the application protocol transmits or receives its first byte of
-+   data. The TLS Handshake Protocol provides connection security that
-+   has three basic properties:
-+
-+     - The peer's identity can be authenticated using asymmetric, or
-+       public key, cryptography (e.g., RSA [RSA], DSS [DSS], etc.). This
-+       authentication can be made optional, but is generally required
-+       for at least one of the peers.
-+
-+     - The negotiation of a shared secret is secure: the negotiated
-+       secret is unavailable to eavesdroppers, and for any authenticated
-+       connection the secret cannot be obtained, even by an attacker who
-+       can place himself in the middle of the connection.
-+
-+     - The negotiation is reliable: no attacker can modify the
-+       negotiation communication without being detected by the parties
-+       to the communication.
-+
-+   One advantage of TLS is that it is application protocol independent.
-+   Higher level protocols can layer on top of the TLS Protocol
-+   transparently. The TLS standard, however, does not specify how
-+   protocols add security with TLS; the decisions on how to initiate TLS
-+   handshaking and how to interpret the authentication certificates
-+   exchanged are left up to the judgment of the designers and
-+   implementors of protocols which run on top of TLS.
-+
-+2. Goals
-+
-+   The goals of TLS Protocol, in order of their priority, are:
-+
-+    1. Cryptographic security: TLS should be used to establish a secure
-+       connection between two parties.
-+
-+    2. Interoperability: Independent programmers should be able to
-+       develop applications utilizing TLS that will then be able to
-+       successfully exchange cryptographic parameters without knowledge
-+       of one another's code.
-+
-+    3. Extensibility: TLS seeks to provide a framework into which new
-+       public key and bulk encryption methods can be incorporated as
-+       necessary. This will also accomplish two sub-goals: to prevent
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 4]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       the need to create a new protocol (and risking the introduction
-+       of possible new weaknesses) and to avoid the need to implement an
-+       entire new security library.
-+
-+    4. Relative efficiency: Cryptographic operations tend to be highly
-+       CPU intensive, particularly public key operations. For this
-+       reason, the TLS protocol has incorporated an optional session
-+       caching scheme to reduce the number of connections that need to
-+       be established from scratch. Additionally, care has been taken to
-+       reduce network activity.
-+
-+3. Goals of this document
-+
-+   This document and the TLS protocol itself are based on the SSL 3.0
-+   Protocol Specification as published by Netscape. The differences
-+   between this protocol and SSL 3.0 are not dramatic, but they are
-+   significant enough that TLS 1.0 and SSL 3.0 do not interoperate
-+   (although TLS 1.0 does incorporate a mechanism by which a TLS
-+   implementation can back down to SSL 3.0). This document is intended
-+   primarily for readers who will be implementing the protocol and those
-+   doing cryptographic analysis of it. The specification has been
-+   written with this in mind, and it is intended to reflect the needs of
-+   those two groups. For that reason, many of the algorithm-dependent
-+   data structures and rules are included in the body of the text (as
-+   opposed to in an appendix), providing easier access to them.
-+
-+   This document is not intended to supply any details of service
-+   definition nor interface definition, although it does cover select
-+   areas of policy as they are required for the maintenance of solid
-+   security.
-+
-+4. Presentation language
-+
-+   This document deals with the formatting of data in an external
-+   representation. The following very basic and somewhat casually
-+   defined presentation syntax will be used. The syntax draws from
-+   several sources in its structure. Although it resembles the
-+   programming language "C" in its syntax and XDR [XDR] in both its
-+   syntax and intent, it would be risky to draw too many parallels. The
-+   purpose of this presentation language is to document TLS only, not to
-+   have general application beyond that particular goal.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 5]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+4.1. Basic block size
-+
-+   The representation of all data items is explicitly specified. The
-+   basic data block size is one byte (i.e. 8 bits). Multiple byte data
-+   items are concatenations of bytes, from left to right, from top to
-+   bottom. From the bytestream a multi-byte item (a numeric in the
-+   example) is formed (using C notation) by:
-+
-+       value = (byte[0] << 8*(n-1)) | (byte[1] << 8*(n-2)) |
-+               ... | byte[n-1];
-+
-+   This byte ordering for multi-byte values is the commonplace network
-+   byte order or big endian format.
-+
-+4.2. Miscellaneous
-+
-+   Comments begin with "/*" and end with "*/".
-+
-+   Optional components are denoted by enclosing them in "[[ ]]" double
-+   brackets.
-+
-+   Single byte entities containing uninterpreted data are of type
-+   opaque.
-+
-+4.3. Vectors
-+
-+   A vector (single dimensioned array) is a stream of homogeneous data
-+   elements. The size of the vector may be specified at documentation
-+   time or left unspecified until runtime. In either case the length
-+   declares the number of bytes, not the number of elements, in the
-+   vector. The syntax for specifying a new type T' that is a fixed
-+   length vector of type T is
-+
-+       T T'[n];
-+
-+   Here T' occupies n bytes in the data stream, where n is a multiple of
-+   the size of T. The length of the vector is not included in the
-+   encoded stream.
-+
-+   In the following example, Datum is defined to be three consecutive
-+   bytes that the protocol does not interpret, while Data is three
-+   consecutive Datum, consuming a total of nine bytes.
-+
-+       opaque Datum[3];      /* three uninterpreted bytes */
-+       Datum Data[9];        /* 3 consecutive 3 byte vectors */
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 6]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Variable length vectors are defined by specifying a subrange of legal
-+   lengths, inclusively, using the notation <floor..ceiling>.  When
-+   encoded, the actual length precedes the vector's contents in the byte
-+   stream. The length will be in the form of a number consuming as many
-+   bytes as required to hold the vector's specified maximum (ceiling)
-+   length. A variable length vector with an actual length field of zero
-+   is referred to as an empty vector.
-+
-+       T T'<floor..ceiling>;
-+
-+   In the following example, mandatory is a vector that must contain
-+   between 300 and 400 bytes of type opaque. It can never be empty. The
-+   actual length field consumes two bytes, a uint16, sufficient to
-+   represent the value 400 (see Section 4.4). On the other hand, longer
-+   can represent up to 800 bytes of data, or 400 uint16 elements, and it
-+   may be empty. Its encoding will include a two byte actual length
-+   field prepended to the vector. The length of an encoded vector must
-+   be an even multiple of the length of a single element (for example, a
-+   17 byte vector of uint16 would be illegal).
-+
-+       opaque mandatory<300..400>;
-+             /* length field is 2 bytes, cannot be empty */
-+       uint16 longer<0..800>;
-+             /* zero to 400 16-bit unsigned integers */
-+
-+4.4. Numbers
-+
-+   The basic numeric data type is an unsigned byte (uint8). All larger
-+   numeric data types are formed from fixed length series of bytes
-+   concatenated as described in Section 4.1 and are also unsigned. The
-+   following numeric types are predefined.
-+
-+       uint8 uint16[2];
-+       uint8 uint24[3];
-+       uint8 uint32[4];
-+       uint8 uint64[8];
-+
-+   All values, here and elsewhere in the specification, are stored in
-+   "network" or "big-endian" order; the uint32 represented by the hex
-+   bytes 01 02 03 04 is equivalent to the decimal value 16909060.
-+
-+4.5. Enumerateds
-+
-+   An additional sparse data type is available called enum. A field of
-+   type enum can only assume the values declared in the definition.
-+   Each definition is a different type. Only enumerateds of the same
-+   type may be assigned or compared. Every element of an enumerated must
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 7]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   be assigned a value, as demonstrated in the following example.  Since
-+   the elements of the enumerated are not ordered, they can be assigned
-+   any unique value, in any order.
-+
-+       enum { e1(v1), e2(v2), ... , en(vn) [[, (n)]] } Te;
-+
-+   Enumerateds occupy as much space in the byte stream as would its
-+   maximal defined ordinal value. The following definition would cause
-+   one byte to be used to carry fields of type Color.
-+
-+       enum { red(3), blue(5), white(7) } Color;
-+
-+   One may optionally specify a value without its associated tag to
-+   force the width definition without defining a superfluous element.
-+   In the following example, Taste will consume two bytes in the data
-+   stream but can only assume the values 1, 2 or 4.
-+
-+       enum { sweet(1), sour(2), bitter(4), (32000) } Taste;
-+
-+   The names of the elements of an enumeration are scoped within the
-+   defined type. In the first example, a fully qualified reference to
-+   the second element of the enumeration would be Color.blue. Such
-+   qualification is not required if the target of the assignment is well
-+   specified.
-+
-+       Color color = Color.blue;     /* overspecified, legal */
-+       Color color = blue;           /* correct, type implicit */
-+
-+   For enumerateds that are never converted to external representation,
-+   the numerical information may be omitted.
-+
-+       enum { low, medium, high } Amount;
-+
-+4.6. Constructed types
-+
-+   Structure types may be constructed from primitive types for
-+   convenience. Each specification declares a new, unique type. The
-+   syntax for definition is much like that of C.
-+
-+       struct {
-+         T1 f1;
-+         T2 f2;
-+         ...
-+         Tn fn;
-+       } [[T]];
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 8]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   The fields within a structure may be qualified using the type's name
-+   using a syntax much like that available for enumerateds. For example,
-+   T.f2 refers to the second field of the previous declaration.
-+   Structure definitions may be embedded.
-+
-+4.6.1. Variants
-+
-+   Defined structures may have variants based on some knowledge that is
-+   available within the environment. The selector must be an enumerated
-+   type that defines the possible variants the structure defines. There
-+   must be a case arm for every element of the enumeration declared in
-+   the select. The body of the variant structure may be given a label
-+   for reference. The mechanism by which the variant is selected at
-+   runtime is not prescribed by the presentation language.
-+
-+       struct {
-+           T1 f1;
-+           T2 f2;
-+           ....
-+           Tn fn;
-+           select (E) {
-+               case e1: Te1;
-+               case e2: Te2;
-+               ....
-+               case en: Ten;
-+           } [[fv]];
-+       } [[Tv]];
-+
-+   For example:
-+
-+       enum { apple, orange } VariantTag;
-+       struct {
-+           uint16 number;
-+           opaque string<0..10>; /* variable length */
-+       } V1;
-+       struct {
-+           uint32 number;
-+           opaque string[10];    /* fixed length */
-+       } V2;
-+       struct {
-+           select (VariantTag) { /* value of selector is implicit */
-+               case apple: V1;   /* VariantBody, tag = apple */
-+               case orange: V2;  /* VariantBody, tag = orange */
-+           } variant_body;       /* optional label on variant */
-+       } VariantRecord;
-+
-+   Variant structures may be qualified (narrowed) by specifying a value
-+   for the selector prior to the type. For example, a
-+
-+
-+
-+Dierks & Allen              Standards Track                     [Page 9]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       orange VariantRecord
-+
-+   is a narrowed type of a VariantRecord containing a variant_body of
-+   type V2.
-+
-+4.7. Cryptographic attributes
-+
-+   The four cryptographic operations digital signing, stream cipher
-+   encryption, block cipher encryption, and public key encryption are
-+   designated digitally-signed, stream-ciphered, block-ciphered, and
-+   public-key-encrypted, respectively. A field's cryptographic
-+   processing is specified by prepending an appropriate key word
-+   designation before the field's type specification. Cryptographic keys
-+   are implied by the current session state (see Section 6.1).
-+
-+   In digital signing, one-way hash functions are used as input for a
-+   signing algorithm. A digitally-signed element is encoded as an opaque
-+   vector <0..2^16-1>, where the length is specified by the signing
-+   algorithm and key.
-+
-+   In RSA signing, a 36-byte structure of two hashes (one SHA and one
-+   MD5) is signed (encrypted with the private key). It is encoded with
-+   PKCS #1 block type 0 or type 1 as described in [PKCS1].
-+
-+   In DSS, the 20 bytes of the SHA hash are run directly through the
-+   Digital Signing Algorithm with no additional hashing. This produces
-+   two values, r and s. The DSS signature is an opaque vector, as above,
-+   the contents of which are the DER encoding of:
-+
-+       Dss-Sig-Value  ::=  SEQUENCE  {
-+            r       INTEGER,
-+            s       INTEGER
-+       }
-+
-+   In stream cipher encryption, the plaintext is exclusive-ORed with an
-+   identical amount of output generated from a cryptographically-secure
-+   keyed pseudorandom number generator.
-+
-+   In block cipher encryption, every block of plaintext encrypts to a
-+   block of ciphertext. All block cipher encryption is done in CBC
-+   (Cipher Block Chaining) mode, and all items which are block-ciphered
-+   will be an exact multiple of the cipher block length.
-+
-+   In public key encryption, a public key algorithm is used to encrypt
-+   data in such a way that it can be decrypted only with the matching
-+   private key. A public-key-encrypted element is encoded as an opaque
-+   vector <0..2^16-1>, where the length is specified by the signing
-+   algorithm and key.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 10]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   An RSA encrypted value is encoded with PKCS #1 block type 2 as
-+   described in [PKCS1].
-+
-+   In the following example:
-+
-+       stream-ciphered struct {
-+           uint8 field1;
-+           uint8 field2;
-+           digitally-signed opaque hash[20];
-+       } UserType;
-+
-+   The contents of hash are used as input for the signing algorithm,
-+   then the entire structure is encrypted with a stream cipher. The
-+   length of this structure, in bytes would be equal to 2 bytes for
-+   field1 and field2, plus two bytes for the length of the signature,
-+   plus the length of the output of the signing algorithm. This is known
-+   due to the fact that the algorithm and key used for the signing are
-+   known prior to encoding or decoding this structure.
-+
-+4.8. Constants
-+
-+   Typed constants can be defined for purposes of specification by
-+   declaring a symbol of the desired type and assigning values to it.
-+   Under-specified types (opaque, variable length vectors, and
-+   structures that contain opaque) cannot be assigned values. No fields
-+   of a multi-element structure or vector may be elided.
-+
-+   For example,
-+
-+       struct {
-+           uint8 f1;
-+           uint8 f2;
-+       } Example1;
-+
-+       Example1 ex1 = {1, 4};  /* assigns f1 = 1, f2 = 4 */
-+
-+5. HMAC and the pseudorandom function
-+
-+   A number of operations in the TLS record and handshake layer required
-+   a keyed MAC; this is a secure digest of some data protected by a
-+   secret. Forging the MAC is infeasible without knowledge of the MAC
-+   secret. The construction we use for this operation is known as HMAC,
-+   described in [HMAC].
-+
-+   HMAC can be used with a variety of different hash algorithms. TLS
-+   uses it in the handshake with two different algorithms: MD5 and SHA-
-+   1, denoting these as HMAC_MD5(secret, data) and HMAC_SHA(secret,
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 11]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   data). Additional hash algorithms can be defined by cipher suites and
-+   used to protect record data, but MD5 and SHA-1 are hard coded into
-+   the description of the handshaking for this version of the protocol.
-+
-+   In addition, a construction is required to do expansion of secrets
-+   into blocks of data for the purposes of key generation or validation.
-+   This pseudo-random function (PRF) takes as input a secret, a seed,
-+   and an identifying label and produces an output of arbitrary length.
-+
-+   In order to make the PRF as secure as possible, it uses two hash
-+   algorithms in a way which should guarantee its security if either
-+   algorithm remains secure.
-+
-+   First, we define a data expansion function, P_hash(secret, data)
-+   which uses a single hash function to expand a secret and seed into an
-+   arbitrary quantity of output:
-+
-+       P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
-+                              HMAC_hash(secret, A(2) + seed) +
-+                              HMAC_hash(secret, A(3) + seed) + ...
-+
-+   Where + indicates concatenation.
-+
-+   A() is defined as:
-+       A(0) = seed
-+       A(i) = HMAC_hash(secret, A(i-1))
-+
-+   P_hash can be iterated as many times as is necessary to produce the
-+   required quantity of data. For example, if P_SHA-1 was being used to
-+   create 64 bytes of data, it would have to be iterated 4 times
-+   (through A(4)), creating 80 bytes of output data; the last 16 bytes
-+   of the final iteration would then be discarded, leaving 64 bytes of
-+   output data.
-+
-+   TLS's PRF is created by splitting the secret into two halves and
-+   using one half to generate data with P_MD5 and the other half to
-+   generate data with P_SHA-1, then exclusive-or'ing the outputs of
-+   these two expansion functions together.
-+
-+   S1 and S2 are the two halves of the secret and each is the same
-+   length. S1 is taken from the first half of the secret, S2 from the
-+   second half. Their length is created by rounding up the length of the
-+   overall secret divided by two; thus, if the original secret is an odd
-+   number of bytes long, the last byte of S1 will be the same as the
-+   first byte of S2.
-+
-+       L_S = length in bytes of secret;
-+       L_S1 = L_S2 = ceil(L_S / 2);
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 12]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   The secret is partitioned into two halves (with the possibility of
-+   one shared byte) as described above, S1 taking the first L_S1 bytes
-+   and S2 the last L_S2 bytes.
-+
-+   The PRF is then defined as the result of mixing the two pseudorandom
-+   streams by exclusive-or'ing them together.
-+
-+       PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
-+                                  P_SHA-1(S2, label + seed);
-+
-+   The label is an ASCII string. It should be included in the exact form
-+   it is given without a length byte or trailing null character.  For
-+   example, the label "slithy toves" would be processed by hashing the
-+   following bytes:
-+
-+       73 6C 69 74 68 79 20 74 6F 76 65 73
-+
-+   Note that because MD5 produces 16 byte outputs and SHA-1 produces 20
-+   byte outputs, the boundaries of their internal iterations will not be
-+   aligned; to generate a 80 byte output will involve P_MD5 being
-+   iterated through A(5), while P_SHA-1 will only iterate through A(4).
-+
-+6. The TLS Record Protocol
-+
-+   The TLS Record Protocol is a layered protocol. At each layer,
-+   messages may include fields for length, description, and content.
-+   The Record Protocol takes messages to be transmitted, fragments the
-+   data into manageable blocks, optionally compresses the data, applies
-+   a MAC, encrypts, and transmits the result. Received data is
-+   decrypted, verified, decompressed, and reassembled, then delivered to
-+   higher level clients.
-+
-+   Four record protocol clients are described in this document: the
-+   handshake protocol, the alert protocol, the change cipher spec
-+   protocol, and the application data protocol. In order to allow
-+   extension of the TLS protocol, additional record types can be
-+   supported by the record protocol. Any new record types should
-+   allocate type values immediately beyond the ContentType values for
-+   the four record types described here (see Appendix A.2). If a TLS
-+   implementation receives a record type it does not understand, it
-+   should just ignore it. Any protocol designed for use over TLS must be
-+   carefully designed to deal with all possible attacks against it.
-+   Note that because the type and length of a record are not protected
-+   by encryption, care should be take to minimize the value of traffic
-+   analysis of these values.
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 13]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+6.1. Connection states
-+
-+   A TLS connection state is the operating environment of the TLS Record
-+   Protocol. It specifies a compression algorithm, encryption algorithm,
-+   and MAC algorithm. In addition, the parameters for these algorithms
-+   are known: the MAC secret and the bulk encryption keys and IVs for
-+   the connection in both the read and the write directions. Logically,
-+   there are always four connection states outstanding: the current read
-+   and write states, and the pending read and write states. All records
-+   are processed under the current read and write states. The security
-+   parameters for the pending states can be set by the TLS Handshake
-+   Protocol, and the Handshake Protocol can selectively make either of
-+   the pending states current, in which case the appropriate current
-+   state is disposed of and replaced with the pending state; the pending
-+   state is then reinitialized to an empty state. It is illegal to make
-+   a state which has not been initialized with security parameters a
-+   current state. The initial current state always specifies that no
-+   encryption, compression, or MAC will be used.
-+
-+   The security parameters for a TLS Connection read and write state are
-+   set by providing the following values:
-+
-+   connection end
-+       Whether this entity is considered the "client" or the "server" in
-+       this connection.
-+
-+   bulk encryption algorithm
-+       An algorithm to be used for bulk encryption. This specification
-+       includes the key size of this algorithm, how much of that key is
-+       secret, whether it is a block or stream cipher, the block size of
-+       the cipher (if appropriate), and whether it is considered an
-+       "export" cipher.
-+
-+   MAC algorithm
-+       An algorithm to be used for message authentication. This
-+       specification includes the size of the hash which is returned by
-+       the MAC algorithm.
-+
-+   compression algorithm
-+       An algorithm to be used for data compression. This specification
-+       must include all information the algorithm requires to do
-+       compression.
-+
-+   master secret
-+       A 48 byte secret shared between the two peers in the connection.
-+
-+   client random
-+       A 32 byte value provided by the client.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 14]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   server random
-+       A 32 byte value provided by the server.
-+
-+   These parameters are defined in the presentation language as:
-+
-+       enum { server, client } ConnectionEnd;
-+
-+       enum { null, rc4, rc2, des, 3des, des40 } BulkCipherAlgorithm;
-+
-+       enum { stream, block } CipherType;
-+
-+       enum { true, false } IsExportable;
-+
-+       enum { null, md5, sha } MACAlgorithm;
-+
-+       enum { null(0), (255) } CompressionMethod;
-+
-+       /* The algorithms specified in CompressionMethod,
-+          BulkCipherAlgorithm, and MACAlgorithm may be added to. */
-+
-+       struct {
-+           ConnectionEnd          entity;
-+           BulkCipherAlgorithm    bulk_cipher_algorithm;
-+           CipherType             cipher_type;
-+           uint8                  key_size;
-+           uint8                  key_material_length;
-+           IsExportable           is_exportable;
-+           MACAlgorithm           mac_algorithm;
-+           uint8                  hash_size;
-+           CompressionMethod      compression_algorithm;
-+           opaque                 master_secret[48];
-+           opaque                 client_random[32];
-+           opaque                 server_random[32];
-+       } SecurityParameters;
-+
-+   The record layer will use the security parameters to generate the
-+   following six items:
-+
-+       client write MAC secret
-+       server write MAC secret
-+       client write key
-+       server write key
-+       client write IV (for block ciphers only)
-+       server write IV (for block ciphers only)
-+
-+   The client write parameters are used by the server when receiving and
-+   processing records and vice-versa. The algorithm used for generating
-+   these items from the security parameters is described in section 6.3.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 15]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Once the security parameters have been set and the keys have been
-+   generated, the connection states can be instantiated by making them
-+   the current states. These current states must be updated for each
-+   record processed. Each connection state includes the following
-+   elements:
-+
-+   compression state
-+       The current state of the compression algorithm.
-+
-+   cipher state
-+       The current state of the encryption algorithm. This will consist
-+       of the scheduled key for that connection. In addition, for block
-+       ciphers running in CBC mode (the only mode specified for TLS),
-+       this will initially contain the IV for that connection state and
-+       be updated to contain the ciphertext of the last block encrypted
-+       or decrypted as records are processed. For stream ciphers, this
-+       will contain whatever the necessary state information is to allow
-+       the stream to continue to encrypt or decrypt data.
-+
-+   MAC secret
-+       The MAC secret for this connection as generated above.
-+
-+   sequence number
-+       Each connection state contains a sequence number, which is
-+       maintained separately for read and write states. The sequence
-+       number must be set to zero whenever a connection state is made
-+       the active state. Sequence numbers are of type uint64 and may not
-+       exceed 2^64-1. A sequence number is incremented after each
-+       record: specifically, the first record which is transmitted under
-+       a particular connection state should use sequence number 0.
-+
-+6.2. Record layer
-+
-+   The TLS Record Layer receives uninterpreted data from higher layers
-+   in non-empty blocks of arbitrary size.
-+
-+6.2.1. Fragmentation
-+
-+   The record layer fragments information blocks into TLSPlaintext
-+   records carrying data in chunks of 2^14 bytes or less. Client message
-+   boundaries are not preserved in the record layer (i.e., multiple
-+   client messages of the same ContentType may be coalesced into a
-+   single TLSPlaintext record, or a single message may be fragmented
-+   across several records).
-+
-+       struct {
-+           uint8 major, minor;
-+       } ProtocolVersion;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 16]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       enum {
-+           change_cipher_spec(20), alert(21), handshake(22),
-+           application_data(23), (255)
-+       } ContentType;
-+
-+       struct {
-+           ContentType type;
-+           ProtocolVersion version;
-+           uint16 length;
-+           opaque fragment[TLSPlaintext.length];
-+       } TLSPlaintext;
-+
-+   type
-+       The higher level protocol used to process the enclosed fragment.
-+
-+   version
-+       The version of the protocol being employed. This document
-+       describes TLS Version 1.0, which uses the version { 3, 1 }. The
-+       version value 3.1 is historical: TLS version 1.0 is a minor
-+       modification to the SSL 3.0 protocol, which bears the version
-+       value 3.0. (See Appendix A.1).
-+
-+   length
-+       The length (in bytes) of the following TLSPlaintext.fragment.
-+       The length should not exceed 2^14.
-+
-+   fragment
-+       The application data. This data is transparent and treated as an
-+       independent block to be dealt with by the higher level protocol
-+       specified by the type field.
-+
-+ Note: Data of different TLS Record layer content types may be
-+       interleaved. Application data is generally of lower precedence
-+       for transmission than other content types.
-+
-+6.2.2. Record compression and decompression
-+
-+   All records are compressed using the compression algorithm defined in
-+   the current session state. There is always an active compression
-+   algorithm; however, initially it is defined as
-+   CompressionMethod.null. The compression algorithm translates a
-+   TLSPlaintext structure into a TLSCompressed structure. Compression
-+   functions are initialized with default state information whenever a
-+   connection state is made active.
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 17]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Compression must be lossless and may not increase the content length
-+   by more than 1024 bytes. If the decompression function encounters a
-+   TLSCompressed.fragment that would decompress to a length in excess of
-+   2^14 bytes, it should report a fatal decompression failure error.
-+
-+       struct {
-+           ContentType type;       /* same as TLSPlaintext.type */
-+           ProtocolVersion version;/* same as TLSPlaintext.version */
-+           uint16 length;
-+           opaque fragment[TLSCompressed.length];
-+       } TLSCompressed;
-+
-+   length
-+       The length (in bytes) of the following TLSCompressed.fragment.
-+       The length should not exceed 2^14 + 1024.
-+
-+   fragment
-+       The compressed form of TLSPlaintext.fragment.
-+
-+ Note: A CompressionMethod.null operation is an identity operation; no
-+       fields are altered.
-+
-+   Implementation note:
-+       Decompression functions are responsible for ensuring that
-+       messages cannot cause internal buffer overflows.
-+
-+6.2.3. Record payload protection
-+
-+   The encryption and MAC functions translate a TLSCompressed structure
-+   into a TLSCiphertext. The decryption functions reverse the process.
-+   The MAC of the record also includes a sequence number so that
-+   missing, extra or repeated messages are detectable.
-+
-+       struct {
-+           ContentType type;
-+           ProtocolVersion version;
-+           uint16 length;
-+           select (CipherSpec.cipher_type) {
-+               case stream: GenericStreamCipher;
-+               case block: GenericBlockCipher;
-+           } fragment;
-+       } TLSCiphertext;
-+
-+   type
-+       The type field is identical to TLSCompressed.type.
-+
-+   version
-+       The version field is identical to TLSCompressed.version.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 18]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   length
-+       The length (in bytes) of the following TLSCiphertext.fragment.
-+       The length may not exceed 2^14 + 2048.
-+
-+   fragment
-+       The encrypted form of TLSCompressed.fragment, with the MAC.
-+
-+6.2.3.1. Null or standard stream cipher
-+
-+   Stream ciphers (including BulkCipherAlgorithm.null - see Appendix
-+   A.6) convert TLSCompressed.fragment structures to and from stream
-+   TLSCiphertext.fragment structures.
-+
-+       stream-ciphered struct {
-+           opaque content[TLSCompressed.length];
-+           opaque MAC[CipherSpec.hash_size];
-+       } GenericStreamCipher;
-+
-+   The MAC is generated as:
-+
-+       HMAC_hash(MAC_write_secret, seq_num + TLSCompressed.type +
-+                     TLSCompressed.version + TLSCompressed.length +
-+                     TLSCompressed.fragment));
-+
-+   where "+" denotes concatenation.
-+
-+   seq_num
-+       The sequence number for this record.
-+
-+   hash
-+       The hashing algorithm specified by
-+       SecurityParameters.mac_algorithm.
-+
-+   Note that the MAC is computed before encryption. The stream cipher
-+   encrypts the entire block, including the MAC. For stream ciphers that
-+   do not use a synchronization vector (such as RC4), the stream cipher
-+   state from the end of one record is simply used on the subsequent
-+   packet. If the CipherSuite is TLS_NULL_WITH_NULL_NULL, encryption
-+   consists of the identity operation (i.e., the data is not encrypted
-+   and the MAC size is zero implying that no MAC is used).
-+   TLSCiphertext.length is TLSCompressed.length plus
-+   CipherSpec.hash_size.
-+
-+6.2.3.2. CBC block cipher
-+
-+   For block ciphers (such as RC2 or DES), the encryption and MAC
-+   functions convert TLSCompressed.fragment structures to and from block
-+   TLSCiphertext.fragment structures.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 19]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       block-ciphered struct {
-+           opaque content[TLSCompressed.length];
-+           opaque MAC[CipherSpec.hash_size];
-+           uint8 padding[GenericBlockCipher.padding_length];
-+           uint8 padding_length;
-+       } GenericBlockCipher;
-+
-+   The MAC is generated as described in Section 6.2.3.1.
-+
-+   padding
-+       Padding that is added to force the length of the plaintext to be
-+       an integral multiple of the block cipher's block length. The
-+       padding may be any length up to 255 bytes long, as long as it
-+       results in the TLSCiphertext.length being an integral multiple of
-+       the block length. Lengths longer than necessary might be
-+       desirable to frustrate attacks on a protocol based on analysis of
-+       the lengths of exchanged messages. Each uint8 in the padding data
-+       vector must be filled with the padding length value.
-+
-+   padding_length
-+       The padding length should be such that the total size of the
-+       GenericBlockCipher structure is a multiple of the cipher's block
-+       length. Legal values range from zero to 255, inclusive. This
-+       length specifies the length of the padding field exclusive of the
-+       padding_length field itself.
-+
-+   The encrypted data length (TLSCiphertext.length) is one more than the
-+   sum of TLSCompressed.length, CipherSpec.hash_size, and
-+   padding_length.
-+
-+ Example: If the block length is 8 bytes, the content length
-+          (TLSCompressed.length) is 61 bytes, and the MAC length is 20
-+          bytes, the length before padding is 82 bytes. Thus, the
-+          padding length modulo 8 must be equal to 6 in order to make
-+          the total length an even multiple of 8 bytes (the block
-+          length). The padding length can be 6, 14, 22, and so on,
-+          through 254. If the padding length were the minimum necessary,
-+          6, the padding would be 6 bytes, each containing the value 6.
-+          Thus, the last 8 octets of the GenericBlockCipher before block
-+          encryption would be xx 06 06 06 06 06 06 06, where xx is the
-+          last octet of the MAC.
-+
-+ Note: With block ciphers in CBC mode (Cipher Block Chaining) the
-+       initialization vector (IV) for the first record is generated with
-+       the other keys and secrets when the security parameters are set.
-+       The IV for subsequent records is the last ciphertext block from
-+       the previous record.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 20]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+6.3. Key calculation
-+
-+   The Record Protocol requires an algorithm to generate keys, IVs, and
-+   MAC secrets from the security parameters provided by the handshake
-+   protocol.
-+
-+   The master secret is hashed into a sequence of secure bytes, which
-+   are assigned to the MAC secrets, keys, and non-export IVs required by
-+   the current connection state (see Appendix A.6). CipherSpecs require
-+   a client write MAC secret, a server write MAC secret, a client write
-+   key, a server write key, a client write IV, and a server write IV,
-+   which are generated from the master secret in that order. Unused
-+   values are empty.
-+
-+   When generating keys and MAC secrets, the master secret is used as an
-+   entropy source, and the random values provide unencrypted salt
-+   material and IVs for exportable ciphers.
-+
-+   To generate the key material, compute
-+
-+       key_block = PRF(SecurityParameters.master_secret,
-+                          "key expansion",
-+                          SecurityParameters.server_random +
-+                          SecurityParameters.client_random);
-+
-+   until enough output has been generated. Then the key_block is
-+   partitioned as follows:
-+
-+       client_write_MAC_secret[SecurityParameters.hash_size]
-+       server_write_MAC_secret[SecurityParameters.hash_size]
-+       client_write_key[SecurityParameters.key_material_length]
-+       server_write_key[SecurityParameters.key_material_length]
-+       client_write_IV[SecurityParameters.IV_size]
-+       server_write_IV[SecurityParameters.IV_size]
-+
-+   The client_write_IV and server_write_IV are only generated for non-
-+   export block ciphers. For exportable block ciphers, the
-+   initialization vectors are generated later, as described below. Any
-+   extra key_block material is discarded.
-+
-+   Implementation note:
-+       The cipher spec which is defined in this document which requires
-+       the most material is 3DES_EDE_CBC_SHA: it requires 2 x 24 byte
-+       keys, 2 x 20 byte MAC secrets, and 2 x 8 byte IVs, for a total of
-+       104 bytes of key material.
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 21]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Exportable encryption algorithms (for which CipherSpec.is_exportable
-+   is true) require additional processing as follows to derive their
-+   final write keys:
-+
-+       final_client_write_key =
-+       PRF(SecurityParameters.client_write_key,
-+                                  "client write key",
-+                                  SecurityParameters.client_random +
-+                                  SecurityParameters.server_random);
-+       final_server_write_key =
-+       PRF(SecurityParameters.server_write_key,
-+                                  "server write key",
-+                                  SecurityParameters.client_random +
-+                                  SecurityParameters.server_random);
-+
-+   Exportable encryption algorithms derive their IVs solely from the
-+   random values from the hello messages:
-+
-+       iv_block = PRF("", "IV block", SecurityParameters.client_random +
-+                      SecurityParameters.server_random);
-+
-+   The iv_block is partitioned into two initialization vectors as the
-+   key_block was above:
-+
-+       client_write_IV[SecurityParameters.IV_size]
-+       server_write_IV[SecurityParameters.IV_size]
-+
-+   Note that the PRF is used without a secret in this case: this just
-+   means that the secret has a length of zero bytes and contributes
-+   nothing to the hashing in the PRF.
-+
-+6.3.1. Export key generation example
-+
-+   TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 requires five random bytes for
-+   each of the two encryption keys and 16 bytes for each of the MAC
-+   keys, for a total of 42 bytes of key material. The PRF output is
-+   stored in the key_block. The key_block is partitioned, and the write
-+   keys are salted because this is an exportable encryption algorithm.
-+
-+       key_block               = PRF(master_secret,
-+                                     "key expansion",
-+                                     server_random +
-+                                     client_random)[0..41]
-+       client_write_MAC_secret = key_block[0..15]
-+       server_write_MAC_secret = key_block[16..31]
-+       client_write_key        = key_block[32..36]
-+       server_write_key        = key_block[37..41]
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 22]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       final_client_write_key  = PRF(client_write_key,
-+                                     "client write key",
-+                                     client_random +
-+                                     server_random)[0..15]
-+       final_server_write_key  = PRF(server_write_key,
-+                                     "server write key",
-+                                     client_random +
-+                                     server_random)[0..15]
-+
-+       iv_block                = PRF("", "IV block", client_random +
-+                                     server_random)[0..15]
-+       client_write_IV = iv_block[0..7]
-+       server_write_IV = iv_block[8..15]
-+
-+7. The TLS Handshake Protocol
-+
-+   The TLS Handshake Protocol consists of a suite of three sub-protocols
-+   which are used to allow peers to agree upon security parameters for
-+   the record layer, authenticate themselves, instantiate negotiated
-+   security parameters, and report error conditions to each other.
-+
-+   The Handshake Protocol is responsible for negotiating a session,
-+   which consists of the following items:
-+
-+   session identifier
-+       An arbitrary byte sequence chosen by the server to identify an
-+       active or resumable session state.
-+
-+   peer certificate
-+       X509v3 [X509] certificate of the peer. This element of the state
-+       may be null.
-+
-+   compression method
-+       The algorithm used to compress data prior to encryption.
-+
-+   cipher spec
-+       Specifies the bulk data encryption algorithm (such as null, DES,
-+       etc.) and a MAC algorithm (such as MD5 or SHA). It also defines
-+       cryptographic attributes such as the hash_size. (See Appendix A.6
-+       for formal definition)
-+
-+   master secret
-+       48-byte secret shared between the client and server.
-+
-+   is resumable
-+       A flag indicating whether the session can be used to initiate new
-+       connections.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 23]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   These items are then used to create security parameters for use by
-+   the Record Layer when protecting application data. Many connections
-+   can be instantiated using the same session through the resumption
-+   feature of the TLS Handshake Protocol.
-+
-+7.1. Change cipher spec protocol
-+
-+   The change cipher spec protocol exists to signal transitions in
-+   ciphering strategies. The protocol consists of a single message,
-+   which is encrypted and compressed under the current (not the pending)
-+   connection state. The message consists of a single byte of value 1.
-+
-+       struct {
-+           enum { change_cipher_spec(1), (255) } type;
-+       } ChangeCipherSpec;
-+
-+   The change cipher spec message is sent by both the client and server
-+   to notify the receiving party that subsequent records will be
-+   protected under the newly negotiated CipherSpec and keys. Reception
-+   of this message causes the receiver to instruct the Record Layer to
-+   immediately copy the read pending state into the read current state.
-+   Immediately after sending this message, the sender should instruct
-+   the record layer to make the write pending state the write active
-+   state. (See section 6.1.) The change cipher spec message is sent
-+   during the handshake after the security parameters have been agreed
-+   upon, but before the verifying finished message is sent (see section
-+   7.4.9).
-+
-+7.2. Alert protocol
-+
-+   One of the content types supported by the TLS Record layer is the
-+   alert type. Alert messages convey the severity of the message and a
-+   description of the alert. Alert messages with a level of fatal result
-+   in the immediate termination of the connection. In this case, other
-+   connections corresponding to the session may continue, but the
-+   session identifier must be invalidated, preventing the failed session
-+   from being used to establish new connections. Like other messages,
-+   alert messages are encrypted and compressed, as specified by the
-+   current connection state.
-+
-+       enum { warning(1), fatal(2), (255) } AlertLevel;
-+
-+       enum {
-+           close_notify(0),
-+           unexpected_message(10),
-+           bad_record_mac(20),
-+           decryption_failed(21),
-+           record_overflow(22),
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 24]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+           decompression_failure(30),
-+           handshake_failure(40),
-+           bad_certificate(42),
-+           unsupported_certificate(43),
-+           certificate_revoked(44),
-+           certificate_expired(45),
-+           certificate_unknown(46),
-+           illegal_parameter(47),
-+           unknown_ca(48),
-+           access_denied(49),
-+           decode_error(50),
-+           decrypt_error(51),
-+           export_restriction(60),
-+           protocol_version(70),
-+           insufficient_security(71),
-+           internal_error(80),
-+           user_canceled(90),
-+           no_renegotiation(100),
-+           (255)
-+       } AlertDescription;
-+
-+       struct {
-+           AlertLevel level;
-+           AlertDescription description;
-+       } Alert;
-+
-+7.2.1. Closure alerts
-+
-+   The client and the server must share knowledge that the connection is
-+   ending in order to avoid a truncation attack. Either party may
-+   initiate the exchange of closing messages.
-+
-+   close_notify
-+       This message notifies the recipient that the sender will not send
-+       any more messages on this connection. The session becomes
-+       unresumable if any connection is terminated without proper
-+       close_notify messages with level equal to warning.
-+
-+   Either party may initiate a close by sending a close_notify alert.
-+   Any data received after a closure alert is ignored.
-+
-+   Each party is required to send a close_notify alert before closing
-+   the write side of the connection. It is required that the other party
-+   respond with a close_notify alert of its own and close down the
-+   connection immediately, discarding any pending writes. It is not
-+   required for the initiator of the close to wait for the responding
-+   close_notify alert before closing the read side of the connection.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 25]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   If the application protocol using TLS provides that any data may be
-+   carried over the underlying transport after the TLS connection is
-+   closed, the TLS implementation must receive the responding
-+   close_notify alert before indicating to the application layer that
-+   the TLS connection has ended. If the application protocol will not
-+   transfer any additional data, but will only close the underlying
-+   transport connection, then the implementation may choose to close the
-+   transport without waiting for the responding close_notify. No part of
-+   this standard should be taken to dictate the manner in which a usage
-+   profile for TLS manages its data transport, including when
-+   connections are opened or closed.
-+
-+   NB: It is assumed that closing a connection reliably delivers
-+       pending data before destroying the transport.
-+
-+7.2.2. Error alerts
-+
-+   Error handling in the TLS Handshake protocol is very simple. When an
-+   error is detected, the detecting party sends a message to the other
-+   party. Upon transmission or receipt of an fatal alert message, both
-+   parties immediately close the connection. Servers and clients are
-+   required to forget any session-identifiers, keys, and secrets
-+   associated with a failed connection. The following error alerts are
-+   defined:
-+
-+   unexpected_message
-+       An inappropriate message was received. This alert is always fatal
-+       and should never be observed in communication between proper
-+       implementations.
-+
-+   bad_record_mac
-+       This alert is returned if a record is received with an incorrect
-+       MAC. This message is always fatal.
-+
-+   decryption_failed
-+       A TLSCiphertext decrypted in an invalid way: either it wasn`t an
-+       even multiple of the block length or its padding values, when
-+       checked, weren`t correct. This message is always fatal.
-+
-+   record_overflow
-+       A TLSCiphertext record was received which had a length more than
-+       2^14+2048 bytes, or a record decrypted to a TLSCompressed record
-+       with more than 2^14+1024 bytes. This message is always fatal.
-+
-+   decompression_failure
-+       The decompression function received improper input (e.g. data
-+       that would expand to excessive length). This message is always
-+       fatal.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 26]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   handshake_failure
-+       Reception of a handshake_failure alert message indicates that the
-+       sender was unable to negotiate an acceptable set of security
-+       parameters given the options available. This is a fatal error.
-+
-+   bad_certificate
-+       A certificate was corrupt, contained signatures that did not
-+       verify correctly, etc.
-+
-+   unsupported_certificate
-+       A certificate was of an unsupported type.
-+
-+   certificate_revoked
-+       A certificate was revoked by its signer.
-+
-+   certificate_expired
-+       A certificate has expired or is not currently valid.
-+
-+   certificate_unknown
-+       Some other (unspecified) issue arose in processing the
-+       certificate, rendering it unacceptable.
-+
-+   illegal_parameter
-+       A field in the handshake was out of range or inconsistent with
-+       other fields. This is always fatal.
-+
-+   unknown_ca
-+       A valid certificate chain or partial chain was received, but the
-+       certificate was not accepted because the CA certificate could not
-+       be located or couldn`t be matched with a known, trusted CA.  This
-+       message is always fatal.
-+
-+   access_denied
-+       A valid certificate was received, but when access control was
-+       applied, the sender decided not to proceed with negotiation.
-+       This message is always fatal.
-+
-+   decode_error
-+       A message could not be decoded because some field was out of the
-+       specified range or the length of the message was incorrect. This
-+       message is always fatal.
-+
-+   decrypt_error
-+       A handshake cryptographic operation failed, including being
-+       unable to correctly verify a signature, decrypt a key exchange,
-+       or validate a finished message.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 27]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   export_restriction
-+       A negotiation not in compliance with export restrictions was
-+       detected; for example, attempting to transfer a 1024 bit
-+       ephemeral RSA key for the RSA_EXPORT handshake method. This
-+       message is always fatal.
-+
-+   protocol_version
-+       The protocol version the client has attempted to negotiate is
-+       recognized, but not supported. (For example, old protocol
-+       versions might be avoided for security reasons). This message is
-+       always fatal.
-+
-+   insufficient_security
-+       Returned instead of handshake_failure when a negotiation has
-+       failed specifically because the server requires ciphers more
-+       secure than those supported by the client. This message is always
-+       fatal.
-+
-+   internal_error
-+       An internal error unrelated to the peer or the correctness of the
-+       protocol makes it impossible to continue (such as a memory
-+       allocation failure). This message is always fatal.
-+
-+   user_canceled
-+       This handshake is being canceled for some reason unrelated to a
-+       protocol failure. If the user cancels an operation after the
-+       handshake is complete, just closing the connection by sending a
-+       close_notify is more appropriate. This alert should be followed
-+       by a close_notify. This message is generally a warning.
-+
-+   no_renegotiation
-+       Sent by the client in response to a hello request or by the
-+       server in response to a client hello after initial handshaking.
-+       Either of these would normally lead to renegotiation; when that
-+       is not appropriate, the recipient should respond with this alert;
-+       at that point, the original requester can decide whether to
-+       proceed with the connection. One case where this would be
-+       appropriate would be where a server has spawned a process to
-+       satisfy a request; the process might receive security parameters
-+       (key length, authentication, etc.) at startup and it might be
-+       difficult to communicate changes to these parameters after that
-+       point. This message is always a warning.
-+
-+   For all errors where an alert level is not explicitly specified, the
-+   sending party may determine at its discretion whether this is a fatal
-+   error or not; if an alert with a level of warning is received, the
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 28]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   receiving party may decide at its discretion whether to treat this as
-+   a fatal error or not. However, all messages which are transmitted
-+   with a level of fatal must be treated as fatal messages.
-+
-+7.3. Handshake Protocol overview
-+
-+   The cryptographic parameters of the session state are produced by the
-+   TLS Handshake Protocol, which operates on top of the TLS Record
-+   Layer. When a TLS client and server first start communicating, they
-+   agree on a protocol version, select cryptographic algorithms,
-+   optionally authenticate each other, and use public-key encryption
-+   techniques to generate shared secrets.
-+
-+   The TLS Handshake Protocol involves the following steps:
-+
-+     - Exchange hello messages to agree on algorithms, exchange random
-+       values, and check for session resumption.
-+
-+     - Exchange the necessary cryptographic parameters to allow the
-+       client and server to agree on a premaster secret.
-+
-+     - Exchange certificates and cryptographic information to allow the
-+       client and server to authenticate themselves.
-+
-+     - Generate a master secret from the premaster secret and exchanged
-+       random values.
-+
-+     - Provide security parameters to the record layer.
-+
-+     - Allow the client and server to verify that their peer has
-+       calculated the same security parameters and that the handshake
-+       occurred without tampering by an attacker.
-+
-+   Note that higher layers should not be overly reliant on TLS always
-+   negotiating the strongest possible connection between two peers:
-+   there are a number of ways a man in the middle attacker can attempt
-+   to make two entities drop down to the least secure method they
-+   support. The protocol has been designed to minimize this risk, but
-+   there are still attacks available: for example, an attacker could
-+   block access to the port a secure service runs on, or attempt to get
-+   the peers to negotiate an unauthenticated connection. The fundamental
-+   rule is that higher levels must be cognizant of what their security
-+   requirements are and never transmit information over a channel less
-+   secure than what they require. The TLS protocol is secure, in that
-+   any cipher suite offers its promised level of security: if you
-+   negotiate 3DES with a 1024 bit RSA key exchange with a host whose
-+   certificate you have verified, you can expect to be that secure.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 29]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   However, you should never send data over a link encrypted with 40 bit
-+   security unless you feel that data is worth no more than the effort
-+   required to break that encryption.
-+
-+   These goals are achieved by the handshake protocol, which can be
-+   summarized as follows: The client sends a client hello message to
-+   which the server must respond with a server hello message, or else a
-+   fatal error will occur and the connection will fail. The client hello
-+   and server hello are used to establish security enhancement
-+   capabilities between client and server. The client hello and server
-+   hello establish the following attributes: Protocol Version, Session
-+   ID, Cipher Suite, and Compression Method. Additionally, two random
-+   values are generated and exchanged: ClientHello.random and
-+   ServerHello.random.
-+
-+   The actual key exchange uses up to four messages: the server
-+   certificate, the server key exchange, the client certificate, and the
-+   client key exchange. New key exchange methods can be created by
-+   specifying a format for these messages and defining the use of the
-+   messages to allow the client and server to agree upon a shared
-+   secret. This secret should be quite long; currently defined key
-+   exchange methods exchange secrets which range from 48 to 128 bytes in
-+   length.
-+
-+   Following the hello messages, the server will send its certificate,
-+   if it is to be authenticated. Additionally, a server key exchange
-+   message may be sent, if it is required (e.g. if their server has no
-+   certificate, or if its certificate is for signing only). If the
-+   server is authenticated, it may request a certificate from the
-+   client, if that is appropriate to the cipher suite selected. Now the
-+   server will send the server hello done message, indicating that the
-+   hello-message phase of the handshake is complete. The server will
-+   then wait for a client response. If the server has sent a certificate
-+   request message, the client must send the certificate message. The
-+   client key exchange message is now sent, and the content of that
-+   message will depend on the public key algorithm selected between the
-+   client hello and the server hello. If the client has sent a
-+   certificate with signing ability, a digitally-signed certificate
-+   verify message is sent to explicitly verify the certificate.
-+
-+   At this point, a change cipher spec message is sent by the client,
-+   and the client copies the pending Cipher Spec into the current Cipher
-+   Spec. The client then immediately sends the finished message under
-+   the new algorithms, keys, and secrets. In response, the server will
-+   send its own change cipher spec message, transfer the pending to the
-+   current Cipher Spec, and send its finished message under the new
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 30]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Cipher Spec. At this point, the handshake is complete and the client
-+   and server may begin to exchange application layer data. (See flow
-+   chart below.)
-+
-+      Client                                               Server
-+
-+      ClientHello                  -------->
-+                                                      ServerHello
-+                                                     Certificate*
-+                                               ServerKeyExchange*
-+                                              CertificateRequest*
-+                                   <--------      ServerHelloDone
-+      Certificate*
-+      ClientKeyExchange
-+      CertificateVerify*
-+      [ChangeCipherSpec]
-+      Finished                     -------->
-+                                               [ChangeCipherSpec]
-+                                   <--------             Finished
-+      Application Data             <------->     Application Data
-+
-+             Fig. 1 - Message flow for a full handshake
-+
-+   * Indicates optional or situation-dependent messages that are not
-+   always sent.
-+
-+  Note: To help avoid pipeline stalls, ChangeCipherSpec is an
-+       independent TLS Protocol content type, and is not actually a TLS
-+       handshake message.
-+
-+   When the client and server decide to resume a previous session or
-+   duplicate an existing session (instead of negotiating new security
-+   parameters) the message flow is as follows:
-+
-+   The client sends a ClientHello using the Session ID of the session to
-+   be resumed. The server then checks its session cache for a match.  If
-+   a match is found, and the server is willing to re-establish the
-+   connection under the specified session state, it will send a
-+   ServerHello with the same Session ID value. At this point, both
-+   client and server must send change cipher spec messages and proceed
-+   directly to finished messages. Once the re-establishment is complete,
-+   the client and server may begin to exchange application layer data.
-+   (See flow chart below.) If a Session ID match is not found, the
-+   server generates a new session ID and the TLS client and server
-+   perform a full handshake.
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 31]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+      Client                                                Server
-+
-+      ClientHello                   -------->
-+                                                       ServerHello
-+                                                [ChangeCipherSpec]
-+                                    <--------             Finished
-+      [ChangeCipherSpec]
-+      Finished                      -------->
-+      Application Data              <------->     Application Data
-+
-+          Fig. 2 - Message flow for an abbreviated handshake
-+
-+   The contents and significance of each message will be presented in
-+   detail in the following sections.
-+
-+7.4. Handshake protocol
-+
-+   The TLS Handshake Protocol is one of the defined higher level clients
-+   of the TLS Record Protocol. This protocol is used to negotiate the
-+   secure attributes of a session. Handshake messages are supplied to
-+   the TLS Record Layer, where they are encapsulated within one or more
-+   TLSPlaintext structures, which are processed and transmitted as
-+   specified by the current active session state.
-+
-+       enum {
-+           hello_request(0), client_hello(1), server_hello(2),
-+           certificate(11), server_key_exchange (12),
-+           certificate_request(13), server_hello_done(14),
-+           certificate_verify(15), client_key_exchange(16),
-+           finished(20), (255)
-+       } HandshakeType;
-+
-+       struct {
-+           HandshakeType msg_type;    /* handshake type */
-+           uint24 length;             /* bytes in message */
-+           select (HandshakeType) {
-+               case hello_request:       HelloRequest;
-+               case client_hello:        ClientHello;
-+               case server_hello:        ServerHello;
-+               case certificate:         Certificate;
-+               case server_key_exchange: ServerKeyExchange;
-+               case certificate_request: CertificateRequest;
-+               case server_hello_done:   ServerHelloDone;
-+               case certificate_verify:  CertificateVerify;
-+               case client_key_exchange: ClientKeyExchange;
-+               case finished:            Finished;
-+           } body;
-+       } Handshake;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 32]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   The handshake protocol messages are presented below in the order they
-+   must be sent; sending handshake messages in an unexpected order
-+   results in a fatal error. Unneeded handshake messages can be omitted,
-+   however. Note one exception to the ordering: the Certificate message
-+   is used twice in the handshake (from server to client, then from
-+   client to server), but described only in its first position. The one
-+   message which is not bound by these ordering rules in the Hello
-+   Request message, which can be sent at any time, but which should be
-+   ignored by the client if it arrives in the middle of a handshake.
-+
-+7.4.1. Hello messages
-+
-+   The hello phase messages are used to exchange security enhancement
-+   capabilities between the client and server. When a new session
-+   begins, the Record Layer's connection state encryption, hash, and
-+   compression algorithms are initialized to null. The current
-+   connection state is used for renegotiation messages.
-+
-+7.4.1.1. Hello request
-+
-+   When this message will be sent:
-+       The hello request message may be sent by the server at any time.
-+
-+   Meaning of this message:
-+       Hello request is a simple notification that the client should
-+       begin the negotiation process anew by sending a client hello
-+       message when convenient. This message will be ignored by the
-+       client if the client is currently negotiating a session. This
-+       message may be ignored by the client if it does not wish to
-+       renegotiate a session, or the client may, if it wishes, respond
-+       with a no_renegotiation alert. Since handshake messages are
-+       intended to have transmission precedence over application data,
-+       it is expected that the negotiation will begin before no more
-+       than a few records are received from the client. If the server
-+       sends a hello request but does not receive a client hello in
-+       response, it may close the connection with a fatal alert.
-+
-+   After sending a hello request, servers should not repeat the request
-+   until the subsequent handshake negotiation is complete.
-+
-+   Structure of this message:
-+       struct { } HelloRequest;
-+
-+ Note: This message should never be included in the message hashes which
-+       are maintained throughout the handshake and used in the finished
-+       messages and the certificate verify message.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 33]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+7.4.1.2. Client hello
-+
-+   When this message will be sent:
-+       When a client first connects to a server it is required to send
-+       the client hello as its first message. The client can also send a
-+       client hello in response to a hello request or on its own
-+       initiative in order to renegotiate the security parameters in an
-+       existing connection.
-+
-+       Structure of this message:
-+           The client hello message includes a random structure, which is
-+           used later in the protocol.
-+
-+           struct {
-+              uint32 gmt_unix_time;
-+              opaque random_bytes[28];
-+           } Random;
-+
-+       gmt_unix_time
-+       The current time and date in standard UNIX 32-bit format (seconds
-+       since the midnight starting Jan 1, 1970, GMT) according to the
-+       sender's internal clock. Clocks are not required to be set
-+       correctly by the basic TLS Protocol; higher level or application
-+       protocols may define additional requirements.
-+
-+   random_bytes
-+       28 bytes generated by a secure random number generator.
-+
-+   The client hello message includes a variable length session
-+   identifier. If not empty, the value identifies a session between the
-+   same client and server whose security parameters the client wishes to
-+   reuse. The session identifier may be from an earlier connection, this
-+   connection, or another currently active connection. The second option
-+   is useful if the client only wishes to update the random structures
-+   and derived values of a connection, while the third option makes it
-+   possible to establish several independent secure connections without
-+   repeating the full handshake protocol. These independent connections
-+   may occur sequentially or simultaneously; a SessionID becomes valid
-+   when the handshake negotiating it completes with the exchange of
-+   Finished messages and persists until removed due to aging or because
-+   a fatal error was encountered on a connection associated with the
-+   session. The actual contents of the SessionID are defined by the
-+   server.
-+
-+       opaque SessionID<0..32>;
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 34]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Warning:
-+       Because the SessionID is transmitted without encryption or
-+       immediate MAC protection, servers must not place confidential
-+       information in session identifiers or let the contents of fake
-+       session identifiers cause any breach of security. (Note that the
-+       content of the handshake as a whole, including the SessionID, is
-+       protected by the Finished messages exchanged at the end of the
-+       handshake.)
-+
-+   The CipherSuite list, passed from the client to the server in the
-+   client hello message, contains the combinations of cryptographic
-+   algorithms supported by the client in order of the client's
-+   preference (favorite choice first). Each CipherSuite defines a key
-+   exchange algorithm, a bulk encryption algorithm (including secret key
-+   length) and a MAC algorithm. The server will select a cipher suite
-+   or, if no acceptable choices are presented, return a handshake
-+   failure alert and close the connection.
-+
-+       uint8 CipherSuite[2];    /* Cryptographic suite selector */
-+
-+   The client hello includes a list of compression algorithms supported
-+   by the client, ordered according to the client's preference.
-+
-+       enum { null(0), (255) } CompressionMethod;
-+
-+       struct {
-+           ProtocolVersion client_version;
-+           Random random;
-+           SessionID session_id;
-+           CipherSuite cipher_suites<2..2^16-1>;
-+           CompressionMethod compression_methods<1..2^8-1>;
-+       } ClientHello;
-+
-+   client_version
-+       The version of the TLS protocol by which the client wishes to
-+       communicate during this session. This should be the latest
-+       (highest valued) version supported by the client. For this
-+       version of the specification, the version will be 3.1 (See
-+       Appendix E for details about backward compatibility).
-+
-+   random
-+       A client-generated random structure.
-+
-+   session_id
-+       The ID of a session the client wishes to use for this connection.
-+       This field should be empty if no session_id is available or the
-+       client wishes to generate new security parameters.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 35]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   cipher_suites
-+       This is a list of the cryptographic options supported by the
-+       client, with the client's first preference first. If the
-+       session_id field is not empty (implying a session resumption
-+       request) this vector must include at least the cipher_suite from
-+       that session. Values are defined in Appendix A.5.
-+
-+   compression_methods
-+       This is a list of the compression methods supported by the
-+       client, sorted by client preference. If the session_id field is
-+       not empty (implying a session resumption request) it must include
-+       the compression_method from that session. This vector must
-+       contain, and all implementations must support,
-+       CompressionMethod.null. Thus, a client and server will always be
-+       able to agree on a compression method.
-+
-+   After sending the client hello message, the client waits for a server
-+   hello message. Any other handshake message returned by the server
-+   except for a hello request is treated as a fatal error.
-+
-+   Forward compatibility note:
-+       In the interests of forward compatibility, it is permitted for a
-+       client hello message to include extra data after the compression
-+       methods. This data must be included in the handshake hashes, but
-+       must otherwise be ignored. This is the only handshake message for
-+       which this is legal; for all other messages, the amount of data
-+       in the message must match the description of the message
-+       precisely.
-+
-+7.4.1.3. Server hello
-+
-+   When this message will be sent:
-+       The server will send this message in response to a client hello
-+       message when it was able to find an acceptable set of algorithms.
-+       If it cannot find such a match, it will respond with a handshake
-+       failure alert.
-+
-+   Structure of this message:
-+       struct {
-+           ProtocolVersion server_version;
-+           Random random;
-+           SessionID session_id;
-+           CipherSuite cipher_suite;
-+           CompressionMethod compression_method;
-+       } ServerHello;
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 36]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   server_version
-+       This field will contain the lower of that suggested by the client
-+       in the client hello and the highest supported by the server. For
-+       this version of the specification, the version is 3.1 (See
-+       Appendix E for details about backward compatibility).
-+
-+   random
-+       This structure is generated by the server and must be different
-+       from (and independent of) ClientHello.random.
-+
-+   session_id
-+       This is the identity of the session corresponding to this
-+       connection. If the ClientHello.session_id was non-empty, the
-+       server will look in its session cache for a match. If a match is
-+       found and the server is willing to establish the new connection
-+       using the specified session state, the server will respond with
-+       the same value as was supplied by the client. This indicates a
-+       resumed session and dictates that the parties must proceed
-+       directly to the finished messages. Otherwise this field will
-+       contain a different value identifying the new session. The server
-+       may return an empty session_id to indicate that the session will
-+       not be cached and therefore cannot be resumed. If a session is
-+       resumed, it must be resumed using the same cipher suite it was
-+       originally negotiated with.
-+
-+   cipher_suite
-+       The single cipher suite selected by the server from the list in
-+       ClientHello.cipher_suites. For resumed sessions this field is the
-+       value from the state of the session being resumed.
-+
-+   compression_method
-+       The single compression algorithm selected by the server from the
-+       list in ClientHello.compression_methods. For resumed sessions
-+       this field is the value from the resumed session state.
-+
-+7.4.2. Server certificate
-+
-+   When this message will be sent:
-+       The server must send a certificate whenever the agreed-upon key
-+       exchange method is not an anonymous one. This message will always
-+       immediately follow the server hello message.
-+
-+   Meaning of this message:
-+       The certificate type must be appropriate for the selected cipher
-+       suite's key exchange algorithm, and is generally an X.509v3
-+       certificate. It must contain a key which matches the key exchange
-+       method, as follows. Unless otherwise specified, the signing
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 37]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       algorithm for the certificate must be the same as the algorithm
-+       for the certificate key. Unless otherwise specified, the public
-+       key may be of any length.
-+
-+       Key Exchange Algorithm  Certificate Key Type
-+
-+       RSA                     RSA public key; the certificate must
-+                               allow the key to be used for encryption.
-+
-+       RSA_EXPORT              RSA public key of length greater than
-+                               512 bits which can be used for signing,
-+                               or a key of 512 bits or shorter which
-+                               can be used for either encryption or
-+                               signing.
-+
-+       DHE_DSS                 DSS public key.
-+
-+       DHE_DSS_EXPORT          DSS public key.
-+
-+       DHE_RSA                 RSA public key which can be used for
-+                               signing.
-+
-+       DHE_RSA_EXPORT          RSA public key which can be used for
-+                               signing.
-+
-+       DH_DSS                  Diffie-Hellman key. The algorithm used
-+                               to sign the certificate should be DSS.
-+
-+       DH_RSA                  Diffie-Hellman key. The algorithm used
-+                               to sign the certificate should be RSA.
-+
-+   All certificate profiles, key and cryptographic formats are defined
-+   by the IETF PKIX working group [PKIX]. When a key usage extension is
-+   present, the digitalSignature bit must be set for the key to be
-+   eligible for signing, as described above, and the keyEncipherment bit
-+   must be present to allow encryption, as described above. The
-+   keyAgreement bit must be set on Diffie-Hellman certificates.
-+
-+   As CipherSuites which specify new key exchange methods are specified
-+   for the TLS Protocol, they will imply certificate format and the
-+   required encoded keying information.
-+
-+   Structure of this message:
-+       opaque ASN.1Cert<1..2^24-1>;
-+
-+       struct {
-+           ASN.1Cert certificate_list<0..2^24-1>;
-+       } Certificate;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 38]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   certificate_list
-+       This is a sequence (chain) of X.509v3 certificates. The sender's
-+       certificate must come first in the list. Each following
-+       certificate must directly certify the one preceding it. Because
-+       certificate validation requires that root keys be distributed
-+       independently, the self-signed certificate which specifies the
-+       root certificate authority may optionally be omitted from the
-+       chain, under the assumption that the remote end must already
-+       possess it in order to validate it in any case.
-+
-+   The same message type and structure will be used for the client's
-+   response to a certificate request message. Note that a client may
-+   send no certificates if it does not have an appropriate certificate
-+   to send in response to the server's authentication request.
-+
-+ Note: PKCS #7 [PKCS7] is not used as the format for the certificate
-+       vector because PKCS #6 [PKCS6] extended certificates are not
-+       used. Also PKCS #7 defines a SET rather than a SEQUENCE, making
-+       the task of parsing the list more difficult.
-+
-+7.4.3. Server key exchange message
-+
-+   When this message will be sent:
-+       This message will be sent immediately after the server
-+       certificate message (or the server hello message, if this is an
-+       anonymous negotiation).
-+
-+       The server key exchange message is sent by the server only when
-+       the server certificate message (if sent) does not contain enough
-+       data to allow the client to exchange a premaster secret. This is
-+       true for the following key exchange methods:
-+
-+           RSA_EXPORT (if the public key in the server certificate is
-+           longer than 512 bits)
-+           DHE_DSS
-+           DHE_DSS_EXPORT
-+           DHE_RSA
-+           DHE_RSA_EXPORT
-+           DH_anon
-+
-+       It is not legal to send the server key exchange message for the
-+       following key exchange methods:
-+
-+           RSA
-+           RSA_EXPORT (when the public key in the server certificate is
-+           less than or equal to 512 bits in length)
-+           DH_DSS
-+           DH_RSA
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 39]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Meaning of this message:
-+       This message conveys cryptographic information to allow the
-+       client to communicate the premaster secret: either an RSA public
-+       key to encrypt the premaster secret with, or a Diffie-Hellman
-+       public key with which the client can complete a key exchange
-+       (with the result being the premaster secret.)
-+
-+   As additional CipherSuites are defined for TLS which include new key
-+   exchange algorithms, the server key exchange message will be sent if
-+   and only if the certificate type associated with the key exchange
-+   algorithm does not provide enough information for the client to
-+   exchange a premaster secret.
-+
-+ Note: According to current US export law, RSA moduli larger than 512
-+       bits may not be used for key exchange in software exported from
-+       the US. With this message, the larger RSA keys encoded in
-+       certificates may be used to sign temporary shorter RSA keys for
-+       the RSA_EXPORT key exchange method.
-+
-+   Structure of this message:
-+       enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
-+
-+       struct {
-+           opaque rsa_modulus<1..2^16-1>;
-+           opaque rsa_exponent<1..2^16-1>;
-+       } ServerRSAParams;
-+
-+       rsa_modulus
-+           The modulus of the server's temporary RSA key.
-+
-+       rsa_exponent
-+           The public exponent of the server's temporary RSA key.
-+
-+       struct {
-+           opaque dh_p<1..2^16-1>;
-+           opaque dh_g<1..2^16-1>;
-+           opaque dh_Ys<1..2^16-1>;
-+       } ServerDHParams;     /* Ephemeral DH parameters */
-+
-+       dh_p
-+           The prime modulus used for the Diffie-Hellman operation.
-+
-+       dh_g
-+           The generator used for the Diffie-Hellman operation.
-+
-+       dh_Ys
-+           The server's Diffie-Hellman public value (g^X mod p).
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 40]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       struct {
-+           select (KeyExchangeAlgorithm) {
-+               case diffie_hellman:
-+                   ServerDHParams params;
-+                   Signature signed_params;
-+               case rsa:
-+                   ServerRSAParams params;
-+                   Signature signed_params;
-+           };
-+       } ServerKeyExchange;
-+
-+       params
-+           The server's key exchange parameters.
-+
-+       signed_params
-+           For non-anonymous key exchanges, a hash of the corresponding
-+           params value, with the signature appropriate to that hash
-+           applied.
-+
-+       md5_hash
-+           MD5(ClientHello.random + ServerHello.random + ServerParams);
-+
-+       sha_hash
-+           SHA(ClientHello.random + ServerHello.random + ServerParams);
-+
-+       enum { anonymous, rsa, dsa } SignatureAlgorithm;
-+
-+       select (SignatureAlgorithm)
-+       {   case anonymous: struct { };
-+           case rsa:
-+               digitally-signed struct {
-+                   opaque md5_hash[16];
-+                   opaque sha_hash[20];
-+               };
-+           case dsa:
-+               digitally-signed struct {
-+                   opaque sha_hash[20];
-+               };
-+       } Signature;
-+
-+7.4.4. Certificate request
-+
-+   When this message will be sent:
-+       A non-anonymous server can optionally request a certificate from
-+       the client, if appropriate for the selected cipher suite. This
-+       message, if sent, will immediately follow the Server Key Exchange
-+       message (if it is sent; otherwise, the Server Certificate
-+       message).
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 41]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Structure of this message:
-+       enum {
-+           rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
-+           (255)
-+       } ClientCertificateType;
-+
-+       opaque DistinguishedName<1..2^16-1>;
-+
-+       struct {
-+           ClientCertificateType certificate_types<1..2^8-1>;
-+           DistinguishedName certificate_authorities<3..2^16-1>;
-+       } CertificateRequest;
-+
-+       certificate_types
-+              This field is a list of the types of certificates requested,
-+              sorted in order of the server's preference.
-+
-+       certificate_authorities
-+           A list of the distinguished names of acceptable certificate
-+           authorities. These distinguished names may specify a desired
-+           distinguished name for a root CA or for a subordinate CA;
-+           thus, this message can be used both to describe known roots
-+           and a desired authorization space.
-+
-+ Note: DistinguishedName is derived from [X509].
-+
-+ Note: It is a fatal handshake_failure alert for an anonymous server to
-+       request client identification.
-+
-+7.4.5. Server hello done
-+
-+   When this message will be sent:
-+       The server hello done message is sent by the server to indicate
-+       the end of the server hello and associated messages. After
-+       sending this message the server will wait for a client response.
-+
-+   Meaning of this message:
-+       This message means that the server is done sending messages to
-+       support the key exchange, and the client can proceed with its
-+       phase of the key exchange.
-+
-+       Upon receipt of the server hello done message the client should
-+       verify that the server provided a valid certificate if required
-+       and check that the server hello parameters are acceptable.
-+
-+   Structure of this message:
-+       struct { } ServerHelloDone;
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 42]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+7.4.6. Client certificate
-+
-+   When this message will be sent:
-+       This is the first message the client can send after receiving a
-+       server hello done message. This message is only sent if the
-+       server requests a certificate. If no suitable certificate is
-+       available, the client should send a certificate message
-+       containing no certificates. If client authentication is required
-+       by the server for the handshake to continue, it may respond with
-+       a fatal handshake failure alert. Client certificates are sent
-+       using the Certificate structure defined in Section 7.4.2.
-+
-+ Note: When using a static Diffie-Hellman based key exchange method
-+       (DH_DSS or DH_RSA), if client authentication is requested, the
-+       Diffie-Hellman group and generator encoded in the client's
-+       certificate must match the server specified Diffie-Hellman
-+       parameters if the client's parameters are to be used for the key
-+       exchange.
-+
-+7.4.7. Client key exchange message
-+
-+   When this message will be sent:
-+       This message is always sent by the client. It will immediately
-+       follow the client certificate message, if it is sent. Otherwise
-+       it will be the first message sent by the client after it receives
-+       the server hello done message.
-+
-+   Meaning of this message:
-+       With this message, the premaster secret is set, either though
-+       direct transmission of the RSA-encrypted secret, or by the
-+       transmission of Diffie-Hellman parameters which will allow each
-+       side to agree upon the same premaster secret. When the key
-+       exchange method is DH_RSA or DH_DSS, client certification has
-+       been requested, and the client was able to respond with a
-+       certificate which contained a Diffie-Hellman public key whose
-+       parameters (group and generator) matched those specified by the
-+       server in its certificate, this message will not contain any
-+       data.
-+
-+   Structure of this message:
-+       The choice of messages depends on which key exchange method has
-+       been selected. See Section 7.4.3 for the KeyExchangeAlgorithm
-+       definition.
-+
-+       struct {
-+           select (KeyExchangeAlgorithm) {
-+               case rsa: EncryptedPreMasterSecret;
-+               case diffie_hellman: ClientDiffieHellmanPublic;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 43]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+           } exchange_keys;
-+       } ClientKeyExchange;
-+
-+7.4.7.1. RSA encrypted premaster secret message
-+
-+   Meaning of this message:
-+       If RSA is being used for key agreement and authentication, the
-+       client generates a 48-byte premaster secret, encrypts it using
-+       the public key from the server's certificate or the temporary RSA
-+       key provided in a server key exchange message, and sends the
-+       result in an encrypted premaster secret message. This structure
-+       is a variant of the client key exchange message, not a message in
-+       itself.
-+
-+   Structure of this message:
-+       struct {
-+           ProtocolVersion client_version;
-+           opaque random[46];
-+       } PreMasterSecret;
-+
-+       client_version
-+           The latest (newest) version supported by the client. This is
-+           used to detect version roll-back attacks. Upon receiving the
-+           premaster secret, the server should check that this value
-+           matches the value transmitted by the client in the client
-+           hello message.
-+
-+       random
-+           46 securely-generated random bytes.
-+
-+       struct {
-+           public-key-encrypted PreMasterSecret pre_master_secret;
-+       } EncryptedPreMasterSecret;
-+
-+ Note: An attack discovered by Daniel Bleichenbacher [BLEI] can be used
-+       to attack a TLS server which is using PKCS#1 encoded RSA. The
-+       attack takes advantage of the fact that by failing in different
-+       ways, a TLS server can be coerced into revealing whether a
-+       particular message, when decrypted, is properly PKCS#1 formatted
-+       or not.
-+
-+       The best way to avoid vulnerability to this attack is to treat
-+       incorrectly formatted messages in a manner indistinguishable from
-+       correctly formatted RSA blocks. Thus, when it receives an
-+       incorrectly formatted RSA block, a server should generate a
-+       random 48-byte value and proceed using it as the premaster
-+       secret. Thus, the server will act identically whether the
-+       received RSA block is correctly encoded or not.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 44]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       pre_master_secret
-+           This random value is generated by the client and is used to
-+           generate the master secret, as specified in Section 8.1.
-+
-+7.4.7.2. Client Diffie-Hellman public value
-+
-+   Meaning of this message:
-+       This structure conveys the client's Diffie-Hellman public value
-+       (Yc) if it was not already included in the client's certificate.
-+       The encoding used for Yc is determined by the enumerated
-+       PublicValueEncoding. This structure is a variant of the client
-+       key exchange message, not a message in itself.
-+
-+   Structure of this message:
-+       enum { implicit, explicit } PublicValueEncoding;
-+
-+       implicit
-+           If the client certificate already contains a suitable
-+           Diffie-Hellman key, then Yc is implicit and does not need to
-+           be sent again. In this case, the Client Key Exchange message
-+           will be sent, but will be empty.
-+
-+       explicit
-+           Yc needs to be sent.
-+
-+       struct {
-+           select (PublicValueEncoding) {
-+               case implicit: struct { };
-+               case explicit: opaque dh_Yc<1..2^16-1>;
-+           } dh_public;
-+       } ClientDiffieHellmanPublic;
-+
-+       dh_Yc
-+           The client's Diffie-Hellman public value (Yc).
-+
-+7.4.8. Certificate verify
-+
-+   When this message will be sent:
-+       This message is used to provide explicit verification of a client
-+       certificate. This message is only sent following a client
-+       certificate that has signing capability (i.e. all certificates
-+       except those containing fixed Diffie-Hellman parameters). When
-+       sent, it will immediately follow the client key exchange message.
-+
-+   Structure of this message:
-+       struct {
-+            Signature signature;
-+       } CertificateVerify;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 45]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       The Signature type is defined in 7.4.3.
-+
-+       CertificateVerify.signature.md5_hash
-+           MD5(handshake_messages);
-+
-+       Certificate.signature.sha_hash
-+           SHA(handshake_messages);
-+
-+   Here handshake_messages refers to all handshake messages sent or
-+   received starting at client hello up to but not including this
-+   message, including the type and length fields of the handshake
-+   messages. This is the concatenation of all the Handshake structures
-+   as defined in 7.4 exchanged thus far.
-+
-+7.4.9. Finished
-+
-+   When this message will be sent:
-+       A finished message is always sent immediately after a change
-+       cipher spec message to verify that the key exchange and
-+       authentication processes were successful. It is essential that a
-+       change cipher spec message be received between the other
-+       handshake messages and the Finished message.
-+
-+   Meaning of this message:
-+       The finished message is the first protected with the just-
-+       negotiated algorithms, keys, and secrets. Recipients of finished
-+       messages must verify that the contents are correct.  Once a side
-+       has sent its Finished message and received and validated the
-+       Finished message from its peer, it may begin to send and receive
-+       application data over the connection.
-+
-+       struct {
-+           opaque verify_data[12];
-+       } Finished;
-+
-+       verify_data
-+           PRF(master_secret, finished_label, MD5(handshake_messages) +
-+           SHA-1(handshake_messages)) [0..11];
-+
-+       finished_label
-+           For Finished messages sent by the client, the string "client
-+           finished". For Finished messages sent by the server, the
-+           string "server finished".
-+
-+       handshake_messages
-+           All of the data from all handshake messages up to but not
-+           including this message. This is only data visible at the
-+           handshake layer and does not include record layer headers.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 46]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+           This is the concatenation of all the Handshake structures as
-+           defined in 7.4 exchanged thus far.
-+
-+   It is a fatal error if a finished message is not preceded by a change
-+   cipher spec message at the appropriate point in the handshake.
-+
-+   The hash contained in finished messages sent by the server
-+   incorporate Sender.server; those sent by the client incorporate
-+   Sender.client. The value handshake_messages includes all handshake
-+   messages starting at client hello up to, but not including, this
-+   finished message. This may be different from handshake_messages in
-+   Section 7.4.8 because it would include the certificate verify message
-+   (if sent). Also, the handshake_messages for the finished message sent
-+   by the client will be different from that for the finished message
-+   sent by the server, because the one which is sent second will include
-+   the prior one.
-+
-+ Note: Change cipher spec messages, alerts and any other record types
-+       are not handshake messages and are not included in the hash
-+       computations. Also, Hello Request messages are omitted from
-+       handshake hashes.
-+
-+8. Cryptographic computations
-+
-+   In order to begin connection protection, the TLS Record Protocol
-+   requires specification of a suite of algorithms, a master secret, and
-+   the client and server random values. The authentication, encryption,
-+   and MAC algorithms are determined by the cipher_suite selected by the
-+   server and revealed in the server hello message. The compression
-+   algorithm is negotiated in the hello messages, and the random values
-+   are exchanged in the hello messages. All that remains is to calculate
-+   the master secret.
-+
-+8.1. Computing the master secret
-+
-+   For all key exchange methods, the same algorithm is used to convert
-+   the pre_master_secret into the master_secret. The pre_master_secret
-+   should be deleted from memory once the master_secret has been
-+   computed.
-+
-+       master_secret = PRF(pre_master_secret, "master secret",
-+                           ClientHello.random + ServerHello.random)
-+       [0..47];
-+
-+   The master secret is always exactly 48 bytes in length. The length of
-+   the premaster secret will vary depending on key exchange method.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 47]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+8.1.1. RSA
-+
-+   When RSA is used for server authentication and key exchange, a 48-
-+   byte pre_master_secret is generated by the client, encrypted under
-+   the server's public key, and sent to the server. The server uses its
-+   private key to decrypt the pre_master_secret. Both parties then
-+   convert the pre_master_secret into the master_secret, as specified
-+   above.
-+
-+   RSA digital signatures are performed using PKCS #1 [PKCS1] block type
-+   1. RSA public key encryption is performed using PKCS #1 block type 2.
-+
-+8.1.2. Diffie-Hellman
-+
-+   A conventional Diffie-Hellman computation is performed. The
-+   negotiated key (Z) is used as the pre_master_secret, and is converted
-+   into the master_secret, as specified above.
-+
-+ Note: Diffie-Hellman parameters are specified by the server, and may
-+       be either ephemeral or contained within the server's certificate.
-+
-+9. Mandatory Cipher Suites
-+
-+   In the absence of an application profile standard specifying
-+   otherwise, a TLS compliant application MUST implement the cipher
-+   suite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.
-+
-+10. Application data protocol
-+
-+   Application data messages are carried by the Record Layer and are
-+   fragmented, compressed and encrypted based on the current connection
-+   state. The messages are treated as transparent data to the record
-+   layer.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 48]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+A. Protocol constant values
-+
-+   This section describes protocol types and constants.
-+
-+A.1. Record layer
-+
-+    struct {
-+        uint8 major, minor;
-+    } ProtocolVersion;
-+
-+    ProtocolVersion version = { 3, 1 };     /* TLS v1.0 */
-+
-+    enum {
-+        change_cipher_spec(20), alert(21), handshake(22),
-+        application_data(23), (255)
-+    } ContentType;
-+
-+    struct {
-+        ContentType type;
-+        ProtocolVersion version;
-+        uint16 length;
-+        opaque fragment[TLSPlaintext.length];
-+    } TLSPlaintext;
-+
-+    struct {
-+        ContentType type;
-+        ProtocolVersion version;
-+        uint16 length;
-+        opaque fragment[TLSCompressed.length];
-+    } TLSCompressed;
-+
-+    struct {
-+        ContentType type;
-+        ProtocolVersion version;
-+        uint16 length;
-+        select (CipherSpec.cipher_type) {
-+            case stream: GenericStreamCipher;
-+            case block:  GenericBlockCipher;
-+        } fragment;
-+    } TLSCiphertext;
-+
-+    stream-ciphered struct {
-+        opaque content[TLSCompressed.length];
-+        opaque MAC[CipherSpec.hash_size];
-+    } GenericStreamCipher;
-+
-+    block-ciphered struct {
-+        opaque content[TLSCompressed.length];
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 49]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+        opaque MAC[CipherSpec.hash_size];
-+        uint8 padding[GenericBlockCipher.padding_length];
-+        uint8 padding_length;
-+    } GenericBlockCipher;
-+
-+A.2. Change cipher specs message
-+
-+    struct {
-+        enum { change_cipher_spec(1), (255) } type;
-+    } ChangeCipherSpec;
-+
-+A.3. Alert messages
-+
-+    enum { warning(1), fatal(2), (255) } AlertLevel;
-+
-+        enum {
-+            close_notify(0),
-+            unexpected_message(10),
-+            bad_record_mac(20),
-+            decryption_failed(21),
-+            record_overflow(22),
-+            decompression_failure(30),
-+            handshake_failure(40),
-+            bad_certificate(42),
-+            unsupported_certificate(43),
-+            certificate_revoked(44),
-+            certificate_expired(45),
-+            certificate_unknown(46),
-+            illegal_parameter(47),
-+            unknown_ca(48),
-+            access_denied(49),
-+            decode_error(50),
-+            decrypt_error(51),
-+            export_restriction(60),
-+            protocol_version(70),
-+            insufficient_security(71),
-+            internal_error(80),
-+            user_canceled(90),
-+            no_renegotiation(100),
-+            (255)
-+        } AlertDescription;
-+
-+    struct {
-+        AlertLevel level;
-+        AlertDescription description;
-+    } Alert;
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 50]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+A.4. Handshake protocol
-+
-+    enum {
-+        hello_request(0), client_hello(1), server_hello(2),
-+        certificate(11), server_key_exchange (12),
-+        certificate_request(13), server_hello_done(14),
-+        certificate_verify(15), client_key_exchange(16),
-+        finished(20), (255)
-+    } HandshakeType;
-+
-+    struct {
-+        HandshakeType msg_type;
-+        uint24 length;
-+        select (HandshakeType) {
-+            case hello_request:       HelloRequest;
-+            case client_hello:        ClientHello;
-+            case server_hello:        ServerHello;
-+            case certificate:         Certificate;
-+            case server_key_exchange: ServerKeyExchange;
-+            case certificate_request: CertificateRequest;
-+            case server_hello_done:   ServerHelloDone;
-+            case certificate_verify:  CertificateVerify;
-+            case client_key_exchange: ClientKeyExchange;
-+            case finished:            Finished;
-+        } body;
-+    } Handshake;
-+
-+A.4.1. Hello messages
-+
-+    struct { } HelloRequest;
-+
-+    struct {
-+        uint32 gmt_unix_time;
-+        opaque random_bytes[28];
-+    } Random;
-+
-+    opaque SessionID<0..32>;
-+
-+    uint8 CipherSuite[2];
-+
-+    enum { null(0), (255) } CompressionMethod;
-+
-+    struct {
-+        ProtocolVersion client_version;
-+        Random random;
-+        SessionID session_id;
-+        CipherSuite cipher_suites<2..2^16-1>;
-+        CompressionMethod compression_methods<1..2^8-1>;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 51]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+    } ClientHello;
-+
-+    struct {
-+        ProtocolVersion server_version;
-+        Random random;
-+        SessionID session_id;
-+        CipherSuite cipher_suite;
-+        CompressionMethod compression_method;
-+    } ServerHello;
-+
-+A.4.2. Server authentication and key exchange messages
-+
-+    opaque ASN.1Cert<2^24-1>;
-+
-+    struct {
-+        ASN.1Cert certificate_list<1..2^24-1>;
-+    } Certificate;
-+
-+    enum { rsa, diffie_hellman } KeyExchangeAlgorithm;
-+
-+    struct {
-+        opaque RSA_modulus<1..2^16-1>;
-+        opaque RSA_exponent<1..2^16-1>;
-+    } ServerRSAParams;
-+
-+    struct {
-+        opaque DH_p<1..2^16-1>;
-+        opaque DH_g<1..2^16-1>;
-+        opaque DH_Ys<1..2^16-1>;
-+    } ServerDHParams;
-+
-+    struct {
-+        select (KeyExchangeAlgorithm) {
-+            case diffie_hellman:
-+                ServerDHParams params;
-+                Signature signed_params;
-+            case rsa:
-+                ServerRSAParams params;
-+                Signature signed_params;
-+        };
-+    } ServerKeyExchange;
-+
-+    enum { anonymous, rsa, dsa } SignatureAlgorithm;
-+
-+    select (SignatureAlgorithm)
-+    {   case anonymous: struct { };
-+        case rsa:
-+            digitally-signed struct {
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 52]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+                opaque md5_hash[16];
-+                opaque sha_hash[20];
-+            };
-+        case dsa:
-+            digitally-signed struct {
-+                opaque sha_hash[20];
-+            };
-+    } Signature;
-+
-+    enum {
-+        rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
-+        (255)
-+    } ClientCertificateType;
-+
-+    opaque DistinguishedName<1..2^16-1>;
-+
-+    struct {
-+        ClientCertificateType certificate_types<1..2^8-1>;
-+        DistinguishedName certificate_authorities<3..2^16-1>;
-+    } CertificateRequest;
-+
-+    struct { } ServerHelloDone;
-+
-+A.4.3. Client authentication and key exchange messages
-+
-+    struct {
-+        select (KeyExchangeAlgorithm) {
-+            case rsa: EncryptedPreMasterSecret;
-+            case diffie_hellman: DiffieHellmanClientPublicValue;
-+        } exchange_keys;
-+    } ClientKeyExchange;
-+
-+    struct {
-+        ProtocolVersion client_version;
-+        opaque random[46];
-+
-+    } PreMasterSecret;
-+
-+    struct {
-+        public-key-encrypted PreMasterSecret pre_master_secret;
-+    } EncryptedPreMasterSecret;
-+
-+    enum { implicit, explicit } PublicValueEncoding;
-+
-+    struct {
-+        select (PublicValueEncoding) {
-+            case implicit: struct {};
-+            case explicit: opaque DH_Yc<1..2^16-1>;
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 53]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+        } dh_public;
-+    } ClientDiffieHellmanPublic;
-+
-+    struct {
-+        Signature signature;
-+    } CertificateVerify;
-+
-+A.4.4. Handshake finalization message
-+
-+    struct {
-+        opaque verify_data[12];
-+    } Finished;
-+
-+A.5. The CipherSuite
-+
-+   The following values define the CipherSuite codes used in the client
-+   hello and server hello messages.
-+
-+   A CipherSuite defines a cipher specification supported in TLS Version
-+   1.0.
-+
-+   TLS_NULL_WITH_NULL_NULL is specified and is the initial state of a
-+   TLS connection during the first handshake on that channel, but must
-+   not be negotiated, as it provides no more protection than an
-+   unsecured connection.
-+
-+    CipherSuite TLS_NULL_WITH_NULL_NULL                = { 0x00,0x00 };
-+
-+   The following CipherSuite definitions require that the server provide
-+   an RSA certificate that can be used for key exchange. The server may
-+   request either an RSA or a DSS signature-capable certificate in the
-+   certificate request message.
-+
-+    CipherSuite TLS_RSA_WITH_NULL_MD5                  = { 0x00,0x01 };
-+    CipherSuite TLS_RSA_WITH_NULL_SHA                  = { 0x00,0x02 };
-+    CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5         = { 0x00,0x03 };
-+    CipherSuite TLS_RSA_WITH_RC4_128_MD5               = { 0x00,0x04 };
-+    CipherSuite TLS_RSA_WITH_RC4_128_SHA               = { 0x00,0x05 };
-+    CipherSuite TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5     = { 0x00,0x06 };
-+    CipherSuite TLS_RSA_WITH_IDEA_CBC_SHA              = { 0x00,0x07 };
-+    CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA      = { 0x00,0x08 };
-+    CipherSuite TLS_RSA_WITH_DES_CBC_SHA               = { 0x00,0x09 };
-+    CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA          = { 0x00,0x0A };
-+
-+   The following CipherSuite definitions are used for server-
-+   authenticated (and optionally client-authenticated) Diffie-Hellman.
-+   DH denotes cipher suites in which the server's certificate contains
-+   the Diffie-Hellman parameters signed by the certificate authority
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 54]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   (CA). DHE denotes ephemeral Diffie-Hellman, where the Diffie-Hellman
-+   parameters are signed by a DSS or RSA certificate, which has been
-+   signed by the CA. The signing algorithm used is specified after the
-+   DH or DHE parameter. The server can request an RSA or DSS signature-
-+   capable certificate from the client for client authentication or it
-+   may request a Diffie-Hellman certificate. Any Diffie-Hellman
-+   certificate provided by the client must use the parameters (group and
-+   generator) described by the server.
-+
-+    CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA   = { 0x00,0x0B };
-+    CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA            = { 0x00,0x0C };
-+    CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA       = { 0x00,0x0D };
-+    CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA   = { 0x00,0x0E };
-+    CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA            = { 0x00,0x0F };
-+    CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA       = { 0x00,0x10 };
-+    CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA  = { 0x00,0x11 };
-+    CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA           = { 0x00,0x12 };
-+    CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x13 };
-+    CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA  = { 0x00,0x14 };
-+    CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA           = { 0x00,0x15 };
-+    CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x16 };
-+
-+   The following cipher suites are used for completely anonymous
-+   Diffie-Hellman communications in which neither party is
-+   authenticated. Note that this mode is vulnerable to man-in-the-middle
-+   attacks and is therefore deprecated.
-+
-+    CipherSuite TLS_DH_anon_EXPORT_WITH_RC4_40_MD5     = { 0x00,0x17 };
-+    CipherSuite TLS_DH_anon_WITH_RC4_128_MD5           = { 0x00,0x18 };
-+    CipherSuite TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA  = { 0x00,0x19 };
-+    CipherSuite TLS_DH_anon_WITH_DES_CBC_SHA           = { 0x00,0x1A };
-+    CipherSuite TLS_DH_anon_WITH_3DES_EDE_CBC_SHA      = { 0x00,0x1B };
-+
-+ Note: All cipher suites whose first byte is 0xFF are considered
-+       private and can be used for defining local/experimental
-+       algorithms. Interoperability of such types is a local matter.
-+
-+ Note: Additional cipher suites can be registered by publishing an RFC
-+       which specifies the cipher suites, including the necessary TLS
-+       protocol information, including message encoding, premaster
-+       secret derivation, symmetric encryption and MAC calculation and
-+       appropriate reference information for the algorithms involved.
-+       The RFC editor's office may, at its discretion, choose to publish
-+       specifications for cipher suites which are not completely
-+       described (e.g., for classified algorithms) if it finds the
-+       specification to be of technical interest and completely
-+       specified.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 55]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+ Note: The cipher suite values { 0x00, 0x1C } and { 0x00, 0x1D } are
-+       reserved to avoid collision with Fortezza-based cipher suites in
-+       SSL 3.
-+
-+A.6. The Security Parameters
-+
-+   These security parameters are determined by the TLS Handshake
-+   Protocol and provided as parameters to the TLS Record Layer in order
-+   to initialize a connection state. SecurityParameters includes:
-+
-+       enum { null(0), (255) } CompressionMethod;
-+
-+       enum { server, client } ConnectionEnd;
-+
-+       enum { null, rc4, rc2, des, 3des, des40, idea }
-+       BulkCipherAlgorithm;
-+
-+       enum { stream, block } CipherType;
-+
-+       enum { true, false } IsExportable;
-+
-+       enum { null, md5, sha } MACAlgorithm;
-+
-+   /* The algorithms specified in CompressionMethod,
-+   BulkCipherAlgorithm, and MACAlgorithm may be added to. */
-+
-+       struct {
-+           ConnectionEnd entity;
-+           BulkCipherAlgorithm bulk_cipher_algorithm;
-+           CipherType cipher_type;
-+           uint8 key_size;
-+           uint8 key_material_length;
-+           IsExportable is_exportable;
-+           MACAlgorithm mac_algorithm;
-+           uint8 hash_size;
-+           CompressionMethod compression_algorithm;
-+           opaque master_secret[48];
-+           opaque client_random[32];
-+           opaque server_random[32];
-+       } SecurityParameters;
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 56]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+B. Glossary
-+
-+   application protocol
-+       An application protocol is a protocol that normally layers
-+       directly on top of the transport layer (e.g., TCP/IP). Examples
-+       include HTTP, TELNET, FTP, and SMTP.
-+
-+   asymmetric cipher
-+       See public key cryptography.
-+
-+   authentication
-+       Authentication is the ability of one entity to determine the
-+       identity of another entity.
-+
-+   block cipher
-+       A block cipher is an algorithm that operates on plaintext in
-+       groups of bits, called blocks. 64 bits is a common block size.
-+
-+   bulk cipher
-+       A symmetric encryption algorithm used to encrypt large quantities
-+       of data.
-+
-+   cipher block chaining (CBC)
-+       CBC is a mode in which every plaintext block encrypted with a
-+       block cipher is first exclusive-ORed with the previous ciphertext
-+       block (or, in the case of the first block, with the
-+       initialization vector). For decryption, every block is first
-+       decrypted, then exclusive-ORed with the previous ciphertext block
-+       (or IV).
-+
-+   certificate
-+       As part of the X.509 protocol (a.k.a. ISO Authentication
-+       framework), certificates are assigned by a trusted Certificate
-+       Authority and provide a strong binding between a party's identity
-+       or some other attributes and its public key.
-+
-+   client
-+       The application entity that initiates a TLS connection to a
-+       server. This may or may not imply that the client initiated the
-+       underlying transport connection. The primary operational
-+       difference between the server and client is that the server is
-+       generally authenticated, while the client is only optionally
-+       authenticated.
-+
-+   client write key
-+       The key used to encrypt data written by the client.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 57]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   client write MAC secret
-+       The secret data used to authenticate data written by the client.
-+
-+   connection
-+       A connection is a transport (in the OSI layering model
-+       definition) that provides a suitable type of service. For TLS,
-+       such connections are peer to peer relationships. The connections
-+       are transient. Every connection is associated with one session.
-+
-+   Data Encryption Standard
-+       DES is a very widely used symmetric encryption algorithm. DES is
-+       a block cipher with a 56 bit key and an 8 byte block size. Note
-+       that in TLS, for key generation purposes, DES is treated as
-+       having an 8 byte key length (64 bits), but it still only provides
-+       56 bits of protection. (The low bit of each key byte is presumed
-+       to be set to produce odd parity in that key byte.) DES can also
-+       be operated in a mode where three independent keys and three
-+       encryptions are used for each block of data; this uses 168 bits
-+       of key (24 bytes in the TLS key generation method) and provides
-+       the equivalent of 112 bits of security. [DES], [3DES]
-+
-+   Digital Signature Standard (DSS)
-+       A standard for digital signing, including the Digital Signing
-+       Algorithm, approved by the National Institute of Standards and
-+       Technology, defined in NIST FIPS PUB 186, "Digital Signature
-+       Standard," published May, 1994 by the U.S. Dept. of Commerce.
-+       [DSS]
-+
-+   digital signatures
-+       Digital signatures utilize public key cryptography and one-way
-+       hash functions to produce a signature of the data that can be
-+       authenticated, and is difficult to forge or repudiate.
-+
-+   handshake
-+       An initial negotiation between client and server that establishes
-+       the parameters of their transactions.
-+
-+   Initialization Vector (IV)
-+       When a block cipher is used in CBC mode, the initialization
-+       vector is exclusive-ORed with the first plaintext block prior to
-+       encryption.
-+
-+   IDEA
-+       A 64-bit block cipher designed by Xuejia Lai and James Massey.
-+       [IDEA]
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 58]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Message Authentication Code (MAC)
-+       A Message Authentication Code is a one-way hash computed from a
-+       message and some secret data. It is difficult to forge without
-+       knowing the secret data. Its purpose is to detect if the message
-+       has been altered.
-+
-+   master secret
-+       Secure secret data used for generating encryption keys, MAC
-+       secrets, and IVs.
-+
-+   MD5
-+       MD5 is a secure hashing function that converts an arbitrarily
-+       long data stream into a digest of fixed size (16 bytes). [MD5]
-+
-+   public key cryptography
-+       A class of cryptographic techniques employing two-key ciphers.
-+       Messages encrypted with the public key can only be decrypted with
-+       the associated private key. Conversely, messages signed with the
-+       private key can be verified with the public key.
-+
-+   one-way hash function
-+       A one-way transformation that converts an arbitrary amount of
-+       data into a fixed-length hash. It is computationally hard to
-+       reverse the transformation or to find collisions. MD5 and SHA are
-+       examples of one-way hash functions.
-+
-+   RC2
-+       A block cipher developed by Ron Rivest at RSA Data Security, Inc.
-+       [RSADSI] described in [RC2].
-+
-+   RC4
-+       A stream cipher licensed by RSA Data Security [RSADSI]. A
-+       compatible cipher is described in [RC4].
-+
-+   RSA
-+       A very widely used public-key algorithm that can be used for
-+       either encryption or digital signing. [RSA]
-+
-+   salt
-+       Non-secret random data used to make export encryption keys resist
-+       precomputation attacks.
-+
-+   server
-+       The server is the application entity that responds to requests
-+       for connections from clients. See also under client.
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 59]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   session
-+       A TLS session is an association between a client and a server.
-+       Sessions are created by the handshake protocol. Sessions define a
-+       set of cryptographic security parameters, which can be shared
-+       among multiple connections. Sessions are used to avoid the
-+       expensive negotiation of new security parameters for each
-+       connection.
-+
-+   session identifier
-+       A session identifier is a value generated by a server that
-+       identifies a particular session.
-+
-+   server write key
-+       The key used to encrypt data written by the server.
-+
-+   server write MAC secret
-+       The secret data used to authenticate data written by the server.
-+
-+   SHA
-+       The Secure Hash Algorithm is defined in FIPS PUB 180-1. It
-+       produces a 20-byte output. Note that all references to SHA
-+       actually use the modified SHA-1 algorithm. [SHA]
-+
-+   SSL
-+       Netscape's Secure Socket Layer protocol [SSL3]. TLS is based on
-+       SSL Version 3.0
-+
-+   stream cipher
-+       An encryption algorithm that converts a key into a
-+       cryptographically-strong keystream, which is then exclusive-ORed
-+       with the plaintext.
-+
-+   symmetric cipher
-+       See bulk cipher.
-+
-+   Transport Layer Security (TLS)
-+       This protocol; also, the Transport Layer Security working group
-+       of the Internet Engineering Task Force (IETF). See "Comments" at
-+       the end of this document.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 60]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+C. CipherSuite definitions
-+
-+CipherSuite                      Is       Key          Cipher      Hash
-+                             Exportable Exchange
-+
-+TLS_NULL_WITH_NULL_NULL               * NULL           NULL        NULL
-+TLS_RSA_WITH_NULL_MD5                 * RSA            NULL         MD5
-+TLS_RSA_WITH_NULL_SHA                 * RSA            NULL         SHA
-+TLS_RSA_EXPORT_WITH_RC4_40_MD5        * RSA_EXPORT     RC4_40       MD5
-+TLS_RSA_WITH_RC4_128_MD5                RSA            RC4_128      MD5
-+TLS_RSA_WITH_RC4_128_SHA                RSA            RC4_128      SHA
-+TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5    * RSA_EXPORT     RC2_CBC_40   MD5
-+TLS_RSA_WITH_IDEA_CBC_SHA               RSA            IDEA_CBC     SHA
-+TLS_RSA_EXPORT_WITH_DES40_CBC_SHA     * RSA_EXPORT     DES40_CBC    SHA
-+TLS_RSA_WITH_DES_CBC_SHA                RSA            DES_CBC      SHA
-+TLS_RSA_WITH_3DES_EDE_CBC_SHA           RSA            3DES_EDE_CBC SHA
-+TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA  * DH_DSS_EXPORT  DES40_CBC    SHA
-+TLS_DH_DSS_WITH_DES_CBC_SHA             DH_DSS         DES_CBC      SHA
-+TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA        DH_DSS         3DES_EDE_CBC SHA
-+TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA  * DH_RSA_EXPORT  DES40_CBC    SHA
-+TLS_DH_RSA_WITH_DES_CBC_SHA             DH_RSA         DES_CBC      SHA
-+TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA        DH_RSA         3DES_EDE_CBC SHA
-+TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA * DHE_DSS_EXPORT DES40_CBC    SHA
-+TLS_DHE_DSS_WITH_DES_CBC_SHA            DHE_DSS        DES_CBC      SHA
-+TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA       DHE_DSS        3DES_EDE_CBC SHA
-+TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA * DHE_RSA_EXPORT DES40_CBC    SHA
-+TLS_DHE_RSA_WITH_DES_CBC_SHA            DHE_RSA        DES_CBC      SHA
-+TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA       DHE_RSA        3DES_EDE_CBC SHA
-+TLS_DH_anon_EXPORT_WITH_RC4_40_MD5    * DH_anon_EXPORT RC4_40       MD5
-+TLS_DH_anon_WITH_RC4_128_MD5            DH_anon        RC4_128      MD5
-+TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA   DH_anon        DES40_CBC    SHA
-+TLS_DH_anon_WITH_DES_CBC_SHA            DH_anon        DES_CBC      SHA
-+TLS_DH_anon_WITH_3DES_EDE_CBC_SHA       DH_anon        3DES_EDE_CBC SHA
-+
-+
-+   * Indicates IsExportable is True
-+
-+      Key
-+      Exchange
-+      Algorithm       Description                        Key size limit
-+
-+      DHE_DSS         Ephemeral DH with DSS signatures   None
-+      DHE_DSS_EXPORT  Ephemeral DH with DSS signatures   DH = 512 bits
-+      DHE_RSA         Ephemeral DH with RSA signatures   None
-+      DHE_RSA_EXPORT  Ephemeral DH with RSA signatures   DH = 512 bits,
-+                                                         RSA = none
-+      DH_anon         Anonymous DH, no signatures        None
-+      DH_anon_EXPORT  Anonymous DH, no signatures        DH = 512 bits
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 61]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+      DH_DSS          DH with DSS-based certificates     None
-+      DH_DSS_EXPORT   DH with DSS-based certificates     DH = 512 bits
-+      DH_RSA          DH with RSA-based certificates     None
-+      DH_RSA_EXPORT   DH with RSA-based certificates     DH = 512 bits,
-+                                                         RSA = none
-+      NULL            No key exchange                    N/A
-+      RSA             RSA key exchange                   None
-+      RSA_EXPORT      RSA key exchange                   RSA = 512 bits
-+
-+   Key size limit
-+       The key size limit gives the size of the largest public key that
-+       can be legally used for encryption in cipher suites that are
-+       exportable.
-+
-+                         Key      Expanded   Effective   IV    Block
-+    Cipher       Type  Material Key Material  Key Bits  Size   Size
-+
-+    NULL       * Stream   0          0           0        0     N/A
-+    IDEA_CBC     Block   16         16         128        8      8
-+    RC2_CBC_40 * Block    5         16          40        8      8
-+    RC4_40     * Stream   5         16          40        0     N/A
-+    RC4_128      Stream  16         16         128        0     N/A
-+    DES40_CBC  * Block    5          8          40        8      8
-+    DES_CBC      Block    8          8          56        8      8
-+    3DES_EDE_CBC Block   24         24         168        8      8
-+
-+   * Indicates IsExportable is true.
-+
-+   Type
-+       Indicates whether this is a stream cipher or a block cipher
-+       running in CBC mode.
-+
-+   Key Material
-+       The number of bytes from the key_block that are used for
-+       generating the write keys.
-+
-+   Expanded Key Material
-+       The number of bytes actually fed into the encryption algorithm
-+
-+   Effective Key Bits
-+       How much entropy material is in the key material being fed into
-+       the encryption routines.
-+
-+   IV Size
-+       How much data needs to be generated for the initialization
-+       vector. Zero for stream ciphers; equal to the block size for
-+       block ciphers.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 62]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Block Size
-+       The amount of data a block cipher enciphers in one chunk; a
-+       block cipher running in CBC mode can only encrypt an even
-+       multiple of its block size.
-+
-+      Hash      Hash      Padding
-+    function    Size       Size
-+      NULL       0          0
-+      MD5        16         48
-+      SHA        20         40
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 63]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+D. Implementation Notes
-+
-+   The TLS protocol cannot prevent many common security mistakes. This
-+   section provides several recommendations to assist implementors.
-+
-+D.1. Temporary RSA keys
-+
-+   US Export restrictions limit RSA keys used for encryption to 512
-+   bits, but do not place any limit on lengths of RSA keys used for
-+   signing operations. Certificates often need to be larger than 512
-+   bits, since 512-bit RSA keys are not secure enough for high-value
-+   transactions or for applications requiring long-term security. Some
-+   certificates are also designated signing-only, in which case they
-+   cannot be used for key exchange.
-+
-+   When the public key in the certificate cannot be used for encryption,
-+   the server signs a temporary RSA key, which is then exchanged. In
-+   exportable applications, the temporary RSA key should be the maximum
-+   allowable length (i.e., 512 bits). Because 512-bit RSA keys are
-+   relatively insecure, they should be changed often. For typical
-+   electronic commerce applications, it is suggested that keys be
-+   changed daily or every 500 transactions, and more often if possible.
-+   Note that while it is acceptable to use the same temporary key for
-+   multiple transactions, it must be signed each time it is used.
-+
-+   RSA key generation is a time-consuming process. In many cases, a
-+   low-priority process can be assigned the task of key generation.
-+
-+   Whenever a new key is completed, the existing temporary key can be
-+   replaced with the new one.
-+
-+D.2. Random Number Generation and Seeding
-+
-+   TLS requires a cryptographically-secure pseudorandom number generator
-+   (PRNG). Care must be taken in designing and seeding PRNGs.  PRNGs
-+   based on secure hash operations, most notably MD5 and/or SHA, are
-+   acceptable, but cannot provide more security than the size of the
-+   random number generator state. (For example, MD5-based PRNGs usually
-+   provide 128 bits of state.)
-+
-+   To estimate the amount of seed material being produced, add the
-+   number of bits of unpredictable information in each seed byte. For
-+   example, keystroke timing values taken from a PC compatible's 18.2 Hz
-+   timer provide 1 or 2 secure bits each, even though the total size of
-+   the counter value is 16 bits or more. To seed a 128-bit PRNG, one
-+   would thus require approximately 100 such timer values.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 64]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+ Warning: The seeding functions in RSAREF and versions of BSAFE prior to
-+          3.0 are order-independent. For example, if 1000 seed bits are
-+          supplied, one at a time, in 1000 separate calls to the seed
-+          function, the PRNG will end up in a state which depends only
-+          on the number of 0 or 1 seed bits in the seed data (i.e.,
-+          there are 1001 possible final states). Applications using
-+          BSAFE or RSAREF must take extra care to ensure proper seeding.
-+          This may be accomplished by accumulating seed bits into a
-+          buffer and processing them all at once or by processing an
-+          incrementing counter with every seed bit; either method will
-+          reintroduce order dependence into the seeding process.
-+
-+D.3. Certificates and authentication
-+
-+   Implementations are responsible for verifying the integrity of
-+   certificates and should generally support certificate revocation
-+   messages. Certificates should always be verified to ensure proper
-+   signing by a trusted Certificate Authority (CA). The selection and
-+   addition of trusted CAs should be done very carefully. Users should
-+   be able to view information about the certificate and root CA.
-+
-+D.4. CipherSuites
-+
-+   TLS supports a range of key sizes and security levels, including some
-+   which provide no or minimal security. A proper implementation will
-+   probably not support many cipher suites. For example, 40-bit
-+   encryption is easily broken, so implementations requiring strong
-+   security should not allow 40-bit keys. Similarly, anonymous Diffie-
-+   Hellman is strongly discouraged because it cannot prevent man-in-
-+   the-middle attacks. Applications should also enforce minimum and
-+   maximum key sizes. For example, certificate chains containing 512-bit
-+   RSA keys or signatures are not appropriate for high-security
-+   applications.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 65]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+E. Backward Compatibility With SSL
-+
-+   For historical reasons and in order to avoid a profligate consumption
-+   of reserved port numbers, application protocols which are secured by
-+   TLS 1.0, SSL 3.0, and SSL 2.0 all frequently share the same
-+   connection port: for example, the https protocol (HTTP secured by SSL
-+   or TLS) uses port 443 regardless of which security protocol it is
-+   using. Thus, some mechanism must be determined to distinguish and
-+   negotiate among the various protocols.
-+
-+   TLS version 1.0 and SSL 3.0 are very similar; thus, supporting both
-+   is easy. TLS clients who wish to negotiate with SSL 3.0 servers
-+   should send client hello messages using the SSL 3.0 record format and
-+   client hello structure, sending {3, 1} for the version field to note
-+   that they support TLS 1.0. If the server supports only SSL 3.0, it
-+   will respond with an SSL 3.0 server hello; if it supports TLS, with a
-+   TLS server hello. The negotiation then proceeds as appropriate for
-+   the negotiated protocol.
-+
-+   Similarly, a TLS server which wishes to interoperate with SSL 3.0
-+   clients should accept SSL 3.0 client hello messages and respond with
-+   an SSL 3.0 server hello if an SSL 3.0 client hello is received which
-+   has a version field of {3, 0}, denoting that this client does not
-+   support TLS.
-+
-+   Whenever a client already knows the highest protocol known to a
-+   server (for example, when resuming a session), it should initiate the
-+   connection in that native protocol.
-+
-+   TLS 1.0 clients that support SSL Version 2.0 servers must send SSL
-+   Version 2.0 client hello messages [SSL2]. TLS servers should accept
-+   either client hello format if they wish to support SSL 2.0 clients on
-+   the same connection port. The only deviations from the Version 2.0
-+   specification are the ability to specify a version with a value of
-+   three and the support for more ciphering types in the CipherSpec.
-+
-+ Warning: The ability to send Version 2.0 client hello messages will be
-+          phased out with all due haste. Implementors should make every
-+          effort to move forward as quickly as possible. Version 3.0
-+          provides better mechanisms for moving to newer versions.
-+
-+   The following cipher specifications are carryovers from SSL Version
-+   2.0. These are assumed to use RSA for key exchange and
-+   authentication.
-+
-+       V2CipherSpec TLS_RC4_128_WITH_MD5          = { 0x01,0x00,0x80 };
-+       V2CipherSpec TLS_RC4_128_EXPORT40_WITH_MD5 = { 0x02,0x00,0x80 };
-+       V2CipherSpec TLS_RC2_CBC_128_CBC_WITH_MD5  = { 0x03,0x00,0x80 };
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 66]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       V2CipherSpec TLS_RC2_CBC_128_CBC_EXPORT40_WITH_MD5
-+                                                  = { 0x04,0x00,0x80 };
-+       V2CipherSpec TLS_IDEA_128_CBC_WITH_MD5     = { 0x05,0x00,0x80 };
-+       V2CipherSpec TLS_DES_64_CBC_WITH_MD5       = { 0x06,0x00,0x40 };
-+       V2CipherSpec TLS_DES_192_EDE3_CBC_WITH_MD5 = { 0x07,0x00,0xC0 };
-+
-+   Cipher specifications native to TLS can be included in Version 2.0
-+   client hello messages using the syntax below. Any V2CipherSpec
-+   element with its first byte equal to zero will be ignored by Version
-+   2.0 servers. Clients sending any of the above V2CipherSpecs should
-+   also include the TLS equivalent (see Appendix A.5):
-+
-+       V2CipherSpec (see TLS name) = { 0x00, CipherSuite };
-+
-+E.1. Version 2 client hello
-+
-+   The Version 2.0 client hello message is presented below using this
-+   document's presentation model. The true definition is still assumed
-+   to be the SSL Version 2.0 specification.
-+
-+       uint8 V2CipherSpec[3];
-+
-+       struct {
-+           uint8 msg_type;
-+           Version version;
-+           uint16 cipher_spec_length;
-+           uint16 session_id_length;
-+           uint16 challenge_length;
-+           V2CipherSpec cipher_specs[V2ClientHello.cipher_spec_length];
-+           opaque session_id[V2ClientHello.session_id_length];
-+           Random challenge;
-+       } V2ClientHello;
-+
-+   msg_type
-+       This field, in conjunction with the version field, identifies a
-+       version 2 client hello message. The value should be one (1).
-+
-+   version
-+       The highest version of the protocol supported by the client
-+       (equals ProtocolVersion.version, see Appendix A.1).
-+
-+   cipher_spec_length
-+       This field is the total length of the field cipher_specs. It
-+       cannot be zero and must be a multiple of the V2CipherSpec length
-+       (3).
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 67]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   session_id_length
-+       This field must have a value of either zero or 16. If zero, the
-+       client is creating a new session. If 16, the session_id field
-+       will contain the 16 bytes of session identification.
-+
-+   challenge_length
-+       The length in bytes of the client's challenge to the server to
-+       authenticate itself. This value must be 32.
-+
-+   cipher_specs
-+       This is a list of all CipherSpecs the client is willing and able
-+       to use. There must be at least one CipherSpec acceptable to the
-+       server.
-+
-+   session_id
-+       If this field's length is not zero, it will contain the
-+       identification for a session that the client wishes to resume.
-+
-+   challenge
-+       The client challenge to the server for the server to identify
-+       itself is a (nearly) arbitrary length random. The TLS server will
-+       right justify the challenge data to become the ClientHello.random
-+       data (padded with leading zeroes, if necessary), as specified in
-+       this protocol specification. If the length of the challenge is
-+       greater than 32 bytes, only the last 32 bytes are used. It is
-+       legitimate (but not necessary) for a V3 server to reject a V2
-+       ClientHello that has fewer than 16 bytes of challenge data.
-+
-+ Note: Requests to resume a TLS session should use a TLS client hello.
-+
-+E.2. Avoiding man-in-the-middle version rollback
-+
-+   When TLS clients fall back to Version 2.0 compatibility mode, they
-+   should use special PKCS #1 block formatting. This is done so that TLS
-+   servers will reject Version 2.0 sessions with TLS-capable clients.
-+
-+   When TLS clients are in Version 2.0 compatibility mode, they set the
-+   right-hand (least-significant) 8 random bytes of the PKCS padding
-+   (not including the terminal null of the padding) for the RSA
-+   encryption of the ENCRYPTED-KEY-DATA field of the CLIENT-MASTER-KEY
-+   to 0x03 (the other padding bytes are random). After decrypting the
-+   ENCRYPTED-KEY-DATA field, servers that support TLS should issue an
-+   error if these eight padding bytes are 0x03. Version 2.0 servers
-+   receiving blocks padded in this manner will proceed normally.
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 68]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+F. Security analysis
-+
-+   The TLS protocol is designed to establish a secure connection between
-+   a client and a server communicating over an insecure channel. This
-+   document makes several traditional assumptions, including that
-+   attackers have substantial computational resources and cannot obtain
-+   secret information from sources outside the protocol. Attackers are
-+   assumed to have the ability to capture, modify, delete, replay, and
-+   otherwise tamper with messages sent over the communication channel.
-+   This appendix outlines how TLS has been designed to resist a variety
-+   of attacks.
-+
-+F.1. Handshake protocol
-+
-+   The handshake protocol is responsible for selecting a CipherSpec and
-+   generating a Master Secret, which together comprise the primary
-+   cryptographic parameters associated with a secure session. The
-+   handshake protocol can also optionally authenticate parties who have
-+   certificates signed by a trusted certificate authority.
-+
-+F.1.1. Authentication and key exchange
-+
-+   TLS supports three authentication modes: authentication of both
-+   parties, server authentication with an unauthenticated client, and
-+   total anonymity. Whenever the server is authenticated, the channel is
-+   secure against man-in-the-middle attacks, but completely anonymous
-+   sessions are inherently vulnerable to such attacks.  Anonymous
-+   servers cannot authenticate clients. If the server is authenticated,
-+   its certificate message must provide a valid certificate chain
-+   leading to an acceptable certificate authority.  Similarly,
-+   authenticated clients must supply an acceptable certificate to the
-+   server. Each party is responsible for verifying that the other's
-+   certificate is valid and has not expired or been revoked.
-+
-+   The general goal of the key exchange process is to create a
-+   pre_master_secret known to the communicating parties and not to
-+   attackers. The pre_master_secret will be used to generate the
-+   master_secret (see Section 8.1). The master_secret is required to
-+   generate the certificate verify and finished messages, encryption
-+   keys, and MAC secrets (see Sections 7.4.8, 7.4.9 and 6.3). By sending
-+   a correct finished message, parties thus prove that they know the
-+   correct pre_master_secret.
-+
-+F.1.1.1. Anonymous key exchange
-+
-+   Completely anonymous sessions can be established using RSA or
-+   Diffie-Hellman for key exchange. With anonymous RSA, the client
-+   encrypts a pre_master_secret with the server's uncertified public key
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 69]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   extracted from the server key exchange message. The result is sent in
-+   a client key exchange message. Since eavesdroppers do not know the
-+   server's private key, it will be infeasible for them to decode the
-+   pre_master_secret. (Note that no anonymous RSA Cipher Suites are
-+   defined in this document).
-+
-+   With Diffie-Hellman, the server's public parameters are contained in
-+   the server key exchange message and the client's are sent in the
-+   client key exchange message. Eavesdroppers who do not know the
-+   private values should not be able to find the Diffie-Hellman result
-+   (i.e. the pre_master_secret).
-+
-+ Warning: Completely anonymous connections only provide protection
-+          against passive eavesdropping. Unless an independent tamper-
-+          proof channel is used to verify that the finished messages
-+          were not replaced by an attacker, server authentication is
-+          required in environments where active man-in-the-middle
-+          attacks are a concern.
-+
-+F.1.1.2. RSA key exchange and authentication
-+
-+   With RSA, key exchange and server authentication are combined. The
-+   public key may be either contained in the server's certificate or may
-+   be a temporary RSA key sent in a server key exchange message.  When
-+   temporary RSA keys are used, they are signed by the server's RSA or
-+   DSS certificate. The signature includes the current
-+   ClientHello.random, so old signatures and temporary keys cannot be
-+   replayed. Servers may use a single temporary RSA key for multiple
-+   negotiation sessions.
-+
-+ Note: The temporary RSA key option is useful if servers need large
-+       certificates but must comply with government-imposed size limits
-+       on keys used for key exchange.
-+
-+   After verifying the server's certificate, the client encrypts a
-+   pre_master_secret with the server's public key. By successfully
-+   decoding the pre_master_secret and producing a correct finished
-+   message, the server demonstrates that it knows the private key
-+   corresponding to the server certificate.
-+
-+   When RSA is used for key exchange, clients are authenticated using
-+   the certificate verify message (see Section 7.4.8). The client signs
-+   a value derived from the master_secret and all preceding handshake
-+   messages. These handshake messages include the server certificate,
-+   which binds the signature to the server, and ServerHello.random,
-+   which binds the signature to the current handshake process.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 70]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+F.1.1.3. Diffie-Hellman key exchange with authentication
-+
-+   When Diffie-Hellman key exchange is used, the server can either
-+   supply a certificate containing fixed Diffie-Hellman parameters or
-+   can use the server key exchange message to send a set of temporary
-+   Diffie-Hellman parameters signed with a DSS or RSA certificate.
-+   Temporary parameters are hashed with the hello.random values before
-+   signing to ensure that attackers do not replay old parameters. In
-+   either case, the client can verify the certificate or signature to
-+   ensure that the parameters belong to the server.
-+
-+   If the client has a certificate containing fixed Diffie-Hellman
-+   parameters, its certificate contains the information required to
-+   complete the key exchange. Note that in this case the client and
-+   server will generate the same Diffie-Hellman result (i.e.,
-+   pre_master_secret) every time they communicate. To prevent the
-+   pre_master_secret from staying in memory any longer than necessary,
-+   it should be converted into the master_secret as soon as possible.
-+   Client Diffie-Hellman parameters must be compatible with those
-+   supplied by the server for the key exchange to work.
-+
-+   If the client has a standard DSS or RSA certificate or is
-+   unauthenticated, it sends a set of temporary parameters to the server
-+   in the client key exchange message, then optionally uses a
-+   certificate verify message to authenticate itself.
-+
-+F.1.2. Version rollback attacks
-+
-+   Because TLS includes substantial improvements over SSL Version 2.0,
-+   attackers may try to make TLS-capable clients and servers fall back
-+   to Version 2.0. This attack can occur if (and only if) two TLS-
-+   capable parties use an SSL 2.0 handshake.
-+
-+   Although the solution using non-random PKCS #1 block type 2 message
-+   padding is inelegant, it provides a reasonably secure way for Version
-+   3.0 servers to detect the attack. This solution is not secure against
-+   attackers who can brute force the key and substitute a new
-+   ENCRYPTED-KEY-DATA message containing the same key (but with normal
-+   padding) before the application specified wait threshold has expired.
-+   Parties concerned about attacks of this scale should not be using
-+   40-bit encryption keys anyway. Altering the padding of the least-
-+   significant 8 bytes of the PKCS padding does not impact security for
-+   the size of the signed hashes and RSA key lengths used in the
-+   protocol, since this is essentially equivalent to increasing the
-+   input block size by 8 bytes.
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 71]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+F.1.3. Detecting attacks against the handshake protocol
-+
-+   An attacker might try to influence the handshake exchange to make the
-+   parties select different encryption algorithms than they would
-+   normally choose. Because many implementations will support 40-bit
-+   exportable encryption and some may even support null encryption or
-+   MAC algorithms, this attack is of particular concern.
-+
-+   For this attack, an attacker must actively change one or more
-+   handshake messages. If this occurs, the client and server will
-+   compute different values for the handshake message hashes. As a
-+   result, the parties will not accept each others' finished messages.
-+   Without the master_secret, the attacker cannot repair the finished
-+   messages, so the attack will be discovered.
-+
-+F.1.4. Resuming sessions
-+
-+   When a connection is established by resuming a session, new
-+   ClientHello.random and ServerHello.random values are hashed with the
-+   session's master_secret. Provided that the master_secret has not been
-+   compromised and that the secure hash operations used to produce the
-+   encryption keys and MAC secrets are secure, the connection should be
-+   secure and effectively independent from previous connections.
-+   Attackers cannot use known encryption keys or MAC secrets to
-+   compromise the master_secret without breaking the secure hash
-+   operations (which use both SHA and MD5).
-+
-+   Sessions cannot be resumed unless both the client and server agree.
-+   If either party suspects that the session may have been compromised,
-+   or that certificates may have expired or been revoked, it should
-+   force a full handshake. An upper limit of 24 hours is suggested for
-+   session ID lifetimes, since an attacker who obtains a master_secret
-+   may be able to impersonate the compromised party until the
-+   corresponding session ID is retired. Applications that may be run in
-+   relatively insecure environments should not write session IDs to
-+   stable storage.
-+
-+F.1.5. MD5 and SHA
-+
-+   TLS uses hash functions very conservatively. Where possible, both MD5
-+   and SHA are used in tandem to ensure that non-catastrophic flaws in
-+   one algorithm will not break the overall protocol.
-+
-+F.2. Protecting application data
-+
-+   The master_secret is hashed with the ClientHello.random and
-+   ServerHello.random to produce unique data encryption keys and MAC
-+   secrets for each connection.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 72]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Outgoing data is protected with a MAC before transmission. To prevent
-+   message replay or modification attacks, the MAC is computed from the
-+   MAC secret, the sequence number, the message length, the message
-+   contents, and two fixed character strings. The message type field is
-+   necessary to ensure that messages intended for one TLS Record Layer
-+   client are not redirected to another. The sequence number ensures
-+   that attempts to delete or reorder messages will be detected. Since
-+   sequence numbers are 64-bits long, they should never overflow.
-+   Messages from one party cannot be inserted into the other's output,
-+   since they use independent MAC secrets. Similarly, the server-write
-+   and client-write keys are independent so stream cipher keys are used
-+   only once.
-+
-+   If an attacker does break an encryption key, all messages encrypted
-+   with it can be read. Similarly, compromise of a MAC key can make
-+   message modification attacks possible. Because MACs are also
-+   encrypted, message-alteration attacks generally require breaking the
-+   encryption algorithm as well as the MAC.
-+
-+ Note: MAC secrets may be larger than encryption keys, so messages can
-+       remain tamper resistant even if encryption keys are broken.
-+
-+F.3. Final notes
-+
-+   For TLS to be able to provide a secure connection, both the client
-+   and server systems, keys, and applications must be secure. In
-+   addition, the implementation must be free of security errors.
-+
-+   The system is only as strong as the weakest key exchange and
-+   authentication algorithm supported, and only trustworthy
-+   cryptographic functions should be used. Short public keys, 40-bit
-+   bulk encryption keys, and anonymous servers should be used with great
-+   caution. Implementations and users must be careful when deciding
-+   which certificates and certificate authorities are acceptable; a
-+   dishonest certificate authority can do tremendous damage.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 73]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+G. Patent Statement
-+
-+   Some of the cryptographic algorithms proposed for use in this
-+   protocol have patent claims on them. In addition Netscape
-+   Communications Corporation has a patent claim on the Secure Sockets
-+   Layer (SSL) work that this standard is based on. The Internet
-+   Standards Process as defined in RFC 2026 requests that a statement be
-+   obtained from a Patent holder indicating that a license will be made
-+   available to applicants under reasonable terms and conditions.
-+
-+   The Massachusetts Institute of Technology has granted RSA Data
-+   Security, Inc., exclusive sub-licensing rights to the following
-+   patent issued in the United States:
-+
-+       Cryptographic Communications System and Method ("RSA"), No.
-+       4,405,829
-+
-+   Netscape Communications Corporation has been issued the following
-+   patent in the United States:
-+
-+       Secure Socket Layer Application Program Apparatus And Method
-+       ("SSL"), No. 5,657,390
-+
-+   Netscape Communications has issued the following statement:
-+
-+       Intellectual Property Rights
-+
-+       Secure Sockets Layer
-+
-+       The United States Patent and Trademark Office ("the PTO")
-+       recently issued U.S. Patent No. 5,657,390 ("the SSL Patent")  to
-+       Netscape for inventions described as Secure Sockets Layers
-+       ("SSL"). The IETF is currently considering adopting SSL as a
-+       transport protocol with security features.  Netscape encourages
-+       the royalty-free adoption and use of the SSL protocol upon the
-+       following terms and conditions:
-+
-+         * If you already have a valid SSL Ref license today which
-+           includes source code from Netscape, an additional patent
-+           license under the SSL patent is not required.
-+
-+         * If you don't have an SSL Ref license, you may have a royalty
-+           free license to build implementations covered by the SSL
-+           Patent Claims or the IETF TLS specification provided that you
-+           do not to assert any patent rights against Netscape or other
-+           companies for the implementation of SSL or the IETF TLS
-+           recommendation.
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 74]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+       What are "Patent Claims":
-+
-+       Patent claims are claims in an issued foreign or domestic patent
-+       that:
-+
-+        1) must be infringed in order to implement methods or build
-+           products according to the IETF TLS specification;  or
-+
-+        2) patent claims which require the elements of the SSL patent
-+           claims and/or their equivalents to be infringed.
-+
-+   The Internet Society, Internet Architecture Board, Internet
-+   Engineering Steering Group and the Corporation for National Research
-+   Initiatives take no position on the validity or scope of the patents
-+   and patent applications, nor on the appropriateness of the terms of
-+   the assurance. The Internet Society and other groups mentioned above
-+   have not made any determination as to any other intellectual property
-+   rights which may apply to the practice of this standard.  Any further
-+   consideration of these matters is the user's own responsibility.
-+
-+Security Considerations
-+
-+   Security issues are discussed throughout this memo.
-+
-+References
-+
-+   [3DES]   W. Tuchman, "Hellman Presents No Shortcut Solutions To DES,"
-+            IEEE Spectrum, v. 16, n. 7, July 1979, pp40-41.
-+
-+   [BLEI]   Bleichenbacher D., "Chosen Ciphertext Attacks against
-+            Protocols Based on RSA Encryption Standard PKCS #1" in
-+            Advances in Cryptology -- CRYPTO'98, LNCS vol. 1462, pages:
-+            1--12, 1998.
-+
-+   [DES]    ANSI X3.106, "American National Standard for Information
-+            Systems-Data Link Encryption," American National Standards
-+            Institute, 1983.
-+
-+   [DH1]    W. Diffie and M. E. Hellman, "New Directions in
-+            Cryptography," IEEE Transactions on Information Theory, V.
-+            IT-22, n. 6, Jun 1977, pp. 74-84.
-+
-+   [DSS]    NIST FIPS PUB 186, "Digital Signature Standard," National
-+            Institute of Standards and Technology, U.S. Department of
-+            Commerce, May 18, 1994.
-+
-+   [FTP]    Postel J., and J. Reynolds, "File Transfer Protocol", STD 9,
-+            RFC 959, October 1985.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 75]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   [HTTP]   Berners-Lee, T., Fielding, R., and H. Frystyk, "Hypertext
-+            Transfer Protocol -- HTTP/1.0", RFC 1945, May 1996.
-+
-+   [HMAC]   Krawczyk, H., Bellare, M., and R. Canetti, "HMAC:  Keyed-
-+            Hashing for Message Authentication," RFC 2104, February
-+            1997.
-+
-+   [IDEA]   X. Lai, "On the Design and Security of Block Ciphers," ETH
-+            Series in Information Processing, v. 1, Konstanz: Hartung-
-+            Gorre Verlag, 1992.
-+
-+   [MD2]    Kaliski, B., "The MD2 Message Digest Algorithm", RFC 1319,
-+            April 1992.
-+
-+   [MD5]    Rivest, R., "The MD5 Message Digest Algorithm", RFC 1321,
-+            April 1992.
-+
-+   [PKCS1]  RSA Laboratories, "PKCS #1: RSA Encryption Standard,"
-+            version 1.5, November 1993.
-+
-+   [PKCS6]  RSA Laboratories, "PKCS #6: RSA Extended Certificate Syntax
-+            Standard," version 1.5, November 1993.
-+
-+   [PKCS7]  RSA Laboratories, "PKCS #7: RSA Cryptographic Message Syntax
-+            Standard," version 1.5, November 1993.
-+
-+   [PKIX]   Housley, R., Ford, W., Polk, W. and D. Solo, "Internet
-+            Public Key Infrastructure: Part I: X.509 Certificate and CRL
-+            Profile", RFC 2459, January 1999.
-+
-+   [RC2]    Rivest, R., "A Description of the RC2(r) Encryption
-+            Algorithm", RFC 2268, January 1998.
-+
-+   [RC4]    Thayer, R. and K. Kaukonen, A Stream Cipher Encryption
-+            Algorithm, Work in Progress.
-+
-+   [RSA]    R. Rivest, A. Shamir, and L. M. Adleman, "A Method for
-+            Obtaining Digital Signatures and Public-Key Cryptosystems,"
-+            Communications of the ACM, v. 21, n. 2, Feb 1978, pp. 120-
-+            126.
-+
-+   [RSADSI] Contact RSA Data Security, Inc., Tel: 415-595-8782
-+
-+   [SCH]    B. Schneier. Applied Cryptography: Protocols, Algorithms,
-+            and Source Code in C, Published by John Wiley & Sons, Inc.
-+            1994.
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 76]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   [SHA]    NIST FIPS PUB 180-1, "Secure Hash Standard," National
-+            Institute of Standards and Technology, U.S. Department of
-+            Commerce, Work in Progress, May 31, 1994.
-+
-+   [SSL2]   Hickman, Kipp, "The SSL Protocol", Netscape Communications
-+            Corp., Feb 9, 1995.
-+
-+   [SSL3]   A. Frier, P. Karlton, and P. Kocher, "The SSL 3.0 Protocol",
-+            Netscape Communications Corp., Nov 18, 1996.
-+
-+   [TCP]    Postel, J., "Transmission Control Protocol," STD 7, RFC 793,
-+            September 1981.
-+
-+   [TEL]    Postel J., and J. Reynolds, "Telnet Protocol
-+            Specifications", STD 8, RFC 854, May 1993.
-+
-+   [TEL]    Postel J., and J. Reynolds, "Telnet Option Specifications",
-+            STD 8, RFC 855, May 1993.
-+
-+   [X509]   CCITT. Recommendation X.509: "The Directory - Authentication
-+            Framework". 1988.
-+
-+   [XDR]    R. Srinivansan, Sun Microsystems, RFC-1832: XDR: External
-+            Data Representation Standard, August 1995.
-+
-+Credits
-+
-+   Win Treese
-+   Open Market
-+
-+   EMail: treese@openmarket.com
-+
-+
-+   Editors
-+
-+   Christopher Allen                  Tim Dierks
-+   Certicom                           Certicom
-+
-+   EMail: callen@certicom.com         EMail: tdierks@certicom.com
-+
-+
-+   Authors' Addresses
-+
-+   Tim Dierks                         Philip L. Karlton
-+   Certicom                           Netscape Communications
-+
-+   EMail: tdierks@certicom.com
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 77]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Alan O. Freier                     Paul C. Kocher
-+   Netscape Communications            Independent Consultant
-+
-+   EMail: freier@netscape.com         EMail: pck@netcom.com
-+
-+
-+   Other contributors
-+
-+   Martin Abadi                       Robert Relyea
-+   Digital Equipment Corporation      Netscape Communications
-+
-+   EMail: ma@pa.dec.com               EMail: relyea@netscape.com
-+
-+   Ran Canetti                        Jim Roskind
-+   IBM Watson Research Center         Netscape Communications
-+
-+   EMail: canetti@watson.ibm.com      EMail: jar@netscape.com
-+
-+
-+   Taher Elgamal                      Micheal J. Sabin, Ph. D.
-+   Securify                           Consulting Engineer
-+
-+   EMail: elgamal@securify.com        EMail: msabin@netcom.com
-+
-+
-+   Anil R. Gangolli                   Dan Simon
-+   Structured Arts Computing Corp.    Microsoft
-+
-+   EMail: gangolli@structuredarts.com EMail:  dansimon@microsoft.com
-+
-+
-+   Kipp E.B. Hickman                  Tom Weinstein
-+   Netscape Communications            Netscape Communications
-+
-+   EMail: kipp@netscape.com           EMail: tomw@netscape.com
-+
-+
-+   Hugo Krawczyk
-+   IBM Watson Research Center
-+
-+   EMail: hugo@watson.ibm.com
-+
-+Comments
-+
-+   The discussion list for the IETF TLS working group is located at the
-+   e-mail address <ietf-tls@lists.consensus.com>. Information on the
-+   group and information on how to subscribe to the list is at
-+   <http://lists.consensus.com/>.
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 78]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+   Archives of the list can be found at:
-+       <http://www.imc.org/ietf-tls/mail-archive/>
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 79]
-+\f
-+RFC 2246              The TLS Protocol Version 1.0          January 1999
-+
-+
-+Full Copyright Statement
-+
-+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
-+
-+   This document and translations of it may be copied and furnished to
-+   others, and derivative works that comment on or otherwise explain it
-+   or assist in its implementation may be prepared, copied, published
-+   and distributed, in whole or in part, without restriction of any
-+   kind, provided that the above copyright notice and this paragraph are
-+   included on all such copies and derivative works.  However, this
-+   document itself may not be modified in any way, such as by removing
-+   the copyright notice or references to the Internet Society or other
-+   Internet organizations, except as needed for the purpose of
-+   developing Internet standards in which case the procedures for
-+   copyrights defined in the Internet Standards process must be
-+   followed, or as required to translate it into languages other than
-+   English.
-+
-+   The limited permissions granted above are perpetual and will not be
-+   revoked by the Internet Society or its successors or assigns.
-+
-+   This document and the information contained herein is provided on an
-+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Dierks & Allen              Standards Track                    [Page 80]
-+\f
-diff -Nur snapshot-20010228-orig/html/ssl/rfc2487.txt snapshot-20010228/html/ssl/rfc2487.txt
---- snapshot-20010228-orig/html/ssl/rfc2487.txt        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/rfc2487.txt     Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,451 @@
-+
-+
-+
-+
-+
-+
-+Network Working Group                                     P. Hoffman
-+Request for Comments: 2487                  Internet Mail Consortium
-+Category: Standards Track                               January 1999
-+
-+
-+            SMTP Service Extension for Secure SMTP over TLS
-+
-+Status of this Memo
-+
-+   This document specifies an Internet standards track protocol for the
-+   Internet community, and requests discussion and suggestions for
-+   improvements.  Please refer to the current edition of the "Internet
-+   Official Protocol Standards" (STD 1) for the standardization state
-+   and status of this protocol.  Distribution of this memo is unlimited.
-+
-+Copyright Notice
-+
-+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
-+
-+1. Abstract
-+
-+   This document describes an extension to the SMTP service that allows
-+   an SMTP server and client to use transport-layer security to provide
-+   private, authenticated communication over the Internet. This gives
-+   SMTP agents the ability to protect some or all of their
-+   communications from eavesdroppers and attackers.
-+
-+2. Introduction
-+
-+   SMTP [RFC-821] servers and clients normally communicate in the clear
-+   over the Internet. In many cases, this communication goes through one
-+   or more router that is not controlled or trusted by either entity.
-+   Such an untrusted router might allow a third party to monitor or
-+   alter the communications between the server and client.
-+
-+   Further, there is often a desire for two SMTP agents to be able to
-+   authenticate each others' identities. For example, a secure SMTP
-+   server might only allow communications from other SMTP agents it
-+   knows, or it might act differently for messages received from an
-+   agent it knows than from one it doesn't know.
-+
-+   TLS [TLS], more commonly known as SSL, is a popular mechanism for
-+   enhancing TCP communications with privacy and authentication. TLS is
-+   in wide use with the HTTP protocol, and is also being used for adding
-+   security to many other common protocols that run over TCP.
-+
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 1]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+2.1 Terminology
-+
-+   The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
-+   "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
-+   document are to be interpreted as described in [RFC-2119].
-+
-+3. STARTTLS Extension
-+
-+   The STARTTLS extension to SMTP is laid out as follows:
-+
-+   (1) the name of the SMTP service defined here is STARTTLS;
-+
-+   (2) the EHLO keyword value associated with the extension is STARTTLS;
-+
-+   (3) the STARTTLS keyword has no parameters;
-+
-+   (4) a new SMTP verb, "STARTTLS", is defined;
-+
-+   (5) no additional parameters are added to any SMTP command.
-+
-+4. The STARTTLS Keyword
-+
-+   The STARTTLS keyword is used to tell the SMTP client that the SMTP
-+   server allows use of TLS. It takes no parameters.
-+
-+5. The STARTTLS Command
-+
-+   The format for the STARTTLS command is:
-+
-+   STARTTLS
-+
-+   with no parameters.
-+
-+   After the client gives the STARTTLS command, the server responds with
-+   one of the following reply codes:
-+
-+   220 Ready to start TLS
-+   501 Syntax error (no parameters allowed)
-+   454 TLS not available due to temporary reason
-+
-+   A publicly-referenced SMTP server MUST NOT require use of the
-+   STARTTLS extension in order to deliver mail locally. This rule
-+   prevents the STARTTLS extension from damaging the interoperability of
-+   the Internet's SMTP infrastructure. A publicly-referenced SMTP server
-+   is an SMTP server which runs on port 25 of an Internet host listed in
-+   the MX record (or A record if an MX record is not present) for the
-+   domain name on the right hand side of an Internet mail address.
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 2]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+   Any SMTP server may refuse to accept messages for relay based on
-+   authentication supplied during the TLS negotiation. An SMTP server
-+   that is not publicly referenced may refuse to accept any messages for
-+   relay or local delivery based on authentication supplied during the
-+   TLS negotiation.
-+
-+   A SMTP server that is not publicly referenced may choose to require
-+   that the client perform a TLS negotiation before accepting any
-+   commands. In this case, the server SHOULD return the reply code:
-+
-+   530 Must issue a STARTTLS command first
-+
-+   to every command other than NOOP, EHLO, STARTTLS, or QUIT. If the
-+   client and server are using the ENHANCEDSTATUSCODES ESMTP extension
-+   [RFC-2034], the status code to be returned SHOULD be 5.7.0.
-+
-+   After receiving a 220 response to a STARTTLS command, the client
-+   SHOULD start the TLS negotiation before giving any other SMTP
-+   commands.
-+
-+   If the SMTP client is using pipelining as defined in RFC 1854, the
-+   STARTTLS command must be the last command in a group.
-+
-+5.1 Processing After the STARTTLS Command
-+
-+   After the TLS handshake has been completed, both parties MUST
-+   immediately decide whether or not to continue based on the
-+   authentication and privacy achieved. The SMTP client and server may
-+   decide to move ahead even if the TLS negotiation ended with no
-+   authentication and/or no privacy because most SMTP services are
-+   performed with no authentication and no privacy, but some SMTP
-+   clients or servers may want to continue only if a particular level of
-+   authentication and/or privacy was achieved.
-+
-+   If the SMTP client decides that the level of authentication or
-+   privacy is not high enough for it to continue, it SHOULD issue an
-+   SMTP QUIT command immediately after the TLS negotiation is complete.
-+   If the SMTP server decides that the level of authentication or
-+   privacy is not high enough for it to continue, it SHOULD reply to
-+   every SMTP command from the client (other than a QUIT command) with
-+   the 554 reply code (with a possible text string such as "Command
-+   refused due to lack of security").
-+
-+   The decision of whether or not to believe the authenticity of the
-+   other party in a TLS negotiation is a local matter. However, some
-+   general rules for the decisions are:
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 3]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+    - A SMTP client would probably only want to authenticate an SMTP
-+      server whose server certificate has a domain name that is the
-+      domain name that the client thought it was connecting to.
-+    - A publicly-referenced  SMTP server would probably want to accept
-+      any certificate from an SMTP client, and would possibly want to
-+      put distinguishing information about the certificate in the
-+      Received header of messages that were relayed or submitted from
-+      the client.
-+
-+5.2 Result of the STARTTLS Command
-+
-+   Upon completion of the TLS handshake, the SMTP protocol is reset to
-+   the initial state (the state in SMTP after a server issues a 220
-+   service ready greeting). The server MUST discard any knowledge
-+   obtained from the client, such as the argument to the EHLO command,
-+   which was not obtained from the TLS negotiation itself. The client
-+   MUST discard any knowledge obtained from the server, such as the list
-+   of SMTP service extensions, which was not obtained from the TLS
-+   negotiation itself. The client SHOULD send an EHLO command as the
-+   first command after a successful TLS negotiation.
-+
-+   The list of SMTP service extensions returned in response to an EHLO
-+   command received after the TLS handshake MAY be different than the
-+   list returned before the TLS handshake. For example, an SMTP server
-+   might not want to advertise support for a particular SASL mechanism
-+   [SASL] unless a client has sent an appropriate client certificate
-+   during a TLS handshake.
-+
-+   Both the client and the server MUST know if there is a TLS session
-+   active.  A client MUST NOT attempt to start a TLS session if a TLS
-+   session is already active. A server MUST NOT return the TLS extension
-+   in response to an EHLO command received after a TLS handshake has
-+   completed.
-+
-+6. Usage Example
-+
-+   The following dialog illustrates how a client and server can start a
-+   TLS session:
-+
-+   S: <waits for connection on TCP port 25>
-+   C: <opens connection>
-+   S: 220 mail.imc.org SMTP service ready
-+   C: EHLO mail.ietf.org
-+   S: 250-mail.imc.org offers a warm hug of welcome
-+   S: 250 STARTTLS
-+   C: STARTTLS
-+   S: 220 Go ahead
-+   C: <starts TLS negotiation>
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 4]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+   C & S: <negotiate a TLS session>
-+   C & S: <check result of negotiation>
-+   C: <continues by sending an SMTP command>
-+   . . .
-+
-+7. Security Considerations
-+
-+   It should be noted that SMTP is not an end-to-end mechanism. Thus, if
-+   an SMTP client/server pair decide to add TLS privacy, they are not
-+   securing the transport from the originating mail user agent to the
-+   recipient.  Further, because delivery of a single piece of mail may
-+   go between more than two SMTP servers, adding TLS privacy to one pair
-+   of servers does not mean that the entire SMTP chain has been made
-+   private. Further, just because an SMTP server can authenticate an
-+   SMTP client, it does not mean that the mail from the SMTP client was
-+   authenticated by the SMTP client when the client received it.
-+
-+   Both the STMP client and server must check the result of the TLS
-+   negotiation to see whether acceptable authentication or privacy was
-+   achieved. Ignoring this step completely invalidates using TLS for
-+   security.  The decision about whether acceptable authentication or
-+   privacy was achieved is made locally, is implementation-dependant,
-+   and is beyond the scope of this document.
-+
-+   The SMTP client and server should note carefully the result of the
-+   TLS negotiation. If the negotiation results in no privacy, or if it
-+   results in privacy using algorithms or key lengths that are deemed
-+   not strong enough, or if the authentication is not good enough for
-+   either party, the client may choose to end the SMTP session with an
-+   immediate QUIT command, or the server may choose to not accept any
-+   more SMTP commands.
-+
-+   A server announcing in an EHLO response that it uses a particular TLS
-+   protocol should not pose any security issues, since any use of TLS
-+   will be at least as secure as no use of TLS.
-+
-+   A man-in-the-middle attack can be launched by deleting the "250
-+   STARTTLS" response from the server. This would cause the client not
-+   to try to start a TLS session. An SMTP client can protect against
-+   this attack by recording the fact that a particular SMTP server
-+   offers TLS during one session and generating an alarm if it does not
-+   appear in the EHLO response for a later session. The lack of TLS
-+   during a session SHOULD NOT result in the bouncing of email, although
-+   it could result in delayed processing.
-+
-+
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 5]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+   Before the TLS handshake has begun, any protocol interactions are
-+   performed in the clear and may be modified by an active attacker. For
-+   this reason, clients and servers MUST discard any knowledge obtained
-+   prior to the start of the TLS handshake upon completion of the TLS
-+   handshake.
-+
-+   The STARTTLS extension is not suitable for authenticating the author
-+   of an email message unless every hop in the delivery chain, including
-+   the submission to the first SMTP server, is authenticated. Another
-+   proposal [SMTP-AUTH] can be used to authenticate delivery and MIME
-+   security multiparts [MIME-SEC] can be used to authenticate the author
-+   of an email message. In addition, the [SMTP-AUTH] proposal offers
-+   simpler and more flexible options to authenticate an SMTP client and
-+   the SASL EXTERNAL mechanism [SASL] MAY be used in conjunction with
-+   the STARTTLS command to provide an authorization identity.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 6]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+A. References
-+
-+   [RFC-821]   Postel, J., "Simple Mail Transfer Protocol", RFC 821,
-+               August 1982.
-+
-+   [RFC-1869]  Klensin, J., Freed, N, Rose, M, Stefferud, E. and D.
-+               Crocker, "SMTP Service Extensions", STD 10, RFC 1869,
-+               November 1995.
-+
-+   [RFC-2034]  Freed, N., "SMTP Service Extension for Returning Enhanced
-+               Error Codes", RFC 2034, October 1996.
-+
-+   [RFC-2119]  Bradner, S., "Key words for use in RFCs to Indicate
-+               Requirement Levels", BCP 14, RFC 2119, March 1997.
-+
-+   [SASL]      Myers, J., "Simple Authentication and Security Layer
-+               (SASL)", RFC 2222, October 1997.
-+
-+   [SMTP-AUTH] "SMTP Service Extension for Authentication", Work in
-+               Progress.
-+
-+   [TLS]       Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
-+               RFC 2246, January 1999.
-+
-+B. Author's Address
-+
-+   Paul Hoffman
-+   Internet Mail Consortium
-+   127 Segre Place
-+   Santa Cruz, CA  95060
-+
-+   Phone: (831) 426-9827
-+   EMail: phoffman@imc.org
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 7]
-+\f
-+RFC 2487                 SMTP Service Extension             January 1999
-+
-+
-+C.  Full Copyright Statement
-+
-+   Copyright (C) The Internet Society (1999).  All Rights Reserved.
-+
-+   This document and translations of it may be copied and furnished to
-+   others, and derivative works that comment on or otherwise explain it
-+   or assist in its implementation may be prepared, copied, published
-+   and distributed, in whole or in part, without restriction of any
-+   kind, provided that the above copyright notice and this paragraph are
-+   included on all such copies and derivative works.  However, this
-+   document itself may not be modified in any way, such as by removing
-+   the copyright notice or references to the Internet Society or other
-+   Internet organizations, except as needed for the purpose of
-+   developing Internet standards in which case the procedures for
-+   copyrights defined in the Internet Standards process must be
-+   followed, or as required to translate it into languages other than
-+   English.
-+
-+   The limited permissions granted above are perpetual and will not be
-+   revoked by the Internet Society or its successors or assigns.
-+
-+   This document and the information contained herein is provided on an
-+   "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
-+   TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
-+   BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
-+   HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
-+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+
-+Hoffman                     Standards Track                     [Page 8]
-+\f
-diff -Nur snapshot-20010228-orig/html/ssl/security.html snapshot-20010228/html/ssl/security.html
---- snapshot-20010228-orig/html/ssl/security.html      Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/security.html   Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,78 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Security Considerations</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Security Considerations</h1>
-+
-+The following sections cover some (possible) security issues with
-+regard to Postfix/TLS. 
-+
-+<h2>Server/Client private key file</h2>
-+
-+Postfix/TLS uses authentication for the server side (mandatory) and
-+the client side (optional). In order to authenticate itself, the
-+according process (smptd/smtp) must be able to access the private
-+key, which must however be kept secret. As these processes are
-+started from 'master' without the possibility of user interaction, it is not
-+possible to supply a password, so that the private key can not be
-+encrypted. 
-+
-+<p>The only protection can therefore come from filesystem access
-+rights, which should be set to 'owner root' and 'readable for owner
-+only':</p>
-+
-+<pre>
-+-rw-------   1 root       sys            887 Apr 29  1999 /etc/postfix/key.pem
-+</pre>
-+
-+<p>This protection is only as good as your host is protected
-+against root exploits.</p>
-+
-+<p>You also should be aware, that people having physical access to
-+your system might be able to 'steal' the private key if they can
-+boot into single user mode without password protection or can move
-+the disk to another computer, on which they have root rights. (Yes,
-+I know there are such things as encrypted filesystems, but they are
-+not in wide spread use today.)</p>
-+
-+<h2>Disk based session cache</h2>
-+
-+If you run disk based session caching (the default) people being
-+able to get hold of the files might be able to figure out security
-+relevant communication parameters. The security situation is
-+however not more dramatic than the private key issue explained
-+above, so I don't consider any additional danger coming from saving
-+session information to stable storage. 
-+
-+<p>As breaking the code with public key cryptography is just a
-+matter of time (even though it might be a very long time), sessions
-+should not be used for an infinite duration. The default value for
-+Postfix/TLS is 1h; RFC2246 (TLSv1) recommends to not use sessions
-+for more than 24h.</p>
-+
-+<h2>DNS issues</h2>
-+
-+One weak point in authentication is the use of the DNS to find out
-+the MX information. Since we do (E)SMTP, we must use the MX
-+information! 
-+
-+<p>As we have to authenticate the server retrieved via MX, somebody
-+able to spoof a wrong MX entry might be able to receive the email,
-+if his host can present a certificate issued by an acceptable CA.
-+The last part is not too difficult if 'standard' CAs like Verisign,
-+Thawte,... are included.</p>
-+
-+<p>The only way to protect against this problem is that for those
-+recipients, for which we want to <strong>enforce</strong>
-+encryption and authentication, the MX lookup must be overridden
-+with an appropriate entry in the /etc/postfix/transport table:</p>
-+
-+<pre>
-+important.dom.ain smtp:[mailserver.important.dom.ain]
-+</pre>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/setup.html snapshot-20010228/html/ssl/setup.html
---- snapshot-20010228-orig/html/ssl/setup.html Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/setup.html      Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,219 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Setting up the certificates</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Setting up the certificates</h1>
-+
-+This section explains what kind of certificates are needed to run
-+postfix with TLS. The certificates (and maybe keys) can be obtained
-+from a third party, that might be a commercial certification
-+authority or your internet service provider. On the long run you do
-+need certificates that are accepted by other Internet parties, so
-+you have to agree with them on certification authorities, of which
-+type they might be. 
-+
-+<h2>Server certificate</h2>
-+
-+To run SMTP with TLS in server mode, your server <strong>
-+must</strong> have a pair of <em>private key</em> and <em>public
-+key</em>. 
-+
-+<p>As the public key must be distributed to the client somehow, it
-+is sent from the server to the client during the startup
-+negotiation. The client however cannot know from just the
-+negotiation, that the public key really belongs to the server and
-+is not faked. Therefore a third component is necessary, a <em>
-+certificate</em> from a certificate authority (CA), that is sent
-+combined with the public key. This <em>server certificate</em>
-+contains the <code>name.of.your.host</code>. The client will then
-+check the <em>signature</em> of the CA on the public key to decide,
-+whether the certificate (and public key) are authentic.</p>
-+
-+<p>So for the server we do need:</p>
-+
-+<ul>
-+<li>1 <em>server private key</em></li>
-+
-+<li>1 server public key signed by a CA, a <em>server
-+certificate</em>, certifying that the public key belongs to <code>
-+name.of.your.host</code>.</li>
-+
-+<li>1 <em>CA certificate</em> with the public key of the CA</li>
-+</ul>
-+
-+For this list I definitely want point out the number of components
-+used to be <strong>1</strong>, because you must have <strong>
-+1</strong>, you cannot have less, you cannot have more! 
-+
-+<h3>Server certificate policy</h3>
-+
-+At this point you have to decide about policy. The client which is
-+going to connect to your host will check the name in the <em>server
-+certificate</em>, the CN (Common Name), against the FQDN (Fully
-+Qualified Domain Name) of your server. If both agree, your server's
-+identity is proved. 
-+
-+<p>To see, whether the certificate itself is authentic, the client
-+itself <em>must have</em> the <em>CA certificate</em>. So, if you
-+want to make it easily accessible to other, unknown parties, you
-+should have your server certificate issued by a well known and well
-+trusted CA. Remember, that your server can only have one server
-+certificate at a time.</p>
-+
-+<p>There are commercial providers (Thawte, Verisign, just to name
-+some), the CA certificats of which are well distributed. Not
-+knowing of other countries, at least in Germany the CERT of the
-+Research Network (DFN) has started a program for universities [<a
-+href="references.html#dfncert">DFNCERT</a>].</p>
-+
-+<p>If you do not care about that for know (you can change that
-+later), you can just become your own CA and distribute your CA cert
-+to those parties who should know it, and you are set. It is not
-+difficult to do.<br>
-+<a href="myownca.html">Lutz's very short course on being your own
-+CA</a>.</p>
-+
-+<h3>Using the certificates with Postfix/TLS</h3>
-+
-+To make the key and certificates available to Postfix/TLS, they
-+must be in "PEM" format. Then you have to tell postfix in main.cf
-+where to find them: 
-+
-+<ul>
-+<li>The private key: 
-+
-+<pre>
-+smtp_tls_key_file = /etc/postfix/key.pem
-+</pre>
-+
-+As the public key is public including the certificate (everybody
-+can get a copy), everybody who has a copy of the private key can
-+fake your identity. It is not too easy, as he must be able to
-+redirect or intercept the IP packages sent to your server, but I
-+have seen a lot of things happening. So protect this key with: 
-+
-+<pre>
-+chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
-+</pre>
-+
-+One more possibility for protection is a passphrase. This is
-+however a problem, as you have to enter it everytime the server has
-+to be started. This has to drawbacks: firstly you would have to
-+enter it to postfix everytime you restart it, which I find quite
-+impractical for an unattended server which might restart
-+automatically after a power outage. Secondly the smtpd processes
-+are independently started from master, so that master would have to
-+pass the passphrase to the clients somehow. Alltogether I think
-+this is impractical and so I don't support by software.</li>
-+
-+<li>The server certificate: This certificate is not secret, as it
-+will be presented to every client anyhow, so you just name it to
-+postfix: 
-+
-+<pre>
-+smtp_tls_cert_file = /etc/postfix/cert.pem
-+</pre>
-+
-+If you like, you can put private key and cert into one file.</li>
-+
-+<li>The CA certificate: To also have the CA certificate available,
-+you put it into a file and name it to Postfix/TLS. We will come
-+back to this file later. 
-+
-+<pre>
-+smtp_tls_CAfile = /etc/postfix/CAcert.pem
-+</pre>
-+</li>
-+</ul>
-+
-+With these certificates you should already have enough to get
-+Postfix/TLS running. 
-+
-+<h3>Postfix/TLS client mode</h3>
-+
-+When connecting to a server offering TLS, postfix can present a
-+client certificate of its own. As realized by now, only one
-+certificate can be managed, so it should be issued on your own
-+hostname. No default is supplied (no certificate is presented),
-+unless you explicitly set the certificate in the configuration. You
-+can use the same certificate as for the server side: 
-+
-+<pre>
-+smtp_tls_key_file = /etc/postfix/key.pem
-+chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
-+</pre>
-+
-+<pre>
-+smtp_tls_cert_file = /etc/postfix/cert.pem
-+</pre>
-+
-+<pre>
-+smtp_tls_CAfile = /etc/postfix/CAcert.pem
-+</pre>
-+
-+<h2>Client certificates</h2>
-+
-+One reason to do all of this work is that I want to do relaying
-+based on client certificates. The clients present a certificate
-+from a CA, that is unique and cannot be faked. 
-+
-+<p>Some clients can have several certificates issued by different
-+CAs. Upon connection the server will pass the client the list of
-+CAs he knows (has the CA certificates) and the client can then pass
-+back a certificate of choice. With Netscape this means, a window is
-+opened and only those client certificates compatible with the
-+server are listed for selection.</p>
-+
-+<p>So if your clients already have certificates from trustable
-+sources, it is not necessary to create a lot of problems. You just
-+have to collect the CA certificates and make them available to
-+Postfix/TLS. If that is not enough, you can still become your own
-+CA to easily create client certificates for your users (which are
-+of course of no use outside your scope).</p>
-+
-+<h3>Listing CA certificates</h3>
-+
-+<p>You have two possibilities to perform this task.</p>
-+
-+<ol>
-+<li>You just add the CA certificates to the <code>
-+smtp[d]_tls_CAfile</code> you already have created, one after the
-+other. This file is probably not very readable, but it has the
-+advantage that it is read at smtpd before switching to chroot jail
-+and hence works in chroot mode.</li>
-+
-+<li>You can add the CA certificates in single files with adequate
-+names to a certificate directory specified in: 
-+
-+<pre>
-+smtpd_tls_CApath = /etc/postfix/certs
-+</pre>
-+
-+Please don't forget to issue a <code>$OPENSSL_HOME/bin/c_rehash
-+/etc/postfix/certs</code> after you have made changes, as the
-+hashes are use to find the right CA certificate. This method should
-+not work in chroot mode.</li>
-+</ol>
-+
-+<h3>Adding client certificates</h3>
-+
-+The client certificates are issued for a DN (Distinguished Name)
-+made up of company, department, name, email... As they may contain
-+blanks, @ signs and colons, it is quite difficult to handle them
-+with standard postfix tools. 
-+
-+<p>A quite practical thing is that every client certificate has a
-+"fingerprint" that is extremely difficult to fake (read this: from
-+my knowledge, it might take years even on fast computers). I have
-+to do some more research about the security of the fingerprint, but
-+at least for relaying it should be secure enough. I will much
-+easier find a host with worse security to send out my SPAM than to
-+fake a client certificate with a matching fingerprint (which I also
-+don't know to from the outside, even from the inside you might
-+protect the fingerprint data with a <code>chmod 400</code>).</p>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/html/ssl/test.html snapshot-20010228/html/ssl/test.html
---- snapshot-20010228-orig/html/ssl/test.html  Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/html/ssl/test.html       Wed Mar 21 13:38:29 2001
-@@ -0,0 +1,178 @@
-+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-+<html>
-+<head>
-+<meta name="generator" content="HTML Tidy, see www.w3.org">
-+<title>Postfix/TLS - Testing</title>
-+</head>
-+<body>
-+<h1>Postfix/TLS - Testing</h1>
-+
-+Testing the package is a little bit difficult, as the communication
-+is encrypted, so that you cannot "imitate" the conversation just by
-+telnetting to the SMTP port. You also cannot capture the packets
-+(well, you can, but if everything is working as advertised, it
-+won't help you :-). 
-+
-+<h2>Included debugging aids</h2>
-+
-+As all of the messages generated by Postfix are sent to the syslog
-+facility, debugging must be done using your normal system logfiles.
-+Postfix/TLS supports the logging levels 0 (very quiet) up to 4 (a
-+dump of the complete conversation, not recommended). 
-+
-+<p>As a first step set <code>smpt[d]_tls_loglevel=2</code> and
-+watch the logfile. Typically you will have problems with the access
-+to the keys or certificates, so you will find error messages
-+here.</p>
-+
-+<p>You can always try to send an email to <tt>
-+postfix_tls-bounce@serv01.aet.tu-cottbus.de</tt> with TLS enabled
-+at your side and watch, what is going to happen :-)</p>
-+
-+<p>While testing the interoperability with ZMailer we learned, that
-+an incorrect certificate type (must be server for the server :-)
-+can lead to connection failures without clear symptoms. It helps to
-+use Netscape 4.5x as a client and carefully study the message boxes
-+and certificate information. I have yet to find out how to identify
-+this problem from postfix to print a suitable warning to the
-+logfile. Hopefully it will be possible without changes in the
-+OpenSSL library.</p>
-+
-+<h2>Platforms</h2>
-+
-+<ul>
-+<li>Development Platform: 
-+
-+<ul>
-+<li>OS: HP-UX 10.20</li>
-+
-+<li>OS: Linux 2.x (SuSE Linux)</li>
-+</ul>
-+</li>
-+
-+<li>Reported Success: 
-+
-+<ul>
-+<li>OS: Solaris 2.5 - Walcir Fontanini
-+&lt;walcir@densis.fee.unicamp.br&gt;</li>
-+</ul>
-+</li>
-+
-+<li>Test Client: 
-+
-+<ul>
-+<li>Software: Netscape 4.5x, Netscape 4.6x, Netscape 4.7x</li>
-+
-+<li>OS: HP-UX 10.20, Linux 2.x, Win95</li>
-+</ul>
-+</li>
-+</ul>
-+
-+Please don't comment on the stability of Netscape, especially not
-+on HP-UX... 
-+
-+<h2>Interoperability</h2>
-+
-+Besides support by generic wrapper solutions, there exist specially
-+crafted extensions for other MTAs: 
-+
-+<ul>
-+<li><strong>Qmail</strong> There is an OpenSource patch available,
-+extending the Qmail [<a href="references.html#qmail">QMAIL</a>] MTA
-+to support RFC2487, written by Frederik Vermeulen [<a href=
-+"references.html#qmailtls">QMAILTLS</a>]. Sending and receiving is
-+working from both sides. 
-+
-+<p>Testing: send mail to <tt>ping@linux.student.kuleuven.ac.be</tt>
-+(will send back complete email including headers).</p>
-+</li>
-+
-+<li><strong>Zmailer</strong> The author/maintainer of ZMailer,
-+Matti Aarnio, has incorporated both server and client side TLS
-+support [<a href="references.html#zmailer">ZMAILER</a>]. 
-+
-+<p>Zmailer -&gt; Postfix works fine,<br>
-+Postfix -&gt; Zmailer does not work, since ESMTP is not recognized
-+(problem reported).</p>
-+
-+<p>Testing: send mail to <tt>autoanswer@mea.tmt.tele.fi</tt> (will
-+send back headers).</p>
-+</li>
-+
-+<li><strong>Sendmail</strong> The commercial verson of sendmail
-+supports client and server TLS, both sides interoperating with
-+Postfix/TLS. As of sendmail-8.11, TLS is also included with the
-+opensource version [<a href=
-+"references.html#sendmail">SENDMAIL</a>]. 
-+
-+<p>Testing: send mail to <tt>bounce@esmtp.org</tt> (will bounce
-+error message including old headers).</p>
-+</li>
-+
-+<li><strong>Postfix</strong> Can send emails to itself :-). 
-+
-+<p>Testing: send mail to <tt>
-+postfix_tls-bounce@serv01.aet.tu-cottbus.de</tt> (will bounce back,
-+includes old headers).</p>
-+</li>
-+</ul>
-+
-+Other reports are welcome. 
-+
-+<h2>Known bugs</h2>
-+
-+This software is just at the beginning, so please be patient. By
-+now I have these points: 
-+
-+<ul>
-+<li>Server side: Under Win95/NT I have some problems with the
-+client certificates. When opening the first connection (and
-+Netscape asks for the password to access the certificate database),
-+the connection hangs. This seems to be caused by Netscape: a dump
-+of the communication shows, that Netscape just does not resume the
-+TLS handshake.<br>
-+<strong>Remark:</strong>I could not reproduce this bug recently
-+after upgrading OpenSSL 0.9.4. I hope it has vanished, but maybe it
-+is just a consequence of playing around with Netscape's security
-+options. More testing required...<br>
-+Workarounds: kill this connection, the next one will work
-+immediately <strong>or</strong> use SSLv2 only (second workaround
-+not recommended). 
-+
-+<p><strong>Should finally be fixed with OpenSSL 0.9.5.</strong></p>
-+</li>
-+
-+<li>Server side: Outlook Express as of Internet Explorer 5 will
-+work with Postfix/TLS, but it will not present any client
-+certificate. So you can encrypt your email transfer but you cannot
-+authenticate (and relay) with client certificates. It only works on
-+port 25 (smtp); on other ports you must use smtpd_tls_wrappermode
-+instead. [<a href="references.html#oe_ssl">Microsoft
-+Knowledgebase</a>]</li>
-+
-+<li>Server side: Outlook Express as of Internet Explorer 4 does not
-+support RFC2487. Use smtpd_tls_wrappermode=yes on a different
-+port(!) instead.</li>
-+
-+<li>Server side: Outlook Express (Mac) seems not to support
-+RFC2487, you must use smtpd_tls_wrappermode on a different port(!)
-+instead.</li>
-+
-+<li>Client side: MS Exchange also in recent versions (5.5) offers
-+STARTTLS even if not configured (from the mailing list [<a href=
-+"references.html#imcorgappstls">IETF-APPS-TLS</a>]). I could not
-+test this without access to such server, so I cannot predict what
-+is going to happen.</li>
-+
-+<li>Client side: TLS connections to a CommunigatePro server fail
-+with a handshake error with older versions of CommunigatePro.
-+Reason is a protocol violation of the CommunigatePro server with
-+respect to SSL-protocol version numbering. The respective part of
-+the protocol is the specification of the client_version in section
-+7.4.7.1. of RFC2246.<br>
-+This problem has been fixed in CommunigatePro 3.3b?? (don't know
-+the exact numbering) around June 09, 2000.</li>
-+</ul>
-+</body>
-+</html>
-+
-diff -Nur snapshot-20010228-orig/man/man8/tlsmgr.8 snapshot-20010228/man/man8/tlsmgr.8
---- snapshot-20010228-orig/man/man8/tlsmgr.8   Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/man/man8/tlsmgr.8        Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,130 @@
-+.TH TLSMGR 8 
-+.ad
-+.fi
-+.SH NAME
-+tlsmgr
-+\-
-+Postfix TLS session cache and PRNG handling manager
-+.SH SYNOPSIS
-+.na
-+.nf
-+\fBtlsmgr\fR [generic Postfix daemon options]
-+.SH DESCRIPTION
-+.ad
-+.fi
-+The tlsmgr process does housekeeping on the session cache database
-+files. It runs through the databases and removes expired entries
-+and entries written by older (incompatible) versions.
-+
-+The tlsmgr is responsible for the PRNG handling. The used internal
-+OpenSSL PRNG has a pool size of 8192 bits (= 1024 bytes). The pool
-+is initially seeded at startup from an external source (EGD or
-+/dev/urandom) and additional seed is obtained later during program
-+run at a configurable period. The exact time of seed query is
-+using random information and is equally distributed in the range of
-+[0-\fBtls_random_reseed_period\fR] with a \fBtls_random_reseed_period\fR
-+having a default of 1 hour.
-+
-+Tlsmgr can be run chrooted and with dropped privileges, as it will
-+connect to the entropy source at startup.
-+
-+The PRNG is additionally seeded internally by the data found in the
-+session cache and timevalues.
-+
-+Tlsmgr reads the old value of the exchange file at startup to keep
-+entropy already collected during previous runs.
-+
-+From the PRNG random pool a cryptographically strong 1024 byte random
-+sequence is written into the PRNG exchange file. The file is updated
-+periodically with the time changing randomly from
-+[0-\fBtls_random_prng_update_period\fR].
-+.SH STANDARDS
-+.na
-+.nf
-+.SH SECURITY
-+.na
-+.nf
-+.ad
-+.fi
-+Tlsmgr is not security-sensitive. It only deals with external data
-+to be fed into the PRNG, the contents is never trusted. The session
-+cache housekeeping will only remove entries if expired and will never
-+touch the contents of the cached data.
-+.SH DIAGNOSTICS
-+.ad
-+.fi
-+Problems and transactions are logged to the syslog daemon.
-+.SH BUGS
-+.ad
-+.fi
-+There is no automatic means to limit the number of entries in the
-+session caches and/or the size of the session cache files.
-+.SH CONFIGURATION PARAMETERS
-+.na
-+.nf
-+.ad
-+.fi
-+The following \fBmain.cf\fR parameters are especially relevant to
-+this program. See the Postfix \fBmain.cf\fR file for syntax details
-+and for default values. Use the \fBpostfix reload\fR command after
-+a configuration change.
-+.SH Session Cache
-+.ad
-+.fi
-+.IP \fBsmtpd_tls_session_cache_database\fR
-+Name of the SDBM file (type sdbm:) containing the SMTP server session
-+cache. If the file does not exist, it is created.
-+.IP \fBsmtpd_tls_session_cache_timeout\fR
-+Expiry time of SMTP server session cache entries in seconds. Entries
-+older than this are removed from the session cache. A cleanup-run is
-+performed periodically every \fBsmtpd_tls_session_cache_timeout\fR
-+seconds. Default is 3600 (= 1 hour).
-+.IP \fBsmtp_tls_session_cache_database\fR
-+Name of the SDBM file (type sdbm:) containing the SMTP client session
-+cache. If the file does not exist, it is created.
-+.IP \fBsmtp_tls_session_cache_timeout\fR
-+Expiry time of SMTP client session cache entries in seconds. Entries
-+older than this are removed from the session cache. A cleanup-run is
-+performed periodically every \fBsmtp_tls_session_cache_timeout\fR
-+seconds. Default is 3600 (= 1 hour).
-+.SH Pseudo Random Number Generator
-+.ad
-+.fi
-+.IP \fBtls_random_source\fR
-+Name of the EGD socket or device or regular file to obtain entropy
-+from. The type of entropy source must be specified by preceding the
-+name with the appropriate type: egd:/path/to/egd_socket,
-+dev:/path/to/devicefile, or /path/to/regular/file.
-+tlsmgr opens \fBtls_random_source\fR and tries to read
-+\fBtls_random_bytes\fR from it.
-+.IP \fBtls_random_bytes\fR
-+Number of bytes to be read from \fBtls_random_source\fR.
-+Default value is 32 bytes. If using EGD, a maximum of 255 bytes is read.
-+.IP \fBtls_random_exchange_name\fR
-+Name of the file written by tlsmgr and read by smtp and smtpd at
-+startup. The length is 1024 bytes. Default value is
-+/etc/postfix/prng_exch.
-+.IP \fBtls_random_reseed_period\fR
-+Time in seconds until the next reseed from external sources is due.
-+This is the maximum value. The actual point in time is calculated
-+with a random factor equally distributed between 0 and this maximum
-+value. Default is 3600 (= 60 minutes).
-+.IP \fBtls_random_prng_update_period\fR
-+Time in seconds until the PRNG exchange file is updated with new
-+pseude random values. This is the maximum value. The actual point
-+in time is calculated with a random factor equally distributed
-+between 0 and this maximum value. Default is 60 (= 1 minute).
-+.SH SEE ALSO
-+.na
-+.nf
-+smtp(8) SMTP client
-+smtpd(8) SMTP server
-+.SH LICENSE
-+.na
-+.nf
-+.ad
-+.fi
-+The Secure Mailer license must be distributed with this software.
-+.SH AUTHOR(S)
-+.na
-+.nf
-diff -Nur snapshot-20010228-orig/src/global/Makefile.in snapshot-20010228/src/global/Makefile.in
---- snapshot-20010228-orig/src/global/Makefile.in      Wed Mar 21 13:26:24 2001
-+++ snapshot-20010228/src/global/Makefile.in   Wed Mar 21 13:32:23 2001
-@@ -18,7 +18,8 @@
-       sent.c smtp_stream.c split_addr.c string_list.c sys_exits.c \
-       timed_ipc.c tok822_find.c tok822_node.c tok822_parse.c \
-       tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \
--      flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c
-+      flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \
-+      pfixtls.c
- OBJS  = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \
-       debug_peer.o debug_process.o defer.o deliver_completed.o \
-       deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \
-@@ -38,7 +39,8 @@
-       sent.o smtp_stream.o split_addr.o string_list.o sys_exits.o \
-       timed_ipc.o tok822_find.o tok822_node.o tok822_parse.o \
-       tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \
--      flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o
-+      flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \
-+      pfixtls.o
- HDRS  = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \
-       config.h debug_peer.h debug_process.h defer.h deliver_completed.h \
-       deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \
-@@ -54,7 +56,7 @@
-       recipient_list.h record.h resolve_clnt.h resolve_local.h \
-       rewrite_clnt.h sent.h smtp_stream.h split_addr.h string_list.h \
-       sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \
--      mbox_conf.h mbox_open.h abounce.h
-+      mbox_conf.h mbox_open.h abounce.h pfixtls.h
- TESTSRC       = rec2stream.c stream2rec.c recdump.c
- WARN  = -W -Wformat -Wimplicit -Wmissing-prototypes \
-       -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
-@@ -1039,3 +1041,14 @@
- xtext.o: ../../include/vbuf.h
- xtext.o: ../../include/vstring.h
- xtext.o: xtext.h
-+pfixtls.o: pfixtls.c
-+pfixtls.o: ../../include/sys_defs.h
-+pfixtls.o: ../../include/iostuff.h
-+pfixtls.o: ../../include/mymalloc.h
-+pfixtls.o: ../../include/vstring.h
-+pfixtls.o: ../../include/vstream.h
-+pfixtls.o: ../../include/dict.h
-+pfixtls.o: ../../include/myflock.h
-+pfixtls.o: ../../include/stringops.h
-+pfixtls.o: mail_params.h
-+pfixtls.o: pfixtls.h
-diff -Nur snapshot-20010228-orig/src/global/mail_params.c snapshot-20010228/src/global/mail_params.c
---- snapshot-20010228-orig/src/global/mail_params.c    Wed Mar 21 13:26:24 2001
-+++ snapshot-20010228/src/global/mail_params.c Wed Mar 21 13:32:23 2001
-@@ -174,6 +174,31 @@
- char   *var_fflush_domains;
- char   *var_def_transport;
- char   *var_mynetworks_style;
-+char   *var_tls_rand_exch_name;
-+char   *var_smtpd_tls_cert_file;
-+char   *var_smtpd_tls_key_file;
-+char   *var_smtpd_tls_dcert_file;
-+char   *var_smtpd_tls_dkey_file;
-+char   *var_smtpd_tls_CAfile;
-+char   *var_smtpd_tls_CApath;
-+char   *var_smtpd_tls_cipherlist;
-+char   *var_smtpd_tls_dh512_param_file;
-+char   *var_smtpd_tls_dh1024_param_file;
-+int     var_smtpd_tls_loglevel;
-+char   *var_smtpd_tls_scache_db;
-+int     var_smtpd_tls_scache_timeout;
-+char   *var_smtp_tls_cert_file;
-+char   *var_smtp_tls_key_file;
-+char   *var_smtp_tls_dcert_file;
-+char   *var_smtp_tls_dkey_file;
-+char   *var_smtp_tls_CAfile;
-+char   *var_smtp_tls_CApath;
-+char   *var_smtp_tls_cipherlist;
-+int     var_smtp_tls_loglevel;
-+char   *var_smtp_tls_scache_db;
-+int     var_smtp_tls_scache_timeout;
-+char   *var_tls_daemon_rand_source;
-+int     var_tls_daemon_rand_bytes;
- char   *var_import_environ;
- char   *var_export_environ;
-@@ -293,6 +318,26 @@
-       VAR_IMPORT_ENVIRON, DEF_IMPORT_ENVIRON, &var_import_environ, 0, 0,
-       VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 0, 0,
-       VAR_MYNETWORKS_STYLE, DEF_MYNETWORKS_STYLE, &var_mynetworks_style, 1, 0,
-+      VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name, 0, 0,
-+      VAR_SMTPD_TLS_CERT_FILE, DEF_SMTPD_TLS_CERT_FILE, &var_smtpd_tls_cert_file, 0, 0,
-+      VAR_SMTPD_TLS_KEY_FILE, DEF_SMTPD_TLS_KEY_FILE, &var_smtpd_tls_key_file, 0, 0,
-+      VAR_SMTPD_TLS_DCERT_FILE, DEF_SMTPD_TLS_DCERT_FILE, &var_smtpd_tls_dcert_file, 0, 0,
-+      VAR_SMTPD_TLS_DKEY_FILE, DEF_SMTPD_TLS_DKEY_FILE, &var_smtpd_tls_dkey_file, 0, 0,
-+      VAR_SMTPD_TLS_CA_FILE, DEF_SMTPD_TLS_CA_FILE, &var_smtpd_tls_CAfile, 0, 0,
-+      VAR_SMTPD_TLS_CA_PATH, DEF_SMTPD_TLS_CA_PATH, &var_smtpd_tls_CApath, 0, 0,
-+      VAR_SMTPD_TLS_CLIST, DEF_SMTPD_TLS_CLIST, &var_smtpd_tls_cipherlist, 0, 0,
-+      VAR_SMTPD_TLS_512_FILE, DEF_SMTPD_TLS_512_FILE, &var_smtpd_tls_dh512_param_file, 0, 0,
-+      VAR_SMTPD_TLS_1024_FILE, DEF_SMTPD_TLS_1024_FILE, &var_smtpd_tls_dh1024_param_file, 0, 0,
-+      VAR_SMTPD_TLS_SCACHE_DB, DEF_SMTPD_TLS_SCACHE_DB, &var_smtpd_tls_scache_db, 0, 0,
-+      VAR_SMTP_TLS_CERT_FILE, DEF_SMTP_TLS_CERT_FILE, &var_smtp_tls_cert_file, 0, 0,
-+      VAR_SMTP_TLS_KEY_FILE, DEF_SMTP_TLS_KEY_FILE, &var_smtp_tls_key_file, 0, 0,
-+      VAR_SMTP_TLS_DCERT_FILE, DEF_SMTP_TLS_DCERT_FILE, &var_smtp_tls_dcert_file, 0, 0,
-+      VAR_SMTP_TLS_DKEY_FILE, DEF_SMTP_TLS_DKEY_FILE, &var_smtp_tls_dkey_file, 0, 0,
-+      VAR_SMTP_TLS_CA_FILE, DEF_SMTP_TLS_CA_FILE, &var_smtp_tls_CAfile, 0, 0,
-+      VAR_SMTP_TLS_CA_PATH, DEF_SMTP_TLS_CA_PATH, &var_smtp_tls_CApath, 0, 0,
-+      VAR_SMTP_TLS_CLIST, DEF_SMTP_TLS_CLIST, &var_smtp_tls_cipherlist, 0, 0,
-+      VAR_SMTP_TLS_SCACHE_DB, DEF_SMTP_TLS_SCACHE_DB, &var_smtp_tls_scache_db, 0, 0,
-+      VAR_TLS_DAEMON_RAND_SOURCE, DEF_TLS_DAEMON_RAND_SOURCE, &var_tls_daemon_rand_source, 0, 0,
-       0,
-     };
-     static CONFIG_STR_FN_TABLE function_str_defaults_2[] = {
-@@ -307,6 +352,9 @@
-       VAR_HASH_QUEUE_DEPTH, DEF_HASH_QUEUE_DEPTH, &var_hash_queue_depth, 1, 0,
-       VAR_FORK_TRIES, DEF_FORK_TRIES, &var_fork_tries, 1, 0,
-       VAR_FLOCK_TRIES, DEF_FLOCK_TRIES, &var_flock_tries, 1, 0,
-+      VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0,
-+      VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0,
-+      VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 0, 0,
-       0,
-     };
-     static CONFIG_TIME_TABLE time_defaults[] = {
-@@ -317,6 +365,8 @@
-       VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0,
-       VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0,
-       VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0,
-+      VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0,
-+      VAR_SMTP_TLS_SCACHTIME, DEF_SMTP_TLS_SCACHTIME, &var_smtp_tls_scache_timeout, 0, 0,
-       VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0,
-       0,
-     };
-diff -Nur snapshot-20010228-orig/src/global/mail_params.h snapshot-20010228/src/global/mail_params.h
---- snapshot-20010228-orig/src/global/mail_params.h    Wed Mar 21 13:26:24 2001
-+++ snapshot-20010228/src/global/mail_params.h Wed Mar 21 13:32:23 2001
-@@ -430,6 +430,34 @@
- #define DEF_DUP_FILTER_LIMIT  1000
- extern int var_dup_filter_limit;
-+#define VAR_TLS_RAND_EXCH_NAME        "tls_random_exchange_name"
-+#define DEF_TLS_RAND_EXCH_NAME        "${config_directory}/prng_exch"
-+extern char *var_tls_rand_exch_name;
-+
-+#define VAR_TLS_RAND_SOURCE   "tls_random_source"
-+#define DEF_TLS_RAND_SOURCE   ""
-+extern char *var_tls_rand_source;
-+
-+#define VAR_TLS_RAND_BYTES    "tls_random_bytes"
-+#define DEF_TLS_RAND_BYTES    32
-+extern int var_tls_rand_bytes;
-+
-+#define VAR_TLS_DAEMON_RAND_SOURCE    "tls_daemon_random_source"
-+#define DEF_TLS_DAEMON_RAND_SOURCE    ""
-+extern char *var_tls_daemon_rand_source;
-+
-+#define VAR_TLS_DAEMON_RAND_BYTES     "tls_daemon_random_bytes"
-+#define DEF_TLS_DAEMON_RAND_BYTES     32
-+extern int var_tls_daemon_rand_bytes;
-+
-+#define VAR_TLS_RESEED_PERIOD "tls_random_reseed_period"
-+#define DEF_TLS_RESEED_PERIOD "3600s"
-+extern int var_tls_reseed_period;
-+
-+#define VAR_TLS_PRNG_UPD_PERIOD       "tls_random_prng_update_period"
-+#define DEF_TLS_PRNG_UPD_PERIOD "60s"
-+extern int var_tls_prng_upd_period;
-+
-  /*
-   * Queue manager: relocated databases.
-   */
-@@ -647,6 +675,10 @@
- #define DEF_SMTP_HELO_TMOUT   "300s"
- extern int var_smtp_helo_tmout;
-+#define VAR_SMTP_STARTTLS_TMOUT       "smtp_starttls_timeout"
-+#define DEF_SMTP_STARTTLS_TMOUT       "300s"
-+extern int var_smtp_starttls_tmout;
-+
- #define VAR_SMTP_MAIL_TMOUT   "smtp_mail_timeout"
- #define DEF_SMTP_MAIL_TMOUT   "300s"
- extern int var_smtp_mail_tmout;
-@@ -699,6 +731,10 @@
- #define DEF_SMTP_BIND_ADDR    ""
- extern char *var_smtp_bind_addr;
-+#define VAR_SMTP_ALWAYS_EHLO  "smtp_always_send_ehlo"
-+#define DEF_SMTP_ALWAYS_EHLO  0
-+extern bool var_smtp_always_ehlo;
-+
-  /*
-   * SMTP server. The soft error limit determines how many errors an SMTP
-   * client may make before we start to slow down; the hard error limit
-@@ -712,6 +748,10 @@
- #define DEF_SMTPD_TMOUT               "300s"
- extern int var_smtpd_tmout;
-+#define VAR_SMTPD_STARTTLS_TMOUT "smtpd_starttls_timeout"
-+#define DEF_SMTPD_STARTTLS_TMOUT "300s"
-+extern int var_smtpd_starttls_tmout;
-+
- #define VAR_SMTPD_RCPT_LIMIT  "smtpd_recipient_limit"
- #define DEF_SMTPD_RCPT_LIMIT  1000
- extern int var_smtpd_rcpt_limit;
-@@ -732,6 +772,146 @@
- #define DEF_SMTPD_JUNK_CMD    1000
- extern int var_smtpd_junk_cmd_limit;
-+#define VAR_SMTPD_TLS_WRAPPER "smtpd_tls_wrappermode"
-+#define DEF_SMTPD_TLS_WRAPPER 0
-+extern bool var_smtpd_tls_wrappermode;
-+
-+#define VAR_SMTPD_USE_TLS     "smtpd_use_tls"
-+#define DEF_SMTPD_USE_TLS     0
-+extern bool var_smtpd_use_tls;
-+
-+#define VAR_SMTPD_ENFORCE_TLS "smtpd_enforce_tls"
-+#define DEF_SMTPD_ENFORCE_TLS 0
-+extern bool var_smtpd_enforce_tls;
-+
-+#define VAR_SMTPD_TLS_ACERT   "smtpd_tls_ask_ccert"
-+#define DEF_SMTPD_TLS_ACERT   0
-+extern bool var_smtpd_tls_ask_ccert;
-+
-+#define VAR_SMTPD_TLS_RCERT   "smtpd_tls_req_ccert"
-+#define DEF_SMTPD_TLS_RCERT   0
-+extern bool var_smtpd_tls_req_ccert;
-+
-+#define VAR_SMTPD_TLS_CCERT_VD        "smtpd_tls_ccert_verifydepth"
-+#define DEF_SMTPD_TLS_CCERT_VD        5
-+extern int var_smtpd_tls_ccert_vd;
-+
-+#define VAR_SMTPD_TLS_CERT_FILE       "smtpd_tls_cert_file"
-+#define DEF_SMTPD_TLS_CERT_FILE       ""
-+extern char *var_smtpd_tls_cert_file;
-+
-+#define VAR_SMTPD_TLS_KEY_FILE        "smtpd_tls_key_file"
-+#define DEF_SMTPD_TLS_KEY_FILE        "$smtpd_tls_cert_file"
-+extern char *var_smtpd_tls_key_file;
-+
-+#define VAR_SMTPD_TLS_DCERT_FILE "smtpd_tls_dcert_file"
-+#define DEF_SMTPD_TLS_DCERT_FILE ""
-+extern char *var_smtpd_tls_dcert_file;
-+
-+#define VAR_SMTPD_TLS_DKEY_FILE       "smtpd_tls_dkey_file"
-+#define DEF_SMTPD_TLS_DKEY_FILE       "$smtpd_tls_dcert_file"
-+extern char *var_smtpd_tls_dkey_file;
-+
-+#define VAR_SMTPD_TLS_CA_FILE "smtpd_tls_CAfile"
-+#define DEF_SMTPD_TLS_CA_FILE ""
-+extern char *var_smtpd_tls_CAfile;
-+
-+#define VAR_SMTPD_TLS_CA_PATH "smtpd_tls_CApath"
-+#define DEF_SMTPD_TLS_CA_PATH ""
-+extern char *var_smtpd_tls_CApath;
-+
-+#define VAR_SMTPD_TLS_CLIST   "smtpd_tls_cipherlist"
-+#define DEF_SMTPD_TLS_CLIST   ""
-+extern char *var_smtpd_tls_cipherlist;
-+
-+#define VAR_SMTPD_TLS_512_FILE        "smtpd_tls_dh512_param_file"
-+#define DEF_SMTPD_TLS_512_FILE        ""
-+extern char *var_smtpd_tls_dh512_param_file;
-+
-+#define VAR_SMTPD_TLS_1024_FILE       "smtpd_tls_dh1024_param_file"
-+#define DEF_SMTPD_TLS_1024_FILE       ""
-+extern char *var_smtpd_tls_dh1024_param_file;
-+
-+#define VAR_SMTPD_TLS_LOGLEVEL        "smtpd_tls_loglevel"
-+#define DEF_SMTPD_TLS_LOGLEVEL        0
-+extern int var_smtpd_tls_loglevel;
-+
-+#define VAR_SMTPD_TLS_RECHEAD "smtpd_tls_received_header"
-+#define DEF_SMTPD_TLS_RECHEAD 0
-+extern bool var_smtpd_tls_received_header;
-+
-+#define VAR_SMTPD_TLS_SCACHE_DB       "smtpd_tls_session_cache_database"
-+#define DEF_SMTPD_TLS_SCACHE_DB       ""
-+extern char *var_smtpd_tls_scache_db;
-+
-+#define VAR_SMTPD_TLS_SCACHTIME       "smtpd_tls_session_cache_timeout"
-+#define DEF_SMTPD_TLS_SCACHTIME       "3600s"
-+extern int var_smtpd_tls_scache_timeout;
-+
-+#define VAR_SMTP_TLS_PER_SITE "smtp_tls_per_site"
-+#define DEF_SMTP_TLS_PER_SITE ""
-+extern char *var_smtp_tls_per_site;
-+
-+#define VAR_SMTP_USE_TLS      "smtp_use_tls"
-+#define DEF_SMTP_USE_TLS      0
-+extern bool var_smtp_use_tls;
-+
-+#define VAR_SMTP_ENFORCE_TLS  "smtp_enforce_tls"
-+#define DEF_SMTP_ENFORCE_TLS  0
-+extern bool var_smtp_enforce_tls;
-+
-+#define VAR_SMTP_TLS_ENFORCE_PN       "smtp_tls_enforce_peername"
-+#define DEF_SMTP_TLS_ENFORCE_PN       1
-+extern bool var_smtp_tls_enforce_peername;
-+
-+#define VAR_SMTP_TLS_SCERT_VD "smtp_tls_scert_verifydepth"
-+#define DEF_SMTP_TLS_SCERT_VD 5
-+extern int var_smtp_tls_scert_vd;
-+
-+#define VAR_SMTP_TLS_CERT_FILE        "smtp_tls_cert_file"
-+#define DEF_SMTP_TLS_CERT_FILE        ""
-+extern char *var_smtp_tls_cert_file;
-+
-+#define VAR_SMTP_TLS_KEY_FILE "smtp_tls_key_file"
-+#define DEF_SMTP_TLS_KEY_FILE "$smtp_tls_cert_file"
-+extern char *var_smtp_tls_key_file;
-+
-+#define VAR_SMTP_TLS_DCERT_FILE "smtp_tls_dcert_file"
-+#define DEF_SMTP_TLS_DCERT_FILE ""
-+extern char *var_smtp_tls_dcert_file;
-+
-+#define VAR_SMTP_TLS_DKEY_FILE        "smtp_tls_dkey_file"
-+#define DEF_SMTP_TLS_DKEY_FILE        "$smtp_tls_dcert_file"
-+extern char *var_smtp_tls_dkey_file;
-+
-+#define VAR_SMTP_TLS_CA_FILE  "smtp_tls_CAfile"
-+#define DEF_SMTP_TLS_CA_FILE  ""
-+extern char *var_smtp_tls_CAfile;
-+
-+#define VAR_SMTP_TLS_CA_PATH  "smtp_tls_CApath"
-+#define DEF_SMTP_TLS_CA_PATH  ""
-+extern char *var_smtp_tls_CApath;
-+
-+#define VAR_SMTP_TLS_CLIST    "smtp_tls_cipherlist"
-+#define DEF_SMTP_TLS_CLIST    ""
-+extern char *var_smtp_tls_cipherlist;
-+
-+#define VAR_SMTP_TLS_LOGLEVEL "smtp_tls_loglevel"
-+#define DEF_SMTP_TLS_LOGLEVEL 0
-+extern int var_smtp_tls_loglevel;
-+
-+#define VAR_SMTP_TLS_NOTEOFFER        "smtp_tls_note_starttls_offer"
-+#define DEF_SMTP_TLS_NOTEOFFER        0
-+extern bool var_smtp_tls_note_starttls_offer;
-+
-+#define VAR_SMTP_TLS_SCACHE_DB        "smtp_tls_session_cache_database"
-+#define DEF_SMTP_TLS_SCACHE_DB        ""
-+extern char *var_smtp_tls_scache_db;
-+
-+#define VAR_SMTP_TLS_SCACHTIME        "smtp_tls_session_cache_timeout"
-+#define DEF_SMTP_TLS_SCACHTIME        "3600s"
-+extern int var_smtp_tls_scache_timeout;
-+
-  /*
-   * SASL authentication support, SMTP server side.
-   */
-@@ -1007,6 +1187,10 @@
- #define DEF_RELAY_DOMAINS     "$mydestination"
- extern char *var_relay_domains;
-+#define VAR_RELAY_CCERTS      "relay_clientcerts"
-+#define DEF_RELAY_CCERTS      ""
-+extern char *var_relay_ccerts;
-+
- #define VAR_CLIENT_CHECKS     "smtpd_client_restrictions"
- #define DEF_CLIENT_CHECKS     ""
- extern char *var_client_checks;
-@@ -1086,6 +1270,8 @@
- #define PERMIT_AUTH_DEST      "permit_auth_destination"
- #define REJECT_UNAUTH_DEST    "reject_unauth_destination"
- #define CHECK_RELAY_DOMAINS   "check_relay_domains"
-+#define PERMIT_TLS_CLIENTCERTS        "permit_tls_clientcerts"
-+#define PERMIT_TLS_ALL_CLIENTCERTS    "permit_tls_all_clientcerts"
- #define VAR_RELAY_CODE                "relay_domains_reject_code"
- #define DEF_RELAY_CODE                554
- extern int var_relay_code;
-diff -Nur snapshot-20010228-orig/src/global/mail_proto.h snapshot-20010228/src/global/mail_proto.h
---- snapshot-20010228-orig/src/global/mail_proto.h     Wed Mar 21 13:26:24 2001
-+++ snapshot-20010228/src/global/mail_proto.h  Wed Mar 21 13:32:23 2001
-@@ -33,6 +33,7 @@
- #define MAIL_SERVICE_LOCAL    "local"
- #define MAIL_SERVICE_PICKUP   "pickup"
- #define MAIL_SERVICE_QUEUE    "qmgr"
-+#define MAIL_SERVICE_TLSMGR   "tlsmgr"
- #define MAIL_SERVICE_RESOLVE  "resolve"
- #define MAIL_SERVICE_REWRITE  "rewrite"
- #define MAIL_SERVICE_VIRTUAL  "virtual"
-diff -Nur snapshot-20010228-orig/src/global/pfixtls.c snapshot-20010228/src/global/pfixtls.c
---- snapshot-20010228-orig/src/global/pfixtls.c        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/global/pfixtls.c     Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,2786 @@
-+/*++
-+/* NAME
-+/*    pfixtls
-+/* SUMMARY
-+/*    interface to openssl routines
-+/* SYNOPSIS
-+/*    #include <pfixtls.h>
-+/*
-+/*    const long scache_db_version;
-+/*    const long openssl_version;
-+/*
-+/*    int pfixtls_serverengine;
-+/*    int pfixtls_serveractive;
-+/*    int pfixtls_peer_verified;
-+/*    char *pfixtls_peer_subject;
-+/*    char *pfixtls_peer_issuer;
-+/*    char *pfixtls_peer_fingerprint;
-+/*
-+/*    int pfixtls_clientengine;
-+/*    int pfixtls_clientactive;
-+/*
-+/*    char *pfixtls_peer_CN;
-+/*    char *pfixtls_issuer_CN;
-+/*    char *pfixtls_protocol;
-+/*    const char *pfixtls_cipher_name;
-+/*    int pfixtls_cipher_usebits;
-+/*    int pfixtls_cipher_algbits;
-+/*
-+/*    int pfixtls_timed_read(fd, buf, len, timeout, unused_context)
-+/*    int fd;
-+/*    void *buf;
-+/*    unsigned len;
-+/*    int timeout;
-+/*    void *context;
-+/*
-+/*    int pfixtls_timed_write(fd, buf, len, timeout, unused_context);
-+/*    int fd;
-+/*    void *buf;
-+/*    unsigned len;
-+/*    int timeout;
-+/*    void *context;
-+/*
-+/*    int pfixtls_init_serverengine(verifydepth, askcert);
-+/*    int verifydepth;
-+/*    int askcert;
-+/*
-+/*    int pfixtls_start_servertls(stream, timeout, peername, peeraddr,
-+/*                                tls_info, requirecert);
-+/*    VSTREAM *stream;
-+/*    int timeout;
-+/*    const char *peername;
-+/*    const char *peeraddr;
-+/*    tls_info_t *tls_info;
-+/*    int requirecert;
-+/*
-+/*    int pfixtls_stop_servertls(stream, failure, tls_info);
-+/*    VSTREAM *stream;
-+/*    int failure;
-+/*    tls_info_t *tls_info;
-+/*    
-+/*    int pfixtls_init_clientengine(verifydepth);
-+/*    int verifydepth;
-+/*
-+/*    int pfixtls_start_clienttls(stream, timeout, peername, peeraddr,
-+/*                                tls_info);
-+/*    VSTREAM *stream;
-+/*    int timeout;
-+/*    const char *peername;
-+/*    const char *peeraddr;
-+/*    tls_info_t *tls_info;
-+/*
-+/*    int pfixtls_stop_clienttls(stream, failure, tls_info);
-+/*    VSTREAM *stream;
-+/*    int failure;
-+/*    tls_info_t *tls_info;
-+/*
-+/* DESCRIPTION
-+/*    This module is the interface between Postfix and the OpenSSL library.
-+/*
-+/*    pfixtls_timed_read() reads the requested number of bytes calling
-+/*    SSL_read(). pfixtls_time_read() will only be called indirect
-+/*    as a VSTREAM_FN function.
-+/*    pfixtls_timed_write() is the corresponding write function.
-+/*
-+/*    pfixtls_init_serverengine() is called once when smtpd is started
-+/*    in order to initialize as much of the TLS stuff as possible.
-+/*    The certificate handling is also decided during the setup phase,
-+/*    so that a peer specific handling is not possible.
-+/*
-+/*    pfixtls_init_clientengine() is the corresponding function called
-+/*    in smtp. Here we take the peer's (server's) certificate in any
-+/*    case.
-+/*
-+/*    pfixtls_start_servertls() activates the TLS feature for the VSTREAM
-+/*    passed as argument. We expect that all buffers are flushed and the
-+/*    TLS handshake can begin immediately. Information about the peer
-+/*    is stored into the tls_info structure passed as argument.
-+/*
-+/*    pfixtls_stop_servertls() sends the "close notify" alert via
-+/*    SSL_shutdown() to the peer and resets all connection specific
-+/*    TLS data. As RFC2487 does not specify a seperate shutdown, it
-+/*    is supposed that the underlying TCP connection is shut down
-+/*    immediately afterwards, so we don't care about additional data
-+/*    coming through the channel.
-+/*    If the failure flag is set, the session is cleared from the cache.
-+/*
-+/*    pfixtls_start_clienttls() and pfixtls_stop_clienttls() are the
-+/*    corresponding functions for smtp.
-+/*
-+/*    Once the TLS connection is initiated, information about the TLS
-+/*    state is available via the tls_info structure:
-+/*    protocol holds the protocol name (SSLv2, SSLv3, TLSv1),
-+/*    tls_info->cipher_name the cipher name (e.g. RC4/MD5),
-+/*    tls_info->cipher_usebits the number of bits actually used (e.g. 40),
-+/*    tls_info->cipher_algbits the number of bits the algorithm is based on
-+/*    (e.g. 128).
-+/*    The last two values may be different when talking to a crippled
-+/*    - ahem - export controled peer (e.g. 40/128).
-+/*
-+/*    The status of the peer certificate verification is available in
-+/*    pfixtls_peer_verified. It is set to 1, when the certificate could
-+/*    be verified.
-+/*    If the peer offered a certifcate, part of the certificate data are
-+/*    available as:
-+/*    tls_info->peer_subject X509v3-oneline with the DN of the peer
-+/*    tls_info->peer_CN extracted CommonName of the peer
-+/*    tls_info->peer_issuer  X509v3-oneline with the DN of the issuer
-+/*    tls_info->peer_CN extracted CommonName of the issuer
-+/*    tls_info->PEER_FINGERPRINT fingerprint of the certificate
-+/*
-+/* DESCRIPTION (SESSION CACHING)
-+/*    In order to achieve high performance when using a lot of connections
-+/*    with TLS, session caching is implemented. It reduces both the CPU load
-+/*    (less cryptograpic operations) and the network load (the amount of
-+/*    certificate data exchanged is reduced).
-+/*    Since postfix uses a setup of independent processes for receiving
-+/*    and sending email, the processes must exchange the session information.
-+/*    Several connections at the same time between the identical peers can
-+/*    occur, so uniqueness and race conditions have to be taken into
-+/*    account.
-+/*    I have checked both Apache-SSL (Ben Laurie), using a seperate "gcache"
-+/*    process and Apache mod_ssl (Ralf S. Engelshall), using shared memory
-+/*    between several identical processes spawned from one parent.
-+/*
-+/*    Postfix/TLS uses a database approach based on the internal "dict"
-+/*    interface. Since the session cache information is approximately
-+/*    1300 bytes binary data, it will not fit into the dbm/ndbm model.
-+/*    It also needs write access to the database, ruling out most other
-+/*    interface, leaving Berkeley DB, which however cannot handle concurrent
-+/*    access by several processes. Hence a modified SDBM (public domain DBM)
-+/*    with enhanced buffer size is used and concurrent write capability
-+/*    is used. SDBM is part of Postfix/TLS.
-+/*
-+/*    Realization:
-+/*    Both (client and server) session cache are realized by individual
-+/*    cache databases. A common database would not make sense, since the
-+/*    key criteria are different (session ID for server, peername for
-+/*    client).
-+/*
-+/*    Server side:
-+/*    Session created by OpenSSL have a 32 byte session id, yielding a
-+/*    64 char file name. I consider these sessions to be unique. If they
-+/*    are not, the last session will win, overwriting the older one in
-+/*    the database. Remember: everything that is lost is a temporary
-+/*    information and not more than a renegotiation will happen.
-+/*    Originating from the same client host, several sessions can come
-+/*    in (e.g. from several users sending mail with Netscape at the same
-+/*    time), so the session id is the correct identifier; the hostname
-+/*    is of no importance, here.
-+/*
-+/*    Client side:
-+/*    We cannot recall sessions based on their session id, because we would
-+/*    have to check every session on disk for a matching server name, so
-+/*    the lookup has to be done based on the FQDN of the peer (receiving
-+/*    host).
-+/*    With regard to uniqueness, we might experience several open connections
-+/*    to the same server at the same time. This is even very likely to
-+/*    happen, since we might have several mails for the same destination
-+/*    in the queue, when a queue run is started. So several smtp´s might
-+/*    negotiate sessions at the same time. We can however only save one
-+/*    session for one host.
-+/*    Like on the server side, the "last write" wins. The reason is
-+/*    quite simple. If we don´t want to overwrite old sessions, an old
-+/*    session file will just stay in place until it is expired. In the
-+/*    meantime we would lose "fresh" session however. So we will keep the
-+/*    fresh one instead to avoid unnecessary renegotiations.
-+/*
-+/*    Session lifetime:
-+/*    RFC2246 recommends a session lifetime of less than 24 hours. The
-+/*    default is 300 seconds (5 minutes) for OpenSSL and is also used
-+/*    this way in e.g. mod_ssl. The typical usage for emails might be
-+/*    humans typing in emails and sending them, which might take just
-+/*    a while, so I think 3600 seconds (1 hour) is a good compromise.
-+/*    If the environment is save (the cached session contains secret
-+/*    key data), one might even consider using a longer timeout. Anyway,
-+/*    since everlasting sessions must be avoided, the session timeout
-+/*    is done based on the creation date of the session and so each
-+/*    session will timeout eventually.
-+/*
-+/*    Connection failures:
-+/*    RFC2246 requires us to remove sessions if something went wrong.
-+/*    Since the in-memory session cache of other smtp[d] processes cannot
-+/*    be controlled by simple means, we completely rely on the disc
-+/*    based session caching and remove all sessions from memory after
-+/*    connection closure.
-+/*
-+/*    Cache cleanup:
-+/*    Since old entries have to be removed from the session cache, a
-+/*    cleanup process is needed that runs through the collected session
-+/*    files on regular basis. The task is performed by tlsmgr based on
-+/*    the timestamp created by pfixtls and included in the saved session,
-+/*    so that tlsmgr has not to care about the SSL_SESSION internal data.
-+/*
-+/* BUGS
-+/*    The memory allocation policy of the OpenSSL library is not well
-+/*    documented, especially when loading sessions from disc. Hence there
-+/*    might be memory leaks.
-+/*
-+/* LICENSE
-+/* AUTHOR(S)
-+/*    Lutz Jaenicke
-+/*    BTU Cottbus
-+/*    Allgemeine Elektrotechnik
-+/*    Universitaetsplatz 3-4
-+/*    D-03044 Cottbus, Germany
-+/*--*/
-+
-+/* System library. */
-+
-+#include <sys_defs.h>
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <sys/time.h>                 /* gettimeofday, not in POSIX */
-+#include <unistd.h>
-+#include <stdio.h>
-+#include <string.h>
-+#include <errno.h>
-+
-+/* Utility library. */
-+
-+#include <iostuff.h>
-+#include <mymalloc.h>
-+#include <vstring.h>
-+#include <vstream.h>
-+#include <dict.h>
-+#include <myflock.h>
-+#include <stringops.h>
-+
-+/* Application-specific. */
-+
-+#include "mail_params.h"
-+#include "pfixtls.h"
-+
-+#define STR   vstring_str
-+
-+const tls_info_t tls_info_zero = {
-+    0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0
-+};
-+
-+#ifdef HAS_SSL
-+
-+/* OpenSSL library. */
-+
-+#include <openssl/lhash.h>
-+#include <openssl/bn.h>
-+#include <openssl/err.h>
-+#include <openssl/pem.h>
-+#include <openssl/x509.h>
-+#include <openssl/ssl.h>
-+
-+/* We must keep some of the info available */
-+static const char hexcodes[] = "0123456789ABCDEF";
-+
-+/*
-+ * When saving sessions, we want to make sure, that the lenght of the key
-+ * is somehow limited. When saving client sessions, the hostname
-+ * can be up to 64 bytes long.
-+ * The length of the actual session id is however not defined in RFC2246.
-+ * OpenSSL defines a SSL_MAX_SSL_SESSION_ID_LENGTH of 32, but nobody
-+ * guarantees, that a client might not try to resume a session with a longer
-+ * session id. So to make sure, we define an upper bound of 64.
-+ */
-+static const int id_maxlength = 64;   /* Max ID length in bytes */
-+
-+/*
-+ * The session_id_context is set, such that the client knows which services
-+ * on a host share the same session information (on the postfix host may
-+ * as well run a TLS-enabled webserver.
-+ */
-+static char server_session_id_context[] = "Postfix/TLS"; /* anything will do */
-+static int TLScontext_index = -1;
-+static int do_dump = 0;
-+static DH *dh_512 = NULL, *dh_1024 = NULL;
-+static SSL_CTX *ctx = NULL;
-+
-+static rand_exch_fd = -1;
-+
-+static DICT *scache_db = NULL;
-+const long scache_db_version = 0x00000002L;
-+const long openssl_version = OPENSSL_VERSION_NUMBER;
-+
-+
-+int     pfixtls_serverengine = 0;
-+static int pfixtls_serveractive = 0;  /* available or not */
-+
-+int     pfixtls_clientengine = 0;
-+static int pfixtls_clientactive = 0;  /* available or not */
-+
-+/*
-+ * Define a maxlength for certificate onelines. The length is checked by
-+ * all routines when copying.
-+ */
-+#define CCERT_BUFSIZ 256
-+
-+typedef struct {
-+  SSL *con;
-+  BIO *internal_bio;                  /* postfix/TLS side of pair */
-+  BIO *network_bio;                   /* netsork side of pair */
-+  char peer_subject[CCERT_BUFSIZ];
-+  char peer_issuer[CCERT_BUFSIZ];
-+  char peer_CN[CCERT_BUFSIZ];
-+  char issuer_CN[CCERT_BUFSIZ];
-+  unsigned char md[EVP_MAX_MD_SIZE];
-+  char fingerprint[EVP_MAX_MD_SIZE * 3];
-+  char peername_save[129];
-+  int enforce_verify_errors;
-+  int enforce_CN;
-+} TLScontext_t;
-+
-+typedef struct {
-+    int pid;
-+    struct timeval tv;
-+} randseed_t;
-+
-+static randseed_t randseed;
-+static struct stat seedfile_stat;
-+
-+/*
-+ * Finally some "backup" DH-Parameters to be loaded, if no parameters are
-+ * explicitely loaded from file.
-+ */
-+static unsigned char dh512_p[] = {
-+    0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2,
-+    0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4,
-+    0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E,
-+    0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5,
-+    0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB,
-+    0x4F, 0x70, 0xBA, 0x5B,
-+};
-+
-+static unsigned char dh512_g[] = {
-+    0x02,
-+};
-+
-+static unsigned char dh1024_p[] = {
-+    0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D,
-+    0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88,
-+    0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51,
-+    0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F,
-+    0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72,
-+    0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76,
-+    0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81,
-+    0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E,
-+    0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6,
-+    0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF,
-+    0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B,
-+};
-+
-+static unsigned char dh1024_g[] = {
-+    0x02,
-+};
-+
-+/*
-+ * DESCRIPTION: Keeping control of the network interface using BIO-pairs.
-+ *
-+ * When the TLS layer is active, all input/output must be filtered through
-+ * it. On the other hand to handle timeout conditions, full control over
-+ * the network socket must be kept. This rules out the "normal way" of
-+ * connecting the TLS layer directly to the socket.
-+ * The TLS layer is realized with a BIO-pair:
-+ *
-+ *     postfix  |   TLS-engine
-+ *       |      |
-+ *       +--------> SSL_operations()
-+ *              |     /\    ||
-+ *              |     ||    \/
-+ *              |   BIO-pair (internal_bio)
-+ *       +--------< BIO-pair (network_bio)
-+ *       |      |
-+ *     socket   |
-+ *
-+ * The normal postfix operations connect to the SSL operations to send
-+ * and retrieve (cleartext) data. Inside the TLS-engine the data are converted
-+ * to/from TLS protocol. The TLS functionality itself is only connected to
-+ * the internal_bio and hence only has status information about this internal
-+ * interface.
-+ * Thus, if the SSL_operations() return successfully (SSL_ERROR_NONE) or want
-+ * to read (SSL_ERROR_WANT_READ) there may as well be data inside the buffering
-+ * BIO-pair. So whenever an SSL_operation() returns without a fatal error,
-+ * the BIO-pair internal buffer must be flushed to the network.
-+ * NOTE: This is especially true in the SSL_ERROR_WANT_READ case: the TLS-layer
-+ * might want to read handshake data, that will never come since its own
-+ * written data will only reach the peer after flushing the buffer!
-+ *
-+ * The BIO-pair buffer size has been set to 8192 bytes, this is an arbitrary
-+ * value that can hold more data than the typical PMTU, so that it does
-+ * not force the generation of packets smaller than necessary.
-+ * It is also larger than the default VSTREAM_BUFSIZE (4096, see vstream.h),
-+ * so that large write operations could be handled within one call.
-+ * The internal buffer in the network/network_bio handling layer has been
-+ * set to the same value, since this seems to be reasonable. The code is
-+ * however able to handle arbitrary values smaller or larger than the
-+ * buffer size in the BIO-pair.
-+ */
-+
-+const ssize_t BIO_bufsiz = 8192;
-+
-+/*
-+ * The interface layer between network and BIO-pair. The BIO-pair buffers
-+ * the data to/from the TLS layer. Hence, at any time, there may be data
-+ * in the buffer that must be written to the network. This writing has
-+ * highest priority because the handshake might fail otherwise.
-+ * Only then a read_request can be satisfied.
-+ */
-+static int network_biopair_interop(int fd, int timeout, BIO *network_bio)
-+{
-+    int want_write;
-+    int num_write;
-+    int write_pos;
-+    int from_bio;
-+    int want_read;
-+    int num_read;
-+    int to_bio;
-+#define NETLAYER_BUFFERSIZE 8192
-+    char buffer[8192];
-+
-+    while ((want_write = BIO_ctrl_pending(network_bio)) > 0) {
-+      if (want_write > NETLAYER_BUFFERSIZE)
-+          want_write = NETLAYER_BUFFERSIZE;
-+      from_bio = BIO_read(network_bio, buffer, want_write);
-+
-+      /*
-+       * Write the complete contents of the buffer. Since TLS performs
-+       * underlying handshaking, we cannot afford to leave the buffer
-+       * unflushed, as we could run into a deadlock trap (the peer
-+       * waiting for a final byte and we already waiting for his reply
-+       * in read position).
-+       */
-+        write_pos = 0;
-+      do {
-+          if (timeout > 0 && write_wait(fd, timeout) < 0)
-+              return (-1);
-+          num_write = write(fd, buffer + write_pos, from_bio - write_pos);
-+          if (num_write <= 0)
-+              return (-1);    /* something happened to the socket */
-+          write_pos += num_write;
-+      } while (write_pos < from_bio);
-+   }
-+
-+   while ((want_read = BIO_ctrl_get_read_request(network_bio)) > 0) {
-+      if (want_read > NETLAYER_BUFFERSIZE)
-+          want_read = NETLAYER_BUFFERSIZE;
-+      if (timeout > 0 && read_wait(fd, timeout) < 0)
-+          return (-1);
-+      num_read = read(fd, buffer, want_read);
-+      if (num_read <= 0)
-+          return (-1);        /* something happened to the socket */
-+      to_bio = BIO_write(network_bio, buffer, num_read);
-+      if (to_bio != num_read)
-+              msg_fatal("to_bio != num_read");
-+    }
-+
-+    return (0);
-+}
-+
-+static void pfixtls_print_errors(void);
-+
-+ /*
-+  * Function to perform the handshake for SSL_accept(), SSL_connect(),
-+  * and SSL_shutdown() and perform the SSL_read(), SSL_write() operations.
-+  * Call the underlying network_biopair_interop-layer to make sure the
-+  * write buffer is flushed after every operation (that did not fail with
-+  * a fatal error).
-+  */
-+static int do_tls_operation(int fd, int timeout, TLScontext_t *TLScontext,
-+                      int (*hsfunc)(SSL *),
-+                      int (*rfunc)(SSL *, char *, int),
-+                      int (*wfunc)(SSL *, const char *, int),
-+                      char *buf, int num)
-+{
-+    int status;
-+    int err;
-+    int retval;
-+    int biop_retval;
-+    int done = 0;
-+
-+    while (!done) {
-+      if (hsfunc)
-+          status = hsfunc(TLScontext->con);
-+      else if (rfunc)
-+          status = rfunc(TLScontext->con, buf, num);
-+      else
-+          status = wfunc(TLScontext->con, (const char *)buf, num);
-+      err = SSL_get_error(TLScontext->con, status);
-+
-+#if (OPENSSL_VERSION_NUMBER <= 0x0090581fL)
-+      /*
-+       * There is a bug up to and including OpenSSL-0.9.5a: if an error
-+       * occurs while checking the peers certificate due to some certificate
-+       * error (e.g. as happend with a RSA-padding error), the error is put
-+       * onto the error stack. If verification is not enforced, this error
-+       * should be ignored, but the error-queue is not cleared, so we
-+       * can find this error here. The bug has been fixed on May 28, 2000.
-+       *
-+       * This bug so far has only manifested as
-+       * 4800:error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01:rsa_pk1.c:100:
-+       * 4800:error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed:rsa_eay.c:396:
-+       * 4800:error:0D079006:asn1 encoding routines:ASN1_verify:bad get asn1 object call:a_verify.c:109:
-+       * so that we specifically test for this error. We print the errors
-+       * to the logfile and automatically clear the error queue. Then we
-+       * retry to get another error code. We cannot do better, since we
-+       * can only retrieve the last entry of the error-queue without
-+       * actually cleaning it on the way.
-+       *
-+       * This workaround is secure, as verify_result is set to "failed"
-+       * anyway.
-+       */
-+      if (err == SSL_ERROR_SSL) {
-+          if (ERR_peek_error() == 0x0407006AL) {
-+              pfixtls_print_errors(); /* Keep information for the logfile */
-+              msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored");
-+              err = SSL_get_error(TLScontext->con, status);
-+          }
-+      }
-+#endif
-+
-+      switch (err) {
-+      case SSL_ERROR_NONE:            /* success */
-+          retval = status;
-+          done = 1;                   /* no break, flush buffer before */
-+                                      /* leaving */
-+      case SSL_ERROR_WANT_WRITE:
-+      case SSL_ERROR_WANT_READ:
-+          biop_retval = network_biopair_interop(fd, timeout,
-+              TLScontext->network_bio);
-+          if (biop_retval < 0)
-+              return (-1);            /* fatal network error */
-+          break;
-+      case SSL_ERROR_ZERO_RETURN:     /* connection was closed cleanly */
-+      case SSL_ERROR_SYSCALL:         
-+      case SSL_ERROR_SSL:
-+      default:
-+          retval = status;
-+          done = 1;
-+          ;
-+      }
-+    };
-+    return retval;
-+}
-+
-+int pfixtls_timed_read(int fd, void *buf, unsigned buf_len, int timeout, 
-+                     void *context)
-+{
-+    int     i;
-+    int     ret;
-+    char    mybuf[40];
-+    char   *mybuf2;
-+    TLScontext_t *TLScontext;
-+
-+    TLScontext = (TLScontext_t *)context;
-+    if (!TLScontext)
-+      msg_fatal("Called tls_timed_read() without TLS-context");
-+ 
-+    ret = do_tls_operation(fd, timeout, TLScontext, NULL, SSL_read, NULL,
-+                        (char *)buf, buf_len);
-+    if ((pfixtls_serveractive && var_smtpd_tls_loglevel >= 4) ||
-+        (pfixtls_clientactive && var_smtp_tls_loglevel >= 4)) {
-+      mybuf2 = (char *) buf;
-+      if (ret > 0) {
-+          i = 0;
-+          while ((i < 39) && (i < ret) && (mybuf2[i] != 0)) {
-+              mybuf[i] = mybuf2[i];
-+              i++;
-+          }
-+          mybuf[i] = '\0';
-+          msg_info("Read %d chars: %s", ret, mybuf);
-+      }
-+    }
-+    return (ret);
-+}
-+
-+int pfixtls_timed_write(int fd, void *buf, unsigned len, int timeout,
-+                      void *context)
-+{
-+    int     i;
-+    char    mybuf[40];
-+    char   *mybuf2;
-+    TLScontext_t *TLScontext;
-+
-+    TLScontext = (TLScontext_t *)context;
-+    if (!TLScontext)
-+      msg_fatal("Called tls_timed_write() without TLS-context");
-+
-+    if ((pfixtls_serveractive && var_smtpd_tls_loglevel >= 4) ||
-+      (pfixtls_clientactive && var_smtp_tls_loglevel >= 4)) {
-+      mybuf2 = (char *) buf;
-+      if (len > 0) {
-+          i = 0;
-+          while ((i < 39) && (i < len) && (mybuf2[i] != 0)) {
-+              mybuf[i] = mybuf2[i];
-+              i++;
-+          }
-+          mybuf[i] = '\0';
-+          msg_info("Write %d chars: %s", len, mybuf);
-+      }
-+    }
-+    return (do_tls_operation(fd, timeout, TLScontext, NULL, NULL, SSL_write,
-+                           buf, len));
-+}
-+
-+/* Add some more entropy to the pool by adding the actual time */
-+
-+static void pfixtls_stir_seed(void)
-+{
-+    GETTIMEOFDAY(&randseed.tv);
-+    RAND_seed(&randseed, sizeof(randseed_t));
-+}
-+
-+/*
-+ * Skeleton taken from OpenSSL crypto/err/err_prn.c.
-+ * Query the error stack and print the error string into the logging facility.
-+ * Clear the error stack on the way.
-+ */
-+
-+static void pfixtls_print_errors(void)
-+{
-+    unsigned long l;
-+    char    buf[256];
-+    const char   *file;
-+    const char   *data;
-+    int     line;
-+    int     flags;
-+    unsigned long es;
-+
-+    es = CRYPTO_thread_id();
-+    while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) {
-+      if (flags & ERR_TXT_STRING)
-+          msg_info("%lu:%s:%s:%d:%s:", es, ERR_error_string(l, buf),
-+                   file, line, data);
-+      else
-+          msg_info("%lu:%s:%s:%d:", es, ERR_error_string(l, buf),
-+                   file, line);
-+    }
-+}
-+
-+ /*
-+  * Set up the cert things on the server side. We do need both the
-+  * private key (in key_file) and the cert (in cert_file).
-+  * Both files may be identical.
-+  *
-+  * This function is taken from OpenSSL apps/s_cb.c
-+  */
-+
-+static int set_cert_stuff(SSL_CTX * ctx, char *cert_file, char *key_file)
-+{
-+    if (cert_file != NULL) {
-+      if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) {
-+          msg_info("unable to get certificate from '%s'", cert_file);
-+          pfixtls_print_errors();
-+          return (0);
-+      }
-+      if (key_file == NULL)
-+          key_file = cert_file;
-+      if (SSL_CTX_use_PrivateKey_file(ctx, key_file,
-+                                      SSL_FILETYPE_PEM) <= 0) {
-+          msg_info("unable to get private key from '%s'", key_file);
-+          pfixtls_print_errors();
-+          return (0);
-+      }
-+      /* Now we know that a key and cert have been set against
-+         * the SSL context */
-+      if (!SSL_CTX_check_private_key(ctx)) {
-+          msg_info("Private key does not match the certificate public key");
-+          return (0);
-+      }
-+    }
-+    return (1);
-+}
-+
-+/* taken from OpenSSL apps/s_cb.c */
-+
-+static RSA *tmp_rsa_cb(SSL * s, int export, int keylength)
-+{
-+    static RSA *rsa_tmp = NULL;
-+
-+    if (rsa_tmp == NULL) {
-+      rsa_tmp = RSA_generate_key(keylength, RSA_F4, NULL, NULL);
-+    }
-+    return (rsa_tmp);
-+}
-+
-+
-+static DH *get_dh512(void)
-+{
-+    DH *dh;
-+
-+    if (dh_512 == NULL) {
-+      /* No parameter file loaded, use the compiled in parameters */
-+      if ((dh = DH_new()) == NULL) return(NULL);
-+      dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
-+      dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
-+      if ((dh->p == NULL) || (dh->g == NULL))
-+          return(NULL);
-+      else
-+          dh_512 = dh;
-+    }
-+    return (dh_512);
-+}
-+
-+static DH *get_dh1024(void)
-+{
-+    DH *dh;
-+
-+    if (dh_1024 == NULL) {
-+      /* No parameter file loaded, use the compiled in parameters */
-+      if ((dh = DH_new()) == NULL) return(NULL);
-+      dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
-+      dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL);
-+      if ((dh->p == NULL) || (dh->g == NULL))
-+          return(NULL);
-+      else
-+          dh_1024 = dh;
-+    }
-+    return (dh_1024);
-+}
-+
-+/* partly inspired by mod_ssl */
-+
-+static DH *tmp_dh_cb(SSL *s, int export, int keylength)
-+{
-+    DH *dh_tmp = NULL;
-+   
-+    if (export) {
-+      if (keylength == 512)
-+          dh_tmp = get_dh512();       /* export cipher */
-+      else if (keylength == 1024)
-+          dh_tmp = get_dh1024();      /* normal */
-+      else
-+          dh_tmp = get_dh1024();      /* not on-the-fly (too expensive) */
-+                                      /* so use the 1024bit instead */
-+    }
-+    else {
-+      dh_tmp = get_dh1024();          /* sign-only certificate */
-+    }
-+    return (dh_tmp);
-+}
-+
-+
-+/*
-+ * Skeleton taken from OpenSSL apps/s_cb.c
-+ *
-+ * The verify_callback is called several times (directly or indirectly) from
-+ * crypto/x509/x509_vfy.c. It is called as a last check for several issues,
-+ * so this verify_callback() has the famous "last word". If it does return "0",
-+ * the handshake is immediately shut down and the connection fails.
-+ *
-+ * Postfix/TLS has two modes, the "use" mode and the "enforce" mode:
-+ *
-+ * In the "use" mode we never want the connection to fail just because there is
-+ * something wrong with the certificate (as we would have sent happily without
-+ * TLS).  Therefore the return value is always "1".
-+ *
-+ * In the "enforce" mode we can shut down the connection as soon as possible.
-+ * In server mode TLS itself may be enforced (e.g. to protect passwords),
-+ * but certificates are optional. In this case the handshake must not fail
-+ * if we are unhappy with the certificate and return "1" in any case.
-+ * Only if a certificate is required the certificate must pass the verification
-+ * and failure to do so will result in immediate termination (return 0).
-+ * In the client mode the decision is made with respect to the peername
-+ * enforcement. If we strictly enforce the matching of the expected peername
-+ * the verification must fail immediatly on verification errors. We can also
-+ * immediatly check the expected peername, as it is the CommonName at level 0.
-+ * In all other cases, the problem is logged, so the SSL_get_verify_result()
-+ * will inform about the verification failure, but the handshake (and SMTP
-+ * connection will continue).
-+ *
-+ * The only error condition not handled inside the OpenSSL-Library is the
-+ * case of a too-long certificate chain, so we check inside verify_callback().
-+ * We only take care of this problem, if "ok = 1", because otherwise the
-+ * verification already failed because of another problem and we don't want
-+ * to overwrite the other error message. And if the verification failed,
-+ * there is no such thing as "more failed", "most failed"... :-)
-+ */
-+
-+static int verify_callback(int ok, X509_STORE_CTX * ctx)
-+{
-+    char    buf[256];
-+    char   *CN_lowercase;
-+    X509   *err_cert;
-+    int     err;
-+    int     depth;
-+    int     verify_depth;
-+    SSL    *con;
-+    TLScontext_t *TLScontext;
-+
-+    err_cert = X509_STORE_CTX_get_current_cert(ctx);
-+    err = X509_STORE_CTX_get_error(ctx);
-+    depth = X509_STORE_CTX_get_error_depth(ctx);
-+
-+    con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
-+    TLScontext = SSL_get_ex_data(con, TLScontext_index);
-+
-+    X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
-+    if (((pfixtls_serverengine) && (var_smtpd_tls_loglevel >= 2)) ||
-+      ((pfixtls_clientengine) && (var_smtp_tls_loglevel >= 2)))
-+      msg_info("Peer cert verify depth=%d %s", depth, buf);
-+
-+    verify_depth = SSL_get_verify_depth(con);
-+    if (ok && (verify_depth >= 0) && (depth > verify_depth)) {
-+      ok = 0;
-+      err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
-+      X509_STORE_CTX_set_error(ctx, err);
-+    }
-+    if (!ok) {
-+      msg_info("verify error:num=%d:%s", err,
-+               X509_verify_cert_error_string(err));
-+    }
-+
-+    if (ok && (depth == 0) && TLScontext->enforce_verify_errors
-+                         && TLScontext->enforce_CN) {
-+      X509_NAME_get_text_by_NID(X509_get_subject_name(err_cert),
-+                          NID_commonName, buf, 256);
-+      CN_lowercase = lowercase(buf);
-+      if (strcmp(TLScontext->peername_save, CN_lowercase)) {
-+          err = X509_V_ERR_CERT_REJECTED;
-+          X509_STORE_CTX_set_error(ctx, err);
-+          msg_info("Verify failure: CommonName in certificate does not match: %s != %s", CN_lowercase, TLScontext->peername_save);
-+          ok = 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);
-+      msg_info("issuer= %s", buf);
-+      break;
-+    case X509_V_ERR_CERT_NOT_YET_VALID:
-+    case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
-+      msg_info("cert not yet valid");
-+      break;
-+    case X509_V_ERR_CERT_HAS_EXPIRED:
-+    case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
-+      msg_info("cert has expired");
-+      break;
-+    }
-+    if (((pfixtls_serverengine) && (var_smtpd_tls_loglevel >= 2)) ||
-+      ((pfixtls_clientengine) && (var_smtp_tls_loglevel >= 2)))
-+      msg_info("verify return:%d", ok);
-+
-+    if (TLScontext->enforce_verify_errors)
-+      return (ok); 
-+    else
-+      return (1);
-+}
-+
-+/* taken from OpenSSL apps/s_cb.c */
-+
-+static void apps_ssl_info_callback(SSL * s, int where, int ret)
-+{
-+    char   *str;
-+    int     w;
-+
-+    w = where & ~SSL_ST_MASK;
-+
-+    if (w & SSL_ST_CONNECT)
-+      str = "SSL_connect";
-+    else if (w & SSL_ST_ACCEPT)
-+      str = "SSL_accept";
-+    else
-+      str = "undefined";
-+
-+    if (where & SSL_CB_LOOP) {
-+          msg_info("%s:%s", str, SSL_state_string_long(s));
-+    } else if (where & SSL_CB_ALERT) {
-+      str = (where & SSL_CB_READ) ? "read" : "write";
-+      if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY)
-+      msg_info("SSL3 alert %s:%s:%s", str,
-+               SSL_alert_type_string_long(ret),
-+               SSL_alert_desc_string_long(ret));
-+    } else if (where & SSL_CB_EXIT) {
-+      if (ret == 0)
-+          msg_info("%s:failed in %s",
-+                   str, SSL_state_string_long(s));
-+      else if (ret < 0) {
-+          msg_info("%s:error in %s",
-+                   str, SSL_state_string_long(s));
-+      }
-+    }
-+}
-+
-+/*
-+ * taken from OpenSSL crypto/bio/b_dump.c, modified to save a lot of strcpy
-+ * and strcat by Matti Aarnio.
-+ */
-+
-+#define TRUNCATE
-+#define DUMP_WIDTH    16
-+
-+static int pfixtls_dump(const char *s, int len)
-+{
-+    int     ret = 0;
-+    char    buf[160 + 1];
-+    char    *ss;
-+    int     i;
-+    int     j;
-+    int     rows;
-+    int     trunc;
-+    unsigned char ch;
-+
-+    trunc = 0;
-+
-+#ifdef TRUNCATE
-+    for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--)
-+      trunc++;
-+#endif
-+
-+    rows = (len / DUMP_WIDTH);
-+    if ((rows * DUMP_WIDTH) < len)
-+      rows++;
-+
-+    for (i = 0; i < rows; i++) {
-+      buf[0] = '\0';                          /* start with empty string */
-+      ss = buf;
-+
-+      sprintf(ss, "%04x ", i * DUMP_WIDTH);
-+      ss += strlen(ss);
-+      for (j = 0; j < DUMP_WIDTH; j++) {
-+          if (((i * DUMP_WIDTH) + j) >= len) {
-+              strcpy(ss, "   ");
-+          } else {
-+              ch = ((unsigned char) *((char *) (s) + i * DUMP_WIDTH + j))
-+                  & 0xff;
-+              sprintf(ss, "%02x%c", ch, j == 7 ? '|' : ' ');
-+              ss += 3;
-+          }
-+      }
-+      ss += strlen(ss);
-+      *ss++ = ' ';
-+      for (j = 0; j < DUMP_WIDTH; j++) {
-+          if (((i * DUMP_WIDTH) + j) >= len)
-+              break;
-+          ch = ((unsigned char) *((char *) (s) + i * DUMP_WIDTH + j)) & 0xff;
-+          *ss++ = (((ch >= ' ') && (ch <= '~')) ? ch : '.');
-+          if (j == 7) *ss++ = ' ';
-+      }
-+      *ss = 0;
-+      /* 
-+       * if this is the last call then update the ddt_dump thing so that
-+         * we will move the selection point in the debug window
-+         */
-+      msg_info("%s", buf);
-+      ret += strlen(buf);
-+    }
-+#ifdef TRUNCATE
-+    if (trunc > 0) {
-+      sprintf(buf, "%04x - <SPACES/NULS>\n", len + trunc);
-+      msg_info("%s", buf);
-+      ret += strlen(buf);
-+    }
-+#endif
-+    return (ret);
-+}
-+
-+
-+
-+/* taken from OpenSSL apps/s_cb.c */
-+
-+static long bio_dump_cb(BIO * bio, int cmd, const char *argp, int argi,
-+                      long argl, long ret)
-+{
-+    if (!do_dump)
-+      return (ret);
-+
-+    if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) {
-+      msg_info("read from %08X [%08lX] (%d bytes => %ld (0x%X))", bio, argp,
-+               argi, ret, ret);
-+      pfixtls_dump(argp, (int) ret);
-+      return (ret);
-+    } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) {
-+      msg_info("write to %08X [%08lX] (%d bytes => %ld (0x%X))", bio, argp,
-+               argi, ret, ret);
-+      pfixtls_dump(argp, (int) ret);
-+    }
-+    return (ret);
-+}
-+
-+
-+ /*
-+  * Callback to retrieve a session from the external session cache.
-+  */
-+static SSL_SESSION *get_session_cb(SSL *ssl, unsigned char *SessionID,
-+                                int length, int *copy)
-+{
-+    SSL_SESSION *session;
-+    char *idstring;
-+    int n;
-+    int uselength;
-+    int hex_length;
-+    const char *session_hex;
-+    pfixtls_scache_info_t scache_info;
-+    unsigned char nibble, *data, *sess_data;
-+
-+    if (length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = length;
-+
-+    idstring = (char *)mymalloc(2 * uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return (NULL);
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      sprintf(idstring + 2 * n, "%02x", SessionID[n]);
-+    if (var_smtpd_tls_loglevel >= 3)
-+      msg_info("Trying to reload Session from disc: %s", idstring);
-+
-+    session = NULL;
-+
-+    session_hex = dict_get(scache_db, idstring);
-+    if (session_hex) {
-+      hex_length = strlen(session_hex);
-+      data = (unsigned char *)mymalloc(hex_length / 2);
-+      if (!data) {
-+          msg_info("could not allocate memory for session reload");
-+          myfree(idstring);
-+          return(NULL);
-+      }
-+
-+      memset(data, 0, hex_length / 2);
-+      for (n = 0; n < hex_length; n++) {
-+          if ((session_hex[n] >= '0') && (session_hex[n] <= '9'))
-+              nibble = session_hex[n] - '0';
-+          else
-+              nibble = session_hex[n] - 'A' + 10;
-+          if (n % 2)
-+              data[n / 2] |= nibble;
-+          else
-+              data[n / 2] |= (nibble << 4);
-+      }
-+
-+      /*
-+       * First check the version numbers, since wrong session data might
-+       * hit us hard (SEGFAULT). We also have to check for expiry.
-+       */
-+      memcpy(&scache_info, data, sizeof(pfixtls_scache_info_t));
-+      if ((scache_info.scache_db_version != scache_db_version) ||
-+          (scache_info.openssl_version != openssl_version) ||
-+          (scache_info.timestamp + var_smtpd_tls_scache_timeout < time(NULL)))
-+          dict_del(scache_db, idstring);
-+      else {
-+          sess_data = data + sizeof(pfixtls_scache_info_t);
-+          session = d2i_SSL_SESSION(NULL, &sess_data,
-+                            hex_length / 2 - sizeof(pfixtls_scache_info_t));
-+          if (!session)
-+              pfixtls_print_errors();
-+      }
-+      myfree((char *)data);
-+    }
-+
-+    if (session && (var_smtpd_tls_loglevel >= 3))
-+      msg_info("Successfully reloaded session from disc");
-+
-+    myfree(idstring);
-+    return (session);
-+}
-+
-+
-+static SSL_SESSION *load_clnt_session(const char *hostname)
-+{
-+    SSL_SESSION *session = NULL;
-+    char *idstring;
-+    int n;
-+    int uselength;
-+    int length;
-+    int hex_length;
-+    const char *session_hex;
-+    pfixtls_scache_info_t scache_info;
-+    unsigned char nibble, *data, *sess_data;
-+
-+    length = strlen(hostname); 
-+    if (length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = length;
-+
-+    idstring = (char *)mymalloc(uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return (NULL);
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      idstring[n] = tolower(hostname[n]);
-+    idstring[uselength] = '\0';
-+    if (var_smtp_tls_loglevel >= 3)
-+      msg_info("Trying to reload Session from disc: %s", idstring);
-+
-+    session_hex = dict_get(scache_db, idstring);
-+    if (session_hex) {
-+      hex_length = strlen(session_hex);
-+      data = (unsigned char *)mymalloc(hex_length / 2);
-+      if (!data) {
-+          msg_info("could not allocate memory for session reload");
-+          myfree(idstring);
-+          return(NULL);
-+      }
-+
-+      memset(data, 0, hex_length / 2);
-+      for (n = 0; n < hex_length; n++) {
-+          if ((session_hex[n] >= '0') && (session_hex[n] <= '9'))
-+              nibble = session_hex[n] - '0';
-+          else
-+              nibble = session_hex[n] - 'A' + 10;
-+          if (n % 2)
-+              data[n / 2] |= nibble;
-+          else
-+              data[n / 2] |= (nibble << 4);
-+      }
-+
-+      /*
-+       * First check the version numbers, since wrong session data might
-+       * hit us hard (SEGFAULT). We also have to check for expiry.
-+       */
-+      memcpy(&scache_info, data, sizeof(pfixtls_scache_info_t));
-+      if ((scache_info.scache_db_version != scache_db_version) ||
-+          (scache_info.openssl_version != openssl_version) ||
-+          (scache_info.timestamp + var_smtpd_tls_scache_timeout < time(NULL)))
-+          dict_del(scache_db, idstring);
-+      else {
-+          sess_data = data + sizeof(pfixtls_scache_info_t);
-+          session = d2i_SSL_SESSION(NULL, &sess_data,
-+                                    hex_length / 2 - sizeof(time_t));
-+          if (!session)
-+              pfixtls_print_errors();
-+      }
-+      myfree((char *)data);
-+    }
-+
-+    myfree(idstring);
-+
-+    if (session && (var_smtp_tls_loglevel >= 3))
-+        msg_info("Successfully reloaded session from disc");
-+
-+    return (session);
-+}
-+
-+
-+static void remove_srvr_session(unsigned char *SessionID, int length)
-+{
-+    VSTRING *buf;
-+    char *idstring;
-+    int n;
-+    int uselength;
-+
-+    if (length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = length;
-+
-+    idstring = (char *)mymalloc(2 * uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return;
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      sprintf(idstring + 2 * n, "%02x", SessionID[n]);
-+    if (var_smtpd_tls_loglevel >= 3)
-+      msg_info("Trying to remove session from disc: %s", idstring);
-+
-+    if (scache_db)
-+      dict_del(scache_db, idstring);
-+
-+    myfree(idstring);
-+}
-+
-+
-+static void remove_clnt_session(const char *hostname)
-+{
-+    char *idstring;
-+    int n;
-+    int uselength;
-+    int length;
-+
-+    length = strlen(hostname);
-+    if (length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = length;
-+
-+    idstring = (char *)mymalloc(uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return;
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      idstring[n] = tolower(hostname[n]);
-+    idstring[uselength] = '\0'; 
-+    if (var_smtp_tls_loglevel >= 3)
-+      msg_info("Trying to remove session from disc: %s", idstring);
-+    if (scache_db)
-+      dict_del(scache_db, idstring);
-+    myfree(idstring);
-+}
-+
-+
-+ /*
-+  * Save a new session to the external cache
-+  */
-+static int new_session_cb(SSL *ssl, SSL_SESSION *session)
-+{
-+    char *idstring;
-+    int n;
-+    int uselength;
-+    int dsize;
-+    int len;
-+    unsigned char *data, *sess_data;
-+    pfixtls_scache_info_t scache_info;
-+    char *hexdata;
-+
-+    if (session->session_id_length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = session->session_id_length;
-+
-+    idstring = (char *)mymalloc(2 * uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return 0;
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      sprintf(idstring + 2 * n, "%02x", session->session_id[n]);
-+
-+    if (var_smtpd_tls_loglevel >= 3)
-+      msg_info("Trying to save Session to disc: %s", idstring);
-+
-+    /*
-+     * Get the session and convert it into some "database" useable form.
-+     * First, get the length of the session to allocate the memory.
-+     */
-+    dsize = i2d_SSL_SESSION(session, NULL);
-+    if (dsize < 0) {
-+      msg_info("Could not access session");
-+      return 0;
-+    }
-+    data = (unsigned char *)mymalloc(dsize + sizeof(pfixtls_scache_info_t));
-+    if (!data) {
-+      msg_info("could not allocate memory for SSL session");
-+      myfree(idstring);
-+      return 0;
-+    }
-+
-+    /*
-+     * OpenSSL is not robust against wrong session data (might SEGFAULT),
-+     * so we secure it against version ids (session cache structure as well
-+     * as OpenSSL version).
-+     */
-+    scache_info.scache_db_version = scache_db_version;
-+    scache_info.openssl_version = openssl_version;
-+
-+    /*
-+     * Put a timestamp, so that expiration can be checked without
-+     * analyzing the session data itself. (We would need OpenSSL funtions,
-+     * since the SSL_SESSION is a private structure.)
-+     */
-+    scache_info.timestamp = time(NULL);
-+
-+    memcpy(data, &scache_info, sizeof(pfixtls_scache_info_t));
-+    sess_data = data + sizeof(pfixtls_scache_info_t);
-+
-+    /*
-+     * Now, obtain the session. Unfortunately, it is binary and dict_update
-+     * cannot handle binary data (it could contain '\0' in it) directly.
-+     * To save memory we could use base64 encoding. To make handling easier,
-+     * we simply use hex format.
-+     */
-+    len = i2d_SSL_SESSION(session, &sess_data);
-+    len += sizeof(pfixtls_scache_info_t);
-+
-+    hexdata = (char *)mymalloc(2 * len + 1);
-+
-+    if (!hexdata) {
-+      msg_info("could not allocate memory for SSL session (HEX)");
-+      myfree((char *)data);
-+      myfree(idstring);
-+      return 0;
-+    }
-+    for (n = 0; n < len; n++) {
-+      hexdata[n * 2] = hexcodes[(data[n] & 0xf0) >> 4];
-+      hexdata[(n * 2) + 1] = hexcodes[(data[n] & 0x0f)];
-+    }
-+    hexdata[len * 2] = '\0';
-+
-+    /*
-+     * The session id is a hex string, all uppercase. We are using SDBM as
-+     * compiled into Postfix with 8kB maximum entry size, so we set a limit
-+     * when caching. If the session is not cached, we have to renegotiate,
-+     * not more, not less. For a real session, this limit should never be
-+     * met
-+     */
-+    if (strlen(idstring) + strlen(hexdata) < 8000)
-+      dict_put(scache_db, idstring, hexdata);
-+
-+    myfree(hexdata);
-+    myfree((char *)data);
-+    myfree(idstring);
-+    return (0);
-+}
-+
-+
-+ /*
-+  * Save the new session to the external cache. As the HostID is given
-+  * by the contacted peer, we may have several negotiations going on at
-+  * the same time for the same peer. This is not purely hypothetical but
-+  * quite likely if several jobs to the same recipient host are in the queue
-+  * and a queue run is started. So we have to take care of race conditions.
-+  * As I consider the TLS-SessionID to be unique, we will first try to
-+  * create a file with the actual SessionID. Once the writing is finished,
-+  * the file is closed and moved to its final name. This way we should be
-+  * able to deal with race conditions, since rename should be atomic.
-+  * If the rename fails for some reason, we will just silently remove
-+  * the temporary file and forget about the session.
-+  */
-+static void save_clnt_session(SSL_SESSION *session, const char *hostname)
-+{
-+    char *idstring;
-+    int length;
-+    int uselength;
-+    int n;
-+    int len;
-+    int dsize;
-+    unsigned char *data, *sess_data;
-+    pfixtls_scache_info_t scache_info;
-+    char *hexdata;
-+
-+    length = strlen(hostname);
-+    if (length > id_maxlength)
-+      uselength = id_maxlength;       /* Limit length of ID */
-+    else
-+      uselength = length;
-+
-+    idstring = (char *)mymalloc(uselength + 1);
-+    if (!idstring) {
-+      msg_info("could not allocate memory for IDstring");
-+      return;
-+    }
-+
-+    for(n=0 ; n < uselength ; n++)
-+      idstring[n] = tolower(hostname[n]);
-+    idstring[uselength] = '\0';
-+    if (var_smtp_tls_loglevel >= 3)
-+      msg_info("Trying to save session for hostID to disc: %s", idstring);
-+
-+    /*
-+     * Get the session and convert it into some "database" useable form.
-+     * First, get the length of the session to allocate the memory.
-+     */
-+    dsize = i2d_SSL_SESSION(session, NULL);
-+    if (dsize < 0) {
-+      msg_info("Could not access session");
-+      return;
-+    }
-+    data = (unsigned char *)mymalloc(dsize + sizeof(pfixtls_scache_info_t));
-+    if (!data) {
-+      msg_info("could not allocate memory for SSL session");
-+      myfree(idstring);
-+      return;
-+    }
-+
-+    /*
-+     * OpenSSL is not robust against wrong session data (might SEGFAULT),
-+     * so we secure it against version ids (session cache structure as well
-+     * as OpenSSL version).
-+     */
-+    scache_info.scache_db_version = scache_db_version;
-+    scache_info.openssl_version = openssl_version;
-+
-+    /*
-+     * Put a timestamp, so that expiration can be checked without
-+     * analyzing the session data itself. (We would need OpenSSL funtions,
-+     * since the SSL_SESSION is a private structure.)
-+     */
-+    scache_info.timestamp = time(NULL);
-+
-+    memcpy(data, &scache_info, sizeof(pfixtls_scache_info_t));
-+    sess_data = data + sizeof(pfixtls_scache_info_t);
-+
-+    /*
-+     * Now, obtain the session. Unfortunately, it is binary and dict_update
-+     * cannot handle binary data (it could contain '\0' in it) directly.
-+     * To save memory we could use base64 encoding. To make handling easier,
-+     * we simply use hex format.
-+     */
-+    len = i2d_SSL_SESSION(session, &sess_data);
-+    len += sizeof(pfixtls_scache_info_t);
-+
-+    hexdata = (char *)mymalloc(2 * len + 1);
-+
-+    if (!hexdata) {
-+      msg_info("could not allocate memory for SSL session (HEX)");
-+      myfree((char *)data);
-+      myfree(idstring);
-+      return;
-+    }
-+    for (n = 0; n < len; n++) {
-+      hexdata[n * 2] = hexcodes[(data[n] & 0xf0) >> 4];
-+      hexdata[(n * 2) + 1] = hexcodes[(data[n] & 0x0f)];
-+    }
-+    hexdata[len * 2] = '\0';
-+
-+    /*
-+     * The session id is a hex string, all uppercase. We are using SDBM as
-+     * compiled into Postfix with 8kB maximum entry size, so we set a limit
-+     * when caching. If the session is not cached, we have to renegotiate,
-+     * not more, not less. For a real session, this limit should never be
-+     * met
-+     */
-+    if (strlen(idstring) + strlen(hexdata) < 8000)
-+      dict_put(scache_db, idstring, hexdata);
-+
-+    myfree(hexdata);
-+    myfree((char *)data);
-+    myfree(idstring);
-+}
-+
-+ /*
-+  * pfixtls_exchange_seed: read bytes from the seed exchange-file (expect
-+  * 1024 bytes)and immediately write back random bytes. Do so with EXCLUSIVE
-+  * lock, so * that each process will find a completely different (and
-+  * reseeded) file.
-+  */
-+static void pfixtls_exchange_seed(void)
-+{
-+    unsigned char buffer[1024];
-+
-+    if (rand_exch_fd == -1)
-+      return;
-+
-+    if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0)
-+        msg_info("Could not lock random exchange file: %s",
-+                  strerror(errno));
-+
-+    lseek(rand_exch_fd, 0, SEEK_SET);
-+    if (read(rand_exch_fd, buffer, 1024) < 0)
-+        msg_fatal("reading exchange file failed");
-+    RAND_seed(buffer, 1024);
-+
-+    RAND_bytes(buffer, 1024);
-+    lseek(rand_exch_fd, 0, SEEK_SET);
-+    if (write(rand_exch_fd, buffer, 1024) != 1024)
-+        msg_fatal("Writing exchange file failed");
-+
-+    if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0)
-+        msg_fatal("Could not unlock random exchange file: %s",
-+                  strerror(errno));
-+}
-+
-+ /*
-+  * This is the setup routine for the SSL server. As smtpd might be called
-+  * more than once, we only want to do the initialization one time.
-+  *
-+  * The skeleton of this function is taken from OpenSSL apps/s_server.c.
-+  */
-+
-+int     pfixtls_init_serverengine(int verifydepth, int askcert)
-+{
-+    int     off = 0;
-+    int     verify_flags = SSL_VERIFY_NONE;
-+    int     rand_bytes;
-+    int     rand_source_dev_fd;
-+    int     rand_source_socket_fd;
-+    unsigned char buffer[255];
-+    char   *CApath;
-+    char   *CAfile;
-+    char   *s_cert_file;
-+    char   *s_key_file;
-+    char   *s_dcert_file;
-+    char   *s_dkey_file;
-+    FILE   *paramfile;
-+
-+    if (pfixtls_serverengine)
-+      return (0);                             /* already running */
-+
-+    if (var_smtpd_tls_loglevel >= 2)
-+      msg_info("starting TLS engine");
-+
-+    /*
-+     * Initialize the OpenSSL library by the book!
-+     * To start with, we must initialize the algorithms.
-+     * We want cleartext error messages instead of just error codes, so we
-+     * load the error_strings.
-+     */
-+    SSL_load_error_strings();
-+    OpenSSL_add_ssl_algorithms();
-+
-+ /*
-+  * Side effect, call a non-existing function to disable TLS usage with an
-+  * outdated OpenSSL version. There is a security reason (verify_result
-+  * is not stored with the session data).
-+  */
-+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
-+    needs_openssl_095_or_later();
-+#endif
-+
-+    /*
-+     * Initialize the PRNG Pseudo Random Number Generator with some seed.
-+     */
-+    randseed.pid = getpid();
-+    GETTIMEOFDAY(&randseed.tv);
-+    RAND_seed(&randseed, sizeof(randseed_t));
-+
-+    /*
-+     * Access the external sources for random seed. We will only query them
-+     * once, this should be sufficient and we will stir our entropy by using
-+     * the prng-exchange file anyway.
-+     * For reliability, we don't consider failure to access the additional
-+     * source fatal, as we can run happily without it (considering that we
-+     * still have the exchange-file). We also don't care how much entropy
-+     * we get back, as we must run anyway. We simply stir in the buffer
-+     * regardless how many bytes are actually in it.
-+     */
-+    if (*var_tls_daemon_rand_source) {
-+      if (!strncmp(var_tls_daemon_rand_source, "dev:", 4)) {
-+          /*
-+           * Source is a random device
-+           */
-+          rand_source_dev_fd = open(var_tls_daemon_rand_source + 4, 0, 0);
-+          if (rand_source_dev_fd == -1) 
-+              msg_info("Could not open entropy device %s",
-+                        var_tls_daemon_rand_source);
-+          else {
-+              if (var_tls_daemon_rand_bytes > 255)
-+                  var_tls_daemon_rand_bytes = 255;
-+              read(rand_source_dev_fd, buffer, var_tls_daemon_rand_bytes);
-+              RAND_seed(buffer, var_tls_daemon_rand_bytes);
-+              close(rand_source_dev_fd);
-+          }
-+      } else if (!strncmp(var_tls_daemon_rand_source, "egd:", 4)) {
-+          /*
-+           * Source is a EGD compatible socket
-+           */
-+          rand_source_socket_fd = unix_connect(var_tls_daemon_rand_source +4,
-+                                               BLOCKING, 10);
-+          if (rand_source_socket_fd == -1)
-+              msg_info("Could not connect to %s", var_tls_daemon_rand_source);
-+          else {
-+              if (var_tls_daemon_rand_bytes > 255)
-+                  var_tls_daemon_rand_bytes = 255;
-+              buffer[0] = 1;
-+              buffer[1] = var_tls_daemon_rand_bytes;
-+              if (write(rand_source_socket_fd, buffer, 2) != 2)
-+                  msg_info("Could not talk to %s",
-+                           var_tls_daemon_rand_source);
-+              else if (read(rand_source_socket_fd, buffer, 1) != 1)
-+                  msg_info("Could not read info from %s",
-+                           var_tls_daemon_rand_source);
-+              else {
-+                  rand_bytes = buffer[0];
-+                  read(rand_source_socket_fd, buffer, rand_bytes);
-+                  RAND_seed(buffer, rand_bytes);
-+              }
-+              close(rand_source_socket_fd);
-+          }
-+      } else {
-+          RAND_load_file(var_tls_daemon_rand_source,
-+                         var_tls_daemon_rand_bytes);
-+      }
-+    }
-+
-+    if (*var_tls_rand_exch_name) {
-+      rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600);
-+      if (rand_exch_fd != -1)
-+          pfixtls_exchange_seed();
-+    }
-+
-+    randseed.pid = getpid();
-+    GETTIMEOFDAY(&randseed.tv);
-+    RAND_seed(&randseed, sizeof(randseed_t));
-+
-+    /*
-+     * The SSL/TLS speficications require the client to send a message in
-+     * the oldest specification it understands with the highest level it
-+     * understands in the message.
-+     * Netscape communicator can still communicate with SSLv2 servers, so it
-+     * sends out a SSLv2 client hello. To deal with it, our server must be
-+     * SSLv2 aware (even if we don´t like SSLv2), so we need to have the
-+     * SSLv23 server here. If we want to limit the protocol level, we can
-+     * add an option to not use SSLv2/v3/TLSv1 later.
-+     */
-+    ctx = SSL_CTX_new(SSLv23_server_method());
-+    if (ctx == NULL) {
-+      pfixtls_print_errors();
-+      return (-1);
-+    };
-+
-+    /*
-+     * Here we might set SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1.
-+     * Of course, the last one would not make sense, since RFC2487 is only
-+     * defined for TLS, but we also want to accept Netscape communicator
-+     * requests, and it only supports SSLv3.
-+     */
-+    off |= SSL_OP_ALL;                /* Work around all known bugs */
-+    SSL_CTX_set_options(ctx, off);
-+
-+    /*
-+     * Set the info_callback, that will print out messages during
-+     * communication on demand.
-+     */
-+    if (var_smtpd_tls_loglevel >= 2)
-+      SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
-+
-+    /*
-+     * Set the list of ciphers, if explicitely given; otherwise the
-+     * (reasonable) default list is kept.
-+     */
-+    if (strlen(var_smtpd_tls_cipherlist) != 0)
-+      if (SSL_CTX_set_cipher_list(ctx, var_smtpd_tls_cipherlist) == 0) {
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+
-+    /*
-+     * Now we must add the necessary certificate stuff: A server key, a
-+     * server certificate, and the CA certificates for both the server
-+     * cert and the verification of client certificates.
-+     * As provided by OpenSSL we support two types of CA certificate handling:
-+     * One possibility is to add all CA certificates to one large CAfile,
-+     * the other possibility is a directory pointed to by CApath, containing
-+     * seperate files for each CA pointed on by softlinks named by the hash
-+     * values of the certificate.
-+     * The first alternative has the advantage, that the file is opened and
-+     * read at startup time, so that you don´t have the hassle to maintain
-+     * another copy of the CApath directory for chroot-jail. On the other
-+     * hand, the file is not really readable.
-+     */
-+    if (strlen(var_smtpd_tls_CAfile) == 0)
-+      CAfile = NULL;
-+    else
-+      CAfile = var_smtpd_tls_CAfile;
-+    if (strlen(var_smtpd_tls_CApath) == 0)
-+      CApath = NULL;
-+    else
-+      CApath = var_smtpd_tls_CApath;
-+
-+    if (CAfile || CApath) {
-+      if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) {
-+          msg_info("TLS engine: cannot load CA data");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+      if (!SSL_CTX_set_default_verify_paths(ctx)) {
-+          msg_info("TLS engine: cannot set verify paths");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+    }
-+
-+    /*
-+     * Now we load the certificate and key from the files and check,
-+     * whether the cert matches the key (internally done by set_cert_stuff().
-+     * We cannot run without (we do not support ADH anonymous Diffie-Hellman
-+     * ciphers as of now).
-+     * We can use RSA certificates ("cert") and DSA certificates ("dcert"),
-+     * both can be made available at the same time. The CA certificates for
-+     * both are handled in the same setup already finished.
-+     * Which one is used depends on the cipher negotiated (that is: the first
-+     * cipher listed by the client which does match the server). A client with
-+     * RSA only (e.g. Netscape) will use the RSA certificate only.
-+     * A client with openssl-library will use RSA first if not especially
-+     * changed in the cipher setup.
-+     */
-+    if (strlen(var_smtpd_tls_cert_file) == 0)
-+      s_cert_file = NULL;
-+    else
-+      s_cert_file = var_smtpd_tls_cert_file;
-+    if (strlen(var_smtpd_tls_key_file) == 0)
-+      s_key_file = NULL;
-+    else
-+      s_key_file = var_smtpd_tls_key_file;
-+
-+    if (strlen(var_smtpd_tls_dcert_file) == 0)
-+      s_dcert_file = NULL;
-+    else
-+      s_dcert_file = var_smtpd_tls_dcert_file;
-+    if (strlen(var_smtpd_tls_dkey_file) == 0)
-+      s_dkey_file = NULL;
-+    else
-+      s_dkey_file = var_smtpd_tls_dkey_file;
-+
-+    if (s_cert_file) {
-+      if (!set_cert_stuff(ctx, s_cert_file, s_key_file)) {
-+          msg_info("TLS engine: cannot load RSA cert/key data");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+    }
-+    if (s_dcert_file) {
-+      if (!set_cert_stuff(ctx, s_dcert_file, s_dkey_file)) {
-+          msg_info("TLS engine: cannot load DSA cert/key data");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+    }
-+    if (!s_cert_file && !s_dcert_file) {
-+      msg_info("TLS engine: do need at least RSA _or_ DSA cert/key data");
-+      return (-1);
-+    }
-+
-+    /*
-+     * Sometimes a temporary RSA key might be needed by the OpenSSL
-+     * library. The OpenSSL doc indicates, that this might happen when
-+     * export ciphers are in use. We have to provide one, so well, we
-+     * just do it.
-+     */
-+    SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
-+
-+    /*
-+     * We might also need dh parameters, which can either be loaded from
-+     * file (preferred) or we simply take the compiled in values.
-+     * First, set the callback that will select the values when requested,
-+     * then load the (possibly) available DH parameters from files.
-+     * We are generous with the error handling, since we do have default
-+     * values compiled in, so we will not abort but just log the error message.
-+     */
-+    SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_cb);
-+    if (strlen(var_smtpd_tls_dh1024_param_file) != 0) {
-+      if ((paramfile = fopen(var_smtpd_tls_dh1024_param_file, "r")) != NULL) {
-+          dh_1024 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
-+          if (dh_1024 == NULL) {
-+              msg_info("TLS engine: cannot load 1024bit DH parameters");
-+              pfixtls_print_errors();
-+          }
-+      }
-+      else {
-+          msg_info("TLS engine: cannot load 1024bit DH parameters: %s: %s",
-+                   var_smtpd_tls_dh1024_param_file, strerror(errno));
-+      }
-+    }
-+    if (strlen(var_smtpd_tls_dh512_param_file) != 0) {
-+      if ((paramfile = fopen(var_smtpd_tls_dh512_param_file, "r")) != NULL) {
-+          dh_512 = PEM_read_DHparams(paramfile, NULL, NULL, NULL);
-+          if (dh_512 == NULL) {
-+              msg_info("TLS engine: cannot load 512bit DH parameters");
-+              pfixtls_print_errors();
-+          }
-+      }
-+      else {
-+          msg_info("TLS engine: cannot load 512bit DH parameters: %s: %s",
-+                   var_smtpd_tls_dh512_param_file, strerror(errno));
-+      }
-+    }
-+
-+    /*
-+     * If we want to check client certificates, we have to indicate it
-+     * in advance. By now we only allow to decide on a global basis.
-+     * If we want to allow certificate based relaying, we must ask the
-+     * client to provide one with SSL_VERIFY_PEER. The client now can
-+     * decide, whether it provides one or not. We can enforce a failure
-+     * of the negotiation with SSL_VERIFY_FAIL_IF_NO_PEER_CERT, if we
-+     * do not allow a connection without one.
-+     * In the "server hello" following the initialization by the "client hello"
-+     * the server must provide a list of CAs it is willing to accept.
-+     * Some clever clients will then select one from the list of available
-+     * certificates matching these CAs. Netscape Communicator will present
-+     * the list of certificates for selecting the one to be sent, or it will
-+     * issue a warning, if there is no certificate matching the available
-+     * CAs.
-+     *
-+     * With regard to the purpose of the certificate for relaying, we might
-+     * like a later negotiation, maybe relaying would already be allowed
-+     * for other reasons, but this would involve severe changes in the
-+     * internal postfix logic, so we have to live with it the way it is.
-+     */
-+    if (askcert)
-+      verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
-+    SSL_CTX_set_verify(ctx, verify_flags, verify_callback);
-+    SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile));
-+
-+    /*
-+     * Initialize the session cache. We only want external caching to
-+     * synchronize between server sessions, so we set it to a minimum value
-+     * of 1. If the external cache is disabled, we won´t cache at all.
-+     * The recall of old sessions "get" and save to disk of just created
-+     * sessions "new" is handled by the appropriate callback functions.
-+     *
-+     * We must not forget to set a session id context to identify to which
-+     * kind of server process the session was related. In our case, the
-+     * context is just the name of the patchkit: "Postfix/TLS".
-+     */
-+    SSL_CTX_sess_set_cache_size(ctx, 1);
-+    SSL_CTX_set_timeout(ctx, var_smtpd_tls_scache_timeout);
-+    SSL_CTX_set_session_id_context(ctx, (void*)&server_session_id_context,
-+                sizeof(server_session_id_context));
-+
-+    /*
-+     * The session cache is realized by an external database file, that
-+     * must be opened before going to chroot jail. Since the session cache
-+     * data can become quite large, "[n]dbm" cannot be used as it has a
-+     * size limit that is by far to small.
-+     */
-+    if (*var_smtpd_tls_scache_db) {
-+      /*
-+       * Insert a test against other dbms here, otherwise while writing
-+       * a session (content to large), we will receive a fatal error!
-+       */
-+      if (strncmp(var_smtpd_tls_scache_db, "sdbm:", 5))
-+          msg_warn("Only sdbm: type allowed for %s",
-+                   var_smtpd_tls_scache_db);
-+      else
-+          scache_db = dict_open(var_smtpd_tls_scache_db, O_RDWR,
-+            DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE);
-+      if (scache_db) {
-+          SSL_CTX_sess_set_get_cb(ctx, get_session_cb);
-+          SSL_CTX_sess_set_new_cb(ctx, new_session_cb);
-+      }
-+      else
-+          msg_warn("Could not open session cache %s",
-+                   var_smtpd_tls_scache_db);
-+    }
-+
-+    /*
-+     * Finally create the global index to access TLScontext information
-+     * inside verify_callback.
-+     */
-+    TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
-+                                          NULL, NULL, NULL);
-+
-+    pfixtls_serverengine = 1;
-+    return (0);
-+}
-+
-+ /*
-+  * This is the actual startup routine for the connection. We expect
-+  * that the buffers are flushed and the "220 Ready to start TLS" was
-+  * send to the client, so that we can immediately can start the TLS
-+  * handshake process.
-+  */
-+int     pfixtls_start_servertls(VSTREAM *stream, int timeout,
-+                              const char *peername, const char *peeraddr,
-+                              tls_info_t *tls_info, int requirecert)
-+{
-+    int     sts;
-+    int     j;
-+    int verify_flags;
-+    unsigned int n;
-+    TLScontext_t *TLScontext;
-+    SSL_SESSION *session;
-+    SSL_CIPHER *cipher;
-+    X509   *peer;
-+
-+    if (!pfixtls_serverengine) {              /* should never happen */
-+      msg_info("tls_engine not running");
-+      return (-1);
-+    }
-+    if (var_smtpd_tls_loglevel >= 1)
-+      msg_info("setting up TLS connection from %s[%s]", peername, peeraddr);
-+
-+    /*
-+     * Allocate a new TLScontext for the new connection and get an SSL
-+     * structure. Add the location of TLScontext to the SSL to later
-+     * retrieve the information inside the verify_callback().
-+     */
-+    TLScontext = (TLScontext_t *)mymalloc(sizeof(TLScontext_t));
-+    if (!TLScontext) {
-+      msg_fatal("Could not allocate 'TLScontext' with mymalloc");
-+    }
-+    if ((TLScontext->con = (SSL *) SSL_new(ctx)) == NULL) {
-+      msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
-+      pfixtls_print_errors();
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
-+      msg_info("Could not set application data for 'TLScontext->con'");
-+      pfixtls_print_errors();
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    /*
-+     * Set the verification parameters to be checked in verify_callback().
-+     */
-+    if (requirecert) {
-+      verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE;
-+      verify_flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-+      TLScontext->enforce_verify_errors = 1;
-+        SSL_set_verify(TLScontext->con, verify_flags, verify_callback);
-+    }
-+    else {
-+      TLScontext->enforce_verify_errors = 0;
-+    }
-+    TLScontext->enforce_CN = 0;
-+
-+    /*
-+     * The TLS connection is realized by a BIO_pair, so obtain the pair.
-+     */
-+    if (!BIO_new_bio_pair(&TLScontext->internal_bio, BIO_bufsiz,
-+                        &TLScontext->network_bio, BIO_bufsiz)) {
-+      msg_info("Could not obtain BIO_pair");
-+      pfixtls_print_errors();
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    /*
-+     * Before really starting anything, try to seed the PRNG a little bit
-+     * more.
-+     */
-+    pfixtls_stir_seed();
-+    pfixtls_exchange_seed();
-+
-+    /*
-+     * Initialize the SSL connection to accept state. This should not be
-+     * necessary anymore since 0.9.3, but the call is still in the library
-+     * and maintaining compatibility never hurts.
-+     */
-+    SSL_set_accept_state(TLScontext->con);
-+
-+    /*
-+     * Connect the SSL-connection with the postfix side of the BIO-pair for
-+     * reading and writing.
-+     */
-+     SSL_set_bio(TLScontext->con, TLScontext->internal_bio,
-+               TLScontext->internal_bio);
-+
-+    /*
-+     * If the debug level selected is high enough, all of the data is
-+     * dumped: 3 will dump the SSL negotiation, 4 will dump everything.
-+     *
-+     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
-+     * Well there is a BIO below the SSL routines that is automatically
-+     * created for us, so we can use it for debugging purposes.
-+     */
-+    if (var_smtpd_tls_loglevel >= 3)
-+      BIO_set_callback(SSL_get_rbio(TLScontext->con), bio_dump_cb);
-+
-+
-+    /* Dump the negotiation for loglevels 3 and 4 */
-+    if (var_smtpd_tls_loglevel >= 3)
-+      do_dump = 1;
-+
-+    /*
-+     * Now we expect the negotiation to begin. This whole process is like a
-+     * black box for us. We totally have to rely on the routines build into
-+     * the OpenSSL library. The only thing we can do we already have done
-+     * by choosing our own callbacks for session caching and certificate
-+     * verification.
-+     *
-+     * Error handling:
-+     * If the SSL handhake fails, we print out an error message and remove
-+     * everything that might be there. A session has to be removed anyway,
-+     * because RFC2246 requires it.
-+     */
-+    sts = do_tls_operation(vstream_fileno(stream), timeout, TLScontext,
-+                         SSL_accept, NULL, NULL, NULL, 0);
-+    if (sts <= 0) {
-+      msg_info("SSL_accept error from %s[%s]: %d", peername, peeraddr, sts);
-+      pfixtls_print_errors();
-+      session = SSL_get_session(TLScontext->con);
-+      if (session && scache_db) {
-+          remove_srvr_session(session->session_id,
-+                              session->session_id_length);
-+          SSL_CTX_remove_session(ctx, session);
-+          if (var_smtpd_tls_loglevel >= 2)
-+              msg_info("SSL session removed");
-+      }
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    /* Only loglevel==4 dumps everything */
-+    if (var_smtpd_tls_loglevel < 4)
-+      do_dump = 0;
-+
-+    /*
-+     * Lets see, whether a peer certificate is available and what is
-+     * the actual information. We want to save it for later use.
-+     */
-+    peer = SSL_get_peer_certificate(TLScontext->con);
-+    if (peer != NULL) {
-+      if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
-+          tls_info->peer_verified = 1;
-+
-+      X509_NAME_oneline(X509_get_subject_name(peer),
-+                        TLScontext->peer_subject, CCERT_BUFSIZ);
-+      if (var_smtpd_tls_loglevel >= 2)
-+          msg_info("subject=%s", TLScontext->peer_subject);
-+      tls_info->peer_subject = TLScontext->peer_subject;
-+      X509_NAME_oneline(X509_get_issuer_name(peer),
-+                        TLScontext->peer_issuer, CCERT_BUFSIZ);
-+      if (var_smtpd_tls_loglevel >= 2)
-+          msg_info("issuer=%s", TLScontext->peer_issuer);
-+      tls_info->peer_issuer = TLScontext->peer_issuer;
-+      if (X509_digest(peer, EVP_md5(), TLScontext->md, &n)) {
-+          for (j = 0; j < (int) n; j++) {
-+              TLScontext->fingerprint[j * 3] =
-+                      hexcodes[(TLScontext->md[j] & 0xf0) >> 4];
-+              TLScontext->fingerprint[(j * 3) + 1] =
-+                      hexcodes[(TLScontext->md[j] & 0x0f)];
-+              if (j + 1 != (int) n)
-+                  TLScontext->fingerprint[(j * 3) + 2] = ':';
-+              else
-+                  TLScontext->fingerprint[(j * 3) + 2] = '\0';
-+          }
-+          if (var_smtpd_tls_loglevel >= 1)
-+              msg_info("fingerprint=%s", TLScontext->fingerprint);
-+          tls_info->peer_fingerprint = TLScontext->fingerprint;
-+      }
-+      X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
-+                        NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ);
-+      tls_info->peer_CN = TLScontext->peer_CN;
-+      X509_NAME_get_text_by_NID(X509_get_issuer_name(peer),
-+                        NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ);
-+      if (var_smtpd_tls_loglevel >= 1) {
-+          if (tls_info->peer_verified)
-+              msg_info("Verified: subject_CN=%s, issuer_CN=%s",
-+                       TLScontext->peer_CN, TLScontext->issuer_CN);
-+          else
-+              msg_info("Unverified: subject_CN=%s, issuer_CN=%s",
-+                       TLScontext->peer_CN, TLScontext->issuer_CN);
-+      }
-+      tls_info->issuer_CN = TLScontext->issuer_CN;
-+      X509_free(peer);
-+    }
-+
-+    /*
-+     * At this point we should have a certificate when required.
-+     * We may however have a cached session, so the callback would never
-+     * be called. We therefore double-check to make sure and remove the
-+     * session, if applicable.
-+     */
-+    if (requirecert) {
-+      if (!tls_info->peer_verified || !tls_info->peer_CN) {
-+          msg_info("Re-used session without peer certificate removed");
-+          remove_srvr_session(session->session_id,
-+                                session->session_id_length);
-+          return (-1);
-+      }
-+    }
-+
-+    /*
-+     * Finally, collect information about protocol and cipher for logging
-+     */
-+    tls_info->protocol = SSL_get_version(TLScontext->con);
-+    cipher = SSL_get_current_cipher(TLScontext->con);
-+    tls_info->cipher_name = SSL_CIPHER_get_name(cipher);
-+    tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher,
-+                                               &(tls_info->cipher_algbits));
-+
-+    pfixtls_serveractive = 1;
-+
-+    /*
-+     * The TLS engine is active, switch to the pfixtls_timed_read/write()
-+     * functions and store the context.
-+     */
-+    vstream_control(stream,
-+                  VSTREAM_CTL_READ_FN, pfixtls_timed_read,
-+                  VSTREAM_CTL_WRITE_FN, pfixtls_timed_write,
-+                  VSTREAM_CTL_CONTEXT, (void *)TLScontext,
-+                  VSTREAM_CTL_END);
-+
-+    msg_info("TLS connection established from %s[%s]: %s with cipher %s (%d/%d bits)",
-+           peername, peeraddr,
-+           tls_info->protocol, tls_info->cipher_name,
-+           tls_info->cipher_usebits, tls_info->cipher_algbits);
-+    pfixtls_stir_seed();
-+
-+    return (0);
-+}
-+
-+ /*
-+  * Shut down the TLS connection, that does mean: remove all the information
-+  * and reset the flags! This is needed if the actual running smtpd is to
-+  * be restarted. We do not give back any value, as there is nothing to
-+  * be reported.
-+  * Since our session cache is external, we will remove the session from
-+  * memory in any case. The SSL_CTX_flush_sessions might be redundant here,
-+  * I however want to make sure nothing is left.
-+  * RFC2246 requires us to remove sessions if something went wrong, as
-+  * indicated by the "failure" value, so we remove it from the external
-+  * cache, too. 
-+  */
-+int     pfixtls_stop_servertls(VSTREAM *stream, int timeout, int failure,
-+                             tls_info_t *tls_info)
-+{
-+    SSL_SESSION *session;
-+    TLScontext_t *TLScontext;
-+
-+    if (pfixtls_serveractive) {
-+      TLScontext = (TLScontext_t *)vstream_context(stream);
-+      session = SSL_get_session(TLScontext->con);
-+        do_tls_operation(vstream_fileno(stream), timeout, TLScontext,
-+                       SSL_shutdown, NULL, NULL, NULL, 0);
-+      if (session) {
-+          if (failure && scache_db) {
-+          remove_srvr_session(session->session_id,
-+                              session->session_id_length);
-+          if (var_smtpd_tls_loglevel >= 2)
-+              msg_info("SSL session removed");
-+          }
-+          SSL_CTX_remove_session(ctx, session);
-+      }
-+      /*
-+       * Free the SSL structure and the BIOs. Warning: the internal_bio is
-+       * connected to the SSL structure and is automatically freed with
-+       * it. Do not free it again (core dump)!!
-+       * Only free the network_bio.
-+       */
-+      SSL_free(TLScontext->con);
-+      BIO_free(TLScontext->network_bio);
-+      myfree((char *)TLScontext);
-+        vstream_control(stream,
-+                  VSTREAM_CTL_READ_FN, (VSTREAM_FN) NULL,
-+                  VSTREAM_CTL_WRITE_FN, (VSTREAM_FN) NULL,
-+                  VSTREAM_CTL_CONTEXT, (void *) NULL,
-+                  VSTREAM_CTL_END);
-+      SSL_CTX_flush_sessions(ctx,time(NULL));
-+
-+      pfixtls_stir_seed();
-+      pfixtls_exchange_seed();
-+
-+      *tls_info = tls_info_zero;
-+      pfixtls_serveractive = 0;
-+
-+    }
-+
-+    return (0);
-+}
-+
-+
-+ /*
-+  * This is the setup routine for the SSL client. As smtpd might be called
-+  * more than once, we only want to do the initialization one time.
-+  *
-+  * The skeleton of this function is taken from OpenSSL apps/s_client.c.
-+  */
-+
-+int     pfixtls_init_clientengine(int verifydepth)
-+{
-+    int     off = 0;
-+    int     verify_flags = SSL_VERIFY_NONE;
-+    int     rand_bytes;
-+    int     rand_source_dev_fd;
-+    int     rand_source_socket_fd;
-+    unsigned char buffer[255];
-+    char   *CApath;
-+    char   *CAfile;
-+    char   *c_cert_file;
-+    char   *c_key_file;
-+
-+
-+    if (pfixtls_clientengine)
-+      return (0);                             /* already running */
-+
-+    if (var_smtp_tls_loglevel >= 2)
-+      msg_info("starting TLS engine");
-+
-+    /*
-+     * Initialize the OpenSSL library by the book!
-+     * To start with, we must initialize the algorithms.
-+     * We want cleartext error messages instead of just error codes, so we
-+     * load the error_strings.
-+     */ 
-+    SSL_load_error_strings();
-+    OpenSSL_add_ssl_algorithms();
-+
-+ /*
-+  * Side effect, call a non-existing function to disable TLS usage with an
-+  * outdated OpenSSL version. There is a security reason (verify_result
-+  * is not stored with the session data).
-+  */
-+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
-+    needs_openssl_095_or_later();
-+#endif
-+
-+    /*
-+     * Initialize the PRNG Pseudo Random Number Generator with some seed.
-+     */
-+    randseed.pid = getpid();
-+    GETTIMEOFDAY(&randseed.tv);
-+    RAND_seed(&randseed, sizeof(randseed_t));
-+
-+    /*
-+     * Access the external sources for random seed. We will only query them
-+     * once, this should be sufficient and we will stir our entropy by using
-+     * the prng-exchange file anyway.
-+     * For reliability, we don't consider failure to access the additional
-+     * source fatal, as we can run happily without it (considering that we
-+     * still have the exchange-file). We also don't care how much entropy
-+     * we get back, as we must run anyway. We simply stir in the buffer
-+     * regardless how many bytes are actually in it.
-+     */
-+    if (*var_tls_daemon_rand_source) {
-+      if (!strncmp(var_tls_daemon_rand_source, "dev:", 4)) {
-+          /*
-+           * Source is a random device
-+           */
-+          rand_source_dev_fd = open(var_tls_daemon_rand_source + 4, 0, 0);
-+          if (rand_source_dev_fd == -1) 
-+              msg_info("Could not open entropy device %s",
-+                        var_tls_daemon_rand_source);
-+          else {
-+              if (var_tls_daemon_rand_bytes > 255)
-+                  var_tls_daemon_rand_bytes = 255;
-+              read(rand_source_dev_fd, buffer, var_tls_daemon_rand_bytes);
-+              RAND_seed(buffer, var_tls_daemon_rand_bytes);
-+              close(rand_source_dev_fd);
-+          }
-+      } else if (!strncmp(var_tls_daemon_rand_source, "egd:", 4)) {
-+          /*
-+           * Source is a EGD compatible socket
-+           */
-+          rand_source_socket_fd = unix_connect(var_tls_daemon_rand_source +4,
-+                                               BLOCKING, 10);
-+          if (rand_source_socket_fd == -1)
-+              msg_info("Could not connect to %s", var_tls_daemon_rand_source);
-+          else {
-+              if (var_tls_daemon_rand_bytes > 255)
-+                  var_tls_daemon_rand_bytes = 255;
-+              buffer[0] = 1;
-+              buffer[1] = var_tls_daemon_rand_bytes;
-+              if (write(rand_source_socket_fd, buffer, 2) != 2)
-+                  msg_info("Could not talk to %s",
-+                           var_tls_daemon_rand_source);
-+              else if (read(rand_source_socket_fd, buffer, 1) != 1)
-+                  msg_info("Could not read info from %s",
-+                           var_tls_daemon_rand_source);
-+              else {
-+                  rand_bytes = buffer[0];
-+                  read(rand_source_socket_fd, buffer, rand_bytes);
-+                  RAND_seed(buffer, rand_bytes);
-+              }
-+              close(rand_source_socket_fd);
-+          }
-+      } else {
-+          RAND_load_file(var_tls_daemon_rand_source,
-+                         var_tls_daemon_rand_bytes);
-+      }
-+    }
-+
-+    if (*var_tls_rand_exch_name) {
-+      rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600);
-+      if (rand_exch_fd != -1)
-+          pfixtls_exchange_seed();
-+    }
-+
-+    randseed.pid = getpid();
-+    GETTIMEOFDAY(&randseed.tv);
-+    RAND_seed(&randseed, sizeof(randseed_t));
-+
-+    /*
-+     * The SSL/TLS speficications require the client to send a message in
-+     * the oldest specification it understands with the highest level it
-+     * understands in the message.
-+     * RFC2487 is only specified for TLSv1, but we want to be as compatible
-+     * as possible, so we will start off with a SSLv2 greeting allowing
-+     * the best we can offer: TLSv1.
-+     * We can restrict this with the options setting later, anyhow.
-+     */
-+    ctx = SSL_CTX_new(SSLv23_client_method());
-+    if (ctx == NULL) {
-+      pfixtls_print_errors();
-+      return (-1);
-+    };
-+
-+    /*
-+     * Here we might set SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1.
-+     * Of course, the last one would not make sense, since RFC2487 is only
-+     * defined for TLS, but we don´t know what is out there. So leave things
-+     * completely open, as of today.
-+     */
-+    off |= SSL_OP_ALL;                /* Work around all known bugs */
-+    SSL_CTX_set_options(ctx, off);
-+
-+    /*
-+     * Set the info_callback, that will print out messages during
-+     * communication on demand.
-+     */
-+    if (var_smtp_tls_loglevel >= 2)
-+      SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback);
-+
-+    /*
-+     * Set the list of ciphers, if explicitely given; otherwise the
-+     * (reasonable) default list is kept.
-+     */
-+    if (strlen(var_smtp_tls_cipherlist) != 0)
-+      if (SSL_CTX_set_cipher_list(ctx, var_smtp_tls_cipherlist) == 0) {
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+
-+    /*
-+     * Now we must add the necessary certificate stuff: A client key, a
-+     * client certificate, and the CA certificates for both the client
-+     * cert and the verification of server certificates.
-+     * In fact, we do not need a client certificate,  so the certificates
-+     * are only loaded (and checked), if supplied. A clever client would
-+     * handle multiple client certificates and decide based on the list
-+     * of acceptable CAs, sent by the server, which certificate to submit.
-+     * OpenSSL does however not do this and also has no callback hoods to
-+     * easily realize it.
-+     *
-+     * As provided by OpenSSL we support two types of CA certificate handling:
-+     * One possibility is to add all CA certificates to one large CAfile,
-+     * the other possibility is a directory pointed to by CApath, containing
-+     * seperate files for each CA pointed on by softlinks named by the hash
-+     * values of the certificate.
-+     * The first alternative has the advantage, that the file is opened and
-+     * read at startup time, so that you don´t have the hassle to maintain
-+     * another copy of the CApath directory for chroot-jail. On the other
-+     * hand, the file is not really readable.
-+     */ 
-+    if (strlen(var_smtp_tls_CAfile) == 0)
-+      CAfile = NULL;
-+    else
-+      CAfile = var_smtp_tls_CAfile;
-+    if (strlen(var_smtp_tls_CApath) == 0)
-+      CApath = NULL;
-+    else
-+      CApath = var_smtp_tls_CApath;
-+    if (CAfile || CApath) {
-+      if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) {
-+          msg_info("TLS engine: cannot load CA data");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+      if (!SSL_CTX_set_default_verify_paths(ctx)) {
-+          msg_info("TLS engine: cannot set verify paths");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+    }
-+
-+    if (strlen(var_smtp_tls_cert_file) == 0)
-+      c_cert_file = NULL;
-+    else
-+      c_cert_file = var_smtp_tls_cert_file;
-+    if (strlen(var_smtp_tls_key_file) == 0)
-+      c_key_file = NULL;
-+    else
-+      c_key_file = var_smtp_tls_key_file;
-+    if (c_cert_file || c_key_file)
-+      if (!set_cert_stuff(ctx, c_cert_file, c_key_file)) {
-+          msg_info("TLS engine: cannot load cert/key data");
-+          pfixtls_print_errors();
-+          return (-1);
-+      }
-+
-+    /*
-+     * Sometimes a temporary RSA key might be needed by the OpenSSL
-+     * library. The OpenSSL doc indicates, that this might happen when
-+     * export ciphers are in use. We have to provide one, so well, we
-+     * just do it.
-+     */
-+    SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb);
-+
-+    /*
-+     * Finally, the setup for the server certificate checking, done
-+     * "by the book".
-+     */
-+    SSL_CTX_set_verify(ctx, verify_flags, verify_callback);
-+
-+    /*
-+     * Initialize the session cache. We only want external caching to
-+     * synchronize between server sessions, so we set it to a minimum value
-+     * of 1. If the external cache is disabled, we won´t cache at all.
-+     *
-+     * In case of the client, there is no callback used in OpenSSL, so
-+     * we must call the session cache functions manually during the process.
-+     */
-+    SSL_CTX_sess_set_cache_size(ctx, 1);
-+    SSL_CTX_set_timeout(ctx, var_smtp_tls_scache_timeout);
-+
-+    /*
-+     * The session cache is realized by an external database file, that
-+     * must be opened before going to chroot jail. Since the session cache
-+     * data can become quite large, "[n]dbm" cannot be used as it has a
-+     * size limit that is by far to small.
-+     */
-+    if (*var_smtp_tls_scache_db) {
-+      /*
-+       * Insert a test against other dbms here, otherwise while writing
-+       * a session (content to large), we will receive a fatal error!
-+       */
-+      if (strncmp(var_smtp_tls_scache_db, "sdbm:", 5))
-+          msg_warn("Only sdbm: type allowed for %s",
-+                   var_smtp_tls_scache_db);
-+      else
-+          scache_db = dict_open(var_smtp_tls_scache_db, O_RDWR,
-+            DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE);
-+      if (!scache_db)
-+          msg_warn("Could not open session cache %s",
-+                   var_smtp_tls_scache_db);
-+    }
-+   
-+    /*
-+     * Finally create the global index to access TLScontext information
-+     * inside verify_callback.
-+     */
-+    TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index",
-+                                          NULL, NULL, NULL);
-+
-+    pfixtls_clientengine = 1;
-+    return (0);
-+}
-+
-+ /*
-+  * This is the actual startup routine for the connection. We expect
-+  * that the buffers are flushed and the "220 Ready to start TLS" was
-+  * received by us, so that we can immediately can start the TLS
-+  * handshake process.
-+  */
-+int     pfixtls_start_clienttls(VSTREAM *stream, int timeout,
-+                              int enforce_peername,
-+                              const char *peername,
-+                              tls_info_t *tls_info)
-+{
-+    int     sts;
-+    int     j;
-+    unsigned int n;
-+    SSL_SESSION *session, *old_session;
-+    SSL_CIPHER *cipher;
-+    X509   *peer;
-+    int     save_session;
-+    int           length;
-+    int     verify_flags;
-+    char   *lowercase_CN;
-+    unsigned char *old_session_id;
-+    TLScontext_t *TLScontext;
-+
-+    if (!pfixtls_clientengine) {              /* should never happen */
-+      msg_info("tls_engine not running");
-+      return (-1);
-+    }
-+    if (var_smtpd_tls_loglevel >= 1)
-+      msg_info("setting up TLS connection to %s", peername);
-+
-+    /*
-+     * Allocate a new TLScontext for the new connection and get an SSL
-+     * structure. Add the location of TLScontext to the SSL to later
-+     * retrieve the information inside the verify_callback().
-+     */
-+    TLScontext = (TLScontext_t *)mymalloc(sizeof(TLScontext_t));
-+    if (!TLScontext) {
-+      msg_fatal("Could not allocate 'TLScontext' with mymalloc");
-+    }
-+    if ((TLScontext->con = (SSL *) SSL_new(ctx)) == NULL) {
-+      msg_info("Could not allocate 'TLScontext->con' with SSL_new()");
-+      pfixtls_print_errors();
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+    if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) {
-+      msg_info("Could not set application data for 'TLScontext->con'");
-+      pfixtls_print_errors();
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    /*
-+     * Set the verification parameters to be checked in verify_callback().
-+     */
-+    if (enforce_peername) {
-+      verify_flags = SSL_VERIFY_PEER;
-+      TLScontext->enforce_verify_errors = 1;
-+      TLScontext->enforce_CN = 1;
-+        SSL_set_verify(TLScontext->con, verify_flags, verify_callback);
-+    }
-+    else {
-+      TLScontext->enforce_verify_errors = 0;
-+      TLScontext->enforce_CN = 0;
-+    }
-+
-+    /*
-+     * The TLS connection is realized by a BIO_pair, so obtain the pair.
-+     */
-+    if (!BIO_new_bio_pair(&TLScontext->internal_bio, BIO_bufsiz,
-+                        &TLScontext->network_bio, BIO_bufsiz)) {
-+      msg_info("Could not obtain BIO_pair");
-+      pfixtls_print_errors();
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    old_session_id = NULL;    /* make sure no old info is kept */
-+    old_session = NULL;
-+
-+    /*
-+     * Find out the hashed HostID for the client cache and try to
-+     * load the session from the cache.
-+     * "old_session_id" holds the session ID of the reloaded session, so that
-+     * we can later check, whether it is really reused.
-+     */
-+    strncpy(TLScontext->peername_save, peername, 128);
-+    TLScontext->peername_save[128] = '\0';  /* in case name is too long */
-+    if (scache_db) {
-+      old_session = load_clnt_session(peername);
-+      if (old_session) {
-+         SSL_set_session(TLScontext->con, old_session);
-+         old_session_id =
-+              (unsigned char *)mymemdup((char *)old_session->session_id,
-+                                   old_session->session_id_length);
-+#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L)
-+          /*
-+           * Ugly Hack: OpenSSL before 0.9.6a (if ever released) does not
-+           * store the verify result in sessions for the client side.
-+           * We modify the session directly which is version specific,
-+           * but this bug is version specific, too.
-+           *
-+           * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before
-+           * beta1 have this bug, it has been fixed during development
-+           * of 0.9.6a. The development version of 0.9.7 can have this
-+           * bug, too. It has been fixed on 2000/11/29.
-+           */
-+          SSL_set_verify_result(TLScontext->con, old_session->verify_result);
-+#endif
-+         
-+      }
-+    }
-+
-+    /*
-+     * Before really starting anything, try to seed the PRNG a little bit
-+     * more.
-+     */
-+    pfixtls_stir_seed();
-+    pfixtls_exchange_seed();
-+
-+    /*
-+     * Initialize the SSL connection to connect state. This should not be
-+     * necessary anymore since 0.9.3, but the call is still in the library
-+     * and maintaining compatibility never hurts.
-+     */
-+    SSL_set_connect_state(TLScontext->con);
-+
-+    /*
-+     * Connect the SSL-connection with the postfix side of the BIO-pair for
-+     * reading and writing.
-+     */
-+     SSL_set_bio(TLScontext->con, TLScontext->internal_bio,
-+               TLScontext->internal_bio);
-+
-+    /*
-+     * If the debug level selected is high enough, all of the data is
-+     * dumped: 3 will dump the SSL negotiation, 4 will dump everything.
-+     *
-+     * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called?
-+     * Well there is a BIO below the SSL routines that is automatically
-+     * created for us, so we can use it for debugging purposes.
-+     */
-+    if (var_smtp_tls_loglevel >= 3)
-+      BIO_set_callback(SSL_get_rbio(TLScontext->con), bio_dump_cb);
-+
-+
-+    /* Dump the negotiation for loglevels 3 and 4 */
-+    if (var_smtp_tls_loglevel >= 3)
-+      do_dump = 1;
-+
-+    /*
-+     * Now we expect the negotiation to begin. This whole process is like a
-+     * black box for us. We totally have to rely on the routines build into
-+     * the OpenSSL library. The only thing we can do we already have done
-+     * by choosing our own callback certificate verification.
-+     *
-+     * Error handling:
-+     * If the SSL handhake fails, we print out an error message and remove
-+     * everything that might be there. A session has to be removed anyway,
-+     * because RFC2246 requires it. 
-+     */
-+    sts = do_tls_operation(vstream_fileno(stream), timeout, TLScontext,
-+                         SSL_connect, NULL, NULL, NULL, 0);
-+    if (sts <= 0) {
-+      msg_info("SSL_connect error to %s: %d", peername, sts);
-+      pfixtls_print_errors();
-+      session = SSL_get_session(TLScontext->con);
-+      if (session) {
-+          if (scache_db)
-+              remove_clnt_session(peername);
-+          SSL_CTX_remove_session(ctx, session);
-+          if (var_smtp_tls_loglevel >= 2)
-+              msg_info("SSL session removed");
-+      }
-+      if ((old_session) && (session != old_session))
-+          SSL_SESSION_free(old_session);      /* Must also be removed */
-+      SSL_free(TLScontext->con);
-+      myfree((char *)TLScontext);
-+      return (-1);
-+    }
-+
-+    /*
-+     * Now we must save the new session to disk, if necessary. If we had
-+     * an old session, its ID was saved in "old_session_id" for comparison.
-+     */
-+    session = SSL_get_session(TLScontext->con);
-+    if (session && scache_db) {
-+      save_session = 1;
-+      if (old_session_id) {
-+          if (memcmp(session->session_id, old_session_id,
-+                     session->session_id_length) == 0) {
-+              if (var_smtp_tls_loglevel >= 3)
-+                  msg_info("Reusing old session");
-+              save_session = 0;
-+          }
-+          myfree((char *)old_session_id);
-+      }
-+      if (save_session) {
-+#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L)
-+          /*
-+           * Ugly Hack: OpenSSL before 0.9.6a (if ever released) does not
-+           * store the verify result in sessions for the client side.
-+           * We modify the session directly which is version specific,
-+           * but this bug is version specific, too.
-+           *
-+           * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before
-+           * beta1 have this bug, it has been fixed during development
-+           * of 0.9.6a. The development version of 0.9.7 can have this
-+           * bug, too. It has been fixed on 2000/11/29.
-+           */
-+          session->verify_result = SSL_get_verify_result(TLScontext->con);
-+#endif
-+          save_clnt_session(session, peername);
-+      }
-+    }
-+    if ((old_session) && (session != old_session))
-+      SSL_SESSION_free(old_session);  /* Remove unused session */
-+
-+    /* Only loglevel==4 dumps everything */
-+    if (var_smtp_tls_loglevel < 4)
-+      do_dump = 0;
-+
-+    /*
-+     * Lets see, whether a peer certificate is available and what is
-+     * the actual information. We want to save it for later use.
-+     */
-+    peer = SSL_get_peer_certificate(TLScontext->con);
-+    if (peer != NULL) {
-+      if (SSL_get_verify_result(TLScontext->con) == X509_V_OK)
-+          tls_info->peer_verified = 1;
-+
-+      X509_NAME_get_text_by_NID(X509_get_subject_name(peer),
-+                        NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ);
-+      tls_info->peer_CN = TLScontext->peer_CN;
-+      X509_NAME_get_text_by_NID(X509_get_issuer_name(peer),
-+                        NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ);
-+      if (var_smtp_tls_loglevel >= 1) {
-+          if (tls_info->peer_verified)
-+              msg_info("Verified: subject_CN=%s, issuer_CN=%s",
-+                       TLScontext->peer_CN, TLScontext->issuer_CN);
-+          else
-+              msg_info("Unverified: subject_CN=%s, issuer_CN=%s",
-+                       TLScontext->peer_CN, TLScontext->issuer_CN);
-+      }
-+      tls_info->issuer_CN = TLScontext->issuer_CN;
-+      X509_free(peer);
-+    }
-+
-+    /*
-+     * At this point the CN should already match the peername, if enforced.
-+     * We may however have a cached session, so the callback would never
-+     * be called. We therefore double-check to make sure and remove the
-+     * session, if applicable.
-+     */
-+    if (enforce_peername) {
-+      if (!tls_info->peer_verified || !tls_info->peer_CN) {
-+          msg_info("Removed session without verifiable peername");
-+          remove_clnt_session(peername);
-+          return (-1);
-+      }
-+      lowercase_CN = lowercase(mystrdup(tls_info->peer_CN));
-+      if (strcmp(peername, lowercase_CN)) {
-+          msg_info("Removed session without non-matching peername");
-+          remove_clnt_session(peername);
-+          myfree(lowercase_CN);
-+          return (-1);
-+      }
-+      myfree(lowercase_CN);
-+    }
-+
-+    /*
-+     * Finally, collect information about protocol and cipher for logging
-+     */ 
-+    tls_info->protocol = SSL_get_version(TLScontext->con);
-+    cipher = SSL_get_current_cipher(TLScontext->con);
-+    tls_info->cipher_name = SSL_CIPHER_get_name(cipher);
-+    tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher,
-+                                               &(tls_info->cipher_algbits));
-+
-+    pfixtls_clientactive = 1;
-+
-+    /*
-+     * The TLS engine is active, switch to the pfixtls_timed_read/write()
-+     * functions.
-+     */
-+    vstream_control(stream,
-+                  VSTREAM_CTL_READ_FN, pfixtls_timed_read,
-+                  VSTREAM_CTL_WRITE_FN, pfixtls_timed_write,
-+                  VSTREAM_CTL_CONTEXT, (void *)TLScontext,
-+                  VSTREAM_CTL_END);
-+
-+    msg_info("TLS connection established to %s: %s with cipher %s (%d/%d bits)",
-+           peername,
-+           tls_info->protocol, tls_info->cipher_name,
-+           tls_info->cipher_usebits, tls_info->cipher_algbits);
-+
-+    pfixtls_stir_seed();
-+
-+    return (0);
-+}
-+
-+ /*
-+  * Shut down the TLS connection, that does mean: remove all the information
-+  * and reset the flags! This is needed if the actual running smtp is to
-+  * be restarted. We do not give back any value, as there is nothing to
-+  * be reported.
-+  * Since our session cache is external, we will remove the session from
-+  * memory in any case. The SSL_CTX_flush_sessions might be redundant here,
-+  * I however want to make sure nothing is left.
-+  * RFC2246 requires us to remove sessions if something went wrong, as
-+  * indicated by the "failure" value,so we remove it from the external
-+  * cache, too.
-+  */
-+int     pfixtls_stop_clienttls(VSTREAM *stream, int timeout, int failure,
-+                             tls_info_t *tls_info)
-+{
-+    SSL_SESSION *session;
-+    TLScontext_t *TLScontext;
-+
-+    if (pfixtls_clientactive) {
-+      TLScontext = (TLScontext_t *)vstream_context(stream);
-+      session = SSL_get_session(TLScontext->con);
-+        do_tls_operation(vstream_fileno(stream), timeout, TLScontext,
-+                       SSL_shutdown, NULL, NULL, NULL, 0);
-+      if (session) {
-+          if (failure && scache_db) {
-+              remove_clnt_session(TLScontext->peername_save);
-+              if (var_smtp_tls_loglevel >= 2)
-+                  msg_info("SSL session removed");
-+          }
-+      }
-+      /*
-+       * Free the SSL structure and the BIOs. Warning: the internal_bio is
-+       * connected to the SSL structure and is automatically freed with
-+       * it. Do not free it again (core dump)!!
-+       * Only free the network_bio.
-+       */
-+      SSL_free(TLScontext->con);
-+      BIO_free(TLScontext->network_bio);
-+      myfree((char *)TLScontext);
-+      vstream_control(stream,
-+                  VSTREAM_CTL_READ_FN, (VSTREAM_FN) NULL,
-+                  VSTREAM_CTL_WRITE_FN, (VSTREAM_FN) NULL,
-+                  VSTREAM_CTL_CONTEXT, (void *) NULL,
-+                  VSTREAM_CTL_END);
-+      SSL_CTX_flush_sessions(ctx,time(NULL));
-+
-+      pfixtls_stir_seed();
-+      pfixtls_exchange_seed();
-+
-+      *tls_info = tls_info_zero;
-+      pfixtls_clientactive = 0;
-+
-+    }
-+
-+    return (0);
-+}
-+
-+
-+#endif /* HAS_SSL */
-diff -Nur snapshot-20010228-orig/src/global/pfixtls.h snapshot-20010228/src/global/pfixtls.h
---- snapshot-20010228-orig/src/global/pfixtls.h        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/global/pfixtls.h     Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,76 @@
-+/*++
-+/* NAME
-+/*      pfixtls 3h
-+/* SUMMARY
-+/*      TLS routines
-+/* SYNOPSIS
-+/*      include "pfixtls.h"
-+/* DESCRIPTION
-+/* .nf
-+/*--*/
-+
-+#ifndef PFIXTLS_H_INCLUDED
-+#define PFIXTLS_H_INCLUDED
-+
-+typedef struct {
-+    int     peer_verified;
-+    char   *peer_subject;
-+    char   *peer_issuer;
-+    char   *peer_fingerprint;
-+    char   *peer_CN;
-+    char   *issuer_CN;
-+    char  **dNSName;
-+    const char *protocol;
-+    const char *cipher_name;
-+    int     cipher_usebits;
-+    int     cipher_algbits;
-+} tls_info_t;
-+
-+extern const tls_info_t tls_info_zero;
-+
-+#ifdef HAS_SSL
-+
-+typedef struct {
-+    long scache_db_version;
-+    long openssl_version;
-+    time_t timestamp;         /* We could add other info here... */
-+} pfixtls_scache_info_t;
-+
-+extern const long scache_db_version;
-+extern const long openssl_version;
-+
-+int     pfixtls_timed_read(int fd, void *buf, unsigned len, int timout,
-+                         void *unused_timeout);
-+int     pfixtls_timed_write(int fd, void *buf, unsigned len, int timeout,
-+                          void *unused_timeout);
-+
-+extern int pfixtls_serverengine;
-+int     pfixtls_init_serverengine(int verifydepth, int askcert);
-+int     pfixtls_start_servertls(VSTREAM *stream, int timeout,
-+                              const char *peername, const char *peeraddr,
-+                              tls_info_t *tls_info, int require_cert);
-+int     pfixtls_stop_servertls(VSTREAM *stream, int timeout, int failure,
-+                             tls_info_t *tls_info);
-+
-+extern int pfixtls_clientengine;
-+int     pfixtls_init_clientengine(int verifydepth);
-+int     pfixtls_start_clienttls(VSTREAM *stream, int timeout,
-+                              int enforce_peername,
-+                              const char *peername,
-+                              tls_info_t *tls_info);
-+int     pfixtls_stop_clienttls(VSTREAM *stream, int timeout, int failure,
-+                             tls_info_t *tls_info);
-+
-+#endif /* PFIXTLS_H_INCLUDED */
-+#endif
-+
-+/* LICENSE
-+/* .ad
-+/* .fi
-+/* AUTHOR(S)
-+/*    Lutz Jaenicke
-+/*    BTU Cottbus
-+/*    Allgemeine Elektrotechnik
-+/*    Universitaetsplatz 3-4
-+/*    D-03044 Cottbus, Germany
-+/*--*/
-diff -Nur snapshot-20010228-orig/src/smtp/Makefile.in snapshot-20010228/src/smtp/Makefile.in
---- snapshot-20010228-orig/src/smtp/Makefile.in        Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/Makefile.in     Wed Mar 21 13:32:23 2001
-@@ -81,6 +81,7 @@
- smtp.o: ../../include/mail_proto.h
- smtp.o: ../../include/iostuff.h
- smtp.o: ../../include/mail_server.h
-+smtp.o: ../../include/pfixtls.h
- smtp.o: smtp.h
- smtp.o: smtp_sasl.h
- smtp_addr.o: smtp_addr.c
-@@ -99,6 +100,7 @@
- smtp_addr.o: ../../include/argv.h
- smtp_addr.o: ../../include/deliver_request.h
- smtp_addr.o: ../../include/recipient_list.h
-+smtp_addr.o: ../../include/pfixtls.h
- smtp_addr.o: smtp_addr.h
- smtp_chat.o: smtp_chat.c
- smtp_chat.o: ../../include/sys_defs.h
-@@ -119,6 +121,7 @@
- smtp_chat.o: ../../include/cleanup_user.h
- smtp_chat.o: ../../include/mail_error.h
- smtp_chat.o: ../../include/name_mask.h
-+smtp_chat.o: ../../include/pfixtls.h
- smtp_chat.o: smtp.h
- smtp_connect.o: smtp_connect.c
- smtp_connect.o: ../../include/sys_defs.h
-@@ -139,6 +142,7 @@
- smtp_connect.o: ../../include/argv.h
- smtp_connect.o: ../../include/deliver_request.h
- smtp_connect.o: ../../include/recipient_list.h
-+smtp_connetc.o: ../../include/pfixtls.h
- smtp_connect.o: smtp_addr.h
- smtp_proto.o: smtp_proto.c
- smtp_proto.o: ../../include/sys_defs.h
-@@ -163,6 +167,7 @@
- smtp_proto.o: ../../include/off_cvt.h
- smtp_proto.o: ../../include/mark_corrupt.h
- smtp_proto.o: ../../include/quote_821_local.h
-+smtp_proto.o: ../../include/pfixtls.h
- smtp_proto.o: smtp.h
- smtp_proto.o: ../../include/argv.h
- smtp_proto.o: smtp_sasl.h
-@@ -206,9 +211,12 @@
- smtp_session.o: ../../include/stringops.h
- smtp_session.o: ../../include/vstring.h
- smtp_session.o: smtp.h
-+smtp_session.o: ../../include/mail_params.h
-+smtp_session.o: ../../include/pfixtls.h
- smtp_session.o: ../../include/argv.h
- smtp_session.o: ../../include/deliver_request.h
- smtp_session.o: ../../include/recipient_list.h
-+smtp_session.o: ../../include/maps.h
- smtp_state.o: smtp_state.c
- smtp_state.o: ../../include/sys_defs.h
- smtp_state.o: ../../include/mymalloc.h
-@@ -220,6 +228,7 @@
- smtp_state.o: ../../include/argv.h
- smtp_state.o: ../../include/deliver_request.h
- smtp_state.o: ../../include/recipient_list.h
-+smtp_state.o: ../../include/pfixtls.h
- smtp_state.o: smtp_sasl.h
- smtp_trouble.o: smtp_trouble.c
- smtp_trouble.o: ../../include/sys_defs.h
-@@ -239,6 +248,7 @@
- smtp_trouble.o: ../../include/name_mask.h
- smtp_trouble.o: smtp.h
- smtp_trouble.o: ../../include/argv.h
-+smtp_trouble.o: ../../include/pfixtls.h
- smtp_unalias.o: smtp_unalias.c
- smtp_unalias.o: ../../include/sys_defs.h
- smtp_unalias.o: ../../include/htable.h
-@@ -251,3 +261,4 @@
- smtp_unalias.o: ../../include/argv.h
- smtp_unalias.o: ../../include/deliver_request.h
- smtp_unalias.o: ../../include/recipient_list.h
-+smtp_unalias.o: ../../include/pfixtls.h
-diff -Nur snapshot-20010228-orig/src/smtp/smtp.c snapshot-20010228/src/smtp/smtp.c
---- snapshot-20010228-orig/src/smtp/smtp.c     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/smtp.c  Wed Mar 21 13:32:23 2001
-@@ -211,6 +211,7 @@
- #include <debug_peer.h>
- #include <mail_error.h>
- #include <deliver_pass.h>
-+#include <pfixtls.h>
- /* Single server skeleton. */
-@@ -227,6 +228,7 @@
-   */
- int     var_smtp_conn_tmout;
- int     var_smtp_helo_tmout;
-+int     var_smtp_starttls_tmout;
- int     var_smtp_mail_tmout;
- int     var_smtp_rcpt_tmout;
- int     var_smtp_data0_tmout;
-@@ -250,6 +252,12 @@
- char   *var_smtp_sasl_passwd;
- bool    var_smtp_sasl_enable;
- char   *var_smtp_bind_addr;
-+int     var_smtp_use_tls;
-+int     var_smtp_enforce_tls;
-+int     var_smtp_tls_enforce_peername;
-+char   *var_smtp_tls_per_site;
-+int     var_smtp_tls_scert_vd;
-+int     var_smtp_tls_note_starttls_offer;
-  /*
-   * Global variables. smtp_errno is set by the address lookup routines and by
-@@ -367,6 +375,14 @@
-       msg_warn("%s is true, but SASL support is not compiled in",
-                VAR_SMTP_SASL_ENABLE);
- #endif
-+    /*
-+     * Initialize the TLS data before entering the chroot jail
-+     */
-+#ifdef HAS_SSL
-+    if (var_smtp_use_tls || var_smtp_enforce_tls || var_smtp_tls_per_site[0])
-+      pfixtls_init_clientengine(var_smtp_tls_scert_vd);
-+    smtp_tls_list_init();
-+#endif
- }
- /* pre_accept - see if tables have changed */
-@@ -402,6 +418,7 @@
-       VAR_SMTP_SASL_PASSWD, DEF_SMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
-       VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
-       VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
-+      VAR_SMTP_TLS_PER_SITE, DEF_SMTP_TLS_PER_SITE, &var_smtp_tls_per_site, 0, 0,
-       0,
-     };
-     static CONFIG_TIME_TABLE time_table[] = {
-@@ -413,10 +430,12 @@
-       VAR_SMTP_DATA1_TMOUT, DEF_SMTP_DATA1_TMOUT, &var_smtp_data1_tmout, 1, 0,
-       VAR_SMTP_DATA2_TMOUT, DEF_SMTP_DATA2_TMOUT, &var_smtp_data2_tmout, 1, 0,
-       VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0,
-+      VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0,
-       0,
-     };
-     static CONFIG_INT_TABLE int_table[] = {
-       VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
-+      VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0,
-       0,
-     };
-     static CONFIG_BOOL_TABLE bool_table[] = {
-@@ -427,6 +446,10 @@
-       VAR_SMTP_ALWAYS_EHLO, DEF_SMTP_ALWAYS_EHLO, &var_smtp_always_ehlo,
-       VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo,
-       VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable,
-+      VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls,
-+      VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls,
-+      VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername,
-+      VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer,
-       0,
-     };
-diff -Nur snapshot-20010228-orig/src/smtp/smtp.h snapshot-20010228/src/smtp/smtp.h
---- snapshot-20010228-orig/src/smtp/smtp.h     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/smtp.h  Wed Mar 21 13:32:23 2001
-@@ -27,6 +27,7 @@
-   * Global library.
-   */
- #include <deliver_request.h>
-+#include <pfixtls.h>
-  /*
-   * State information associated with each SMTP delivery. We're bundling the
-@@ -75,9 +76,14 @@
-     char   *addr;                     /* mail exchanger */
-     char   *namaddr;                  /* mail exchanger */
-     int     best;                     /* most preferred host */
-+    int     tls_use_tls;              /* can do TLS */
-+    int     tls_enforce_tls;          /* must do TLS */
-+    int     tls_enforce_peername;     /* cert must match */
-+    tls_info_t tls_info;              /* TLS connection state */
- } SMTP_SESSION;
--extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, char *, char *);
-+extern void smtp_tls_list_init(void);
-+extern SMTP_SESSION *smtp_session_alloc(char *, VSTREAM *, char *, char *);
- extern void smtp_session_free(SMTP_SESSION *);
-  /*
-diff -Nur snapshot-20010228-orig/src/smtp/smtp_connect.c snapshot-20010228/src/smtp/smtp_connect.c
---- snapshot-20010228-orig/src/smtp/smtp_connect.c     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/smtp_connect.c  Wed Mar 21 13:32:23 2001
-@@ -116,6 +116,7 @@
- #include <mail_params.h>
- #include <own_inet_addr.h>
-+#include <pfixtls.h>
- /* DNS library. */
-@@ -128,7 +129,7 @@
- /* smtp_connect_addr - connect to explicit address */
--static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port,
-+static SMTP_SESSION *smtp_connect_addr(char *dest, DNS_RR *addr, unsigned port,
-                                              VSTRING *why)
- {
-     char   *myname = "smtp_connect_addr";
-@@ -262,7 +263,7 @@
-       vstream_fclose(stream);
-       return (0);
-     }
--    return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
-+    return (smtp_session_alloc(dest, stream, addr->name, inet_ntoa(sin.sin_addr)));
- }
- /* smtp_connect_host - direct connection to host */
-@@ -280,7 +281,7 @@
-      */
-     addr_list = smtp_host_addr(host, why);
-     for (addr = addr_list; addr; addr = addr->next) {
--      if ((session = smtp_connect_addr(addr, port, why)) != 0) {
-+      if ((session = smtp_connect_addr(host, addr, port, why)) != 0) {
-           session->best = 1;
-           break;
-       }
-@@ -309,7 +310,7 @@
-      */
-     addr_list = smtp_domain_addr(name, why, found_myself);
-     for (addr = addr_list; addr; addr = addr->next) {
--      if ((session = smtp_connect_addr(addr, port, why)) != 0) {
-+      if ((session = smtp_connect_addr(name, addr, port, why)) != 0) {
-           session->best = (addr->pref == addr_list->pref);
-           break;
-       }
-diff -Nur snapshot-20010228-orig/src/smtp/smtp_proto.c snapshot-20010228/src/smtp/smtp_proto.c
---- snapshot-20010228-orig/src/smtp/smtp_proto.c       Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/smtp_proto.c    Wed Mar 21 13:32:23 2001
-@@ -99,6 +99,7 @@
- #include <off_cvt.h>
- #include <mark_corrupt.h>
- #include <quote_821_local.h>
-+#include <pfixtls.h>
- /* Application-specific. */
-@@ -153,6 +154,8 @@
-     char   *words;
-     char   *word;
-     int     n;
-+    int     oldfeatures;
-+    int     rval;
-     /*
-      * Prepare for disaster.
-@@ -206,7 +209,8 @@
-                                  session->namaddr,
-                                  translit(resp->str, "\n", " ")));
-     }
--
-+    if (var_smtp_always_ehlo)
-+      state->features |= SMTP_FEATURE_ESMTP;
-     /*
-      * Pick up some useful features offered by the SMTP server. XXX Until we
-      * have a portable routine to convert from string to off_t with proper
-@@ -215,6 +219,7 @@
-      * advertises a really huge message size limit.
-      */
-     lines = resp->str;
-+    oldfeatures = state->features;            /* remember */
-     while ((words = mystrtok(&lines, "\n")) != 0) {
-       if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
-           if (strcasecmp(word, "8BITMIME") == 0)
-@@ -223,6 +228,8 @@
-               state->features |= SMTP_FEATURE_PIPELINING;
-           else if (strcasecmp(word, "SIZE") == 0)
-               state->features |= SMTP_FEATURE_SIZE;
-+         else if (strcasecmp(word, "STARTTLS") == 0)
-+              state->features |= SMTP_FEATURE_STARTTLS;
- #ifdef USE_SASL_AUTH
-           else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
-               smtp_sasl_helo_auth(state, words);
-@@ -241,6 +248,129 @@
-     if (msg_verbose)
-       msg_info("server features: 0x%x", state->features);
-+#ifdef HAS_SSL
-+    if ((state->features & SMTP_FEATURE_STARTTLS) &&
-+      (var_smtp_tls_note_starttls_offer) &&
-+      (!(session->tls_enforce_tls || session->tls_use_tls)))
-+      msg_info("Host offered STARTTLS: [%s]", session->host);
-+    if ((session->tls_enforce_tls) &&
-+      !(state->features & SMTP_FEATURE_STARTTLS))
-+    {
-+      /*
-+       * We are enforced to use TLS but it is not offered, so we will give
-+       * up on this host. We won't even try STARTTLS, because we could
-+       * receive a "500 command unrecognized" which would bounce the
-+       * message. We instead want to delay until STARTTLS becomes
-+       * available.
-+       */
-+      return (smtp_site_fail(state, 450, "Could not start TLS: not offered"));
-+    }
-+    if ((session->tls_enforce_tls) && !pfixtls_clientengine) {
-+      /*
-+       * We would like to start client TLS, but our own TLS-engine is
-+       * not running.
-+       */
-+      return (smtp_site_fail(state, 450,
-+               "Could not start TLS: our TLS-engine not running"));
-+    }
-+    if ((state->features & SMTP_FEATURE_STARTTLS) &&
-+      ((session->tls_use_tls && pfixtls_clientengine) ||
-+       (session->tls_enforce_tls))) {
-+      /*
-+         * Try to use the TLS feature
-+         */
-+      smtp_chat_cmd(state, "STARTTLS");
-+      if ((resp = smtp_chat_resp(state))->code / 100 != 2) {
-+          state->features &= ~SMTP_FEATURE_STARTTLS;
-+          /*
-+           * At this point a political decision is necessary. If we
-+           * enforce usage of tls, we have to close the connection
-+           * now.
-+           */
-+          if (session->tls_enforce_tls)
-+              return (smtp_site_fail(state, resp->code,
-+                                       "host %s refused to start TLS: %s",
-+                                         session->host,
-+                                         translit(resp->str, "\n", " ")));
-+      } else {
-+          if (rval = pfixtls_start_clienttls(session->stream,
-+                                             var_smtp_starttls_tmout,
-+                                             session->tls_enforce_peername,
-+                                             session->host,
-+                                             &(session->tls_info)))
-+              return (smtp_site_fail(state, 450,
-+                               "Could not start TLS: client failure"));
-+
-+
-+          /*
-+           * Now the connection is established and maybe we do have a
-+           * validated cert with a CommonName in it. For logging, we
-+           * will check the CommonName against the name of the host.
-+           * In enforce_peername state, the handshake would already have
-+           * been terminated so the check here is for logging only!
-+           */
-+          if (session->tls_info.peer_CN != NULL) {
-+              if (!session->tls_info.peer_verified) {
-+                  msg_info("Peer certficate could not be verified");
-+                  if (session->tls_enforce_tls) {
-+                      pfixtls_stop_clienttls(session->stream,
-+                                             var_smtp_starttls_tmout, 1,
-+                                             &(session->tls_info));
-+                      return(smtp_site_fail(state, 450, "TLS-failure: Could not verify certificate"));
-+                  }
-+              }
-+              if (strcasecmp(session->tls_info.peer_CN, session->host)) {
-+                  msg_info("Hostname/Certificate mismatch: %s != %s",
-+                      session->host, session->tls_info.peer_CN);
-+              } else if (msg_verbose) {
-+                  msg_info("Match: %s == %s", session->tls_info.peer_CN,
-+                       session->host);
-+              }
-+          } else if (session->tls_enforce_tls) {
-+              pfixtls_stop_clienttls(session->stream,
-+                                     var_smtp_starttls_tmout, 1,
-+                                     &(session->tls_info));
-+              return (smtp_site_fail(state, 450, "TLS-failure: Cannot verify hostname"));
-+          }
-+
-+          /*
-+           * At this point we have to re-negotiate the "EHLO" to reget
-+           * the feature-list
-+           */
-+          state->features = oldfeatures;
-+          if (state->features & SMTP_FEATURE_ESMTP) {
-+              smtp_chat_cmd(state, "EHLO %s", var_myhostname);
-+              if ((resp = smtp_chat_resp(state))->code / 100 != 2)
-+                  state->features &= ~SMTP_FEATURE_ESMTP;
-+          }
-+          lines = resp->str;
-+          (void) mystrtok(&lines, "\n");
-+          while ((words = mystrtok(&lines, "\n")) != 0) {
-+              if (mystrtok(&words, "- ") &&
-+                  (word = mystrtok(&words, " \t")) != 0) {
-+                  if (strcasecmp(word, "8BITMIME") == 0)
-+                      state->features |= SMTP_FEATURE_8BITMIME;
-+                  else if (strcasecmp(word, "PIPELINING") == 0)
-+                      state->features |= SMTP_FEATURE_PIPELINING;
-+                  else if (strcasecmp(word, "SIZE") == 0)
-+                      state->features |= SMTP_FEATURE_SIZE;
-+                  else if (strcasecmp(word, "STARTTLS") == 0)
-+                      state->features |= SMTP_FEATURE_STARTTLS;
-+#ifdef USE_SASL_AUTH
-+                  else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0)
-+                      smtp_sasl_helo_auth(state, words);
-+#endif
-+              }
-+          }
-+          /*
-+           * Actually, at this point STARTTLS should not be offered
-+           * anymore, so we could check for a protocol violation, but
-+           * what should we do then?
-+           */
-+
-+      }
-+    }
-+#endif
- #ifdef USE_SASL_AUTH
-     if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH))
-       return (smtp_sasl_helo_login(state));
-diff -Nur snapshot-20010228-orig/src/smtp/smtp_session.c snapshot-20010228/src/smtp/smtp_session.c
---- snapshot-20010228-orig/src/smtp/smtp_session.c     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtp/smtp_session.c  Wed Mar 21 13:32:23 2001
-@@ -42,15 +42,42 @@
- #include <vstream.h>
- #include <stringops.h>
-+#include <mail_params.h>
-+#include <maps.h>
-+#include <pfixtls.h>
-+
- /* Application-specific. */
- #include "smtp.h"
-+#ifdef HAS_SSL
-+/* static lists */
-+static MAPS *tls_per_site;
-+
-+/* smtp_tls_list_init - initialize lists */
-+
-+void smtp_tls_list_init(void)
-+{
-+    tls_per_site = maps_create(VAR_SMTP_TLS_PER_SITE, var_smtp_tls_per_site,
-+                             DICT_FLAG_LOCK);
-+}
-+#endif
-+
- /* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */
--SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, char *host, char *addr)
-+SMTP_SESSION *smtp_session_alloc(char *dest, VSTREAM *stream, char *host, char *addr)
- {
-     SMTP_SESSION *session;
-+    const char *lookup;
-+    char *lookup_key;
-+    int host_dont_use = 0;
-+    int host_use = 0;
-+    int host_enforce = 0;
-+    int host_enforce_peername = 0;
-+    int recipient_dont_use = 0;
-+    int recipient_use = 0;
-+    int recipient_enforce = 0;
-+    int recipient_enforce_peername = 0;
-     session = (SMTP_SESSION *) mymalloc(sizeof(*session));
-     session->stream = stream;
-@@ -58,6 +85,61 @@
-     session->addr = mystrdup(addr);
-     session->namaddr = concatenate(host, "[", addr, "]", (char *) 0);
-     session->best = 1;
-+    session->tls_use_tls = session->tls_enforce_tls = 0;
-+    session->tls_enforce_peername = 0;
-+#ifdef HAS_SSL
-+    lookup_key = lowercase(mystrdup(host));
-+    if (lookup = maps_find(tls_per_site, lookup_key, 0)) {
-+      if (!strcasecmp(lookup, "NONE"))
-+          host_dont_use = 1;
-+      else if (!strcasecmp(lookup, "MAY"))
-+          host_use = 1;
-+      else if (!strcasecmp(lookup, "MUST"))
-+          host_enforce = host_enforce_peername = 1;
-+      else if (!strcasecmp(lookup, "MUST_NOPEERMATCH"))
-+          host_enforce = 1;
-+      else
-+          msg_warn("Unknown TLS state for receiving host %s: '%s', using default policy", session->host, lookup);
-+    }
-+    myfree(lookup_key);
-+    lookup_key = lowercase(mystrdup(dest));
-+    if (lookup = maps_find(tls_per_site, dest, 0)) {
-+      if (!strcasecmp(lookup, "NONE"))
-+          recipient_dont_use = 1;
-+      else if (!strcasecmp(lookup, "MAY"))
-+          recipient_use = 1;
-+      else if (!strcasecmp(lookup, "MUST"))
-+          recipient_enforce = recipient_enforce_peername = 1;
-+      else if (!strcasecmp(lookup, "MUST_NOPEERMATCH"))
-+          recipient_enforce = 1;
-+      else
-+          msg_warn("Unknown TLS state for recipient domain %s: '%s', using default policy", dest, lookup);
-+    }
-+    myfree(lookup_key);
-+
-+    if ((var_smtp_enforce_tls && !host_dont_use) || host_enforce ||
-+       recipient_enforce)
-+      session->tls_enforce_tls = session->tls_use_tls = 1;
-+
-+    /*
-+     * Set up peername checking. We want to make sure that a MUST* entry in
-+     * the tls_per_site table always has precedence. MUST always must lead to
-+     * a peername check, MUST_NOPEERMATCH must always disable it. Only when
-+     * no explicit setting has been found, the default will be used.
-+     * There is the case left, that both "host" and "recipient" settings
-+     * conflict. In this case, the "host" setting wins.
-+     */
-+    if (host_enforce && host_enforce_peername)
-+      session->tls_enforce_peername = 1;
-+    else if (recipient_enforce && recipient_enforce_peername)
-+      session->tls_enforce_peername = 1;
-+    else if (var_smtp_enforce_tls && var_smtp_tls_enforce_peername)
-+      session->tls_enforce_peername = 1;
-+
-+    else if ((var_smtp_use_tls && !host_dont_use) || host_use || recipient_use)
-+      session->tls_use_tls = 1;
-+#endif
-+    session->tls_info = tls_info_zero;
-     return (session);
- }
-@@ -65,6 +147,11 @@
- void    smtp_session_free(SMTP_SESSION *session)
- {
-+#ifdef HAS_SSL
-+    vstream_fflush(session->stream);
-+    pfixtls_stop_clienttls(session->stream, var_smtp_starttls_tmout, 0,
-+                         &(session->tls_info));
-+#endif
-     vstream_fclose(session->stream);
-     myfree(session->host);
-     myfree(session->addr);
-diff -Nur snapshot-20010228-orig/src/smtpd/Makefile.in snapshot-20010228/src/smtpd/Makefile.in
---- snapshot-20010228-orig/src/smtpd/Makefile.in       Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtpd/Makefile.in    Wed Mar 21 13:32:23 2001
-@@ -120,6 +120,7 @@
- smtpd.o: ../../include/tok822.h
- smtpd.o: ../../include/resolve_clnt.h
- smtpd.o: ../../include/mail_server.h
-+smtpd.o: ../../include/pfixtls.h
- smtpd.o: smtpd_token.h
- smtpd.o: smtpd.h
- smtpd.o: smtpd_check.h
-@@ -147,6 +148,7 @@
- smtpd_chat.o: ../../include/cleanup_user.h
- smtpd_chat.o: ../../include/mail_error.h
- smtpd_chat.o: ../../include/name_mask.h
-+smtpd_chat.o: ../../include/pfixtls.h
- smtpd_chat.o: smtpd.h
- smtpd_chat.o: ../../include/mail_stream.h
- smtpd_chat.o: smtpd_chat.h
-@@ -177,6 +179,7 @@
- smtpd_check.o: ../../include/mail_conf.h
- smtpd_check.o: ../../include/maps.h
- smtpd_check.o: ../../include/mail_addr_find.h
-+smtpd_check.o: ../../include/pfixtls.h
- smtpd_check.o: smtpd.h
- smtpd_check.o: ../../include/mail_stream.h
- smtpd_check.o: smtpd_sasl_glue.h
-@@ -193,6 +196,7 @@
- smtpd_peer.o: ../../include/vstream.h
- smtpd_peer.o: ../../include/argv.h
- smtpd_peer.o: ../../include/mail_stream.h
-+smtpd_peer.o: ../../include/pfixtls.h
- smtpd_sasl_glue.o: smtpd_sasl_glue.c
- smtpd_sasl_glue.o: ../../include/sys_defs.h
- smtpd_sasl_glue.o: ../../include/msg.h
-@@ -243,6 +247,7 @@
- smtpd_state.o: ../../include/vstring.h
- smtpd_state.o: ../../include/argv.h
- smtpd_state.o: ../../include/mail_stream.h
-+smtpd_state.o: ../../include/pfixtls.h
- smtpd_state.o: smtpd_chat.h
- smtpd_state.o: smtpd_sasl_glue.h
- smtpd_token.o: smtpd_token.c
-@@ -252,3 +257,4 @@
- smtpd_token.o: smtpd_token.h
- smtpd_token.o: ../../include/vstring.h
- smtpd_token.o: ../../include/vbuf.h
-+smtpd_token.o: ../../include/pfixtls.h
-diff -Nur snapshot-20010228-orig/src/smtpd/smtpd.c snapshot-20010228/src/smtpd/smtpd.c
---- snapshot-20010228-orig/src/smtpd/smtpd.c   Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtpd/smtpd.c        Wed Mar 21 13:32:23 2001
-@@ -283,6 +283,7 @@
- #include <mail_stream.h>
- #include <mail_queue.h>
- #include <tok822.h>
-+#include <pfixtls.h>
- /* Single-threaded server skeleton. */
-@@ -307,6 +308,7 @@
-   */
- int     var_smtpd_rcpt_limit;
- int     var_smtpd_tmout;
-+char   *var_relay_ccerts;
- int     var_smtpd_soft_erlim;
- int     var_smtpd_hard_erlim;
- int     var_queue_minfree;            /* XXX use off_t */
-@@ -350,6 +352,14 @@
- char   *var_smtpd_sasl_realm;
- char   *var_filter_xport;
- bool    var_broken_auth_clients;
-+int     var_smtpd_starttls_tmout;
-+int     var_smtpd_tls_wrappermode;
-+int     var_smtpd_use_tls;
-+int     var_smtpd_enforce_tls;
-+int     var_smtpd_tls_ask_ccert;
-+int     var_smtpd_tls_req_ccert;
-+int     var_smtpd_tls_ccert_vd;
-+int     var_smtpd_tls_received_header;
-  /*
-   * Global state, for stand-alone mode queue file cleanup. When this is
-@@ -445,11 +455,21 @@
-     else
-       smtpd_chat_reply(state, "250-SIZE");
-     smtpd_chat_reply(state, "250-ETRN");
-+#ifdef HAS_SSL
-+    if ((state->tls_use_tls || state->tls_enforce_tls) && (!state->tls_active))
-+      smtpd_chat_reply(state, "250-STARTTLS");
-+#endif
- #ifdef USE_SASL_AUTH
-     if (var_smtpd_sasl_enable) {
-+#ifdef HAS_SSL
-+      if (!state->tls_enforce_tls || state->tls_active) {
-+#endif
-       smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list);
-       if (var_broken_auth_clients)
-           smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list);
-+#ifdef HAS_SSL
-+      }
-+#endif
-     }
- #endif
-     smtpd_chat_reply(state, "250 8BITMIME");
-@@ -807,11 +827,76 @@
-     state->rcpt_count = 0;
- }
-+/* CN_sanitize - make sure, the CN-string is well behaved */
-+
-+static void CN_sanitize(char *CNstring)
-+{
-+    int i;
-+    int len;
-+    int parencount;
-+
-+    /*
-+     * The information included in the CN (CommonName) of the peer and its
-+     * issuer can be included into the Received: header line. The characters
-+     * allowed as well as comment nesting are limited by RFC822.
-+     */
-+
-+    len = strlen(CNstring);
-+    /*
-+     * The Received: header can only contain characters. Make sure that only
-+     * acceptable characters are printed. Maybe we could allow more, but
-+     * not everything makes sense inside a CommonName.
-+     */
-+    for (i = 0; i < len; i++) 
-+      if (!((CNstring[i] >= 'A') && (CNstring[i] <='Z')) &&
-+          !((CNstring[i] >= 'a') && (CNstring[i] <='z')) &&
-+          !((CNstring[i] >= '0') && (CNstring[i] <='9')) &&
-+          (CNstring[i] != '(') && (CNstring[i] != ')') &&
-+          (CNstring[i] != '[') && (CNstring[i] != ']') &&
-+          (CNstring[i] != '{') && (CNstring[i] != '}') &&
-+          (CNstring[i] != '<') && (CNstring[i] != '>') &&
-+          (CNstring[i] != '?') && (CNstring[i] != '!') &&
-+          (CNstring[i] != ';') && (CNstring[i] != ':') &&
-+          (CNstring[i] != '"') && (CNstring[i] != '\'') &&
-+          (CNstring[i] != '/') && (CNstring[i] != '|') &&
-+          (CNstring[i] != '+') && (CNstring[i] != '&') &&
-+          (CNstring[i] != '~') && (CNstring[i] != '@') &&
-+          (CNstring[i] != '#') && (CNstring[i] != '$') &&
-+          (CNstring[i] != '%') && (CNstring[i] != '&') &&
-+          (CNstring[i] != '^') && (CNstring[i] != '*') &&
-+          (CNstring[i] != '_') && (CNstring[i] != '-') &&
-+          (CNstring[i] != '.') && (CNstring[i] != ' '))
-+          CNstring[i] = '?';
-+
-+    /*
-+     * This information will go into the Received: header inside a comment.
-+     * Since comments can be nested, parentheses '(' and ')' must match.
-+     */
-+    parencount = 0;
-+    for (i = 0; i < len; i++) {
-+      if (CNstring[i] == '(')
-+          parencount++;
-+      else if (CNstring[i] == ')')
-+          parencount--;
-+    }
-+    /*
-+     * The necessary condition is violated. Do YOU know, where to correct?
-+     * I don't know, so I will practically remove all parentheses.
-+     */
-+    if (parencount != 0) {
-+      for (i = 0; i < len; i++)
-+          if ((CNstring[i] == '(') || (CNstring[i] == ')'))
-+              CNstring[i] = '/';
-+    }
-+}
-+
- /* data_cmd - process DATA command */
- static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
- {
-     char   *start;
-+    char   *peer_CN;
-+    char   *issuer_CN;
-     int     len;
-     int     curr_rec_type;
-     int     prev_rec_type;
-@@ -846,6 +931,35 @@
-               "Received: from %s (%s [%s])",
-               state->helo_name ? state->helo_name : state->name,
-               state->name, state->addr);
-+    if (var_smtpd_tls_received_header && state->tls_active) {
-+      rec_fprintf(state->cleanup, REC_TYPE_NORM,
-+                  "\t(using %s with cipher %s (%d/%d bits))",
-+                  state->tls_info.protocol, state->tls_info.cipher_name,
-+                  state->tls_info.cipher_usebits,
-+                  state->tls_info.cipher_algbits);
-+      if (state->tls_info.peer_CN) {
-+            peer_CN = mystrdup(state->tls_info.peer_CN);
-+          CN_sanitize(peer_CN);
-+            issuer_CN = mystrdup(state->tls_info.issuer_CN);
-+          CN_sanitize(issuer_CN);
-+          if (state->tls_info.peer_verified)
-+              rec_fprintf(state->cleanup, REC_TYPE_NORM,
-+                      "\t(Client CN \"%s\", Issuer CN \"%s\" (verified OK))",
-+                      peer_CN, issuer_CN);
-+          else
-+              rec_fprintf(state->cleanup, REC_TYPE_NORM,
-+                      "\t(Client CN \"%s\", Issuer CN \"%s\" (not verified))",
-+                      peer_CN, issuer_CN);
-+          myfree(issuer_CN);
-+          myfree(peer_CN);
-+      }
-+      else if (var_smtpd_tls_ask_ccert)
-+          rec_fprintf(state->cleanup, REC_TYPE_NORM,
-+                      "\t(Client did not present a certificate)");
-+      else
-+          rec_fprintf(state->cleanup, REC_TYPE_NORM,
-+                      "\t(No client certificate requested)");
-+    }
-     if (state->rcpt_count == 1 && state->recipient) {
-       rec_fprintf(state->cleanup, REC_TYPE_NORM,
-                   "\tby %s (%s) with %s id %s",
-@@ -1144,6 +1258,77 @@
-     return (0);
- }
-+static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv)
-+{
-+    char   *err;
-+
-+#ifdef HAS_SSL
-+    if (argc != 1) {
-+      state->error_mask |= MAIL_ERROR_PROTOCOL;
-+      smtpd_chat_reply(state, "501 Syntax: STARTTLS");
-+      return (-1);
-+    }
-+    if (state->tls_active != 0) {
-+      state->error_mask |= MAIL_ERROR_PROTOCOL;
-+      smtpd_chat_reply(state, "554 Error: TLS already active");
-+      return (-1);
-+    }
-+    if (state->tls_use_tls == 0) {
-+      state->error_mask |= MAIL_ERROR_PROTOCOL;
-+      smtpd_chat_reply(state, "502 Error: command not implemented");
-+      return (-1);
-+    }
-+    if (!pfixtls_serverengine) {
-+      smtpd_chat_reply(state, "454 TLS not available due to temporary reason");
-+      return (0);
-+    }
-+    smtpd_chat_reply(state, "220 Ready to start TLS");
-+    vstream_fflush(state->client);
-+    /*
-+     * When deciding about continuing the handshake, we will stop when a
-+     * client certificate was _required_ and none was presented or the
-+     * verification failed. This however does only make sense when TLS is
-+     * enforced. Otherwise we would happily perform perform the SMTP
-+     * transaction without any STARTTLS at all! So only have the handshake
-+     * fail when TLS is also enforced.
-+     */
-+    if (pfixtls_start_servertls(state->client, var_smtpd_starttls_tmout,
-+                              state->name, state->addr, &(state->tls_info),
-+                      (var_smtpd_tls_req_ccert && state->tls_enforce_tls))) {
-+      /*
-+         * Typically the connection is hanging at this point, so
-+         * we should try to shut it down by force! Unfortunately this
-+         * problem is not addressed in postfix!
-+         */
-+      return (-1);
-+    }
-+    state->tls_active = 1;
-+    helo_reset(state);
-+    mail_reset(state);
-+    rcpt_reset(state);
-+    return (0);
-+#else
-+    state->error_mask |= MAIL_ERROR_PROTOCOL;
-+    smtpd_chat_reply(state, "502 Error: command not implemented");
-+    return (-1);
-+#endif
-+}
-+
-+static void tls_reset(SMTPD_STATE *state)
-+{
-+    int failure = 0;
-+
-+    if (state->reason && state->where && strcmp(state->where, SMTPD_AFTER_DOT))
-+      failure = 1;
-+#ifdef HAS_SSL
-+    vstream_fflush(state->client);
-+    if (state->tls_active)
-+      pfixtls_stop_servertls(state->client, var_smtpd_starttls_tmout,
-+                             failure, &(state->tls_info));
-+#endif
-+    state->tls_active = 0;
-+}
-+
-  /*
-   * The table of all SMTP commands that we know. Set the junk limit flag on
-   * any command that can be repeated an arbitrary number of times without
-@@ -1161,6 +1346,10 @@
-     "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT,
-     "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT,
-+#ifdef HAS_SSL
-+    "STARTTLS", starttls_cmd, 0,
-+#endif
-+
- #ifdef USE_SASL_AUTH
-     "AUTH", smtpd_sasl_auth_cmd, 0,
- #endif
-@@ -1250,9 +1439,28 @@
-               state->error_count++;
-               continue;
-           }
-+          if (state->tls_enforce_tls &&
-+              !state->tls_active &&
-+              cmdp->action != starttls_cmd &&
-+              cmdp->action != noop_cmd &&
-+              cmdp->action != ehlo_cmd &&
-+              cmdp->action != quit_cmd) {
-+              smtpd_chat_reply(state,
-+                               "530 Must issue a STARTTLS command first");
-+              state->error_count++;
-+              continue;
-+          }
-           state->where = cmdp->name;
--          if (cmdp->action(state, argc, argv) != 0)
-+          if (cmdp->action(state, argc, argv) != 0) {
-               state->error_count++;
-+              /*
-+               * Die after TLS negotiation failure, as there is no
-+               * stable way to recover from a possible mixture of
-+               * TLS and SMTP protocol from the client.
-+               */
-+              if (cmdp->action == starttls_cmd)
-+                  break;
-+          }
-           if ((cmdp->flags & SMTPD_CMD_FLAG_LIMIT)
-               && state->junk_cmds++ > var_smtpd_junk_cmd_limit)
-               state->error_count++;
-@@ -1289,6 +1497,7 @@
-      * Cleanup whatever information the client gave us during the SMTP
-      * dialog.
-      */
-+    tls_reset(state);
-     helo_reset(state);
- #ifdef USE_SASL_AUTH
-     if (var_smtpd_sasl_enable)
-@@ -1321,6 +1530,36 @@
-      * machines.
-      */
-     smtpd_state_init(&state, stream);
-+#ifdef HAS_SSL
-+    state.tls_use_tls = var_smtpd_use_tls | var_smtpd_enforce_tls;
-+    state.tls_enforce_tls = var_smtpd_enforce_tls;
-+    if (var_smtpd_tls_wrappermode) {
-+      /*
-+       * TLS has been set to wrapper mode, meaning that we run on a
-+       * seperate port and we must switch to TLS layer before actually
-+       * performing the SMTP protocol. This implies enforce-mode.
-+       */
-+      state.tls_use_tls = state.tls_enforce_tls = 1;
-+      if (pfixtls_start_servertls(state.client, var_smtpd_starttls_tmout,
-+                                    state.name, state.addr, &state.tls_info,
-+                                  var_smtpd_tls_req_ccert)) {
-+            /*
-+             * Typically the connection is hanging at this point, so
-+             * we should try to shut it down by force! Unfortunately this
-+             * problem is not addressed in postfix!
-+             */
-+            return;
-+      }
-+      state.tls_active = 1;
-+    }
-+#else
-+    state.tls_use_tls = 0;
-+    state.tls_enforce_tls = 0;
-+#endif
-+
-+    /*
-+     * Provide the SMTP service.
-+     */
-     /*
-      * See if we need to turn on verbose logging for this client.
-@@ -1338,10 +1577,6 @@
-       smtpd_chat_reply(&state, "220 %s", var_smtpd_banner);
-       msg_info("connect from %s[%s]", state.name, state.addr);
-     }
--
--    /*
--     * Provide the SMTP service.
--     */
-     smtpd_proto(&state);
-     /*
-@@ -1408,7 +1643,6 @@
- static void pre_jail_init(char *unused_name, char **unused_argv)
- {
--
-     /*
-      * Initialize blacklist/etc. patterns before entering the chroot jail, in
-      * case they specify a filename pattern.
-@@ -1424,6 +1658,12 @@
-       msg_warn("%s is true, but SASL support is not compiled in",
-                VAR_SMTPD_SASL_ENABLE);
- #endif
-+
-+#ifdef HAS_SSL
-+    if (var_smtpd_use_tls || var_smtpd_enforce_tls || var_smtpd_tls_wrappermode)
-+      pfixtls_init_serverengine(var_smtpd_tls_ccert_vd,
-+                                var_smtpd_tls_ask_ccert);
-+#endif
- }
- /* main - the main program */
-@@ -1446,10 +1686,12 @@
-       VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0,
-       VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
-       VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
-+      VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0,
-       0,
-     };
-     static CONFIG_TIME_TABLE time_table[] = {
-       VAR_SMTPD_TMOUT, DEF_SMTPD_TMOUT, &var_smtpd_tmout, 1, 0,
-+      VAR_SMTPD_STARTTLS_TMOUT, DEF_SMTPD_STARTTLS_TMOUT, &var_smtpd_starttls_tmout, 1, 0,
-       VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
-       0,
-     };
-@@ -1461,6 +1703,12 @@
-       VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
-       VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable,
-       VAR_BROKEN_AUTH_CLNTS, DEF_BROKEN_AUTH_CLNTS, &var_broken_auth_clients,
-+      VAR_SMTPD_TLS_WRAPPER, DEF_SMTPD_TLS_WRAPPER, &var_smtpd_tls_wrappermode,
-+      VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls,
-+      VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls,
-+      VAR_SMTPD_TLS_ACERT, DEF_SMTPD_TLS_ACERT, &var_smtpd_tls_ask_ccert,
-+      VAR_SMTPD_TLS_RCERT, DEF_SMTPD_TLS_RCERT, &var_smtpd_tls_req_ccert,
-+      VAR_SMTPD_TLS_RECHEAD, DEF_SMTPD_TLS_RECHEAD, &var_smtpd_tls_received_header,
-       0,
-     };
-     static CONFIG_STR_TABLE str_table[] = {
-@@ -1485,6 +1733,7 @@
-       VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0,
-       VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 1, 0,
-       VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
-+      VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_relay_ccerts, 0, 0,
-       0,
-     };
-@@ -1501,3 +1750,4 @@
-                      MAIL_SERVER_PRE_ACCEPT, pre_accept,
-                      0);
- }
-+
-diff -Nur snapshot-20010228-orig/src/smtpd/smtpd.h snapshot-20010228/src/smtpd/smtpd.h
---- snapshot-20010228-orig/src/smtpd/smtpd.h   Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtpd/smtpd.h        Wed Mar 21 13:32:23 2001
-@@ -32,6 +32,7 @@
-   * Global library.
-   */
- #include <mail_stream.h>
-+#include <pfixtls.h>
-  /*
-   * Variables that keep track of conversation state. There is only one SMTP
-@@ -76,6 +77,10 @@
-     VSTRING *sasl_encoded;
-     VSTRING *sasl_decoded;
- #endif
-+    int     tls_active;
-+    int     tls_use_tls;
-+    int     tls_enforce_tls;
-+    tls_info_t tls_info;
- } SMTPD_STATE;
- extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
-diff -Nur snapshot-20010228-orig/src/smtpd/smtpd_check.c snapshot-20010228/src/smtpd/smtpd_check.c
---- snapshot-20010228-orig/src/smtpd/smtpd_check.c     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtpd/smtpd_check.c  Wed Mar 21 13:32:23 2001
-@@ -268,6 +268,7 @@
- #include <namadr_list.h>
- #include <domain_list.h>
-+#include <string_list.h>
- #include <mail_params.h>
- #include <canon_addr.h>
- #include <resolve_clnt.h>
-@@ -320,6 +321,9 @@
-   */
- static DOMAIN_LIST *relay_domains;
- static NAMADR_LIST *mynetworks;
-+#ifdef HAS_SSL
-+static MAPS *relay_ccerts;
-+#endif
-  /*
-   * Pre-parsed restriction lists.
-@@ -445,6 +449,10 @@
-      */
-     mynetworks = namadr_list_init(var_mynetworks);
-     relay_domains = domain_list_init(var_relay_domains);
-+#ifdef HAS_SSL
-+    relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_relay_ccerts,
-+                             DICT_FLAG_LOCK);
-+#endif
-     /*
-      * Pre-parse and pre-open the recipient maps.
-@@ -771,6 +779,36 @@
- static int permit_auth_destination(char *recipient);
-+/* permit_tls_clientcerts - OK/DUNNO for message relaying */
-+
-+#ifdef HAS_SSL
-+static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs)
-+{
-+    char   *low_name;
-+    const char *found;
-+
-+    if (state->tls_info.peer_verified && permit_all_certs) {
-+      if (msg_verbose)
-+          msg_info("Relaying allowed for all verified client certificates");
-+      return(SMTPD_CHECK_OK);
-+    }
-+
-+    if (state->tls_info.peer_verified && state->tls_info.peer_fingerprint) {
-+      low_name = lowercase(mystrdup(state->tls_info.peer_fingerprint));
-+      found = maps_find(relay_ccerts, low_name, DICT_FLAG_FIXED);
-+      myfree(low_name);
-+      if (found) {
-+          if (msg_verbose)
-+              msg_info("Relaying allowed for certified client: %s", found);
-+          return (SMTPD_CHECK_OK);
-+      } else if (msg_verbose)
-+          msg_info("relay_clientcerts: No match for fingerprint '%s'",
-+                   state->tls_info.peer_fingerprint);
-+    }
-+    return (SMTPD_CHECK_DUNNO);
-+}
-+#endif
-+
- /* check_relay_domains - OK/FAIL for message relaying */
- static int check_relay_domains(SMTPD_STATE *state, char *recipient,
-@@ -1673,6 +1711,12 @@
-               status = permit_sasl_auth(state,
-                                         SMTPD_CHECK_OK, SMTPD_CHECK_DUNNO);
- #endif
-+#ifdef HAS_SSL
-+      } else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) {
-+        status = permit_tls_clientcerts(state, 1);
-+      } else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) {
-+        status = permit_tls_clientcerts(state, 0);
-+#endif
-       } else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) {
-           if (state->recipient)
-               status = reject_unknown_address(state, state->recipient,
-@@ -2060,6 +2104,7 @@
- char   *var_rcpt_checks = "";
- char   *var_etrn_checks = "";
- char   *var_relay_domains = "";
-+char   *var_relay_ccerts = "";
- char   *var_mynetworks = "";
- char   *var_notify_classes = "";
-diff -Nur snapshot-20010228-orig/src/smtpd/smtpd_state.c snapshot-20010228/src/smtpd/smtpd_state.c
---- snapshot-20010228-orig/src/smtpd/smtpd_state.c     Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/smtpd/smtpd_state.c  Wed Mar 21 13:32:23 2001
-@@ -91,6 +91,10 @@
-     state->recursion = 0;
-     state->msg_size = 0;
-     state->junk_cmds = 0;
-+    state->tls_active = 0;
-+    state->tls_use_tls = 0;
-+    state->tls_enforce_tls = 0;
-+    state->tls_info = tls_info_zero;
- #ifdef USE_SASL_AUTH
-     if (SMTPD_STAND_ALONE(state))
-diff -Nur snapshot-20010228-orig/src/tlsmgr/Makefile.in snapshot-20010228/src/tlsmgr/Makefile.in
---- snapshot-20010228-orig/src/tlsmgr/Makefile.in      Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/tlsmgr/Makefile.in   Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,75 @@
-+SHELL = /bin/sh
-+SRCS  = tlsmgr.c
-+OBJS  = tlsmgr.o
-+HDRS  =
-+TESTSRC       =
-+WARN  = -W -Wformat -Wimplicit -Wmissing-prototypes \
-+      -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
-+      -Wunused
-+DEFS  = -I. -I$(INC_DIR) -D$(SYSTYPE)
-+CFLAGS        = $(DEBUG) $(OPT) $(DEFS)
-+TESTPROG= 
-+PROG  = tlsmgr
-+INC_DIR       = ../../include
-+LIBS  = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a
-+
-+.c.o:;        $(CC) $(CFLAGS) -c $*.c
-+
-+$(PROG):      $(OBJS) $(LIBS)
-+      $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
-+
-+Makefile: Makefile.in
-+      (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@
-+
-+test: $(TESTPROG)
-+
-+update: ../../libexec/$(PROG)
-+
-+../../libexec/$(PROG): $(PROG)
-+      cp $(PROG) ../../libexec
-+
-+printfck: $(OBJS) $(PROG)
-+      rm -rf printfck
-+      mkdir printfck
-+      cp *.h printfck
-+      sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
-+      set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
-+      cd printfck; make "INC_DIR=../../../../include" `cd ../..; ls *.o`
-+
-+lint:
-+      lint $(DEFS) $(SRCS) $(LINTFIX)
-+
-+clean:
-+      rm -f *.o *core $(PROG) $(TESTPROG) junk 
-+      rm -rf printfck
-+
-+tidy: clean
-+
-+depend: $(MAKES)
-+      (sed '1,/^# do not edit/!d' Makefile.in; \
-+      set -e; for i in [a-z][a-z0-9]*.c; do \
-+          $(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
-+          -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
-+      done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
-+      @make -f Makefile.in Makefile
-+
-+# do not edit below this line - it is generated by 'make depend'
-+tlsmgr.o: tlsmgr.c
-+tlsmgr.o: ../../include/sys_defs.h
-+tlsmgr.o: ../../include/msg.h
-+tlsmgr.o: ../../include/events.h
-+tlsmgr.o: ../../include/vstream.h
-+tlsmgr.o: ../../include/vbuf.h
-+tlsmgr.o: ../../include/dict.h
-+tlsmgr.o: ../../include/argv.h
-+tlsmgr.o: ../../include/vstring.h
-+tlsmgr.o: ../../include/stringops.h
-+tlsmgr.o: ../../include/mymalloc.h
-+tlsmgr.o: ../../include/connect.h
-+tlsmgr.o: ../../include/myflock.h
-+tlsmgr.o: ../../include/mail_conf.h
-+tlsmgr.o: ../../include/mail_params.h
-+tlsmgr.o: ../../include/iostuff.h
-+tlsmgr.o: ../../include/master_proto.h
-+tlsmgr.o: ../../include/mail_server.h
-+tlsmgr.o: ../../include/pfixtls.h
-diff -Nur snapshot-20010228-orig/src/tlsmgr/tlsmgr.c snapshot-20010228/src/tlsmgr/tlsmgr.c
---- snapshot-20010228-orig/src/tlsmgr/tlsmgr.c Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/tlsmgr/tlsmgr.c      Wed Mar 21 13:32:23 2001
-@@ -0,0 +1,598 @@
-+/*++
-+/* NAME
-+/*    tlsmgr 8
-+/* SUMMARY
-+/*    Postfix TLS session cache and PRNG handling manager
-+/* SYNOPSIS
-+/*    \fBtlsmgr\fR [generic Postfix daemon options]
-+/* DESCRIPTION
-+/*    The tlsmgr process does housekeeping on the session cache database
-+/*    files. It runs through the databases and removes expired entries
-+/*    and entries written by older (incompatible) versions.
-+/*
-+/*    The tlsmgr is responsible for the PRNG handling. The used internal
-+/*    OpenSSL PRNG has a pool size of 8192 bits (= 1024 bytes). The pool
-+/*    is initially seeded at startup from an external source (EGD or
-+/*    /dev/urandom) and additional seed is obtained later during program
-+/*    run at a configurable period. The exact time of seed query is
-+/*    using random information and is equally distributed in the range of
-+/*    [0-\fBtls_random_reseed_period\fR] with a \fBtls_random_reseed_period\fR
-+/*    having a default of 1 hour.
-+/*
-+/*    Tlsmgr can be run chrooted and with dropped privileges, as it will
-+/*    connect to the entropy source at startup.
-+/*
-+/*    The PRNG is additionally seeded internally by the data found in the
-+/*    session cache and timevalues.
-+/*
-+/*    Tlsmgr reads the old value of the exchange file at startup to keep
-+/*    entropy already collected during previous runs.
-+/*
-+/*    From the PRNG random pool a cryptographically strong 1024 byte random
-+/*    sequence is written into the PRNG exchange file. The file is updated
-+/*    periodically with the time changing randomly from
-+/*    [0-\fBtls_random_prng_update_period\fR].
-+/* STANDARDS
-+/* SECURITY
-+/* .ad
-+/* .fi
-+/*    Tlsmgr is not security-sensitive. It only deals with external data
-+/*    to be fed into the PRNG, the contents is never trusted. The session
-+/*    cache housekeeping will only remove entries if expired and will never
-+/*    touch the contents of the cached data.
-+/* DIAGNOSTICS
-+/*    Problems and transactions are logged to the syslog daemon.
-+/* BUGS
-+/*    There is no automatic means to limit the number of entries in the
-+/*    session caches and/or the size of the session cache files.
-+/* CONFIGURATION PARAMETERS
-+/* .ad
-+/* .fi
-+/*    The following \fBmain.cf\fR parameters are especially relevant to
-+/*    this program. See the Postfix \fBmain.cf\fR file for syntax details
-+/*    and for default values. Use the \fBpostfix reload\fR command after
-+/*    a configuration change.
-+/* .SH Session Cache
-+/* .ad
-+/* .fi
-+/* .IP \fBsmtpd_tls_session_cache_database\fR
-+/*    Name of the SDBM file (type sdbm:) containing the SMTP server session
-+/*    cache. If the file does not exist, it is created.
-+/* .IP \fBsmtpd_tls_session_cache_timeout\fR
-+/*    Expiry time of SMTP server session cache entries in seconds. Entries
-+/*    older than this are removed from the session cache. A cleanup-run is
-+/*    performed periodically every \fBsmtpd_tls_session_cache_timeout\fR
-+/*    seconds. Default is 3600 (= 1 hour).
-+/* .IP \fBsmtp_tls_session_cache_database\fR
-+/*    Name of the SDBM file (type sdbm:) containing the SMTP client session
-+/*    cache. If the file does not exist, it is created.
-+/* .IP \fBsmtp_tls_session_cache_timeout\fR
-+/*    Expiry time of SMTP client session cache entries in seconds. Entries
-+/*    older than this are removed from the session cache. A cleanup-run is
-+/*    performed periodically every \fBsmtp_tls_session_cache_timeout\fR
-+/*    seconds. Default is 3600 (= 1 hour).
-+/* .SH Pseudo Random Number Generator
-+/* .ad
-+/* .fi
-+/* .IP \fBtls_random_source\fR
-+/*    Name of the EGD socket or device or regular file to obtain entropy
-+/*    from. The type of entropy source must be specified by preceding the
-+/*      name with the appropriate type: egd:/path/to/egd_socket,
-+/*      dev:/path/to/devicefile, or /path/to/regular/file.
-+/*    tlsmgr opens \fBtls_random_source\fR and tries to read
-+/*    \fBtls_random_bytes\fR from it.
-+/* .IP \fBtls_random_bytes\fR
-+/*    Number of bytes to be read from \fBtls_random_source\fR.
-+/*    Default value is 32 bytes. If using EGD, a maximum of 255 bytes is read.
-+/* .IP \fBtls_random_exchange_name\fR
-+/*    Name of the file written by tlsmgr and read by smtp and smtpd at
-+/*    startup. The length is 1024 bytes. Default value is
-+/*    /etc/postfix/prng_exch.
-+/* .IP \fBtls_random_reseed_period\fR
-+/*    Time in seconds until the next reseed from external sources is due.
-+/*    This is the maximum value. The actual point in time is calculated
-+/*    with a random factor equally distributed between 0 and this maximum
-+/*    value. Default is 3600 (= 60 minutes).
-+/* .IP \fBtls_random_prng_update_period\fR
-+/*    Time in seconds until the PRNG exchange file is updated with new
-+/*    pseude random values. This is the maximum value. The actual point
-+/*    in time is calculated with a random factor equally distributed
-+/*    between 0 and this maximum value. Default is 60 (= 1 minute).
-+/* SEE ALSO
-+/*    smtp(8) SMTP client
-+/*    smtpd(8) SMTP server
-+/* LICENSE
-+/* .ad
-+/* .fi
-+/*    The Secure Mailer license must be distributed with this software.
-+/* AUTHOR(S)
-+/*--*/
-+
-+/* System library. */
-+
-+#include <sys_defs.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <ctype.h>
-+#include <errno.h>
-+#include <string.h>
-+#include <sys/time.h>                 /* gettimeofday, not POSIX */
-+
-+/* OpenSSL library. */
-+#ifdef HAS_SSL
-+#include <openssl/rand.h>             /* For the PRNG */
-+#endif
-+
-+/* Utility library. */
-+
-+#include <msg.h>
-+#include <events.h>
-+#include <dict.h>
-+#include <stringops.h>
-+#include <mymalloc.h>
-+#include <connect.h>
-+#include <myflock.h>
-+
-+/* Global library. */
-+
-+#include <mail_conf.h>
-+#include <mail_params.h>
-+#include <pfixtls.h>
-+
-+/* Master process interface */
-+
-+#include <master_proto.h>
-+#include <mail_server.h>
-+
-+/* Application-specific. */
-+
-+ /*
-+  * Tunables.
-+  */
-+char   *var_tls_rand_source;
-+int   var_tls_rand_bytes;
-+int   var_tls_reseed_period;
-+int   var_tls_prng_upd_period;
-+
-+static int rand_exch_fd;
-+static int rand_source_dev_fd = -1;
-+static int rand_source_socket_fd = -1;
-+static int srvr_scache_db_active;
-+static int clnt_scache_db_active;
-+static DICT *srvr_scache_db = NULL;
-+static DICT *clnt_scache_db = NULL;
-+
-+static void tlsmgr_prng_upd_event(int unused_event, char *dummy)
-+{
-+    struct timeval tv;
-+    unsigned char buffer[1024];
-+    int next_period;
-+
-+#ifdef HAS_SSL
-+    /*
-+     * It is time to update the PRNG exchange file. Since other processes might
-+     * have added entropy, we do this in a read_stir-back_write cycle.
-+     */
-+    GETTIMEOFDAY(&tv);
-+    RAND_seed(&tv, sizeof(struct timeval));
-+
-+    if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0)
-+      msg_fatal("Could not lock random exchange file: %s",
-+                strerror(errno));
-+
-+    lseek(rand_exch_fd, 0, SEEK_SET);
-+    if (read(rand_exch_fd, buffer, 1024) < 0)
-+      msg_fatal("reading exchange file failed");
-+    RAND_seed(buffer, 1024);
-+
-+    RAND_bytes(buffer, 1024);
-+    lseek(rand_exch_fd, 0, SEEK_SET);
-+    if (write(rand_exch_fd, buffer, 1024) != 1024)
-+      msg_fatal("Writing exchange file failed");
-+
-+    if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0)
-+      msg_fatal("Could not unlock random exchange file: %s",
-+                strerror(errno));
-+
-+    /*
-+     * Make prediction difficult for outsiders and calculate the time for the
-+     * next execution randomly.
-+     */
-+    next_period = (var_tls_prng_upd_period * buffer[0]) / 255;
-+    event_request_timer(tlsmgr_prng_upd_event, dummy, next_period);
-+#endif
-+}
-+
-+
-+static void tlsmgr_reseed_event(int unused_event, char *dummy)
-+{
-+    int egd_success;
-+    int next_period;
-+    int rand_bytes;
-+    char buffer[255];
-+    struct timeval tv;
-+    unsigned char randbyte;
-+
-+#ifdef HAS_SSL
-+    /*
-+     * It is time to reseed the PRNG.
-+     */
-+
-+    GETTIMEOFDAY(&tv);
-+    RAND_seed(&tv, sizeof(struct timeval));
-+    if (rand_source_dev_fd != -1) {
-+      rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes);
-+      if (rand_bytes > 0)
-+          RAND_seed(buffer, rand_bytes);
-+      else if (rand_bytes < 0) {
-+          msg_fatal("Read from entropy device %s failed",
-+                    var_tls_rand_source);
-+      }
-+    } else if (rand_source_socket_fd != -1) {
-+      egd_success = 0;
-+      buffer[0] = 1;
-+      buffer[1] = var_tls_rand_bytes;
-+      if (write(rand_source_socket_fd, buffer, 2) != 2)
-+          msg_info("Could not talk to %s", var_tls_rand_source);
-+      else if (read(rand_source_socket_fd, buffer, 1) != 1)
-+          msg_info("Could not read info from %s", var_tls_rand_source);
-+      else {
-+          rand_bytes = buffer[0];
-+          if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes)
-+              msg_info("Could not read data from %s", var_tls_rand_source);
-+          else {
-+              egd_success = 1;
-+              RAND_seed(buffer, rand_bytes);
-+          }
-+      }
-+      if (!egd_success) {
-+          msg_info("Lost connection to EGD-device, exiting to reconnect.");
-+          exit(0);
-+      }
-+    } else if (*var_tls_rand_source) {
-+      rand_bytes = RAND_load_file(var_tls_rand_source, var_tls_rand_bytes);
-+    }
-+
-+    /*
-+     * Make prediction difficult for outsiders and calculate the time for the
-+     * next execution randomly.
-+     */
-+    RAND_bytes(&randbyte, 1);
-+    next_period = (var_tls_reseed_period * randbyte) / 255;
-+    event_request_timer(tlsmgr_reseed_event, dummy, next_period);
-+#endif
-+}
-+
-+
-+static int tlsmgr_do_scache_check(DICT *scache_db, int scache_timeout,
-+                                int start)
-+{
-+#ifdef HAS_SSL
-+    int func;
-+    int len;
-+    int n;
-+    int delete = 0;
-+    int result;
-+    struct timeval tv;
-+    const char *member;
-+    const char *value;
-+    char *member_copy;
-+    unsigned char nibble, *data;
-+    pfixtls_scache_info_t scache_info;
-+
-+    GETTIMEOFDAY(&tv);
-+    RAND_seed(&tv, sizeof(struct timeval));
-+
-+    /*
-+     * Run through the given dictionary and check the stored sessions.
-+     * If "start" is set to 1, a new run is initiated, otherwise the next
-+     * item is accessed. The state is internally kept in the DICT.
-+     */
-+    if (start)
-+      func = DICT_SEQ_FUN_FIRST;
-+    else
-+      func = DICT_SEQ_FUN_NEXT;
-+    result = dict_seq(scache_db, func, &member, &value);
-+
-+    if (result > 0)
-+      return 0;       /* End of list reached */
-+    else if (result < 0)
-+      msg_fatal("Database fault, should already be caught.");
-+    else {
-+      member_copy = mystrdup(member);
-+      len = strlen(value);
-+      RAND_seed(value, len);          /* Use it to increase entropy */
-+      if (len < 2 * sizeof(pfixtls_scache_info_t))
-+          delete = 1;         /* Messed up, delete */
-+      else if (len > 2 * sizeof(pfixtls_scache_info_t))
-+          len = 2 * sizeof(pfixtls_scache_info_t);
-+      if (!delete) {
-+          data = (unsigned char *)(&scache_info);
-+          memset(data, 0, len / 2);
-+          for (n = 0; n < len; n++) {
-+            if ((value[n] >= '0') && (value[n] <= '9'))
-+                nibble = value[n] - '0';
-+            else
-+                nibble = value[n] - 'A' + 10;
-+            if (n % 2)
-+                data[n / 2] |= nibble;
-+            else
-+                data[n / 2] |= (nibble << 4);
-+        }
-+
-+        if ((scache_info.scache_db_version != scache_db_version) ||
-+            (scache_info.openssl_version != openssl_version) ||
-+            (scache_info.timestamp + scache_timeout < time(NULL)))
-+          delete = 1;
-+      }
-+      if (delete)
-+          result = dict_del(scache_db, member_copy);
-+      myfree(member_copy);
-+    }
-+
-+    if (delete && result)
-+      msg_info("Could not delete %s", member);
-+    return 1;
-+
-+#else
-+    return 0;
-+#endif
-+}
-+
-+static void tlsmgr_clnt_cache_run_event(int unused_event, char *dummy)
-+{
-+
-+    /*
-+     * This routine runs when it is time for another tls session cache scan.
-+     * Make sure this routine gets called again in the future.
-+     */
-+    clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db, 
-+                              var_smtp_tls_scache_timeout, 1);
-+    event_request_timer(tlsmgr_clnt_cache_run_event, dummy,
-+               var_smtp_tls_scache_timeout);
-+}
-+
-+
-+static void tlsmgr_srvr_cache_run_event(int unused_event, char *dummy)
-+{
-+
-+    /*
-+     * This routine runs when it is time for another tls session cache scan.
-+     * Make sure this routine gets called again in the future.
-+     */
-+    srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db,
-+                              var_smtpd_tls_scache_timeout, 1);
-+    event_request_timer(tlsmgr_srvr_cache_run_event, dummy,
-+               var_smtpd_tls_scache_timeout);
-+}
-+
-+
-+static DICT *tlsmgr_cache_open(const char *dbname)
-+{
-+    DICT *retval;
-+    char *dbpagname;
-+    char *dbdirname;
-+
-+    /*
-+     * First, try to find out the real name of the database file, so that
-+     * it can be removed.
-+     */
-+    if (!strncmp(dbname, "sdbm:", 5)) {
-+      dbpagname = concatenate(dbname + 5, ".pag", NULL);
-+      REMOVE(dbpagname);
-+      myfree(dbpagname);
-+      dbdirname = concatenate(dbname + 5, ".dir", NULL);
-+      REMOVE(dbdirname);
-+      myfree(dbdirname);
-+    }
-+    else {
-+      msg_warn("Only type sdbm: supported: %s", dbname);
-+      return NULL;
-+    }
-+
-+    /*
-+     * Now open the dictionary. Do it with O_EXCL, so that we only open a
-+     * fresh file. If we cannot open it with a fresh file, then we won't
-+     * touch it.
-+     */
-+    retval = dict_open(dbname, O_RDWR | O_CREAT | O_EXCL,
-+            DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE);
-+    if (!retval)
-+      msg_warn("Could not create dictionary %s", dbname);
-+    return retval;
-+}
-+
-+/* tlsmgr_trigger_event - respond to external trigger(s) */
-+
-+static void tlsmgr_trigger_event(char *buf, int len,
-+                                     char *unused_service, char **argv)
-+{
-+    /*
-+     * Sanity check. This service takes no command-line arguments.
-+     */
-+    if (argv[0])
-+      msg_fatal("unexpected command-line argument: %s", argv[0]);
-+
-+}
-+
-+/* tlsmgr_loop - queue manager main loop */
-+
-+static int tlsmgr_loop(char *unused_name, char **unused_argv)
-+{
-+    /*
-+     * This routine runs as part of the event handling loop, after the event
-+     * manager has delivered a timer or I/O event (including the completion
-+     * of a connection to a delivery process), or after it has waited for a
-+     * specified amount of time. The result value of qmgr_loop() specifies
-+     * how long the event manager should wait for the next event.
-+     */
-+#define DONT_WAIT     0
-+#define WAIT_FOR_EVENT        (-1)
-+
-+    if (clnt_scache_db_active)
-+      clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db,
-+                                      var_smtp_tls_scache_timeout, 0);
-+    if (srvr_scache_db_active)
-+      srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db,
-+                                      var_smtpd_tls_scache_timeout, 0);
-+    if (clnt_scache_db_active || srvr_scache_db_active)
-+      return (DONT_WAIT);
-+    return (WAIT_FOR_EVENT);
-+}
-+
-+/* pre_accept - see if tables have changed */
-+
-+static void pre_accept(char *unused_name, char **unused_argv)
-+{
-+    if (dict_changed()) {
-+      msg_info("table has changed -- exiting");
-+      exit(0);
-+    }
-+}
-+
-+/* tlsmgr_pre_init - pre-jail initialization */
-+
-+static void tlsmgr_pre_init(char *unused_name, char **unused_argv)
-+{
-+    int rand_bytes;
-+    unsigned char buffer[255];
-+
-+#ifdef HAS_SSL
-+    /*
-+     * Access the external sources for random seed. We may not be able to
-+     * access them again if we are sent to chroot jail, so we must leave
-+     * dev: and egd: type sources open.
-+     */
-+    if (*var_tls_rand_source) {
-+        if (!strncmp(var_tls_rand_source, "dev:", 4)) {
-+          /*
-+           * Source is a random device
-+           */
-+          rand_source_dev_fd = open(var_tls_rand_source + 4, 0, 0);
-+          if (rand_source_dev_fd == -1) 
-+              msg_fatal("Could not open entropy device %s",
-+                        var_tls_rand_source);
-+          if (var_tls_rand_bytes > 255)
-+              var_tls_rand_bytes = 255;
-+          rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes);
-+          RAND_seed(buffer, rand_bytes);
-+      } else if (!strncmp(var_tls_rand_source, "egd:", 4)) {
-+          /*
-+           * Source is a EGD compatible socket
-+           */
-+          rand_source_socket_fd = unix_connect(var_tls_rand_source +4,
-+                                               BLOCKING, 10);
-+          if (rand_source_socket_fd == -1)
-+              msg_fatal("Could not connect to %s", var_tls_rand_source);
-+          if (var_tls_rand_bytes > 255)
-+              var_tls_rand_bytes = 255;
-+          buffer[0] = 1;
-+          buffer[1] = var_tls_rand_bytes;
-+          if (write(rand_source_socket_fd, buffer, 2) != 2)
-+              msg_fatal("Could not talk to %s", var_tls_rand_source);
-+          if (read(rand_source_socket_fd, buffer, 1) != 1)
-+              msg_fatal("Could not read info from %s", var_tls_rand_source);
-+          rand_bytes = buffer[0];
-+          if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes)
-+              msg_fatal("Could not read data from %s", var_tls_rand_source);
-+          RAND_seed(buffer, rand_bytes);
-+      } else {
-+          rand_bytes = RAND_load_file(var_tls_rand_source,
-+                                      var_tls_rand_bytes);
-+      }
-+    }
-+#endif
-+
-+    /*
-+     * Now open the PRNG exchange file
-+     */
-+    if (*var_tls_rand_exch_name) {
-+      rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600);
-+    }
-+
-+    /*
-+     * Finally, open the session cache files. Remove old files, if still there.
-+     * If we could not remove the old files, something is pretty wrong and we
-+     * won't touch it!!
-+     */
-+    if (*var_smtp_tls_scache_db)
-+      clnt_scache_db = tlsmgr_cache_open(var_smtp_tls_scache_db);
-+    if (*var_smtpd_tls_scache_db)
-+      srvr_scache_db = tlsmgr_cache_open(var_smtpd_tls_scache_db);
-+}
-+
-+/* qmgr_post_init - post-jail initialization */
-+
-+static void tlsmgr_post_init(char *unused_name, char **unused_argv)
-+{
-+    unsigned char buffer[1024];
-+
-+    /*
-+     * This routine runs after the skeleton code has entered the chroot jail.
-+     * Prevent automatic process suicide after a limited number of client
-+     * requests or after a limited amount of idle time.
-+     */
-+    var_use_limit = 0;
-+    var_idle_limit = 0;
-+
-+#ifdef HAS_SSL
-+    /*
-+     * Complete thie initialization by reading the additional seed from the
-+     * PRNG exchange file. Don't care how many bytes were actually read, just
-+     * seed buffer into the PRNG, regardless of its contents.
-+     */
-+    if (rand_exch_fd >= 0) {
-+      if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) == -1)
-+          msg_fatal("Could not lock random exchange file: %s",
-+                    strerror(errno));
-+      read(rand_exch_fd, buffer, 1024);
-+      if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) == -1)
-+          msg_fatal("Could not unlock random exchange file: %s",
-+                    strerror(errno));
-+      RAND_seed(buffer, 1024);
-+      tlsmgr_prng_upd_event(0, (char *) 0);
-+      tlsmgr_reseed_event(0, (char *) 0);
-+    }
-+#endif
-+
-+    clnt_scache_db_active = 0;
-+    srvr_scache_db_active = 0;
-+    if (clnt_scache_db)
-+      tlsmgr_clnt_cache_run_event(0, (char *) 0);
-+    if (srvr_scache_db)
-+      tlsmgr_srvr_cache_run_event(0, (char *) 0);
-+}
-+
-+/* main - the main program */
-+
-+int     main(int argc, char **argv)
-+{
-+    static CONFIG_STR_TABLE str_table[] = {
-+      VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source, 0, 0,
-+      0,
-+    };
-+    static CONFIG_TIME_TABLE time_table[] = {
-+      VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 0, 0,
-+      VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_upd_period, 0, 0,
-+      0,
-+    };
-+    static CONFIG_INT_TABLE int_table[] = {
-+      VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 0, 0,
-+      0,
-+    };
-+
-+    /*
-+     * Use the trigger service skeleton, because no-one else should be
-+     * monitoring our service port while this process runs, and because we do
-+     * not talk back to the client.
-+     */
-+    trigger_server_main(argc, argv, tlsmgr_trigger_event,
-+                      MAIL_SERVER_TIME_TABLE, time_table,
-+                      MAIL_SERVER_INT_TABLE, int_table,
-+                      MAIL_SERVER_STR_TABLE, str_table,
-+                      MAIL_SERVER_PRE_INIT, tlsmgr_pre_init,
-+                      MAIL_SERVER_POST_INIT, tlsmgr_post_init,
-+                      MAIL_SERVER_LOOP, tlsmgr_loop,
-+                      MAIL_SERVER_PRE_ACCEPT, pre_accept,
-+                      0);
-+}
-diff -Nur snapshot-20010228-orig/src/util/Makefile.in snapshot-20010228/src/util/Makefile.in
---- snapshot-20010228-orig/src/util/Makefile.in        Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/util/Makefile.in     Wed Mar 21 13:32:23 2001
-@@ -23,7 +23,7 @@
-       clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
-       sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \
-       hex_quote.c dict_alloc.c rand_sleep.c sane_time.c dict_debug.c \
--      sane_socketpair.c
-+      sane_socketpair.c dict_sdbm.c sdbm.c
- OBJS  = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
-       close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
-       dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
-@@ -48,7 +48,7 @@
-       clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
-       sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \
-       hex_quote.o dict_alloc.o rand_sleep.o sane_time.o dict_debug.o \
--      sane_socketpair.o
-+      sane_socketpair.o dict_sdbm.o sdbm.o
- HDRS  = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
-       dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
-       dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
-@@ -64,7 +64,7 @@
-       vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \
-       dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \
-       watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h \
--      sane_time.h sane_socketpair.h
-+      sane_time.h sane_socketpair.h dict_sdbm.h sdbm.h
- TESTSRC       = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
-       stream_test.c dup2_pass_on_exec.c
- WARN  = -W -Wformat -Wimplicit -Wmissing-prototypes \
-@@ -469,6 +469,7 @@
- dict_open.o: dict_unix.h
- dict_open.o: dict_tcp.h
- dict_open.o: dict_dbm.h
-+dict_open.o: dict_sdbm.h
- dict_open.o: dict_db.h
- dict_open.o: dict_nis.h
- dict_open.o: dict_nisplus.h
-@@ -1051,3 +1052,9 @@
- write_wait.o: sys_defs.h
- write_wait.o: msg.h
- write_wait.o: iostuff.h
-+sdbm.o: sdbm.c
-+sdbm.o: sdbm.h
-+dict_sdbm.o: sdbm.h
-+dict_sdbm.o: dict_sdbm.c
-+dict_sdbm.o: dict_sdbm.h
-+dict_sdbm.o: sys_defs.h
-diff -Nur snapshot-20010228-orig/src/util/dict_open.c snapshot-20010228/src/util/dict_open.c
---- snapshot-20010228-orig/src/util/dict_open.c        Wed Mar 21 13:26:25 2001
-+++ snapshot-20010228/src/util/dict_open.c     Wed Mar 21 13:32:23 2001
-@@ -157,6 +157,7 @@
- #include <dict_env.h>
- #include <dict_unix.h>
- #include <dict_tcp.h>
-+#include <dict_sdbm.h>
- #include <dict_dbm.h>
- #include <dict_db.h>
- #include <dict_nis.h>
-@@ -184,6 +185,7 @@
- #if 0
-     DICT_TYPE_TCP, dict_tcp_open,
- #endif
-+    "sdbm", dict_sdbm_open,
- #ifdef HAS_DBM
-     DICT_TYPE_DBM, dict_dbm_open,
- #endif
-diff -Nur snapshot-20010228-orig/src/util/dict_sdbm.c snapshot-20010228/src/util/dict_sdbm.c
---- snapshot-20010228-orig/src/util/dict_sdbm.c        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/util/dict_sdbm.c     Wed Mar 21 13:32:24 2001
-@@ -0,0 +1,407 @@
-+/*++
-+/* NAME
-+/*    dict_sdbm 3
-+/* SUMMARY
-+/*    dictionary manager interface to SDBM files
-+/* SYNOPSIS
-+/*    #include <dict_sdbm.h>
-+/*
-+/*    DICT    *dict_sdbm_open(path, open_flags, dict_flags)
-+/*    const char *name;
-+/*    const char *path;
-+/*    int     open_flags;
-+/*    int     dict_flags;
-+/* DESCRIPTION
-+/*    dict_sdbm_open() opens the named SDBM database and makes it available
-+/*    via the generic interface described in dict_open(3).
-+/* DIAGNOSTICS
-+/*    Fatal errors: cannot open file, file write error, out of memory.
-+/* SEE ALSO
-+/*    dict(3) generic dictionary manager
-+/*    sdbm(3) data base subroutines
-+/* LICENSE
-+/* .ad
-+/* .fi
-+/*    The Secure Mailer license must be distributed with this software.
-+/* AUTHOR(S)
-+/*    Wietse Venema
-+/*    IBM T.J. Watson Research
-+/*    P.O. Box 704
-+/*    Yorktown Heights, NY 10598, USA
-+/*--*/
-+
-+#include "sys_defs.h"
-+
-+/* System library. */
-+
-+#include <sys/stat.h>
-+#include <string.h>
-+#include <unistd.h>
-+
-+/* Utility library. */
-+
-+#include "msg.h"
-+#include "mymalloc.h"
-+#include "htable.h"
-+#include "iostuff.h"
-+#include "vstring.h"
-+#include "myflock.h"
-+#include "stringops.h"
-+#include "dict.h"
-+#include "dict_sdbm.h"
-+#include "sdbm.h"
-+
-+/* Application-specific. */
-+
-+typedef struct {
-+    DICT    dict;                     /* generic members */
-+    SDBM   *dbm;                      /* open database */
-+    char   *path;                     /* pathname */
-+} DICT_SDBM;
-+
-+/* dict_sdbm_lookup - find database entry */
-+
-+static const char *dict_sdbm_lookup(DICT *dict, const char *name)
-+{
-+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
-+    datum   dbm_key;
-+    datum   dbm_value;
-+    static VSTRING *buf;
-+    const char *result = 0;
-+
-+    dict_errno = 0;
-+
-+    /*
-+     * Acquire an exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
-+      msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
-+
-+    /*
-+     * See if this DBM file was written with one null byte appended to key
-+     * and value.
-+     */
-+    if (dict->flags & DICT_FLAG_TRY1NULL) {
-+      dbm_key.dptr = (void *) name;
-+      dbm_key.dsize = strlen(name) + 1;
-+      dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
-+      if (dbm_value.dptr != 0) {
-+          dict->flags &= ~DICT_FLAG_TRY0NULL;
-+          result = dbm_value.dptr;
-+      }
-+    }
-+
-+    /*
-+     * See if this DBM file was written with no null byte appended to key and
-+     * value.
-+     */
-+    if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
-+      dbm_key.dptr = (void *) name;
-+      dbm_key.dsize = strlen(name);
-+      dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
-+      if (dbm_value.dptr != 0) {
-+          if (buf == 0)
-+              buf = vstring_alloc(10);
-+          vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
-+          dict->flags &= ~DICT_FLAG_TRY1NULL;
-+          result = vstring_str(buf);
-+      }
-+    }
-+
-+    /*
-+     * Release the exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
-+      msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
-+
-+    return (result);
-+}
-+
-+/* dict_sdbm_update - add or update database entry */
-+
-+static void dict_sdbm_update(DICT *dict, const char *name, const char *value)
-+{
-+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
-+    datum   dbm_key;
-+    datum   dbm_value;
-+    int     status;
-+
-+    dbm_key.dptr = (void *) name;
-+    dbm_value.dptr = (void *) value;
-+    dbm_key.dsize = strlen(name);
-+    dbm_value.dsize = strlen(value);
-+
-+    /*
-+     * If undecided about appending a null byte to key and value, choose a
-+     * default depending on the platform.
-+     */
-+    if ((dict->flags & DICT_FLAG_TRY1NULL)
-+      && (dict->flags & DICT_FLAG_TRY0NULL)) {
-+#ifdef DBM_NO_TRAILING_NULL
-+      dict->flags &= ~DICT_FLAG_TRY1NULL;
-+#else
-+      dict->flags &= ~DICT_FLAG_TRY0NULL;
-+#endif
-+    }
-+
-+    /*
-+     * Optionally append a null byte to key and value.
-+     */
-+    if (dict->flags & DICT_FLAG_TRY1NULL) {
-+      dbm_key.dsize++;
-+      dbm_value.dsize++;
-+    }
-+
-+    /*
-+     * Acquire an exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
-+      msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
-+
-+    /*
-+     * Do the update.
-+     */
-+    if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value,
-+     (dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0)
-+      msg_fatal("error writing SDBM database %s: %m", dict_sdbm->path);
-+    if (status) {
-+      if (dict->flags & DICT_FLAG_DUP_IGNORE)
-+           /* void */ ;
-+      else if (dict->flags & DICT_FLAG_DUP_WARN)
-+          msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
-+      else
-+          msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
-+    }
-+
-+    /*
-+     * Release the exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
-+      msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
-+}
-+
-+
-+/* dict_sdbm_delete - delete one entry from the dictionary */
-+
-+static int dict_sdbm_delete(DICT *dict, const char *name)
-+{
-+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
-+    datum   dbm_key;
-+    int     status = 1;
-+    int     flags = 0;
-+
-+    /*
-+     * Acquire an exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
-+      msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
-+
-+    /*
-+     * See if this DBM file was written with one null byte appended to key
-+     * and value.
-+     */
-+    if (dict->flags & DICT_FLAG_TRY1NULL) {
-+      dbm_key.dptr = (void *) name;
-+      dbm_key.dsize = strlen(name) + 1;
-+      sdbm_clearerr(dict_sdbm->dbm);
-+      if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
-+          if (sdbm_error(dict_sdbm->dbm) != 0)        /* fatal error */
-+              msg_fatal("error deleting from %s: %m", dict_sdbm->path);
-+          status = 1;                         /* not found */
-+      } else {
-+          dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */
-+      }
-+    }
-+
-+    /*
-+     * See if this DBM file was written with no null byte appended to key and
-+     * value.
-+     */
-+    if (status > 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
-+      dbm_key.dptr = (void *) name;
-+      dbm_key.dsize = strlen(name);
-+      sdbm_clearerr(dict_sdbm->dbm);
-+      if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
-+          if (sdbm_error(dict_sdbm->dbm) != 0)        /* fatal error */
-+              msg_fatal("error deleting from %s: %m", dict_sdbm->path);
-+          status = 1;                         /* not found */
-+      } else {
-+          dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */
-+      }
-+    }
-+
-+    /*
-+     * Release the exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
-+      msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
-+
-+    return (status);
-+}
-+
-+/* traverse the dictionary */
-+
-+static int dict_sdbm_sequence(DICT *dict, const int function,
-+                                   const char **key, const char **value)
-+{
-+    char   *myname = "dict_sdbm_sequence";
-+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
-+    datum   dbm_key;
-+    datum   dbm_value;
-+    int     status = 0;
-+    static VSTRING *key_buf;
-+    static VSTRING *value_buf;
-+
-+    /*
-+     * Acquire an exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
-+      msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
-+
-+    /*
-+     * Determine and execute the seek function. It returns the key.
-+     */
-+    switch (function) {
-+    case DICT_SEQ_FUN_FIRST:
-+      dbm_key = sdbm_firstkey(dict_sdbm->dbm);
-+      break;
-+    case DICT_SEQ_FUN_NEXT:
-+      dbm_key = sdbm_nextkey(dict_sdbm->dbm);
-+      break;
-+    default:
-+      msg_panic("%s: invalid function: %d", myname, function);
-+    }
-+
-+    /*
-+     * Release the exclusive lock.
-+     */
-+    if ((dict->flags & DICT_FLAG_LOCK)
-+      && myflock(dict->fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
-+      msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
-+
-+    if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
-+
-+      /*
-+       * See if this DB file was written with one null byte appended to key
-+       * an d value or not. If necessary, copy the key.
-+       */
-+      if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) {
-+          *key = dbm_key.dptr;
-+      } else {
-+          if (key_buf == 0)
-+              key_buf = vstring_alloc(10);
-+          vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize);
-+          *key = vstring_str(key_buf);
-+      }
-+
-+      /*
-+       * Fetch the corresponding value.
-+       */
-+      dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
-+
-+      if (dbm_value.dptr != 0 && dbm_value.dsize > 0) {
-+
-+          /*
-+           * See if this DB file was written with one null byte appended to
-+           * key and value or not. If necessary, copy the key.
-+           */
-+          if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) {
-+              *value = dbm_value.dptr;
-+          } else {
-+              if (value_buf == 0)
-+                  value_buf = vstring_alloc(10);
-+              vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize);
-+              *value = vstring_str(value_buf);
-+          }
-+      } else {
-+
-+          /*
-+           * Determine if we have hit the last record or an error
-+           * condition.
-+           */
-+          if (sdbm_error(dict_sdbm->dbm))
-+              msg_fatal("error seeking %s: %m", dict_sdbm->path);
-+          return (1);                         /* no error: eof/not found
-+                                               * (should not happen!) */
-+      }
-+    } else {
-+
-+      /*
-+       * Determine if we have hit the last record or an error condition.
-+       */
-+      if (sdbm_error(dict_sdbm->dbm))
-+          msg_fatal("error seeking %s: %m", dict_sdbm->path);
-+      return (1);                             /* no error: eof/not found */
-+    }
-+    return (0);
-+}
-+
-+/* dict_sdbm_close - disassociate from data base */
-+
-+static void dict_sdbm_close(DICT *dict)
-+{
-+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
-+
-+    sdbm_close(dict_sdbm->dbm);
-+    myfree(dict_sdbm->path);
-+    myfree((char *) dict_sdbm);
-+}
-+
-+/* dict_sdbm_open - open SDBM data base */
-+
-+DICT   *dict_sdbm_open(const char *path, int open_flags, int dict_flags)
-+{
-+    DICT_SDBM *dict_sdbm;
-+    struct stat st;
-+    SDBM   *dbm;
-+    char   *dbm_path;
-+    int     lock_fd;
-+
-+    if (dict_flags & DICT_FLAG_LOCK) {
-+      dbm_path = concatenate(path, ".pag", (char *) 0);
-+      if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0)
-+          msg_fatal("open database %s: %m", dbm_path);
-+      if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
-+          msg_fatal("shared-lock database %s for open: %m", dbm_path);
-+    }
-+
-+    /*
-+     * XXX SunOS 5.x has no const in dbm_open() prototype.
-+     */
-+    if ((dbm = sdbm_open((char *) path, open_flags, 0644)) == 0)
-+      msg_fatal("open database %s.{dir,pag}: %m", path);
-+
-+    if (dict_flags & DICT_FLAG_LOCK) {
-+      if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
-+          msg_fatal("unlock database %s for open: %m", dbm_path);
-+      if (close(lock_fd) < 0)
-+          msg_fatal("close database %s: %m", dbm_path);
-+      myfree(dbm_path);
-+    }
-+    dict_sdbm = (DICT_SDBM *) mymalloc(sizeof(*dict_sdbm));
-+    dict_sdbm->dict.lookup = dict_sdbm_lookup;
-+    dict_sdbm->dict.update = dict_sdbm_update;
-+    dict_sdbm->dict.delete = dict_sdbm_delete;
-+    dict_sdbm->dict.sequence = dict_sdbm_sequence;
-+    dict_sdbm->dict.close = dict_sdbm_close;
-+    dict_sdbm->dict.fd = sdbm_pagfno(dbm);
-+    if (fstat(dict_sdbm->dict.fd, &st) < 0)
-+      msg_fatal("dict_sdbm_open: fstat: %m");
-+    dict_sdbm->dict.mtime = st.st_mtime;
-+    close_on_exec(sdbm_pagfno(dbm), CLOSE_ON_EXEC);
-+    close_on_exec(sdbm_dirfno(dbm), CLOSE_ON_EXEC);
-+    dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
-+    if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
-+      dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
-+    dict_sdbm->dbm = dbm;
-+    dict_sdbm->path = mystrdup(path);
-+
-+    return (&dict_sdbm->dict);
-+}
-diff -Nur snapshot-20010228-orig/src/util/dict_sdbm.h snapshot-20010228/src/util/dict_sdbm.h
---- snapshot-20010228-orig/src/util/dict_sdbm.h        Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/util/dict_sdbm.h     Wed Mar 21 13:32:24 2001
-@@ -0,0 +1,35 @@
-+#ifndef _DICT_SDBM_H_INCLUDED_
-+#define _DICT_SDBM_H_INCLUDED_
-+
-+/*++
-+/* NAME
-+/*    dict_dbm 3h
-+/* SUMMARY
-+/*    dictionary manager interface to DBM files
-+/* SYNOPSIS
-+/*    #include <dict_dbm.h>
-+/* DESCRIPTION
-+/* .nf
-+
-+ /*
-+  * Utility library.
-+  */
-+#include <dict.h>
-+
-+ /*
-+  * External interface.
-+  */
-+extern DICT *dict_sdbm_open(const char *, int, int);
-+
-+/* LICENSE
-+/* .ad
-+/* .fi
-+/*    The Secure Mailer license must be distributed with this software.
-+/* AUTHOR(S)
-+/*    Wietse Venema
-+/*    IBM T.J. Watson Research
-+/*    P.O. Box 704
-+/*    Yorktown Heights, NY 10598, USA
-+/*--*/
-+
-+#endif
-diff -Nur snapshot-20010228-orig/src/util/sdbm.c snapshot-20010228/src/util/sdbm.c
---- snapshot-20010228-orig/src/util/sdbm.c     Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/util/sdbm.c  Wed Mar 21 13:32:24 2001
-@@ -0,0 +1,939 @@
-+/*++
-+/* NAME
-+/*      sdbm 3h
-+/* SUMMARY
-+/*      SDBM Simple DBM: ndbm work-alike hashed database library
-+/* SYNOPSIS
-+/*      include "sdbm.h"
-+/* DESCRIPTION
-+/* .nf
-+/*--*/
-+
-+/*
-+ * sdbm - ndbm work-alike hashed database library
-+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
-+ * author: oz@nexus.yorku.ca
-+ * status: public domain.
-+ *
-+ * core routines
-+ */
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#ifdef WIN32
-+#include <io.h>
-+#include <errno.h>
-+#else
-+#include <unistd.h>
-+#endif
-+#include <sys/types.h>
-+#include <sys/stat.h>
-+#include <fcntl.h>
-+#include <errno.h>
-+#include <string.h>
-+#ifdef __STDC__
-+#include <stddef.h>
-+#endif
-+
-+#include <sdbm.h>
-+
-+/*
-+ * useful macros
-+ */
-+#define bad(x)          ((x).dptr == NULL || (x).dsize <= 0)
-+#define exhash(item)    sdbm_hash((item).dptr, (item).dsize)
-+#define ioerr(db)       ((db)->flags |= DBM_IOERR)
-+
-+#define OFF_PAG(off)    (long) (off) * PBLKSIZ
-+#define OFF_DIR(off)    (long) (off) * DBLKSIZ
-+
-+static long masks[] =
-+{
-+    000000000000, 000000000001, 000000000003, 000000000007,
-+    000000000017, 000000000037, 000000000077, 000000000177,
-+    000000000377, 000000000777, 000000001777, 000000003777,
-+    000000007777, 000000017777, 000000037777, 000000077777,
-+    000000177777, 000000377777, 000000777777, 000001777777,
-+    000003777777, 000007777777, 000017777777, 000037777777,
-+    000077777777, 000177777777, 000377777777, 000777777777,
-+    001777777777, 003777777777, 007777777777, 017777777777
-+};
-+
-+datum   nullitem =
-+{NULL, 0};
-+
-+typedef struct
-+{
-+    int     dirf;                     /* directory file descriptor */
-+    int     pagf;                     /* page file descriptor */
-+    int     flags;                    /* status/error flags, see below */
-+    long    maxbno;                   /* size of dirfile in bits */
-+    long    curbit;                   /* current bit number */
-+    long    hmask;                    /* current hash mask */
-+    long    blkptr;                   /* current block for nextkey */
-+    int     keyptr;                   /* current key for nextkey */
-+    long    blkno;                    /* current page to read/write */
-+    long    pagbno;                   /* current page in pagbuf */
-+    char   *pagbuf;                   /* page file block buffer */
-+    long    dirbno;                   /* current block in dirbuf */
-+    char   *dirbuf;                   /* directory file block buffer */
-+}       DBM;
-+
-+
-+/* ************************* */
-+
-+/*
-+ * sdbm - ndbm work-alike hashed database library
-+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
-+ * author: oz@nexus.yorku.ca
-+ * status: public domain. keep it that way.
-+ *
-+ * hashing routine
-+ */
-+
-+/*
-+ * polynomial conversion ignoring overflows
-+ * [this seems to work remarkably well, in fact better
-+ * then the ndbm hash function. Replace at your own risk]
-+ * use: 65599   nice.
-+ *      65587   even better.
-+ */
-+static long sdbm_hash (char *str, int len)
-+{
-+    unsigned long n = 0;
-+
-+#ifdef DUFF
-+#define HASHC   n = *str++ + 65599 * n
-+    if (len > 0)
-+      {
-+        int     loop = (len + 8 - 1) >> 3;
-+
-+        switch (len & (8 - 1))
-+          {
-+          case 0:
-+              do
-+                {
-+                    HASHC;
-+          case 7:
-+                    HASHC;
-+          case 6:
-+                    HASHC;
-+          case 5:
-+                    HASHC;
-+          case 4:
-+                    HASHC;
-+          case 3:
-+                    HASHC;
-+          case 2:
-+                    HASHC;
-+          case 1:
-+                    HASHC;
-+                }
-+              while (--loop);
-+          }
-+
-+      }
-+#else
-+    while (len--)
-+      n = *str++ + 65599 * n;
-+#endif
-+    return n;
-+}
-+
-+/*
-+ * check page sanity:
-+ * number of entries should be something
-+ * reasonable, and all offsets in the index should be in order.
-+ * this could be made more rigorous.
-+ */
-+static int chkpage (char *pag)
-+{
-+    int     n;
-+    int     off;
-+    short  *ino = (short *) pag;
-+
-+    if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof (short))
-+              return 0;
-+
-+    if (n > 0)
-+      {
-+        off = PBLKSIZ;
-+        for (ino++; n > 0; ino += 2)
-+          {
-+              if (ino[0] > off || ino[1] > off ||
-+                  ino[1] > ino[0])
-+                  return 0;
-+              off = ino[1];
-+              n -= 2;
-+          }
-+      }
-+    return 1;
-+}
-+
-+/*
-+ * search for the key in the page.
-+ * return offset index in the range 0 < i < n.
-+ * return 0 if not found.
-+ */
-+static int seepair (char *pag, int n, char *key, int siz)
-+{
-+    int     i;
-+    int     off = PBLKSIZ;
-+    short  *ino = (short *) pag;
-+
-+    for (i = 1; i < n; i += 2)
-+      {
-+        if (siz == off - ino[i] &&
-+            memcmp (key, pag + ino[i], siz) == 0)
-+            return i;
-+        off = ino[i + 1];
-+      }
-+    return 0;
-+}
-+
-+#ifdef SEEDUPS
-+static int duppair (char *pag, datum key)
-+{
-+    short  *ino = (short *) pag;
-+
-+    return ino[0] > 0 && seepair (pag, ino[0], key.dptr, key.dsize) > 0;
-+}
-+
-+#endif
-+
-+/* ************************* */
-+
-+/*
-+ * sdbm - ndbm work-alike hashed database library
-+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
-+ * author: oz@nexus.yorku.ca
-+ * status: public domain.
-+ *
-+ * page-level routines
-+ */
-+
-+/*
-+ * page format:
-+ *      +------------------------------+
-+ * ino  | n | keyoff | datoff | keyoff |
-+ *      +------------+--------+--------+
-+ *      | datoff | - - - ---->         |
-+ *      +--------+---------------------+
-+ *      |        F R E E A R E A       |
-+ *      +--------------+---------------+
-+ *      |  <---- - - - | data          |
-+ *      +--------+-----+----+----------+
-+ *      |  key   | data     | key      |
-+ *      +--------+----------+----------+
-+ *
-+ * calculating the offsets for free area:  if the number
-+ * of entries (ino[0]) is zero, the offset to the END of
-+ * the free area is the block size. Otherwise, it is the
-+ * nth (ino[ino[0]]) entry's offset.
-+ */
-+
-+static int fitpair (char *pag, int need)
-+{
-+    int     n;
-+    int     off;
-+    int     avail;
-+    short  *ino = (short *) pag;
-+
-+    off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
-+    avail = off - (n + 1) * sizeof (short);
-+    need += 2 * sizeof (short);
-+
-+    return need <= avail;
-+}
-+
-+static void putpair (char *pag, datum key, datum val)
-+{
-+    int     n;
-+    int     off;
-+    short  *ino = (short *) pag;
-+
-+    off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ;
-+/*
-+ * enter the key first
-+ */
-+    off -= key.dsize;
-+    (void) memcpy (pag + off, key.dptr, key.dsize);
-+    ino[n + 1] = off;
-+/*
-+ * now the data
-+ */
-+    off -= val.dsize;
-+    (void) memcpy (pag + off, val.dptr, val.dsize);
-+    ino[n + 2] = off;
-+/*
-+ * adjust item count
-+ */
-+    ino[0] += 2;
-+}
-+
-+static datum getpair (char *pag, datum key)
-+{
-+    int     i;
-+    int     n;
-+    datum   val;
-+    short  *ino = (short *) pag;
-+
-+    if ((n = ino[0]) == 0)
-+      return nullitem;
-+
-+    if ((i = seepair (pag, n, key.dptr, key.dsize)) == 0)
-+      return nullitem;
-+
-+    val.dptr = pag + ino[i + 1];
-+    val.dsize = ino[i] - ino[i + 1];
-+    return val;
-+}
-+
-+static datum getnkey (char *pag, int num)
-+{
-+    datum   key;
-+    int     off;
-+    short  *ino = (short *) pag;
-+
-+    num = num * 2 - 1;
-+    if (ino[0] == 0 || num > ino[0])
-+      return nullitem;
-+
-+    off = (num > 1) ? ino[num - 1] : PBLKSIZ;
-+
-+    key.dptr = pag + ino[num];
-+    key.dsize = off - ino[num];
-+
-+    return key;
-+}
-+
-+static int delpair (char *pag, datum key)
-+{
-+    int     n;
-+    int     i;
-+    short  *ino = (short *) pag;
-+
-+    if ((n = ino[0]) == 0)
-+      return 0;
-+
-+    if ((i = seepair (pag, n, key.dptr, key.dsize)) == 0)
-+      return 0;
-+/*
-+ * found the key. if it is the last entry
-+ * [i.e. i == n - 1] we just adjust the entry count.
-+ * hard case: move all data down onto the deleted pair,
-+ * shift offsets onto deleted offsets, and adjust them.
-+ * [note: 0 < i < n]
-+ */
-+    if (i < n - 1)
-+      {
-+        int     m;
-+        char   *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]);
-+        char   *src = pag + ino[i + 1];
-+        int     zoo = dst - src;
-+
-+/*
-+ * shift data/keys down
-+ */
-+        m = ino[i + 1] - ino[n];
-+#ifdef DUFF
-+#define MOVB    *--dst = *--src
-+        if (m > 0)
-+          {
-+              int     loop = (m + 8 - 1) >> 3;
-+
-+              switch (m & (8 - 1))
-+                {
-+                case 0:
-+                    do
-+                      {
-+                          MOVB;
-+                case 7:
-+                          MOVB;
-+                case 6:
-+                          MOVB;
-+                case 5:
-+                          MOVB;
-+                case 4:
-+                          MOVB;
-+                case 3:
-+                          MOVB;
-+                case 2:
-+                          MOVB;
-+                case 1:
-+                          MOVB;
-+                      }
-+                    while (--loop);
-+                }
-+          }
-+#else
-+        dst -= m;
-+        src -= m;
-+        memmove (dst, src, m);
-+#endif
-+/*
-+ * adjust offset index up
-+ */
-+        while (i < n - 1)
-+          {
-+              ino[i] = ino[i + 2] + zoo;
-+              i++;
-+          }
-+      }
-+    ino[0] -= 2;
-+    return 1;
-+}
-+
-+static void splpage (char *pag, char *new, long sbit)
-+{
-+    datum   key;
-+    datum   val;
-+
-+    int     n;
-+    int     off = PBLKSIZ;
-+    char    cur[PBLKSIZ];
-+    short  *ino = (short *) cur;
-+
-+    (void) memcpy (cur, pag, PBLKSIZ);
-+    (void) memset (pag, 0, PBLKSIZ);
-+    (void) memset (new, 0, PBLKSIZ);
-+
-+    n = ino[0];
-+    for (ino++; n > 0; ino += 2)
-+      {
-+        key.dptr = cur + ino[0];
-+        key.dsize = off - ino[0];
-+        val.dptr = cur + ino[1];
-+        val.dsize = ino[0] - ino[1];
-+/*
-+ * select the page pointer (by looking at sbit) and insert
-+ */
-+        (void) putpair ((exhash (key) & sbit) ? new : pag, key, val);
-+
-+        off = ino[1];
-+        n -= 2;
-+      }
-+}
-+
-+static int getdbit (DBM * db, long dbit)
-+{
-+    long    c;
-+    long    dirb;
-+
-+    c = dbit / BYTESIZ;
-+    dirb = c / DBLKSIZ;
-+
-+    if (dirb != db->dirbno)
-+      {
-+        if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0
-+            || read (db->dirf, db->dirbuf, DBLKSIZ) < 0)
-+            return 0;
-+        db->dirbno = dirb;
-+      }
-+
-+    return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ);
-+}
-+
-+static int setdbit (DBM * db, long dbit)
-+{
-+    long    c;
-+    long    dirb;
-+
-+    c = dbit / BYTESIZ;
-+    dirb = c / DBLKSIZ;
-+
-+    if (dirb != db->dirbno)
-+      {
-+        if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0
-+            || read (db->dirf, db->dirbuf, DBLKSIZ) < 0)
-+            return 0;
-+        db->dirbno = dirb;
-+      }
-+
-+    db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ);
-+
-+    if (dbit >= db->maxbno)
-+      db->maxbno += DBLKSIZ * BYTESIZ;
-+
-+    if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0
-+      || write (db->dirf, db->dirbuf, DBLKSIZ) < 0)
-+      return 0;
-+
-+    return 1;
-+}
-+
-+/*
-+ * getnext - get the next key in the page, and if done with
-+ * the page, try the next page in sequence
-+ */
-+static datum getnext (DBM * db)
-+{
-+    datum   key;
-+
-+    for (;;)
-+      {
-+        db->keyptr++;
-+        key = getnkey (db->pagbuf, db->keyptr);
-+        if (key.dptr != NULL)
-+            return key;
-+/*
-+ * we either run out, or there is nothing on this page..
-+ * try the next one... If we lost our position on the
-+ * file, we will have to seek.
-+ */
-+        db->keyptr = 0;
-+        if (db->pagbno != db->blkptr++)
-+            if (lseek (db->pagf, OFF_PAG (db->blkptr), SEEK_SET) < 0)
-+                break;
-+        db->pagbno = db->blkptr;
-+        if (read (db->pagf, db->pagbuf, PBLKSIZ) <= 0)
-+            break;
-+        if (!chkpage (db->pagbuf))
-+            break;
-+      }
-+
-+    return ioerr (db), nullitem;
-+}
-+
-+/*
-+ * all important binary trie traversal
-+ */
-+static int getpage (DBM * db, long hash)
-+{
-+    int     hbit;
-+    long    dbit;
-+    long    pagb;
-+
-+    dbit = 0;
-+    hbit = 0;
-+    while (dbit < db->maxbno && getdbit (db, dbit))
-+      dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1);
-+
-+    db->curbit = dbit;
-+    db->hmask = masks[hbit];
-+
-+    pagb = hash & db->hmask;
-+/*
-+ * see if the block we need is already in memory.
-+ * note: this lookaside cache has about 10% hit rate.
-+ */
-+    if (pagb != db->pagbno)
-+      {
-+/*
-+ * note: here, we assume a "hole" is read as 0s.
-+ * if not, must zero pagbuf first.
-+ */
-+        if (lseek (db->pagf, OFF_PAG (pagb), SEEK_SET) < 0
-+            || read (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+            return 0;
-+        if (!chkpage (db->pagbuf))
-+            return 0;
-+        db->pagbno = pagb;
-+      }
-+    return 1;
-+}
-+
-+/*
-+ * makroom - make room by splitting the overfull page
-+ * this routine will attempt to make room for SPLTMAX times before
-+ * giving up.
-+ */
-+static int makroom (DBM * db, long hash, int need)
-+{
-+    long    newp;
-+    char    twin[PBLKSIZ];
-+    char   *pag = db->pagbuf;
-+    char   *new = twin;
-+    int     smax = SPLTMAX;
-+
-+    do
-+      {
-+/*
-+ * split the current page
-+ */
-+        (void) splpage (pag, new, db->hmask + 1);
-+/*
-+ * address of the new page
-+ */
-+        newp = (hash & db->hmask) | (db->hmask + 1);
-+
-+/*
-+ * write delay, read avoidence/cache shuffle:
-+ * select the page for incoming pair: if key is to go to the new page,
-+ * write out the previous one, and copy the new one over, thus making
-+ * it the current page. If not, simply write the new page, and we are
-+ * still looking at the page of interest. current page is not updated
-+ * here, as sdbm_store will do so, after it inserts the incoming pair.
-+ */
-+        if (hash & (db->hmask + 1))
-+          {
-+              if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0
-+                  || write (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+                  return 0;
-+              db->pagbno = newp;
-+              (void) memcpy (pag, new, PBLKSIZ);
-+          }
-+        else if (lseek (db->pagf, OFF_PAG (newp), SEEK_SET) < 0
-+                 || write (db->pagf, new, PBLKSIZ) < 0)
-+            return 0;
-+
-+        if (!setdbit (db, db->curbit))
-+            return 0;
-+/*
-+ * see if we have enough room now
-+ */
-+        if (fitpair (pag, need))
-+            return 1;
-+/*
-+ * try again... update curbit and hmask as getpage would have
-+ * done. because of our update of the current page, we do not
-+ * need to read in anything. BUT we have to write the current
-+ * [deferred] page out, as the window of failure is too great.
-+ */
-+        db->curbit = 2 * db->curbit +
-+            ((hash & (db->hmask + 1)) ? 2 : 1);
-+        db->hmask |= db->hmask + 1;
-+
-+        if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0
-+            || write (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+            return 0;
-+
-+      }
-+    while (--smax);
-+/*
-+ * if we are here, this is real bad news. After SPLTMAX splits,
-+ * we still cannot fit the key. say goodnight.
-+ */
-+#ifdef BADMESS
-+    (void) write (2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44);
-+#endif
-+    return 0;
-+
-+}
-+
-+static SDBM *sdbm_prep (char *dirname, char *pagname, int flags, int mode)
-+{
-+    SDBM   *db;
-+    struct stat dstat;
-+
-+    if ((db = (SDBM *) mymalloc (sizeof (SDBM))) == NULL)
-+      return errno = ENOMEM, (SDBM *) NULL;
-+
-+    db->flags = 0;
-+    db->blkptr = 0;
-+    db->keyptr = 0;
-+/*
-+ * adjust user flags so that WRONLY becomes RDWR,
-+ * as required by this package. Also set our internal
-+ * flag for RDONLY if needed.
-+ */
-+    if (flags & O_WRONLY)
-+      flags = (flags & ~O_WRONLY) | O_RDWR;
-+    else if ((flags & 03) == O_RDONLY)
-+      db->flags = DBM_RDONLY;
-+#if defined(OS2) || defined(MSDOS) || defined(WIN32)
-+    flags |= O_BINARY;
-+#endif
-+
-+/*
-+ * Make sure to ignore the O_EXCL option, as the file might exist due
-+ * to the locking.
-+ */
-+    flags &= ~O_EXCL;
-+
-+/*
-+ * open the files in sequence, and stat the dirfile.
-+ * If we fail anywhere, undo everything, return NULL.
-+ */
-+
-+    if ((db->pagf = open (pagname, flags, mode)) > -1)
-+      {
-+        if ((db->dirf = open (dirname, flags, mode)) > -1)
-+          {
-+/*
-+ * need the dirfile size to establish max bit number.
-+ */
-+              if (fstat (db->dirf, &dstat) == 0)
-+                {
-+                    /*
-+                       * success
-+                       */
-+                    return db;
-+                }
-+              msg_info ("closing dirf");
-+              (void) close (db->dirf);
-+          }
-+        msg_info ("closing pagf");
-+        (void) close (db->pagf);
-+      }
-+    myfree ((char *) db);
-+    return (SDBM *) NULL;
-+}
-+
-+static DBM *sdbm_internal_open (SDBM * sdbm)
-+{
-+    DBM    *db;
-+    struct stat dstat;
-+
-+    if ((db = (DBM *) mymalloc (sizeof (DBM))) == NULL)
-+      return errno = ENOMEM, (DBM *) NULL;
-+
-+    db->flags = sdbm->flags;
-+    db->hmask = 0;
-+    db->blkptr = sdbm->blkptr;
-+    db->keyptr = sdbm->keyptr;
-+    db->pagf = sdbm->pagf;
-+    db->dirf = sdbm->dirf;
-+    db->pagbuf = sdbm->pagbuf;
-+    db->dirbuf = sdbm->dirbuf;
-+
-+/*
-+ * need the dirfile size to establish max bit number.
-+ */
-+    if (fstat (db->dirf, &dstat) == 0)
-+      {
-+/*
-+ * zero size: either a fresh database, or one with a single,
-+ * unsplit data page: dirpage is all zeros.
-+ */
-+        db->dirbno = (!dstat.st_size) ? 0 : -1;
-+        db->pagbno = -1;
-+        db->maxbno = dstat.st_size * BYTESIZ;
-+
-+        (void) memset (db->pagbuf, 0, PBLKSIZ);
-+        (void) memset (db->dirbuf, 0, DBLKSIZ);
-+        return db;
-+      }
-+    myfree ((char *) db);
-+    return (DBM *) NULL;
-+}
-+
-+static void sdbm_internal_close (DBM * db)
-+{
-+    if (db == NULL)
-+      errno = EINVAL;
-+    else
-+      {
-+        myfree ((char *) db);
-+      }
-+}
-+
-+datum   sdbm_fetch (SDBM * sdb, datum key)
-+{
-+    datum   retval;
-+    DBM    *db;
-+
-+    if (sdb == NULL || bad (key))
-+      return errno = EINVAL, nullitem;
-+
-+    if (!(db = sdbm_internal_open (sdb)))
-+      return errno = EINVAL, nullitem;
-+
-+    if (getpage (db, exhash (key)))
-+      {
-+        retval = getpair (db->pagbuf, key);
-+        sdbm_internal_close (db);
-+        return retval;
-+      }
-+
-+    sdbm_internal_close (db);
-+
-+    return ioerr (sdb), nullitem;
-+}
-+
-+int     sdbm_delete (SDBM * sdb, datum key)
-+{
-+    int     retval;
-+    DBM    *db;
-+
-+    if (sdb == NULL || bad (key))
-+      return errno = EINVAL, -1;
-+    if (sdbm_rdonly (sdb))
-+      return errno = EPERM, -1;
-+
-+    if (!(db = sdbm_internal_open (sdb)))
-+      return errno = EINVAL, -1;
-+
-+    if (getpage (db, exhash (key)))
-+      {
-+        if (!delpair (db->pagbuf, key))
-+            retval = -1;
-+/*
-+ * update the page file
-+ */
-+        else if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0
-+                 || write (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+            retval = ioerr (sdb), -1;
-+        else
-+            retval = 0;
-+      }
-+    else
-+      retval = ioerr (sdb), -1;
-+
-+    sdbm_internal_close (db);
-+
-+    return retval;
-+}
-+
-+int     sdbm_store (SDBM * sdb, datum key, datum val, int flags)
-+{
-+    int     need;
-+    int     retval;
-+    long    hash;
-+    DBM    *db;
-+
-+    if (sdb == NULL || bad (key))
-+      return errno = EINVAL, -1;
-+    if (sdbm_rdonly (sdb))
-+      return errno = EPERM, -1;
-+
-+    need = key.dsize + val.dsize;
-+/*
-+ * is the pair too big (or too small) for this database ??
-+ */
-+    if (need < 0 || need > PAIRMAX)
-+      return errno = EINVAL, -1;
-+
-+    if (!(db = sdbm_internal_open (sdb)))
-+      return errno = EINVAL, -1;
-+
-+    if (getpage (db, (hash = exhash (key))))
-+      {
-+/*
-+ * if we need to replace, delete the key/data pair
-+ * first. If it is not there, ignore.
-+ */
-+        if (flags == DBM_REPLACE)
-+            (void) delpair (db->pagbuf, key);
-+#ifdef SEEDUPS
-+        else if (duppair (db->pagbuf, key))
-+          {
-+              sdbm_internal_close (db);
-+              return 1;
-+          }
-+#endif
-+/*
-+ * if we do not have enough room, we have to split.
-+ */
-+        if (!fitpair (db->pagbuf, need))
-+            if (!makroom (db, hash, need))
-+              {
-+                  sdbm_internal_close (db);
-+                  return ioerr (db), -1;
-+              }
-+/*
-+ * we have enough room or split is successful. insert the key,
-+ * and update the page file.
-+ */
-+        (void) putpair (db->pagbuf, key, val);
-+
-+        if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0
-+            || write (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+          {
-+              sdbm_internal_close (db);
-+              return ioerr (db), -1;
-+          }
-+        /*
-+           * success
-+           */
-+        sdbm_internal_close (db);
-+        return 0;
-+      }
-+
-+    sdbm_internal_close (db);
-+    return ioerr (sdb), -1;
-+}
-+
-+/*
-+ * the following two routines will break if
-+ * deletions aren't taken into account. (ndbm bug)
-+ */
-+datum   sdbm_firstkey (SDBM * sdb)
-+{
-+    datum   retval;
-+    DBM    *db;
-+
-+    if (sdb == NULL)
-+      return errno = EINVAL, nullitem;
-+
-+    if (!(db = sdbm_internal_open (sdb)))
-+      return errno = EINVAL, nullitem;
-+
-+/*
-+ * start at page 0
-+ */
-+    if (lseek (db->pagf, OFF_PAG (0), SEEK_SET) < 0
-+      || read (db->pagf, db->pagbuf, PBLKSIZ) < 0)
-+      {
-+        sdbm_internal_close (db);
-+        return ioerr (sdb), nullitem;
-+      }
-+    db->pagbno = 0;
-+    db->blkptr = 0;
-+    db->keyptr = 0;
-+
-+    retval = getnext (db);
-+    sdb->blkptr = db->blkptr;
-+    sdb->keyptr = db->keyptr;
-+    sdbm_internal_close (db);
-+    return retval;
-+}
-+
-+datum   sdbm_nextkey (SDBM * sdb)
-+{
-+    datum   retval;
-+    DBM    *db;
-+
-+    if (sdb == NULL)
-+      return errno = EINVAL, nullitem;
-+
-+    if (!(db = sdbm_internal_open (sdb)))
-+      return errno = EINVAL, nullitem;
-+
-+    retval = getnext (db);
-+    sdb->blkptr = db->blkptr;
-+    sdb->keyptr = db->keyptr;
-+    sdbm_internal_close (db);
-+    return retval;
-+}
-+
-+void    sdbm_close (SDBM * db)
-+{
-+    if (db == NULL)
-+      errno = EINVAL;
-+    else
-+      {
-+        (void) close (db->dirf);
-+        (void) close (db->pagf);
-+        myfree ((char *) db);
-+      }
-+}
-+
-+SDBM   *sdbm_open (char *file, int flags, int mode)
-+{
-+    SDBM   *db;
-+    char   *dirname;
-+    char   *pagname;
-+    int     n;
-+
-+    if (file == NULL || !*file)
-+      return errno = EINVAL, (SDBM *) NULL;
-+/*
-+ * need space for two seperate filenames
-+ */
-+    n = strlen (file) * 2 + strlen (DIRFEXT) + strlen (PAGFEXT) + 2;
-+
-+    if ((dirname = (char *) mymalloc ((unsigned) n)) == NULL)
-+      return errno = ENOMEM, (SDBM *) NULL;
-+/*
-+ * build the file names
-+ */
-+    dirname = strcat (strcpy (dirname, file), DIRFEXT);
-+    pagname = strcpy (dirname + strlen (dirname) + 1, file);
-+    pagname = strcat (pagname, PAGFEXT);
-+
-+    db = sdbm_prep (dirname, pagname, flags, mode);
-+    myfree ((char *) dirname);
-+    return db;
-+}
-+
-diff -Nur snapshot-20010228-orig/src/util/sdbm.h snapshot-20010228/src/util/sdbm.h
---- snapshot-20010228-orig/src/util/sdbm.h     Thu Jan  1 01:00:00 1970
-+++ snapshot-20010228/src/util/sdbm.h  Wed Mar 21 13:32:24 2001
-@@ -0,0 +1,97 @@
-+/*++
-+/* NAME
-+/*      sdbm 3h
-+/* SUMMARY
-+/*      SDBM Simple DBM: ndbm work-alike hashed database library
-+/* SYNOPSIS
-+/*      include "sdbm.h"
-+/* DESCRIPTION
-+/* .nf
-+/*--*/
-+
-+#ifndef UTIL_SDBM_H
-+#define UTIL_SDBM_H
-+
-+/*
-+ * sdbm - ndbm work-alike hashed database library
-+ * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978).
-+ * author: oz@nexus.yorku.ca
-+ * status: public domain.
-+ */
-+
-+#define DUFF    /* go ahead and use the loop-unrolled version */
-+
-+#include <stdio.h>
-+
-+#define DBLKSIZ 16384                   /* SSL cert chains require more */
-+#define PBLKSIZ 8192                    /* SSL cert chains require more */
-+#define PAIRMAX 8008                    /* arbitrary on PBLKSIZ-N */
-+#define SPLTMAX 10                      /* maximum allowed splits */
-+                                        /* for a single insertion */
-+#define DIRFEXT ".dir"
-+#define PAGFEXT ".pag"
-+
-+typedef struct {
-+        int dirf;                      /* directory file descriptor */
-+        int pagf;                      /* page file descriptor */
-+        int flags;                     /* status/error flags, see below */
-+        long blkptr;                   /* current block for nextkey */
-+        int keyptr;                    /* current key for nextkey */
-+        char pagbuf[PBLKSIZ];          /* page file block buffer */
-+        char dirbuf[DBLKSIZ];          /* directory file block buffer */
-+} SDBM;
-+
-+#define DBM_RDONLY      0x1            /* data base open read-only */
-+#define DBM_IOERR       0x2            /* data base I/O error */
-+
-+/*
-+ * utility macros
-+ */
-+#define sdbm_rdonly(db)         ((db)->flags & DBM_RDONLY)
-+#define sdbm_error(db)          ((db)->flags & DBM_IOERR)
-+
-+#define sdbm_clearerr(db)       ((db)->flags &= ~DBM_IOERR)  /* ouch */
-+
-+#define sdbm_dirfno(db) ((db)->dirf)
-+#define sdbm_pagfno(db) ((db)->pagf)
-+
-+typedef struct {
-+        char *dptr;
-+        int dsize;
-+} datum;
-+
-+extern datum nullitem;
-+
-+/*
-+ * flags to sdbm_store
-+ */
-+#define DBM_INSERT      0
-+#define DBM_REPLACE     1
-+
-+/*
-+ * ndbm interface
-+ */
-+extern SDBM *sdbm_open(char *, int, int);
-+extern void sdbm_close(SDBM *);
-+extern datum sdbm_fetch(SDBM *, datum);
-+extern int sdbm_delete(SDBM *, datum);
-+extern int sdbm_store(SDBM *, datum, datum, int);
-+extern datum sdbm_firstkey(SDBM *);
-+extern datum sdbm_nextkey(SDBM *);
-+
-+/*
-+ * sdbm - ndbm work-alike hashed database library
-+ * tuning and portability constructs [not nearly enough]
-+ * author: oz@nexus.yorku.ca
-+ */
-+
-+#define BYTESIZ         8
-+
-+/*
-+ * important tuning parms (hah)
-+ */
-+
-+#define SEEDUPS                 /* always detect duplicates */
-+#define BADMESS                 /* generate a message for worst case:
-+                                   cannot make room after SPLTMAX splits */
-+#endif /* UTIL_SDBM_H */
-diff -Nur snapshot-20010228-orig/src/util/vstream.c snapshot-20010228/src/util/vstream.c
---- snapshot-20010228-orig/src/util/vstream.c  Wed Mar 21 13:26:27 2001
-+++ snapshot-20010228/src/util/vstream.c       Wed Mar 21 13:32:24 2001
-@@ -72,6 +72,9 @@
- /*    int     vstream_fileno(stream)
- /*    VSTREAM *stream;
- /*
-+/*    void    *vstream_context(stream)
-+/*    VSTREAM *stream;
-+/*
- /*    int     vstream_ferror(stream)
- /*    VSTREAM *stream;
- /*
-@@ -249,6 +252,9 @@
- /*    vstream_fileno() gives access to the file handle associated with
- /*    a buffered stream. With streams that have separate read/write
- /*    file descriptors, the result is the current descriptor.
-+/*
-+/*    vstream_context() returns the application context that is passed on to
-+/*    the application-specified read/write routines.
- /*
- /*    VSTREAM_PATH() is an unsafe macro that returns the name stored
- /*    with vstream_fopen() or with vstream_control(). The macro is
-diff -Nur snapshot-20010228-orig/src/util/vstream.h snapshot-20010228/src/util/vstream.h
---- snapshot-20010228-orig/src/util/vstream.h  Wed Mar 21 13:26:27 2001
-+++ snapshot-20010228/src/util/vstream.h       Wed Mar 21 13:32:24 2001
-@@ -90,6 +90,7 @@
- #define VSTREAM_GETCHAR()     VSTREAM_GETC(VSTREAM_IN)
- #define vstream_fileno(vp)    ((vp)->fd)
-+#define vstream_context(vp)   ((vp)->context)
- #define vstream_ferror(vp)    vbuf_error(&(vp)->buf)
- #define vstream_feof(vp)      vbuf_eof(&(vp)->buf)
- #define vstream_ftimeout(vp)  vbuf_timeout(&(vp)->buf)
diff --git a/postfix-virtual.patch b/postfix-virtual.patch
deleted file mode 100644 (file)
index ee2ce36..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-diff -ruN snapshot-20001005.orig/Makefile.in snapshot-20001005/Makefile.in
---- snapshot-20001005.orig/Makefile.in Sun Oct  1 02:42:42 2000
-+++ snapshot-20001005/Makefile.in      Mon Dec  4 21:33:21 2000
-@@ -6,7 +6,7 @@
-       src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \
-       src/showq src/postalias src/postcat src/postconf src/postdrop \
-       src/postkick src/postlock src/postlog src/postmap src/postsuper \
--      src/nqmgr src/spawn src/flush # src/base64 proto man html
-+      src/nqmgr src/spawn src/flush virtual # src/base64 proto man html
- default: update
-diff -ruN snapshot-20001005.orig/src/global/mail_params.h snapshot-20001005/src/global/mail_params.h
---- snapshot-20001005.orig/src/global/mail_params.h    Thu Oct  5 05:23:06 2000
-+++ snapshot-20001005/src/global/mail_params.h Mon Dec  4 21:34:53 2000
-@@ -1057,6 +1057,28 @@
- extern void mail_params_init(void);
-+/*
-+ * Tunables for the "virtual" local delivery agent
-+ */
-+#define VAR_VIRT_MAILBOX_MAPS  "virtual_mailbox_maps"
-+#define DEF_VIRT_MAILBOX_MAPS  ""
-+extern char *var_mailbox_maps;
-+#define VAR_VIRT_UID_MAPS      "virtual_uid_maps"
-+#define DEF_VIRT_UID_MAPS      ""
-+extern char *var_uid_maps;
-+#define VAR_VIRT_GID_MAPS      "virtual_gid_maps"
-+#define DEF_VIRT_GID_MAPS      ""
-+extern char *var_gid_maps;
-+#define VAR_VIRT_USEDOTLOCK    "virtual_usedotlock"
-+#define DEF_VIRT_USEDOTLOCK    0
-+extern bool var_virt_usedotlock;
-+#define VAR_VIRT_MINUID                "virtual_minimum_uid"
-+#define DEF_VIRT_MINUID                100
-+extern int  var_virt_minimum_uid;
-+#define VAR_VIRT_MAILBOX_BASE  "virtual_mailbox_base"
-+#define DEF_VIRT_MAILBOX_BASE  ""
-+extern char *var_virt_mailbox_base;
-+
-  /*
-   * Content inspection and filtering.
-   */
-diff -ruN virtual.orig/mailbox.c virtual/mailbox.c
---- virtual.orig/mailbox.c     Sun Jan 23 12:31:22 2000
-+++ snapshot-20001005/virtual/mailbox.c        Mon Dec  4 21:48:03 2000
-@@ -135,7 +135,7 @@
-           if (deliver_flock(vstream_fileno(dst), why) < 0)
-               vstream_fclose(dst);
-           else if (mail_copy(COPY_ATTR(state.msg_attr), dst,
--                             copy_flags, why) == 0) {
-+                             copy_flags, "\n", why) == 0) {
-               status = 0;
-           }
-       }
-diff -ruN virtual.orig/maildir.c virtual/maildir.c
---- virtual.orig/maildir.c     Sun Jan 23 12:31:23 2000
-+++ snapshot-20001005/virtual/maildir.c        Mon Dec  4 21:49:33 2000
-@@ -130,7 +130,7 @@
-           || (dst = vstream_fopen(tmpfile, O_WRONLY | O_CREAT | O_EXCL, 0600)) == 0)) {
-       vstring_sprintf(why, "create %s: %m", tmpfile);
-     } else {
--      if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, why) == 0) {
-+      if (mail_copy(COPY_ATTR(state.msg_attr), dst, copy_flags, "\n", why) == 0) {
-           if (link(tmpfile, newfile) < 0
-               && (errno != ENOENT
-                   || (make_dirs(curdir, 0700), make_dirs(newdir, 0700)) < 0
This page took 0.671034 seconds and 4 git commands to generate.