diff -Pur postfix-2.1.5/IPv6-ChangeLog postfix-2.1.5-ti1.25/IPv6-ChangeLog --- postfix-2.1.5/IPv6-ChangeLog Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/IPv6-ChangeLog Mon Sep 20 16:34:05 2004 @@ -0,0 +1,483 @@ +ChangeLog for Dean Strik's IPv6 patch for Postfix. The patch is based on +PLD's patch, which in turn seems to be based on KAME's. For more information: + + http://www.ipnet6.org/postfix/ + +--------------------------------------------------------------------- + +Version 1.25 Postfix release 2.1.3-2.1.5 + Postfix release 2.0.20 + Postfix snapshot 2.2-200406{16,28} + + Bugfix: Misplaced myfree() caused a small memory leak. Reported + by Christian von Roques. + File: util/match_ops.c + + Removed the colon (:) from the characters XFORWARD replaces by + a question mark (IPv6 addresses looked like 2001?610?1108?5010??1 + in logging). Reported by Philipp Morger. + File: smtpd/smtpd.c + +Version 1.24 Postfix release 2.1.1 + Postfix release 2.0.20 + Postfix snapshot 2.0.19-20040312 + Postfix snapshot 2.2-20040504 + + Bugfix: Prefixlen non-null host portion validation (in CIDR maps + for example) yielded incorrect results sometimes because signed + arithmetic was used instead of unsigned. + File: util/match_ops.c + + Patch correction: The TLS+IPv6 patch for Postfix 2.1.0 missed + the master.cf update (used for new installations). Added it + back. + +Version 1.23 Postfix release 2.1.0 + Postfix release 2.0.20 + Postfix snapshot 2.0.19-20040312 + + Patch fixes: Several code fixes to make the patch compile + and work correctly when compiled without IPv6 support. + + Bugfix (Solaris only?): address family length was not updated + which could cause client hostname validation errors. + File: smtpd/smtpd_peer.c + + Portability: added support for Darwin 7.3+. This may need + some further testing. + + Cleanup: Restructure and redocument interface address + retrieval functions. (This reduced the number of preprocessor + statements from 99 to 93 ;) + File: util/inet_addr_local.c + + Cleanup: make several explicit casts to have compilers shut + their pie holes about uninteresting things. + +Version 1.22 Postfix release 2.0.19 + Postfix snapshot 2.0.19-20040312 + + Feature: Support "inet_interfaces = IPv4:all" and + "inet_interfaces = IPv6:all", to restrict postfix to use + either IPv4-only or IPv6-only. A more complete implementation + will be part of a future patch. (Slightly modified) patch by + Michal Ludvig, SuSE. + Files: util/interfaces_to_af.[ch], util/inet_addr_local.c, + global/own_inet_addr.c, global/wildcard_inet_addr.[ch], + master/master_ent.ch + + Bugfix: In Postfix snapshots, a #define was misplaced with + the effect that IPv6 subnets were not included in auto- + generated $mynetworks (i.e., mynetworks not defined in main.cf, + when also mynetworks_style=subnet) on Linux 2.x systems. + File: utils/sys_defs.h + +Version 1.21a Postfix snapshots 2.0.18-2004{0122,0205,0209} + 2.0.19-20040312 + + TLS/snapshot version: Update TLS patch to 0.8.18-20040122. + Performed as a total repatch. 0.8.18 is cleaner with tls_* + variables if TLS is not actually compiled in. + +Version 1.21 Postfix releases 2.0.18 - 2.0.19 + Postfix snapshot 2.0.16-20031231 + + Bugfix: The SMTP client could fail to setup a connection, + erroring with a bogus "getaddrinfo(...): hostname nor servname + provided" warning, because the wrong address was selected. + File: smtp/smtp_connect.c + + Safety: in dynamically growing data structures, update the + length info after (instead of before) updating the data size. + File: util/inet_addr_list.c + +Version 1.20 Postfix release 2.0.16 + Postfix snapshot 2.0.16-20031207 + + Bugfix: The SMTP client would abort when binding to specific + IPv6 addresses. + File: smtp/smtp_connect.c + + Synchronisation/bugfix: LMTP source address binding is identical + to the SMTP source binding setup, avoiding the need for + lmtp_bind_address(6) if inet_interfaces is set to a single + host for an address family. + File: lmtp/lmtp_connect.c + +Version 1.19 Postfix release 2.0.16 + Postfix snapshot 2.0.16-20031207 + + Bugfix: Synchronisation of TLS patches in snapshots of 1.18[ab] + was not complete, causing a crash of smtpd if used with the new + proxy agent. + File: smtpd/smtpd.c + + Bugfix: SMTP source address binding based on a single hostname + in inet_interfaces did not work since the code counted IPv4 and + IPv6 addresses instead of only the used address family. Fixed, + thereby no longer requiring exact specification of + smtp_bind_address(6) in this case. + File: smtp/smtp_connect.c + + Bugfix: The QMQP sink server did not compile correctly. This + program, part of smtpstone tools, is not compiled or installed + by default. + File: smtpstone/qmqp-sink.c + + Bugfix: NI_WITHSCOPEID was not correctly defined everywhere, + which could result in EAI_BADFLAGS. Changed location of + definition to correct it. + Files: util/sys_defs.h, util/inet_addr_list.h + +Version 1.18b Postfix snapshot 2.0.16-20030921 + + IPv6 support: Added IPv6-enabled code to the new snapshot + check_*_{ns,mx}_access restrictions. + File: smtpd/smtpd_check.c + +Version 1.18a Postfix release 2.0.16 + + Update (TLS patches): Updated Lutz Jaenicke's TLS patch to + version 0.8.16. See pfixtls/ChangeLog for details. + Diff contributed by Tuomo Soini. + + The TLS+IPv6 patch now contains the original TLS patch + documentation from Lutz Jaenicke. + +Version 1.18 Postfix releases 2.0.14 - 2.0.15 + Postfix snapshot 2.0.14-20030812 + + Bugfix: Perform actual hostname verification in the SMTP + and QMTP servers. This was never supported in the IPv6 + patch. Reported by Wolfgang S. Rupprecht. + Files: smtpd/smtpd_peer.c, qmqpd/qmqpd_peer.c + + IPv6 address ranges using address/prefixlength (e.g. in + mynetworks and access maps) should be written as + [ipv6:addr:ess]/plen (e.g. [fec0:10:20::]/48). The old + supported syntax, [ipv6:addr:ess/plen] is deprecated and + support will be removed in a later version. + Thanks to Dr. Peter Bieringer and Pekka Savola for discussion. + Files: util/match_ops.c, global/mynetworks.c + + Explicitly prefer IPv6 over IPv4 addresses when delivering + to a host when MX lookups are disabled when SMTP address + randomization is on (default). + File: smtp/smtp_addr.c + + Compliance: write IPv6 address literals in mail headers + as [IPv6:addr] instead of [addr] as per RFC 2821:4.1.3 + tagging requirement, for example [IPv6:fec0:10:20::1]. + Pointed out by Dr. Peter Bieringer. + Files: smtpd/smtpd{,_peer,_state}.c, smtpd/smtpd.h + +Version 1.17 Postfix release 2.0.13, 2.0.14 + Postfix snapshot 2.0.13-20030706, 2.0.14-20030812 + + Bugfix: Two memory allocation/deallocation bugs were + introduced in patch 1.16. The impact of these bugs could + be 'arbitrary' memory corruption. + File: util/match_ops.c + +Version 1.16 Postfix release 2.0.13 + Postfix snapshot 2.0.13-20030706 + + Cleanup: rewrote match_ops.c. This rewrite is partly based on + patch by Takahiro Igarashi. The rewrite enables some better + handling of scoped addresses, and drops all GPL code from the + patch, easying license considerations. Also, allowed for + use of this code by the CIDR maps. + Files: util/match_ops.[ch] + + Bugfix: correctly relay for scoped unicast addresses when + applicable. Until now, while Postfix was able to recognize + scoped addresses, it was not able to see e.g. fe80::10%fxp0 + as local in mynetworks validation. KAME-only code. + (I've never heard of people using scoped addresses (think + link-local addresses) for mail relaying though...) + Files: util/inet_addr_list.[ch] + + Feature (snapshot only): rewrote CIDR maps code to support + IPv6 addresses, using new match_ops code. Allow the use + of [::/0] since it allows one to easily disable further + checks for IPv6 addresses. + File: util/dict_cidr.c + + Consistency: require IPv6 addresses in inet_interfaces to + be enclosed in square brackets. + File: util/inet_addr_host.c + + Bugfix: (Linux2-only) A #define was misspelled. This could + lead to Postfix being unable to read the system's local IPv6 + addresses (e.g. when using inet_interfaces). + Spotted by Jochen Friedrich. + File: util/sys_defs.h + + Cleanup: require non-null host portion in CIDR / + prefixlength notations for IPv6 (was IPv4-only). + +Version 1.15a Postfix release 2.0.13 + + Update (TLS patches): Updated Lutz Jaenicke's TLS patch + to version 0.8.15. This version introduces new options + for managing SASL mechanisms. More information at: + http://www.aet.tu-cottbus.de/personen/jaenicke/pfixtls/ + Diff contributed by Tuomo Soini. + +Version 1.15 Postfix release 2.0.12, 2.0.13 + Postfix snapshot 2.0.12-20030621 + + Bugfix (TLS-snapshots only): a change in Postfix snapshot + 2.0.11-20030609 broke initialisation of TLS in smtpd, + causing TLS to both be unadvertised and unaccepted. + This was fixed again by reordering initialisation. + File: smtpd/smtpd.c + + Update (TLS patches): Updated Lutz Jaenicke's TLS patch + to version 0.8.14. This version introduces a few fixes and + uses USE_SSL instead of HAS_SSL. More information at: + http://www.aet.tu-cottbus.de/personen/jaenicke/pfixtls/ + Diff contributed by Tuomo Soini. + + Bugfix (Postfix releases only - this was already added to + the snapshots in patch 1.14). KAME derived systems only. + Correctly decode scoped addresses, including network + interface specifiers. + File: util/inet_addr_local.c + +Version 1.14 Postfix releases 2.0.9, 2.0.10, 2.0.11, 2.0.12 + Postfix snapshots 2.0.9-20030424, 2.0.10-20030521, + 2.0.11-20030609, 2.0.12-20030611 + + Patch change: made the patch available as an IPv6-only + patch (i.e., without the TLS code). This on popular + request by users and packagers. + A TLS+IPv6 version is still available of course. + + Bugfix: correctly decode scoped addresses from now on + (KAME derived systems only). I think the original code + was written by Itojun, so I'm rather puzzled that it + didn't work... + File: util/inet_addr_local.c + + Bugfix/portability: Recent KAME snapshots return both + TCP and SCTP address information on getaddrinfo() if + no protocol was specified. This causes the socket counts + to be wrong, confusing child processes. + Merged patch by JINMEI Tatuya of KAME to fix this. + Files: master/master.h, master/master_{ent,conf}.[ch], + util/inet_listen.c + + Documentation: added an IPV6_README file to the patch. + This file contains the primary documentation. Also, + added a sample-ipv6.cf to describe the (currently few) + IPv6 related main.cf parameters. + + Bugfix: the netmask structures for the *unsupported* + platforms (boldly assume /64) were added to the wrong + list (addresses instead of masks). This bug did not affect + any supported platform though. + File: util/inet_addr_local.c + + Portability: added support for HP/Compaq Tru64Unix V5.1 + and later. (compiled with CompaqCC only). + Thanks to Sten Spans for providing root access to an + IPv6-connected Tru64 testing machine. + +Version 1.13 Postfix releases 2.0.4 - 2.0.9 + Postfix snapshots 2.0.3-20030126 - 2.0.7-20030319 + + Bugfix: Due to a missing storage pointer, DNS lookup + results in the permit_mx_backups code were not processed, + and smtpd would likely crash. + Thanks to Wouter de Jong for reporting the crashes. + File: smtpd/smtpd_check.c + + Incompatible change: The addresses given to the parameters + smtp_bind_address6 and lmtp_bind_address6 now need to be + enclosed in square brackets for consistency. + Files: [ls]mtp/[ls]mtp_connect.c + +Version 1.12 Postfix releases 2.0.2, 2.0.3 + Postfix snapshots 2.0.2-20030115, 2.0.3-20030126 + + Bugfix/workaround (Solaris): A simplified comparison + function for Solaris' qsort() function, would result + in corruption of network addresses in the SMTP client. + Fixed. Reported with possible fix by Edvard Tuinder. + File: smtp/smtp_addr.c + +Version 1.11 Postfix releases 2.0.0.x, 2.0.1, 2.0.2 + Postfix snapshots 2.0.0-20030105, 2.0.1-20030112 + 2.0.2-20030115 + + Bugfix (Solaris): Properly initialize lifconf structure + when requesting host interface addresses. If you get + warnings about SIOCGLIFCONF with earlier versions, + please upgrade. + File: util/inet_addr_local.c + + Patch fix: fixed compilation errors in case the patch is + applied but built without IPv6 support (i.e., on unsupported + platforms). + +Version 1.10 Postfix snapshots 1.1.12-200212{19,21} + Postfix releases 2.0.0, 2.0.0.{1,2} + Postfix snapshots 2.0.0-20021223 - 2.0.0-20030101 + + 'Bugfix': don't show spurious warnings on Linux systems + about missing /proc/net/if_inet6 unless verbose mode + is enabled. + File: util/inet_addr_local.c + + Bugfix: If unable to create a socket for a specific adress + in the SMTP client (e.g., when trying to create an IPv6 + connection while the local host has no configured IPv6 + addresses), then stop the attempt. + File: smtp/smtp_connect.c + + Small bugfix: never query DNS for . + This syntax now correctly generates an error immediately. + File: global/resolve_local.c + + Updated TLS patch to 0.8.12-1.1.12-20021219-0.9.6h, fixing + a bug with "sendmail -bs". + +Version 1.9 Postfix version 1.1.11-20021115 + Postfix version 1.1.12-2002{1124,1209-1213} + + Bugfix: with getifaddrs() code (*BSD, linux-USAGI), IPv4 + netmasks were set to /32 effectively. Work around broken + netmask data structures (*BSD only perhaps). + + Bugfix: same data corruption in another place created + entirely wrong IPv4 netmasks. Work around broken + SIOCGIFNETMASK structure. + + New code was added for correct IPv6 netmasks. The original + code did not contain IPv6 netmask support at all! + For Solaris, use SIOCGLIF*; Linux: /proc/net/if_inet6. + Getifaddrs() support is used otherwise. This should cover + all supported systems. Other systems also work, prefix + length is always set to /64 then. + + Since there are no classes (context: Class A, class B etc + networks) with IPv6, default to IPv6 subnet style if the + mynetworks style is 'class'. I recommend against this style + anyway. + + Added support to display IPv6 nets mynetworks output. + +Version 1.8 Postfix version 1.1.11-200211{01,15} + + An earlier author of the patch made a typo in the GAI_STRERROR() + macro, resulting in bogus error messages when checking for + PTR records. Fixed. + + IPv4-mapped addresses in the smtpd are converted to true IPv4 + addresses just after the connection has been made. This means + that all IPv4-mapped addresses are now logged as true IPv4 + addresses. Hence beside RBL checks, also access maps now treat + IPv4-mapped addresses as native IPv4. Note that ::ffff:... + entries in your access tables will no longer work. + + You can now specify IPv6 'parent' networks in your access maps, + e.g. to reject all mail from 3ffe:200:... nodes, add the line + 3ffe:200 REJECT + Use of trailing colons is discouraged because postmap will + warn about it possibly being an alias... + NOTE: I'll soon obsolete this again in favor of the more + common address/len notation. This was just so trivial to add + that it didn't hurt and I needed it :) + + For easy reference, the version of the TLS/IPv6 patch can be + dynamically queried using the tls_ipv6_version variable. + This gives the short version (like, "1.8"). + + The service bind address for 'inet' sockets in master.cf (e.g., + smtpd), must be enclosed in square brackets '[..]' for IPv6 + addresses. The old style (without brackets) still works but is + unsupported and may be removed in the future. Example + [::1]:smtp inet n - n - - smtpd + +Version 1.7 Postfix version 1.1.11-20021029 - 1.1.11-20021101 + + Postfix' SMTP client performs randomization of MX addresses + when sending mail. This however could result in A records + being used before AAAA records. This has been corrected. + + Note that from Postfix version 1.1.11-20021029 on, there is + a proxy_interfaces parameter. This has of course not been + ported to IPv6 addresses... + +Version 1.6 Postfix version 1.1.11-20020928 + + Added IPv6 support for backup_mx_networks feature; also the + behaviour when DNS lookups fail when checking whether the + local host is an MX for a domain conforms to the IPv4 case: + defer rather than allow. + +Version 1.5 Postfix version 1.1.11-20020917 + + I introduced two bugs when I rewrote my older LMTP IPv6 patch. + These bugs effectively rendered LMTP useless. Now fixed. + Bugs spotted by Kaj Niemi. + + Now supports Solaris 8 and 9. Due to lack of testing equipment, + this has been only tested in production on Solaris 9, both + with gcc and the Sun Workshop Compiler. + +Version 1.4 Postfix version 1.1.11-20020822 - 1.1.11-20020917 + + OpenBSD (>=200003) and FreeBSD release 4 and up now use + getifaddrs(). This makes for cleaner code. The old code + seems to be bug-ridden anyway. + + Got rid of some compiler warnings. Should be cleaner on + Alpha as well now. Thanks to Sten Spans for providing me + access to an Alpha running FreeBSD4. + + Fixed an old bug in smtpd memory alloation if you compiled + without IPv6 support (the wrong buffer size was used. This + was harmless for IPv6-enabled compiles since the sizes were + equal then). + + Added ChangeLog to the patch (as IPv6-ChangeLog) (this + was absent in 1.3 contrary to docs). + +Version 1.3 Postfix version 1.1.11-20020613 - 1.1.11-20020718 + + FYI: In postfix version 1.1.11-20020718, DNS lookups for + AAAA can be done natively. The code matches the code in + the patch (though the #ifdef changed from INET6 to T_AAAA). + This change causes the patch for 1.1.11-20020718 to be a + bit smaller. + +Version 1.2 Postfix version 1.1.11-20020613 + + Added IPv6 support for the LMTP client. + + Added lmtp_bind_address and lmtp_bind_address6 parameters, + similar to those for smtp. + + Added IPv6 support for the QMQP server. + +Version 1.1 Postfix version 1.1.11-20020602 - 1.1.11-20020613 + + Added parameter smtp_bind_address6. By using this parameter, + it is possible to bind to an IPv6 address, independently of + IPv4 address binding. + + Lutz fixed a bug in his TLS patch regarding SASL. Incorporated. + +Version 1.0.x Postfix version 1.1.8-20020505 - 1.1.11-20020602 + + Patch derived from PLD's IPv6 patch for Postfix, revision 1.10 + which applied to early Postfix snapshots 1.1.x. Updated this + patch to apply to 1.1.8-20020505. + + Added compile-time checks for SS_LEN. Some Linux installations, + and maybe other systems, do define SA_LEN, but not SS_LEN. + + Several updates of postfix snapshots. + diff -Pur postfix-2.1.5/Makefile.in postfix-2.1.5-ti1.25/Makefile.in --- postfix-2.1.5/Makefile.in Wed Apr 14 20:57:00 2004 +++ postfix-2.1.5-ti1.25/Makefile.in Mon Sep 20 15:01:52 2004 @@ -7,7 +7,7 @@ src/pipe src/showq src/postalias src/postcat src/postconf src/postdrop \ src/postkick src/postlock src/postlog src/postmap src/postqueue \ src/postsuper src/qmqpd src/spawn src/flush src/verify \ - src/virtual src/proxymap + src/virtual src/proxymap src/tlsmgr MANDIRS = proto man html default: update diff -Pur postfix-2.1.5/README_FILES/IPV6_README postfix-2.1.5-ti1.25/README_FILES/IPV6_README --- postfix-2.1.5/README_FILES/IPV6_README Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/README_FILES/IPV6_README Mon Sep 20 16:34:09 2004 @@ -0,0 +1,158 @@ +Postfix IPv6 / IPv6+TLS patch +Maintained by Dean C. Strik + +These patches add IPv6 support to Postfix. A combo TLS+IPv6 patch is +available as a replacement for Lutz Jaenicke's TLS patch. + +More information about these IPv6 patches can be found on Dean Strik's +postfix website at + http://www.ipnet6.org/postfix/ + +CONTENTS +--------- + - Supported platforms + - Downloads + - Installation + - Configuration + - Mailing list + - Known issues + - Reporting bugs + +SUPPORTED PLATFORMS +-------------------- + +Currently, the following platforms are supported: + - FreeBSD 4.x/5.x + - OpenBSD 2.x/3.x + - NetBSD 1.5+ + - Solaris 8/9 + - Linux 2.x + - Darwin 7.3+ + - Tru64Unix V5.1+ +Postfix may work on other versions of these operating systems or +other operating systems entirely. If you find a problem on one +of the above platforms, please contact me at . + +DOWNLOADS +---------- + +The official download site is + + http://www.ipnet6.org/postfix/ + +Patches are offered as HTTP and FTP downloads here. To directly +access the files on the FTP server, use the following address: + + ftp://ftp.stack.nl/pub/postfix/tls+ipv6/ + +The patches are in gzipped context diff format. + +INSTALLATION +------------- + +The patch is distributed as a gzipped context diff. This used to +be unified diff (more readable), but it was changed because to +avoid unidiff limitations. + +We assume postfix is already extracted, to the directory + postfix-2.1.5 + +1. Decompress the patch: + e.g. $ gunzip tls+ipv6-1.25-pf-2.1.5.patch.gz +2. Change directory to the postfix source directory + e.g. $ cd postfix-2.1.5 +3. Apply the patch + e.g. $ patch -s -p 1 < ../tls+ipv6-1.25-pf-2.1.5.patch +4. Build postfix. The IPv6 patch does not require additional environment + variables or arguments to 'make'. + +CONFIGURATION +-------------- + +In theory, no post-installation configuration of postfix is +required, although you may want to extend the value of the +'mynetworks' parameter to include the IPv6 networks the system is +in. + +Also you can restrict Postfix to use IPv6-only or IPv4-only by +changing the 'inet_interfaces' parameter. + +The main.cf parameters regarding IPv6 are documented in the file +'sample-ipv6.cf' in the samples/ directory. + +MAILING LISTS +-------------- + +I've created two mailing lists about using IPv6 with Postfix. +There's a general list (postfix-ipv6) that can be used for discussion. +Also, there's an announcement-only list (postfix-ipv6-announce) +for people who only want to get the announcements. +All announcements are cross-posted to postfix-ipv6 though. + +List name: postfix-ipv6 +List type: Discussion / general (incl. announcements) +List info: http://lists.stack.nl/mailman/listinfo/postfix-ipv6 +List archive: http://lists.stack.nl/pipermail/postfix-ipv6 +List admin: Dean Strik + +List name: postfix-ipv6-announce +List type: Announcements only, moderated +List info: http://lists.stack.nl/mailman/listinfo/postfix-ipv6-announce +List archive: http://lists.stack.nl/pipermail/postfix-ipv6-announce +List admin: Dean Strik + +KNOWN ISSUES +------------- + +The patch comes with an IPv6-ChangeLog file. Please always validate +whether you have the latest version. You can always download the +latest ChangeLog at + + ftp://ftp.stack.nl/pub/postfix/tls+ipv6/ChangeLog + +The following 'issues' and todo items are known (none critical): + + - It is not currently supported to use Postfix network daemons + (such as smtp and smtpd) chrooted on Linux systems without + mounting the proc filesystem under /var/spool/postfix/proc + This is because the proc filesystem is required on Linux to + obtain the system's IPv6 address information. + + - The 'smtp_host_lookup' parameter is not effective with IPv6. + This is because a different lookup mechanism is used that + cannot easily disable the 'local' (i.e., non-DNS) lookups. + Whether local files or the DNS are used first, is determined + by your operating system, e.g. in /etc/nsswitch.conf or + /etc/host.conf. + + - The order of IPv6/IPv4 outgoing connection attempts is not + yet configurable. This will be configurable in a later, + soon to be released version. Currently, IPv6 is tried before + IPv4. + + - No IPv6 open relay checks. Since there is no IPv6 RBL service + around at the moment (I'm considering setting one up but it's + not a very hot issue), no lookups for IPv6 clients are ever done. + Let's not have a lot of worthless DNS traffic. Of course, when + this gets implemented, IPv6 client lookups will only be made + to DNSBLs that support these. + + - Tru64Unix: Using 'mynetworks_style = subnet' (which I do not + recommend in any case...) causes Postfix to assume a /64 for + all IPv6-connected IPv6 subnets. I have yet to find a good way + for obtaining the prefixlength. Suggestions are welcome! + +REPORTING BUGS +--------------- + +Of course there may be bugs in the patch. Please report bugs in the +patch to . Please be thorough in the report. +Patches, when possible, are greatly appreciated too! + +Please differentiate when possible between + - Problems in vanilla Postfix: + - Problems in Lutz' TLS patch: + - Problems in the IPv6 code: + +-- +Dean Strik diff -Pur postfix-2.1.5/conf/master.cf postfix-2.1.5-ti1.25/conf/master.cf --- postfix-2.1.5/conf/master.cf Wed Apr 21 13:35:32 2004 +++ postfix-2.1.5-ti1.25/conf/master.cf Mon Sep 20 15:01:52 2004 @@ -78,13 +78,16 @@ # (yes) (yes) (yes) (never) (100) # ========================================================================== smtp inet n - n - - smtpd -#submission inet n - n - - smtpd -# -o smtpd_etrn_restrictions=reject +#smtps inet n - n - - smtpd +# -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes +#submission inet n - n - - smtpd +# -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes -o smtpd_etrn_restrictions=reject #628 inet n - n - - qmqpd pickup fifo n - n 60 1 pickup cleanup unix n - n - 0 cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - n 300 1 oqmgr +#tlsmgr fifo - - n 300 1 tlsmgr rewrite unix - - n - - trivial-rewrite bounce unix - - n - 0 bounce defer unix - - n - 0 bounce diff -Pur postfix-2.1.5/conf/postfix-files postfix-2.1.5-ti1.25/conf/postfix-files --- postfix-2.1.5/conf/postfix-files Thu Apr 22 19:20:50 2004 +++ postfix-2.1.5-ti1.25/conf/postfix-files Mon Sep 20 15:01:52 2004 @@ -78,6 +78,7 @@ $daemon_directory/smtp:f:root:-:755 $daemon_directory/smtpd:f:root:-:755 $daemon_directory/spawn:f:root:-:755 +$daemon_directory/tlsmgr:f:root:-:755 $daemon_directory/trivial-rewrite:f:root:-:755 $daemon_directory/verify:f:root:-:755 $daemon_directory/virtual:f:root:-:755 @@ -165,6 +166,7 @@ $manpage_directory/man8/smtp.8:f:root:-:644 $manpage_directory/man8/smtpd.8:f:root:-:644 $manpage_directory/man8/spawn.8:f:root:-:644 +$manpage_directory/man8/tlsmgr.8:f:root:-:644 $manpage_directory/man8/trace.8:f:root:-:644 $manpage_directory/man8/trivial-rewrite.8:f:root:-:644 $manpage_directory/man8/verify.8:f:root:-:644 @@ -214,6 +216,7 @@ $readme_directory/FILTER_README:f:root:-:644 $readme_directory/HOSTING_README:f:root:-:644:o $readme_directory/INSTALL:f:root:-:644 +$readme_directory/IPV6_README:f:root:-:644 $readme_directory/LDAP_README:f:root:-:644 $readme_directory/LINUX_README:f:root:-:644 $readme_directory/LMTP_README:f:root:-:644 diff -Pur postfix-2.1.5/conf/sample-ipv6.cf postfix-2.1.5-ti1.25/conf/sample-ipv6.cf --- postfix-2.1.5/conf/sample-ipv6.cf Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/conf/sample-ipv6.cf Mon Sep 20 15:01:53 2004 @@ -0,0 +1,70 @@ +# 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 IPv6 operation of Postfix. Most of +# the parameters below are also described in the subsystem-specific +# sample cf files. + +# GENERAL CONTROLS + +# The inet_interfaces parameter specifies the network interface +# addresses that this mail system receives mail on. By default, +# the software claims all active interfaces on the machine. The +# parameter also controls delivery of mail to user@[ip.address]. +# +# You can also specify "all" (the default), or restrict the +# protocol family to IPv4 or IPv6, using "IPv4:all" and "IPv6:all", +# respectively. +# +# Note: you need to stop and start Postfix when this parameter changes. +# +#inet_interfaces = IPv4:all +#inet_interfaces = IPv6:all +inet_interfaces = all + +# IPv6 network ranges are written in the form [ipv6:addr:range]/plen. +# For example, a mynetworks specification could like this this: +# +mynetworks = [2001:db0:1000::/48] [::1/128] 127.0.0.1 192.168.0.0/16 + +# SMTP CLIENT CONTROLS + +# It can be preferable to assign a certain source address for outgoing +# SMTP connections. Since multiple address families (IPv4, IPv6) are +# supported, we need one binding address per address family. +# +# For IPv4, we use the smtp_bind_address parameter. The address is +# specified as an unbracketed dotquad IP. +# For IPv6, we use the smtp_bind_address6 parameter. The address is +# specified as a bracketed hex IPv6 address. +# +# The default is to bind to the wildcard IPv4 and IPv4 addresses, +# i.e. the address is automatically determined by the kernel based +# on the destination address. +# +smtp_bind_address = 1.2.3.4 +smtp_bind_address6 = [2001:610:1108:5010::225] + +# LMTP CLIENT CONTROLS + +# It's also possible that you want to assign a source address for +# LMTP client connections. This is not very likely, but possible +# anyway. Syntax and semantics are identical to the case described +# under 'SMTP CLIENT CONTROLS'. +# +lmtp_bind_address = 1.2.3.4 +lmtp_bind_address6 = [2001:610:1108:5010::225] + +# MISCELLANEOUS PARAMETERS + +# The tls_ipv6_version parameter specifies the version number of the +# TLS+IPv6 or IPv6 patch by Dean Strik. This version string can be +# used in e.g. bugreports. +# Note that the non-TLS version of the patch still names this parameter +# tls_ipv6_version. To determine whether TLS was actually compiled in, +# there are a lot of sources to look at it, for example check whether +# the parameter smtp_use_tls is defined. +# +tls_ipv6_version = 1.25 + diff -Pur postfix-2.1.5/conf/sample-tls.cf postfix-2.1.5-ti1.25/conf/sample-tls.cf --- postfix-2.1.5/conf/sample-tls.cf Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/conf/sample-tls.cf Mon Sep 20 15:01:53 2004 @@ -0,0 +1,499 @@ +# 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 using "smtpd_use_tls". (Note: when invoked +# via "sendmail -bs", STARTTLS is never offered due to insufficient +# privileges to access the private key. This is intended behaviour.) +# +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. (Note: when invoked via "sendmail -bs", STARTTLS +# is never offered due to insufficient privileges to access the private key. +# This is intended behaviour.) +# +# 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 + +# Sending AUTH data over an unencrypted channel poses a security risk. When +# smtpd_tls_enforce_tls is set, AUTH will only be announced and accepted, +# once the TLS layer has been activated via the STARTTLS protocol. If +# TLS layer encryption is optional, it may however still be useful to only +# offer AUTH, when TLS is active. To not break compatiblity with unpatched +# postfix versions, the default is to accept AUTH without encryption. In +# order to change this behaviour, set smtpd_tls_auth_only = yes. +# +# smtpd_tls_auth_only = no + +# 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). Checks are performed against +# all names provided as dNSNames in the SubjectAlternativeName. If no +# dNSNames are specified, the CommonName is checked. +# 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 -Pur postfix-2.1.5/makedefs postfix-2.1.5-ti1.25/makedefs --- postfix-2.1.5/makedefs Wed Apr 14 20:59:43 2004 +++ postfix-2.1.5-ti1.25/makedefs Mon Sep 20 15:01:53 2004 @@ -313,6 +313,33 @@ ;; esac +# Check for IPv6 support + +if [ -z "$NO_IPV6" ] ; then +if [ -f /usr/include/netinet6/in6.h ] ; then + grep __KAME__ /usr/include/netinet6/in6.h 2>&1 >/dev/null + if [ $? = 1 ]; then + INET6= + else + if [ -f /usr/local/v6/lib/libinet6.a ]; then + INET6=kame + else + INET6=kame-merged + fi + fi +fi +if [ -z "$INET6" -a -f /usr/include/netinet/ip6.h ]; then + case "$SYSTYPE" in + SUNOS5) INET6=solaris ;; + OSF1) INET6=osf1 ;; + *) ;; + esac +fi +if [ -z "$INET6" -a -f /usr/include/netinet/ip6.h -a -f /usr/include/linux/icmpv6.h ]; then + INET6=linux +fi +fi # [-z NO_IPV6] + # Defaults that can be overruled (make makefiles CC=cc OPT=-O6 DEBUG=) # Disable optimizations by default when compiling for Purify. Disable # optimizations by default with gcc 2.8, until the compiler is known to @@ -331,6 +358,31 @@ ${WARN='-W -Wformat -Wimplicit -Wmissing-prototypes \ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ -Wunused'} + +case "$INET6" in +kame) + CCARGS="$CCARGS -DINET6 -DINET6_KAME" + CCARGS="$CCARGS -D__ss_family=ss_family -D__ss_len=ss_len" + if test -f /usr/local/v6/lib/libinet6.a; then + SYSLIBS="$SYSLIBS -L/usr/local/v6/lib -linet6" + fi + ;; +kame-merged) + CCARGS="$CCARGS -DINET6 -DINET6_KAME" + CCARGS="$CCARGS -D__ss_family=ss_family -D__ss_len=ss_len" + ;; +solaris|osf1) + CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family -D__ss_len=ss_len" + ;; +linux) + CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family" + if test -f /usr/include/libinet6/netinet/ip6.h -a \ + -f /usr/lib/libinet6.a; then + CCARGS="$CCARGS -I/usr/include/libinet6 -DUSAGI_LIBINET6" + SYSLIBS="$SYSLIBS -linet6" + fi + ;; +esac export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS diff -Pur postfix-2.1.5/man/man8/tlsmgr.8 postfix-2.1.5-ti1.25/man/man8/tlsmgr.8 --- postfix-2.1.5/man/man8/tlsmgr.8 Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/man/man8/tlsmgr.8 Mon Sep 20 15:01:53 2004 @@ -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 -Pur postfix-2.1.5/pfixtls/ACKNOWLEDGEMENTS postfix-2.1.5-ti1.25/pfixtls/ACKNOWLEDGEMENTS --- postfix-2.1.5/pfixtls/ACKNOWLEDGEMENTS Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/ACKNOWLEDGEMENTS Mon Sep 20 15:01:53 2004 @@ -0,0 +1,56 @@ +- Walcir Fontanini + * tested on Solaris 2.5 and and reported missing "snprintf()" + -> was fixed in pfixtls-0.1.2 + * contributed the script to add fingerprints + contributed/fp.csh + +- Matti Aarnio (www.zmailer.org) + * updated pfixtls_dump to need fewer strcat and strcpy calls. + +- Cerebus + * Missing variable initialization in client mode enable STARTTLS + negotiation even when not wanted. + -> fixed in pfixtls-0.2.8 + +- Bodo Moeller + * The SSL connection was not shut down at the end of the session, because + SSL_CTX_set_quiet_shutdown() was set. This however did not mean "do a + quiet shutdown" but "do not shutdown SSL". + -> fixed in pfixtls-0.3.3 + +- Jeff Johnson + * noted that the patch code will not compile with SSL disabled anymore, + because a ´#ifdef HAS_SSL #endif´ encapsulation was missing in + smtp/smtp_connect.c. This must have been in since the very beginning + of client mode support (0.2.x). + -> fixed in 0.3.6 + +- Craig Sanders + * noted that the Received: header does not contain sufficient information + whether a client certificate was not requested or not presented. + He also reminded me that the session cache must be cleared when + experimenting with the setup and certificates, what is not explained + in the documenation. + -> fixed in 0.4.4 + +- Claus Assmann + * pointed out that the Received: header logging about the TLS state violated + RFC822. The TLS information must be in comment form "(info)". + -> fixed in 0.6.3 + +- Wietse Venema + * uncounted important suggestions to start the integration into the Postfix + mainstream code. + * code adjustments in the dict_*() database code to allow easier inclusion + and use for session caching, and this is only the beginning :-) + -> started reprogramming Postfix/TLS to fit both Wietse's and my + requirements as of 0.6.0 + +- Damien Miller + * Found mismatch between documentation and code with regard to logging. + -> fixed in 0.6.6 + +- Deti Fliegl + * Provided an initial patch to support SubjectAlternativeName/dNSName + checks. + -> added in 0.8.14 diff -Pur postfix-2.1.5/pfixtls/CHANGES postfix-2.1.5-ti1.25/pfixtls/CHANGES --- postfix-2.1.5/pfixtls/CHANGES Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/CHANGES Mon Sep 20 15:01:53 2004 @@ -0,0 +1,2385 @@ +2004/02/02 == Release 0.8.18 == + +2004/02/02 + - Incorporated Luca Berra's information into the patchkit and ran tests + with my own versions. + +2004/02/01 + - Reports about server side SMTP failure with Carsten's patch can be + found on postfix-users. + 'Luca Berra' informs, that he discoverd another + failure of the GNU patch program with a misplaced patch hunk in + smtpd.c + +2004/01/30 + - Edited in additional #ifdef USE_SSL conditionals. If the TLS patch + is applied but not activated (USE_SSL is not defined), a warning is + printed as soon as TLS shall be used. + +2004/01/23 + - Postfix 2.0.18-20040122 is now available. Several patch conflicts occur. + Even more: one hunk of the patch (which is provided in unified diff) + fails in smtp.c and causes a segmentation violation. + Carsten Hoeger provides an adapted patch kit. + +2004/01/02 == Released 0.8.17 == + +2004/01/02 + - Postfix-2.0.16-20031231 is released. No patch conflicts. + - Changed autoresponder for TLS tests to "The Postfix Book" echo + responder (provided by Patrick Koetter and Ralf Hildebrandt). + +2003/12/30 + - Postfix-2.0.16-20031226 is released. No patch conflicts. + +2003/12/26 + - Postfix-2.0.16-20031224 is released. Resolved patch conflicts. + +2003/12/16 + - Postfix-2.0.16-20031215 is released. Resolved patch conflicts. + - src/global/pfixtls.c: changed occurance of "ssize_t" to "size_t" + as some quite old operating systems do no have ssize_t + (Reported by Klaus Jaehne for SunOS 4.1.4). + - src/global/pfixtls.c: both the client and the server engine did + print out messages even when tls_loglevel was set to 0 (reported + by Florian Effenberger ): evaluate loglevel + before printing any message. + +2003/11/17 == Re-released 0.8.16 == + +2003/11/17 + - Postfix 2.0.16-20031113 is released. Some minor patch conflicts. + +2003/10/27 == Re-released 0.8.16 == + +2003/10/24 + - Postfix 2.0.16-20031022 is released. Some minor patch conflicts. + +2003/09/23 == Re-released 0.8.16 == + +2003/09/23 + - Postfix 2.0.16 and 2.0.16-20030921 are now available. + Resolved some minor patch conflicts. + +2003/09/10 == Released 0.8.16 == + +2003/09/09 + - Postfix 2.0.15 has been released including another workaround for + select() on Solaris problems. It contains additional code to catch + EAGAIN on read() in the timed_read() routine (and the respective + precautions in timed_write() + - Note: this fix is not yet part of Postfix 2.0.14-20030812. + - Added corresponding code to pfixtls_timed_read()/_write(). + - Changed SSL wrappermode behaviour: use smtpd_sasl_tls_security_options + instead of smtpd_sasl_security_options as is to be expected because TLS + is active. (Bug reported by Bob Snyder .) + +2003/08/29 == Re-released 0.8.15 == + +2003/08/29 + - Adapted patchkit to Postfix 2.0.14. No patch conflicts. + +2003/07/17 == Re-released 0.8.15a (-20030715 only) == + +2003/07/16 + - Experimental version Postfix 2.0.14-20030715 is released, including + the SASL changes. Resolved some minor patch conflicts. + +2003/07/11 == Released 0.8.15a (-20030706 only) == + +2003/07/11 + - Received error report about about TLS failing with the new smtpd_proxy + feature including instructions on how to reproduce. + (Did receive an earlier report on 2003/07/09, that however indicated other + setup problems, so that the actual problem was not visible.) + - Analysis: when introducing the new smtpd_proxy feature, different mechnisms + where introduced to either write to the cleanup daemon (as before) or to + the smtpd_proxy connection. Functions and streams are now expressed in + out_fprintf() function pointers etc. being assigned accordingly. + When updating to 0.8.15/2.0.13-20030706 this change was missed and the + routine adding the TLS information to the Received: headers did use the + older rec_fprintf() functions etc. This did work fine for the traditional + connection to the cleanup service, but naturally failed for smtpd_proxy + (with a segmentation violation). + Solution: access out_stream via the according pointers. + - The 2.0.13 stable version is not affected. + +2003/07/08 == Released 0.8.15 == + +2003/07/07 + - Postfix 2.0.13 and 2.0.13-20030706 are released. + Patchkit for 2.0.13 applies cleanly. + Patchkit for 2.0.13-20030607 requires several adaptations (patch conflicts, + no functional changes). + - Slightly modified SASL interface code (smpt[d]_sasl_glue layer) to + allow setting the security policy during session setup instead of + process start. This allows to actually choose SASL mechanisms available + depending on the availability of TLS encryption and authentication. + New parameters: smtpd_sasl_tls_security_options, + smtp_sasl_tls_security_options, smtp_sasl_tls_verified_security_options + - Submitted change to SASL interface to Wietse, who accepted the change + as part of the Snapshot line. + +2003/06/19 == Released 0.8.14 == + +2003/06/19 + - Add support for SubjectAlternativeName "dNSName" entries in certificate + checking (applies for client mode only). + If the client connects to the server, it does check the list of dNSName + entries against the expected hostname (therefore allowing the server to + have multiple identities). As described in RFC2818 (HTTP over TLS), + CommonName (CN) entries are only checked, if no dNSName entries are found + at all. + Initial patch proposed by Deti Fliegl , reworked to + follow the RFC2818 rules and some cleanup. + +2003/06/18 + - Checked out similar settings, found another missing entry: + var_smtp_scert_vd was missing src/smtp/smtp.c. + - Renamed HAS_SSL to USE_SSL for compilation (have to use -DUSE_SSL + in the future). Currently pfixtls.h will take care of setting + USE_SSL, when HAS_SSL has been defined. + +2003/06/17 + - Received bug reports about Postfix/TLS failing (connection closing) + after having finished the "STARTTLS"/"220 Ready to start TLS" + dialogue. (Actually the first report came in via private mail on + 2003/06/12, but the information was too diffuse to track down). + Tracking down became possible after it became clear, that only Solaris + systems are affected. + Analysis: + * As of 2003/06/09 postfix uses non-blocking socket I/O for the SMTP + connection on Solaris platforms. This requires using "select()" style + waiting before read() or write() access (which are not prepared EAGAIN + or EWOULDBLOCK in the Postfix case and therefore indicate error). + * As the var_smtpd_starttls_tmout variable is not correctly initialized + (value is 0), the select() style function is not called, therefore + read() fails with EAGAIN and the connection is closed due to a + presumed error condition. + * The initialization of the variable should be done in the time_table[] + list during main(). + The entry however was lost during the patch adaptation from 0.7.13e + to 0.7.14-snap20020107 on 2002/01/07. + Impact: + * On Solaris systems, STARTTLS fails during handshake (server only). + * On other systems, the TLS negotiation phase is not protected by the + smtpd_starttls_tmout (default 300s) value and may hang until the + watchdog kills smtpd, if the client does not continue the handshake. + Restored var_smtpd_starttls_tmout variable initialization. + +2003/06/12 == Re-released 0.8.13 == + +2003/06/11 + - Adapted to snapshot 2.0.12-20030611. No patch conflicts. + +2003/06/11 + - Adapted to snapshot 2.0.11-20030609. One minor patch conflict. + +2003/05/23 == Re-released 0.8.13 == + +2003/05/23 + - First release against snapshot 2.0.10-20030523. + +2003/04/26 == Re-released 0.8.13 == + +2003/04/26 + - Updated patchkit to apply to Postfix 2.0.9. + - Updated patchkit-name to reflect the release of OpenSSL 0.9.7b. + +2003/03/06 == Re-released 0.8.13 == + +2003/03/06 + - Postfix 2.0.6 has been released. No patch conflicts. + +2003/03/02 == Re-released 0.8.13 == + +2003/03/02 + - Postfix 2.0.4 has been released. "patch" should work with some warnings + about moved line numbers. + - OpenSSL 0.9.7a has been released. No visible changes with respect to + Postfix/TLS. + +2003/01/26 == Re-released 0.8.13 == + +2003/01/26 + - Postfix 2.0.3 has been released. One minor patch-conflict. + +2003/01/13 == Released 0.8.13 == + +2003/01/13 + - Postfix 2.0.1 has been released. Some minor patch conflicts resolved. + - Added HOWTO documents contributed by Justin Davies + to the contribution area. + - Added RFC3207 (SMTP Service Extension for Secure SMTP over Transport Layer + Security) to the documentation. RFC3207 is the successor of RFC2487. + - Updated TODO list to reflect release ideas up to the release of + Postfix/TLS 0.9.0. (Or will it finally be 1.0.0? :-) + +2002/12/30 + - OpenSSL 0.9.7 has been released. Postfix/TLS works best with the new + 0.9.7 release. + +2002/12/24 == Re-released 0.8.12 == + +2002/12/24 + - Postfix 2.0.0.1 has been released. Resolved one minor patch conflict. + +2002/12/20 == Re-released 0.8.12 == + +2002/12/20 + - Postfix snapshot 1.1.12-20021214 has been released. Resolved minor + patch conflicts. + +2002/12/15 == Re-released 0.8.12 == + +2002/12/15 + - Postfix snapshot 1.1.12-20021214 has been released. Two minor patch + conflicts. + +2002/12/06 == Released 0.8.12 == + +2002/12/06 + - OpenSSL 0.9.6h has been released. Update documentation and filenames + to reflect this new release. + - Minor bug fix: when calling "sendmail -bs", smtpd is not run with + superuser permissions, therefore the loading of the private key fails. + STARTTLS is not used anyway, so the key is not needed anyway, but the + failure to load creates a misleading warning. + Do not initialize TLS engine at all when not started with superuser + permissions. + +2002/12/03 + - Postfix snapshot 1.1.12-20021203 has been released. Resolved one patch + conflict. + +2002/11/01 == Re-released 0.8.11a == + +2002/11/01 + - Postfix snapshot 1.1.11-20021031 has been released. No patch conflicts. + +2002/10/30 == Re-released 0.8.11a == + +2002/10/30 + - Postfix snapshot 1.1.11-20021029 has been released. No patch conflicts. + +2002/09/30 == Re-released 0.8.11a == + +2002/09/30 + - Postfix snapshot 1.1.11-20020928 has been released. No patch conflices. + +2002/09/24 + - Postfix snapshot 1.1.11-20020923 has been released. Adapt patchkit. + +2002/09/19 == Re-released 0.8.11a == + +2002/09/18 + - Postfix snapshot 1.1.11-20020917 has been released. Adapt patchkit. + +2002/08/23 == Re-released 0.8.11a == + +2002/08/23 + - Postfix snapshot 1.1.11-20020822 has been released. Adapt patchkit. + +2002/08/20 + - Postfix snapshot 1.1.11-20020819 has been released with several + enhancements and changes. Adapt patchkit (minor issues). + +2002/08/12 + - OpenSSL has experienced several (security critical) updates. + +2002/07/26 == Re-released 0.8.11a == + +2002/07/26 + - On popular demand, a new diff for the snapshot version of Postfix + is created: postfix-1.1.11-20020719. + +2002/06/18 == Re-released 0.8.11a == + +2002/06/18 + - On popular demand, a new diff for the snapshot versions of Postfix + is created: postfix-1.1.11-20020613. + +2002/06/03 == Released 0.8.11a == + +2002/06/03 + - When compiling with SSL but without SASL, compilation fails due to + the modification of state->sasl_mechanism_list that is not part of the + "state" structure when SASL is not compiled in. + This bug was introduced in version 0.8.11. + Bug reported and patch supplied by Bernd Matthes + . + +2002/05/29 == Released 0.8.11 == + +2002/05/29 + - Postfix 1.1.11 is released. + +2002/05/25 + - Fix processing of options after STARTTLS handshaking: AUTH= was not + handled, as the "=" was not recognized as for the extension list for + the case without TLS. (The TLS case was a copy of an older version + of the code not yet containing the "=" and the change in the main + code slipped through without noting the difference, hence the option + as not added to the TLS part. + Found by "Christoph Vogel" . + +2002/05/24 + - Bug reported by "Christoph Vogel" : + Client side AUTH does not work, if STARTTLS is used: if a server + announces AUTH and STARTTLS, AUTH is being used if TLS is disabled. + Once TLS is enabled, AUTH is still offered by the server, but the + client does not use it any longer. + Reason: when AUTH is offered, not only the SMTP_REATURE_AUTH flag + is set in state->features, but also the available mechanisms are + remembered in state->sasl_mechanism_list. As AUTH may be offered + twice by some hosts (in the correct "AUTH mech" form and the older + and deprecated "AUTH=mech" form), a check against processing the + line twice is included in smtp_sasl_helo_auth(). This check now + prevented the correct processing in the second evaluation of the + ESMTP extensions offered after the STARTTLS activation. + Solution: reset state->sasl_mechanism_list before processing the + extension list just like state->features. + +2002/05/15 == Released 0.8.10 == + +2002/05/15 + - Postfix 1.1.10 has been released. No changes. + +2002/05/14 == Released 0.8.9 == + +2002/05/14 + - Postfix 1.1.9 has been released. Patchkit requires a small adjustment + (supplied by Tuomo Soini ). + +2002/05/10 == Released 0.8.8 == + +2002/05/10 + - OpenSSL 0.9.6d has been released. Release the unchanged patchkit + with a new version number and under a new filename to indicate + that it should be built against 0.9.6d (it has the session caching + failure of 0.9.6c fixed). Update documentation accordingly. + +2002/05/05 + - Postfix 1.1.8 has been released, the patchkit applies cleanly. + +2002/04/03 == Re-released 0.8.7 == + +2002/04/03 + - Postfix 1.1.7 has been released, the patchkit applies cleanly. + Re-released the patchkit. + +2002/03/29 == Released 0.8.7 == + +2002/03/29 + - Postfix/TLS did not honor the per-recipient-switching-off in SMTP + client mode via tls_per_site (per-host-switching off was honored). + Patch by Will Day . + +2002/03/27 == Released 0.8.6 == + +2002/03/27 + - Postfix 1.1.6 has been released. Adapted patchkit to resolve minor + patch conflict. (Template provided by Simon Matter + ) + +2002/03/13 == Released 0.8.5 == + +2002/03/13 + - Postfix 1.1.5 has been released. The patchkit would apply cleanly, but + obviously the "lock_fd" change that applies to dict_dbm.c (Wietse) + also has to be applied to dict_sdbm.c. Tuomo Soini + kindly provided this change. + +2002/02/25 == Released 0.8.4 == + +2002/02/25 + - Postfix 1.1.4 became visible. One patch conflict in a Makefile + (Carsten Hoeger ). + +2002/02/21 + - Dates in this CHANGES document were showing 2001 even though 2002 already + began :-). Fixed. (Marvin Solomon ) + +2002/02/07 + - Bug in the documentation (setup.html): the main.cf variables for the + SMTP server process have to be named smtpd_* instead of smtp_*. + Found by Andreas Piesk . + +2002/02/03 == Released 0.8.3 == + +2002/02/03 + - Patch from Andreas Piesk : remove some compiler warnings + by using explicit type casts in hexdump print statements. + - Re-released otherwise unchanged patchkit against Postfix-1.1.3. + +2002/01/30 == Released 0.8.2 == + +2002/01/30 + - Re-released unchanged patchkit against Postfix-1.1.2. + +2002/01/24 == Released 0.8.1 == + +2002/01/24 + - Postfix-1.1.1 has been released. The patchkit needed some small adjustment. + - Both Tuomo Soini and Carsten Hoeger + helped out with this small adjustment. As a side effect of Carsten's + complete pfixtls.diff, which I compared after applying Tuomo's adjustment, + I found that pfixtls.c contained several wrong "'" characters: on the + german keyboard there is an accent looking like the apostroph but producing + a different binary code. Obviously on Carsten's machine the code was + changed which became obvious during the comparison. + (Conclusion: I wrote the comments affected on my SuSE-Linux PC at home with + german keyboard. In my university-office I do have HP-UX workstations + with US keyboards.) + +2002/01/22 == Released 0.8.0 == + +2002/01/22 + - Received a comment from Wietse on the mailing list, that it is better + to resolve the "standalone" issue by using the already available + SMTPD_STAND_ALONE() macro in smtpd. Undid 0.7.16 change and made + new change in smtpd.c. + - Updated links in the References section of the documentation. + +2002/01/21 == Released 0.7.16 == + +2002/01/21 + - When calling "sendmail -bs" and STARTTLS is enabled, smtpd tries to + read the private key and fails due to insufficient permissions (smtpd + is run with the privileges of the user). This case is caught since + version 0.6.18 of the Postfix/TLS patchkit: STARTTLS is still being + offered but a "465 temporary failure" message is issued. Some mailers + (read this: PINE) will then refuse to continue. (And an irritating + error message indicating the failure to read the key will be logged.) + Experienced by "Lucky Green" . + - Solution: Disable STARTTLS when running "sendmail -bs" by adding + "-o smtpd_use_tls=no -o smtpd_enforce_tls=no" to smtpd's arguments + upon startup. Using STARTTLS does not make sense in simulated + SMTP mode. + +2002/01/18 == Released 0.7.15 == + +2002/01/18 + - Postfix 1.1.0 has been released. The patchkit for the former snapshot + version applied cleanly and now becomes the patchkit for the stable + version. + +2002/01/16 == Released 0.7.14a == + +2002/01/16 + - Snapshot-20020115 is released. Adapted patchkit. + - Add Postfix/TLS entries into the new conf/postfix-files + (Tuomo Soini , Carsten Hoeger ). + +2002/01/14 + - OpenSSL: a user reported that session caching stopped working for him + with OpenSSL 0.9.6c. I found that this is also true for my own + Postfix/TLS installation. + Solution: server side session caching is broken in OpenSSL 0.9.6c when + using non-blocking semantics (Postfix/TLS is affected as it uses + BIO-pairs); sessions are simply not added to the cache. This bug + is not security relevant. A fix has been applied to the OpenSSL source + tree for the next release. + +2002/01/08 == Released 0.7.14 == + +2002/01/07 + - New snapshots released as release candidates. Adapted the patchkit + to snapshot-20020107. Moved our production servers from 20010228-pl08 + to snapshot-20020107 with the adapted patchkit. + - Fix documentation: tlsmgr can be run chrooted since a long time. + +2001/12/21 + - OpenSSL 0.9.6c is released. Postfix/TLS is fully compatible. + +2001/12/19 == Released 0.7.13e == + +2001/12/19 + - Adapted patchkit to snapshot-20011217. + +2001/12/12 == Released 0.7.13d == + +2001/12/12 + - Adapted patchkit to snapshot-20011210. Adaption provided by + Tuomo Soini . + +2001/11/28 == Released 0.7.13c == + +2001/11/28 + - Adapted patchkit to snapshot-20011127. + +2001/11/26 == Released 0.7.13b == + +2001/11/26 + - Adapted patchkit to snapshot-20011125. + +2001/11/22 == Released 0.7.13a == + +2001/11/22 + - Adapted patchkit to snapshot-20011121. + +2001/11/15 == Released 0.7.13 == + +2001/11/15 + - Adapted patchkit to postfix-20010228-pl08 and snapshot-20011115. + +2001/11/06 == Re-released 0.7.12 == + +2001/11/06 + - Snapshot-20011105 released. No patch conflicts, but in order to have + the pfixtls-* filename and home page entry reflect the new version, + I'll re-release 0.7.12. + +2001/11/05 == Released 0.7.12 == + +2001/11/05 + - Release of Postfix-20010228-pl06 and snapshot-20011104. The snapshot + version had some minor patch conflicts to be resolved. + +2001/10/14 == Released 0.7.11 == + +2001/10/14 + - Bug fix (client mode): when the peername is checked against the CommonName + in the certificate, the comparison does not correclty ignore the case + (the peername as returned by DNS query or set in the transport map + is not transformed to lower case). This bug was introduced in 0.7.5. + +2001/10/09 == Released 0.7.10 == + +2001/10/09 + - Snapshot-20011008 is released. Some minor adaptions are required to + sort out patch conflicts. + +2001/09/28 + - Received patch from Uwe Ohse : There is a bug in sdbm's + handling of the .dir file, that also applies to Postfix/TLS. + The problem only appears for large databases. + - The example entries in conf/master.cf for the submission and smtps services + use "chroot=y" flags, while the Postfix default is "chroot=n". This could + lead to hardly explainable problems when users did not note this fact + during setup. + Fixed example entries to also use "chroot=n" default. + +2001/09/18 + - Wietse releases Postfix-20010228-pl05. The patch applies cleanly with + "patch -p1 ...", so it is not necessary to release a new patchkit. + +2001/09/04 == Released 0.7.9 == + +2001/09/04 + - Due to unititialized variable in smtpd_state.c, AUTH may not be offered + without TLS even though smtpd_tls_auth_only was not enabled. + (Patch from Nick Simicich .) + +2001/08/29 + - In the snapshot-20010808 version of 0.7.9, the "tlsmgr" line in the sample + conf/master.cf is missing (reported by Will Day ). Fixed. + +2001/08/27 == Released 0.7.8 == + +2001/08/27 + - Received bugreport about issuer_CN imprints consisting of long strings + of nonsense. This only appeard with certificates issued from a certain + CA (RSA Data Security Inc., Secure Server Certification Authority). + (Will Day ) + - The problem: the issuer data of this certificate is: + Issuer + C=US + O=RSA Data Security, Inc. + OU=Secure Server Certification Authority + It does not contain a CN (CommonName) field. OpenSSL's + X509_NAME_get_text_by_NID() function does not catch this condition + (no error flag set), but it also does not set the name in the memory + location specified. + - Solution: + 1. Preset the memory for the string to '\0', so that a string of length + 0 is obtained on the failure described above. + 2. When no CN data is available, use the O (Organization) field + instead. The data are used for logging only (it is the issuer, not + the subject name), so this change does not affect functionality. + +2001/08/22 == Released 0.7.7 == + +2001/08/22 + - Found one more bug: erronously called SSL_get_ex_new_index() instead + of SSL_SESSION_get_ex_new_index() (note the _SESSION missing). This + could be responsible for the failure at the locations found during + debugging. Works fine on HP-UX (did also before), must cross check + at home... + +2001/08/21 + - Received report, that smtp (client) fails with signal 11 (platform: + linux redhat). Cannot reproduce any problem on HP-UX (did run 1 + week in production before release). But malloc() and stack strategies + are different between platforms. + - Can reproduce the failure on my Linux PC at home :-(. + - Found one bug in new_session_cb(): on successfull external caching, + success is reported by a return value of 1. This however must be another + bug, as it has nothing to do with the locations of the failure, when + analyzing the core dumps/running under debugger. + Still getting SIGSEGV... + +2001/08/20 == Released 0.7.6 == + +2001/08/20 + - Following "popular demand" implemented new feature and configuration option + "smtpd_tls_auth_only": Only allow authentication using the AUTH protocol, + when the TLS encryption layer is active. Default is "no" in order to + keep compatiblity to postfix without TLS patch. + This option does not distinguish between different AUTH mechanisms. + +2001/08/16 == Released 0.7.5 == + +2001/08/15 + - The new session cache handling is working now at my site for quite some + time. + - Client side: modified peername matching code, such that wildcard + certificates can be used. Matching is done as in HTTP/TLS: only the + leftmost part of the hostname may be replaced by a '*'. + +2001/08/09 + - Further debugged the CRYPTO_set_ex_data() functionality. + - Unified "external cache write" and "external cache remove" callbacks + for client and server side. The "external cache read" functions are not + that easy to combine, as the lookup keys are quite different and do not + match the fixed interface to the callback function. + - Change shutdown behaviour according to SSL_shutdown(). When SSL_shutdown() + returns, the shutdown handshake may not be complete, if we were the first + party to send the shutdown alert. We must call SSL_shutdown() again, + to wait for the peer's alert. + +2001/08/08 + - Postfix snapshot 20010808 is being released. + +2001/08/08 + - Rewrite server side to remove externally cached sessions via callback. + - Rewrite client side to remove externally cached sessions via callback. + This turns out to be more difficult as expected, as the client side + session cache is sorted by hostnames, but the callbacks are called + with the SSL_SESSION objects. The information must be stored into the + SSL_SESSION objects by using the CRYPTO_set_ex_data() functionality, + the documentation of which, ahem, ... + - Reloading sessions stays separate, as the functionality is different. + +2001/08/07 + - Started reworking the session cache code. + * On the server side the retrieval from the external cache and the writing + to the cache are handled by callback functions. The removal is handled + directly. + * On the client side, all session cache operations are performed explicitly. + * The explicit handling is on the client side is bad, as it requires a + quite complicated logic to detect session reuse and the appropriate + handling. + * The explicit handling of session removal on both sides is bad, as + the OpenSSL library will remove sessions (on session failure) according + to the TLS specifications automatically, so we want to take advantage + of this feature and have the externally cached sessions removed as + required via callback. + - First step: on the client side, also use the new_session_cb(), so that + new sessions are automatically saved to the external cache on creation. + +2001/08/01 + - Postfix-20010228-pl04 is being released. + +2001/07/11 == Released 0.7.4 == + +2001/07/10 + - Postfix snapshot 20010709 was released. Resolved some minor patch + conflicts. + +2001/07/10 + - OpenSSL 0.9.6b has been released including a security fix for the + libraries internal pseudo random number generator. + * Note: to exploit the weakness, an attacker must be able to retrieve + single random bytes. As in Postfix/TLS random bytes are only used + indirectly during the SSL handshake, an attacker could never access + the PRNG in the way required to exploit the weakness. + * Postfix/TLS is therefore not vulnerable (as are most (all?) applications + utilizing the SSL layer). + * The OpenSSL team however recommends to upgrade or install the bugfix + included in the announcement in any case. + * Details can be found at http://www.openssl.org/ + +2001/05/31 == Released 0.7.3a == + +2001/05/30 + - Report from : TLS logging does not work. + Reason: parameters are not evaluated in mail_params.c, as the corresponding + lines for other_int_defaults[] were missing from the patch. This + only affected the 0.7.3-snapshot version, the version for "stable" + is correct. + I will release 0.7.3a with this fix only for the snapshot version to keep + version numbering consistent with the "stable" version. + +2001/05/28 == Released 0.7.3 == + +2001/05/28 + - Upgraded to snapshot-20010425: resolved some minor patch conflicts. + No functional changes. + +2001/05/16 + - Received french documentation (doc_french/) contributed by + Etienne Roulland . + +2001/05/03 == Released 0.7.2 == + +2001/05/03 + - Postfix-Snapshot 20010502 is released. Bernhard Rosenkraenzer + supplies an adapted patch for Postfix/TLS, as the + normal patch has several rejections because of code changes; + functionality has not changed. + +2001/05/01 + - Patchlevel 02 of Postfix 20010228 is being released. The Postfix/TLS + patchkit applies cleanly when using the "-p1" switch to patch. + +2001/04/09 == Released 0.7.1 == + +2001/04/06 + - OpenSSL 0.9.6a is released. It contains several bugfixes and will become + the recommended version to be used with Postfix/TLS. + I will run some more test and then re-release Postfix/TLS (without + additional changes to the source) as 0.7.1 to make people aware of the + new versions of Postfix and OpenSSL. + +2001/04/05 + - Hint from Bodo Moeller : + the "Known Bugs" section in doc/test.html actually contains bugs + of clients and/or interoperatbility problems. Better name it + "Known interoperability problems" and rename the entries + "Postfix/TLS server" and "Postfix/TLS client" to improve clarity. + +2001/03/29 + - Patchlevel 01 of Postfix 20010228 is being released. The Postfix/TLS + patchkit applies cleanly when using the "-p1" switch to patch. + OpenSSL 0.9.6a will be out within the next handful of days, so I will + delay the release of a new patchlevel until then. + +2001/03/01 == Released 0.7.0 == + - IMPORTANT: If you are upgrading from a much older version, you will find + that some configuration options have changed over time (fingerprints are + now handled with ':'. check_relay_ccerts is now permit_tls_clientcerts. + Session caching has been reworked.) + It is recommended to re-read the sample-tls.cf file or the html version + in the documentation. + +2001/03/01 + - Wietse has announced the _release_ version (non-beta) or postfix: + 20010228! + - Applied the Patchkit to the _release_ version (not the snapshot version). + Resolved one minor patch conflict. + - So, it's time to call this Postfix/TLS 0.7.0. + +2001/02/26 == Released 0.6.38 == + +2001/02/26 + - Snapshot-20010225 has been released. Resolved one minor patch conflict. + +2001/02/23 == Released 0.6.37 == + +2001/02/23 + - Snapshot-20010222 has been announced as RELEASE CANDIDAT. Resolved one + minor patch conflict. + - Removed "check_relay_ccerts" restriction which has been replaced + by "permit_tls_clientcerts" in 0.6.24. (Was left in until now for + transition.) + - Do not try to save session data > 8kB, since this cannot be handled + by SDBM. (This is more or less academical, since I have never met a + session even half that large.) + +2001/02/19 == Released 0.6.36 == + +2001/02/05 + - Snapshot-20010204 has been released. Resolved one minor patch conflict. + +2001/02/03 == Released 0.6.35 == + +2001/02/03 + - Snapshot-20010202 has been released. Resolved one minor patch conflict. + +2001/01/29 == Released 0.6.34 == + +2001/01/29 + - Snapshot-20010128 has been released. Resolved some minor patch conflicts. + +2001/01/11 == Released 0.6.33 == + +2001/01/10 + - Discussion in Thread "When to get peer certificate?" continues and it + comes out, that cross references between datastructures are well maintained + inside OpenSSL. A fact not well known due to lack of documentation + (seems I am facing some more work on the OpenSSL manpages :-). + - Moved around data needed for the certificate verification: a lot of + "static" entries globally needed inside pfixtls.c could now be moved + into the connection specific TLScontext. + +2001/01/07 == Released 0.6.32 == + +2001/01/07 + - Since now the checks at handshake stage (in pfixtls.c) are more strict, + some of the checks in smptd.c and smtp_proto.c could be removed. + At a later point I can probably move even more checks into pfixtls.c... + +2001/01/05 + - Had a discussion with Ari Pirinen on openssl-users + (Thread: When to get peer certificate?) about the earliest possible + place to check the CommonName of the peer against the expected name. + (This is what smtp does when enforcing the peername of the server it + is connecting to.) + The final result was, that the check can already been done inside the + verifiy_callback() routine even before the handshake is completed. + The positive side effect is, that since the session is never completly + established, it is also not cached on either client or server. + - Since this is a good idea, I have extended the verify_callback in + src/global/pfixtls.c to check the CommonName of the peer (if applicable) + and have the handshake shut down immediatly on failure. I have also + changed the behaviour so that whenever a positive certificate verification + is required, the handshake is shut down immediatly. + (The versions up to now did delay these checks until the session was + established and then shut down the connection. I had established this + practice while working on BIO-pairs and running into a bug in + OpenSSL 0.9.5 (fixed now) and with the verify depth.) + +2000/12/23 == Released 0.6.31 == + +2000/12/23 + - Bug: When only enabling smtpd_tls_wrappermode and not additionally setting + smtpd_use_tls or smtpd_enforce_tls, the TLS engine was not fired up on + startup of smtpd + Fixed: also start TLS engine when only smtpd_tls_wrappermode is enabled. + (Experienced by "Fiamingo, Frank" ) + +2000/12/18 == Released 0.6.30 == + +2000/12/18 + - New snapshot 20001217 has been released. Due to the change of "timeout" + parameters now being its own class and table, the old patchkit does not + apply cleanly! + - Checked out Postfix/TLS parameters being timeout values and put them into + the new style time parameter table. This allows to specify time values + like 3600s or 1h. Updated sample configuration to reflect this new style. + - "Fiamingo, Frank" pointed out to me, that there are + three parameters in src/global/mail_params.h (namely DEF_TLS_RAND_EXCH_NAME, + DEF_SMTPD_TLS_CERT_FILE, DEF_SMTPD_TLS_CA_FILE) that are hardcoded as + "/etc/postfix/something". + This does not match the usual style of postfix, where no paths are + hardcoded this way. I have removed the defaults for CERT_FILE and CA_FILE. + The RAND_EXCH is needed for good PRNG seeding on systems without + /dev/urandom, I however don't know yet, how to rearrange this requirement. + I could use the Postfix internal mechanisms to enforce a parameter, but + this would annoy people having compiled in TLS but not activated. + +2000/12/13 == Released 0.6.29 == + +2000/12/13 + - Snapshot-20001212 has been released. + - Undid bugfixes for 20001210 which now are included in the new snapshot. + +2000/12/12 == Released 0.6.28 == + +2000/12/12 + - Added bugfix provided by Wietse on postfix-users@postfix.org for + "postconf -m" behaviour. + +2000/12/11 + - New snapshot-20001210 released. Some patch conflicts occur. Additionally + * adjusted calls to myflock() to changed interface, + * fixed bug in smtpd_sasl_glue(), where a change to the name_mask() + call was not applied in the original snapshot. + +2000/12/05 == Released 0.6.27 == + +2000/12/04 + - Print informational message "SSL session removed" only when + var_smtp[d]_loglevel >= 2. (Proposed by Craig Sanders .) + - Extend logging of "setting up TLS connection from/to" and corresponding + success/failure messages so that they include the hostname/ip address. + This way it is much easier to automatically analyze errors by simply + grepping for e.g. "SSL_accept error" and immediately get the peer + causing the problem without further logfile processing. + (Proposed by Craig Sanders .) + - When experiencing a TLS failure due to TLS-enforced failure in client mode + (no certificate or hostname/certificate mismatch etc), immediately shut + down the TLS mode with "failure" indication, so that the SSL session is + removed immediately. This way a new session is always enforced in the + case the peer has fixed the problem; no need to wait for the timeout. + +2000/11/29 == Released 0.6.26 == + +2000/11/29 + - Found security relevant bug in the OpenSSL library: the verify_result + stating whether or not the certificate verification succeeded is not + stored in the session data to be cached and reused. + - This bug was found during the development of Postfix/TLS around one + year ago, the bug in the library was however only fixed for the server + side. At that time I also tested the server side behaviour but ommitted + to check the client side, too. + - Versions before Postfix/TLS 0.4.4 experienced this problem for both + server and client side. Before 0.6.0 a workaround was active for both + sides, which has been removed at 0.6.0 in the believe that the bug + was gone (I only tested the server side, which was fixed). + - Fixed that bug in OpenSSL also for the client side (I can do this myelf + now that I have been invited to join the OpenSSL developers team :-). + The fix is availabe as of today and will be part of the 0.9.7 release + of OpenSSL (or 0.9.6a, if this release will be published). + - Included a workaround inside Postfix/TLS for OpenSSL library versions + before 0.9.6a or 0.9.7, respectively. + +********************** Begin Description + + - By not caching the verify_result for the client side, the following + behaviour could appear: + * The problem can only appear when smtp_tls_session_cache_database + is activated. + * smtp_use_tls = yes + X On the first connection, the certificate fails verification, failure + is logged: + smtp[*]: Unverified: subject_CN=serv01.aet.tu-cottbus.de, issuer_CN=BTU-CA + For any following connections until the session times out (default 1 hour), + the peer certificate seems to pass verification: + smtp[*]: Verified: subject_CN=serv01.aet.tu-cottbus.de, issuer_CN=BTU-CA + X Security Impact: + Unverified certificates are logged as if verification had succeeded. + * smtp_enforce_tls = yes + X After the verification failure, the session is never correctly established + and hence not reused. + X Security impact: + None, as the session is never reused. + * smtp_enforce_tls = yes after smtp_tls_enforce_tls = yes for a server. + X If the session has been recorded with use_tls and then for this server + enforce_tls is set, the wrong verify_result could be used within the + session cache timeout (default = 1 hour). + X Security impact: + If TLS shall be enforced for a recipient, there is a window of approx. + one hour from setting the "enforce_tls" switch until a verification + failure is noted. For this to happen, a TLS session to that server must + have been used with use_tls set and the not-verifiable certificate must + have been recorded in that session. + - Evaluation: + Even though this _is_ a security problem, I consider risk to be *low*, + given the conditions under which the problem might occur. + +********************** End Description + +2000/11/27 == Released 0.6.25 == + +2000/11/26 + - Added "permit_tls_all_clientcerts" for smtpd_recipient_restrictions. + When this option is enabled, any valid client certificate allows relaying. + This can be practical, if e.g. a company has a special CA to create + these certificates and only this CA is "trusted". It however does not + allow finer control, so if e.g. an employee leaves, he could still + relay. Postfix/TLS does not (yet) allow CRL (certificate revocation lists). + (Added on popular demand.) + - Make the client behaviour more configurabe: when enforcing TLS connections, + the peer's name is checked against the CommonName in its certificate. + New configuration variable "smtp_tls_enforce_peername" (default=yes) + can now be used to accept peername!=CommonName. The server's certificate + must still pass the verifcation process against a trusted CA! + In tls_per_site, the according key is MUST_NOPEERMATCH. + (Added on demand.) + +2000/11/24 + - If the server requires a client certificate and no certificate is presented + or the certificate fails verification, the connection is shut down but + no information is logged. + -> add according msg_info() in smtpd/smtpd.c:startls_cmd(). + - If TLS is not enforced, it does not make sense for a server to require a + client certificate. If no STARTTLS is issued, the SMTP would continue + anyway, so why shut down when TLS is activated without verifyable client + certificate? + -> ignore smtpd_tls_req_ccert=yes, if TLS is not enforced and only treat + like smtpd_tls_ask_ccert = yes with an according information logged. + +2000/11/22 == Released 0.6.24 == + +2000/11/22 + - Installed on my own servers and changed configuration to use the new + "permit_tls_clientcerts" option name. Patchkit will be released after + some hours of successfull operation. + +2000/11/21 + - New snapshot-20001121 is being released. The patch applies without any + conflict when applied with "patch -p1", so no need to rush out an updated + patchkit. + - Rename the smtpd_recipient_restrictions option from "check_relay_ccerts" + to "permit_tls_clientcerts" to better match the naming scheme. + Leave in the old option for now to not break existing configurations. + The final incompatible removing is scheduled of release 0.7.0 of the + patchkit which will be matching the next "stable" release of postfix. + - There is no manual page for tlsmgr.8 (pointed out by Terje Elde + ). + Fix the comments at the beginning of tlsmgr.c and create tlsmgr.8. + - In the session cache code an additional 20 bytes were allocated when + converting SSL_SESSION data to binary using i2d_SSL_SESSION(). + In adding these 20 bytes to the size listed by i2d_SSL_SESSION() I followed + the example in the OpenSSL source (PEM_ASN1_write()). These 20 bytes are + only added since when writing the PEM, a 20 byte checksum is added, so + we don't need it in our case -> removed. + (Researched after Carlos Vicente asked what these + 20 bytes are good for :-) + +2000/10/30 == Re-Released 0.6.23 == + +2000/10/30 + - Postfix snapshot-20001030 with an important bug fix is made available. + The patchkit applies without any problem (patch -p1). + Hence, I re-release the 0.66.23 release for the new snapshot. + +2000/10/30 == Released 0.6.23 == + +2000/10/30 + - New Postfix snapshot 20001029 available with some important bug fix. + Adjusted patchkit (only minor conflicts). + +2000/10/27 + - The CN_sanitize function (src/smtpd/smtpd.c) that shall make sure that + no illegal sign is included into the Received: header does not work + on systems were "char" is unsigned by default. + (Linux on s390, found by Carsten Hoeger ) + -> Worked out a more precise (even though not looking elegant) solution + that checks out all acceptable characters. + - Sent new smptd.c to Carsten Hoeger for testing, will wait with new + Postfix/TLS release. + +2000/10/06 == Released 0.6.22 == + +2000/10/06 + - snapshot-20001005 has been released, featuring fast ETRN. Only some minor + patch conflicts needed to be resolved. + +2000/09/28 == Released 0.6.21 == + +2000/09/28 + - snapshot-20000924 seems to be somewhat longer lasting. I have been asked + for a new Postfix/TLS release against snapshot-20000924, hence I will + create one. + - Running OpenSSL 0.9.6 for a week now to my full satisfaction. I will bump + bump up the Postfix/TLS version counting to include "0.9.6", even though + it will still run fine with 0.9.5a. + +2000/09/25/ + - snapshot-20000924 is available; only small adjustments. + - Wietse seems to release new snaphots on a daily basis, it doesn't make + sense to follow with a new Postfix/TLS release every day. + +2000/09/23 == Released 0.6.20 == + +2000/09/23 + - Recompile OpenSSL-0.9.6-beta3 with the change and reinstall old pfixtls.c: + works again. Hence, all versions of Postfix/TLS working against 0.9.5a + will also work again 0.9.6-final, which shall be released on 2000/09/24! + - Wietse releases snapshot-20000923, patchkit adapted. + - Went through the "install.html" document to add a remark about + OpenSSL-0.9.6. This document is of historic quality but did not fit + actual versions of Postfix/TLS, we are far beyond OpenSSL 0.9.2: Updated. + +2000/09/22 + - Wietse releases snapshot-20000922. The source directory hierarchie has + changed, so the patch needs to be adjusted at several places. + - Run tests against OpenSSL 0.9.6-beta3: problems occur! + * Certificates are no longer verified, since an informationa flag about the + CA certificate search process is written into the error storage and + thus misinterpreted as verification failure. + * Changed Postfix/TLS source to maintain its own error storage based on + the verify_callback, send out according warning to Postfix/TLS mailing + list. + * Unfortunately, this will break all older versions of Postfix/TLS. + Sent out analysis to OpenSSL-bugs@openssl.org. + * Additional change is made to OpenSSL: the new behaviour is only activated + when a special flag is set, so compatibility is restored! + +2000/09/21 + - Wietse releases snapshot-20000921. Some minor patch conflicts resolved. + +2000/09/14 == Released 0.6.19 == + +2000/09/14 + - Received a bug report: Postfix/TLS will accept a mail even though + smtpd_req_ccert=yes (require use of client certificate) and no + client certificate is presented. + Reason: when no client certificate is presented SSL_get_verify_result() + will return X509_V_OK, since this is the default value. + Solution: only set "peer_verified" internal information, if the + verify_result is X509_V_OK _and_ a peer certificate is available. + Remark: This default value does not make too much sense. I will file + a bug report/patch before the next release of OpenSSL... + +2000/09/03 == Released 0.6.18 == + +2000/09/03 + - When calling "sendmail -bs", smtpd is started without root privileges, + hence it cannot open the private key file and the session cache database. + Since the database routines do not offer a graceful return (only fatal + and abort), this leads to a failure when TLS and session caching is + activated. + This affects PINE users (noted by Craig Sanders ). + Solution: Try to read the private key first; if that fails, we can + gracefully recover and won't touch the session cache database at all. + - When STARTTLS is configured for smtpd but does not work (e.g. because of + unaccessible keys), smtpd answers with "465 TLS not available due to + temporary reasons". After that the connection was closed, this is however + not necessary, as the client may decide to continue without TLS activated. + - Craig Sanders contributes a script to automatically + generate the keys and certificates for Postfix/TLS usage. Added + "make-postfix-cert.sh" to the contributed/ directory. + +2000/09/02 == Released 0.6.17 == + +2000/09/02 + - Craig Sanders reports that he has connection problems + with a site; the message in the log is: + SSL_connect error 0 + 8847:error:140943F2:SSL routines:SSL3_READ_BYTES:sslv3 alert unexpected message:s3_pkt.c:956:SSL alert number 10: + * This is the error caused by the faulty TLS implementation with + CommunigatePro. The bug is fixed in later versions of CommunigatePro, + The site shall be contacted, they should update. + - More important, he reports a segmentation fault immediately after this + problem. + - Bug: when not using session caching and an error occurs during the TLS + handshake, pfixtls_start_clienttls() tried to remove the erronous + session from a non-existant session cache. + Fix: check the existence of the session cache before trying to access it. + Comment: at all other places in the code this condition was already + caught. + - Remark: actually session caching was configured, but the configuration + variable was mistyped because... + it was wrong in conf/sample-tls.cf and doc/conf.html. + The correct values are "smtp[d]_tls_session_cache_database" instead of + "smtp[d]_tls_use_session_cache_database". + Unfortunately this is not flagged by Postfix... + +2000/08/25 == Released 0.6.16 == + +2000/08/25 + - Make sure, that the smtp[d] processes will try to access the "daemon" + entropy sources, but will only print an info when not available. Using + the PRNG-exchange file, they can happily run without. + - Moved HAS_SSL checks, such that the package compiles also when configured + without -DHAS_SSL. + +2000/08/24 + - Changed the handling of the PRNG-exchange file. Until now it was written + by tlsmgr and read by the smtp[d] daemons. This had the disadvantage, that + until tlsmgr rewrote new bytes to the file, all starting daemons read the + same seed (to which some more bits, but not too much were added). + - Now the file is handled in read->stir into pool->write back mode, so that + every daemon will add its own entropy bits. + - The smtp[d] processes will do so when starting, when opening a TLS + connection and when closing. + - The tlsmgr will also read back the file and add it to its pool, so that + no entropy is lost. + - This change significantly increases the "self seeding" capability of + the TLS service. + +2000/08/09 + - Cleaned up the new PRNG-seeding. + - When tlsmgr looses connection to an EGD-source (because it was restarted), + tlsmgr performes an exit(0), so that a newly started tlsmgr can reconnect. + [chroot/dropped privileges]. + +2000/08/04 + - Introduced new entropy sources for single daemons: + * tls_daemon_random_source + Using this source (same style as for tlsmgr), each starting daemon can + obtain additional entropy (32 bytes by default). The PRNG-exchange file + is still read. + - I am not sure about the policy for this feature. If such a source is + given, should a failure be considered fatal? + +2000/07/23 + - Started reworking the PRNG seeding: + * tlsmgr now recognizes tls_random_source as + dev:/dev/urandom /* Direct read from device file */ + egd:/path/to/socket /* Connection via EGD-socket */ + /path/of/plain-file + * If a dev: or egd: is given, tlsmgr will connect and keep the connection + open, so that it now can run in chroot-mode with dropped privileges. + - Since EGD can be drained, but the connection is permanently open, only + suck a small number of bytes (default 32) at a time, but do it more + often. + +2000/08/09 == Released 0.6.15 == + +2000/08/09 + - Traced through OpenSSL to learn more about the verify_callback-feature. + The callback is called several times. When it returns "1", the handshake + will continue, when it calls "0", the handshake will immediately fail + (and Postfix/TLS will also close the TCP connection). + - Following the sample in the OpenSSL-apps, the verification chain depth + was the only property triggering this effect, so this stood hidden until + now. Obviously, users having longer chains did set the verifcation + depth accordingly or they gave up, since this was never reported... + - Changed the behaviour of verify_callback() to never return "0", such that + we can deal with the verification result later in a more consistent manner. + If we only enable and not enforce, we simply want to ignore problems with + the certificate. + - verify_callback() did not print out all information, since the wrong + state variables (pfixtls_*active instead of pfixtls_*engine) were + checked. The *active state variables are only set later. + As the verify process now became rather narrative, the normal logging + is only done in loglevel 2! + - Arrrghhh. The conf/sample-tls.cf _and_ the html-docu (which is actually + copied from conf/sample-tls.cf) has wrong names for the verification- + depth parameters. *_vd instead of *_verifydepth and ccert<->scert. + [Wondering, why this never popped up before...] + - Changed the default-verifydepth to "5" which should suffice for most + cases. Maybe the limit could also be completely removed, but we should + at least receive a warning hint when something goes wild. + Since OpenSSL>=0.9.5 is required for Postfix/TLS anyway, certificate chain + verification can now be used, so the caution applied before is no longer + necessary. + +2000/08/08 + - Tracked down the double-free() call in smtp with Efence. SSL_free() + does call SSL_SESSION_free() on the negotiated session. Hence, I must + not call SSL_SESSION_free() on the session in question, it will be + removed anyway. + - Also tracked down the certificate chain feature. Reason is the + verify_callback() in global/pfixtls.c. It flags a chain depth that + is too long as fatal, hence the connection is immediately closed. + +2000/08/04 + - Received information from Alain Thivillon : + FreeBSD-CURRENT offers malloc() with additional checks enabled. + After successfully delivering, smtp dumps core with free() called + twice in TLS mode. + - I noted, that there is a communication problem with his site an my new + certificate issued by the universities computer center (which has a chain + depth of 2). Step back to the old self certificate for the time being. + +2000/07/27 == Released 0.6.14 == + +2000/07/27 + - Introduced new configuration parameter "smtpd_tls_wrappermode" that + enables the (deprecated) old style SSL-wrapping around SMTP. It could + be run on a different port (once smtps=465) was recommended for this + services. + This method is used by old versions of Outlook (Express), the Mac versions + and even actual versions, when not run on port 25. + [Actually it was only a handful of lines, so it doesn't hurt too much, + even though it does not follow any RFC.] + - I recommend using this option only from master.cf. Example lines added + to conf/master.cf and description added to Postfix/TLS-doc/conf.html. + - When having SASL enabled and TLS-enforce mode in "smtpd", only offer + AUTH, when TLS has been activated. Otherwise the client might simply + send the unencrypted credentials before it receives + 530 Must issue a STARTTLS command first + and an eavesdropper already has what he was looking for. + +2000/07/19 == Released 0.6.13 == + +2000/07/19 + - Changed the library-initializaton call to new naming scheme + (SSLeay_add_ssl_algorithms() to OpenSSL_add_ssl_algorithms() :-). + - Updated documentation to reflect the use of chain certificates with + CAfile and smtp[d]_tls_cert_file (see 2000/07/06). + - Documentation: the interoperability problem with CommunigatePro has been + solved: CommunigatePro violated the TLS-RFC and has been fixed. + - Typo: It is "to stir" not "to stirl" :-) + +2000/07/06 + - Received certificate for our site from our computer center. It's a chain + certificate. Now load the cert with SSL_CTX_use_certificate_chain_file(), + in order to better load the chain CA certificates. + +2000/07/04 + - Reported Wietse about a possible problem in the SASL code, a relay check + may also be performed if sasl was not enabled and might lead to unwanted + relay. + As the fix is in my own codebase, I will leave it Postfix/TLS until a + new snapshot (or final release) is available. + +2000/06/02 == Released 0.6.12 == + +2000/06/02 + - Adapted to Snapshot-20000531 (minor patch conflict). + - Cleaned up some old header file dependencies in global/pfixtls.c and + global/Makefile.in that are no longer needed due to the interface changes + (timed_read()/write()) in 0.6.7. + +2000/05/29 == Released 0.6.11 == + +2000/05/29 + - Following Bodo Moeller's analysis, the error is due to a mismatch between + the CA certificate accessible in the smtp[d]_tls_CAfile and the one used + in the actual certificate (smtp[d]_tls_cert_file). + Daniel Miller fixed his setup and the problem is gone. + - Introduced a workaround into Postfix/TLS: if the padding error is found, + it is removed from the error-queue by Postfix/TLS, in order to protect + more sites from experiencing this problem. + - Added a warning to conf/sample-tls.cf + - Updated to the latest snapshot-20000528. + +2000/05/27 + - After some fiddling around working through the binary certificate data to + see where it is modified at 0.6.10, I actually note, that both 0.6.9 and + 0.6.10 choke on the data. Now going back up through the functions very + fast reveals the problem: + * The certificate supplied triggers the "RSA-padding" error in any case. + Since the certificate authencity is not enforced on OpenSSL-library level + but inside postfix later, the error is not enforced. + The error messages generated stay however in the error queue. + - For blocking sockets, the SSL_accept()/connect() calls return + "success", so the error-queue is never checked. + - With BIO-pairs, the error queue is checked to find out, whether the + function has just to be called again to continue the handshake, so + the error messages are found and the connection is shut down due to + the error condition. + - Submitted bug report to Bodo Moeller. Bug fix is checked into the OpenSSL + CVS archive: if the error is ignored during the handshake, clear the + error-queue. + * The next release of OpenSSL will behave consistently. + - This leaves open the question, why the RSA-padding error is issued in the + first place. Sent a query to the OpenSSL-* mailing lists. + +2000/05/26 + - A second site experiencing this problem pops up. + -> Issued a warning to the postfix_tls mailing list. + +2000/05/24 + - Contacted Damien Miller . He did not change his TLS setup + in the last time. He is running Postfix/TLS-0.6.6. + - Contacted Bodo Moeller , the author + of the BIO-pair part of OpenSSL for some debugging hints. Received several + worthful remarks on what to look for. + - Checked byte-for-byte the data fed into the OpenSSL-library. It does not + differ between 0.6.9 and 0.6.10, so my handling seems to be actually + correct. + +2000/05/23 + - A communication error occurs when talking to mail.mindrot.org: + SSL_accept error -1 + 10264:error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01:rsa_pk1.c:100: + 10264:error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed:rsa_eay.c:396: + 10264:error:0D079006:asn1 encoding routines:ASN1_verify:bad get asn1 object call:a_verify.c:109: + - The error occurs both in client and server mode. 0.6.9 does not show + this problem. + - Tried to connect with several other sites, all connections are fine, + this includes sendmail and qmail peers; hence decided to not recall 0.6.10. + +2000/05/23 == Released 0.6.10 == + +2000/05/23 + - Sent a note to openssl-dev@openssl.org about the behaviour of SSL_free() + and BIO_free(), hoping for some clarification whether my way of doing + it is the recommended way. + - Run the software in production mode on my own servers... + - Finished writing the in-source documentation. + - Updated sample-tls.cf and sample-smtp[d].cf to reflect the new timeout + parameters. + +2000/05/21 + - Removed error messages produced by the now non-blocking behaviour of the + TLS layer [apps_ssl_info_callback()]. + +2000/05/20 + - Took results home and tried to run it on my Linux-box: SEGV after + successfully handling the SMTP session!! + * It seems that the SSL_free() and BIO_free() functions interact. + SSL_free() releases the underlying BIO and it will bomb out when + it is then explicitely BIO_free()'ed again and vice versa. + * It did not bomb out on HP-UX, but such things happen. I however want to + know, why the example program does not fail... + * With respect to the bevaviour as is, SSL_free(TLScontext->con); + BIO_free(TLScontext->network_bio) and not touching + TLScontext->internal_bio works. + - Introduced special timeout values for the TLS negotiation stage, as the + timeout values may change with protocol state (suggested by Wietse). + - Started writing a full description of the BIO-pair concept and its + special treatment into the pfixtls.c sourcecode. + +2000/05/19 + - Systematicly implemented a generalized layer handling: + * do_tls_operation() is the generic handler for all SSL_*() input/output + functions. It deals with the non-blocking behaviour of this functions, + requiring appropriate retrys. + * network_biopair_interop() handles the interaction between the socket/fd + and the buffering BIO-pair. + +2000/05/18 + - Based on the example in openssl-0.9.5a/ssl/ssltest.c realized the first + usage of BIO-pairs. (Can do server handshaking.) + - Learned, that the BIO-pair has its own buffering that needs its own + flushing. It is not enough to relay on the SSL_ERROR_WANT_READ/WRITE + state information. + +2000/05/17 == Released 0.6.9 == + - Important: the seperator in the relay-fingerprints is now ':'!!! + Don't forget to change your relay_clientcerts databases. + +2000/05/16 + - Changed pfixtls.c to only use the interface described in util/vstream.c + for handling the VSTREAM. + * Added vstream_context() macro to the VSTREAM-interface. + - Introduce TLScontext to identify the connection instead of the file + descriptor. Move all static data (SSL structure and information gathered + about the connection) into the context. + The TLScontext is allocated on TLS-start for a connection and saved with + the VSTREAM, so several streams can be used at the same time. + - Removed "pfixtls_setfd()" as it is no longer needed. + - Changed the relay_clientcerts list from string_list_* to maps_* interface + to allow usage of ":" in the list. + THIS IS AN INCOMPATIBLE CHANGE!!!! + - Updated documentation accordingly. + +2000/05/12 == Re-released 0.6.8 == + +2000/05/12 + - Wietse announces snapshot-20000511 with an important bugfix. + - Since upgrading from 20000507 to 20000511 is highly recommended, + Postfix/TLS 0.6.8 is re-released for this snapshot (the patch applied + cleanly, just the name of the toplevel directory has changed). + +2000/05/11 == Released 0.6.8 == + +2000/05/11 + - Unlike expected I found some time to install the latest cyrus-sasl-1.5.21 + and test some parts the integration. It does, well, work as advertised + (and the advertisement in SASL_README is not too optimistic). + - When checking all of the rejected patch-snippets for 0.6.6->0.6.7 + I missed the parameter "smtpd_enforce_tls" (noted since I wanted to + enforce TLS encryption while playing around with plaintext passwords) + in the static CONFIG_BOOL_TABLE bool_table[] = {..} in smtpd/smtpd.c + -> I will immediately release a corrected version 0.6.8. + +2000/05/11 == Released 0.6.7 == + +2000/05/11 + - The latest sendmail.8.11.0.Beta1 includes STARTTLS support; it is available + in source code and also uses OpenSSL. + +2000/05/10 + - After having it running at home (Linux) I also install it at work for + the field test. + - No time to install the SASL kit, so this part stays untested as of now. + +2000/05/09 + - Downloaded snaphot and apply the patchkit. + - Straightened out the rejected parts of the patch. + - Due to the new layering with timed_read() and timed_write() functions + the integration of the TLS layer needed special adjustment. + * When TLS is active, the timed_read() and timed_write() functions are + replaced by the corresponding pfixtls_timed_read() and + pfixtls_timed_write() functions. When the TLS functionality is stopped, + the old functions are restored. + * The names of the pfixtls_timed_*() functions are looking into the future, + because they are working as before, the timeout functionality is not + in, yet. + +2000/05/08 + - Wietse announces snapshot-20000507 with a lot of changes. Especially + important: the I/O handling of the smtp-stream has been changed to + a more layered technique that allows easier integration of the TLS layer. + +2000/04/27 == Released 0.6.6 == + +2000/04/27 + - Fixed inconsistency between documentation and actual behaviour: peer + certificate information was not logged at level 1 (found by + Damien Miller ). + * While at it: the logged information did not say whether the certificate + data logged passed verification or not: fixed. (The information logged + in the Received: header already contained that information.) + - Backported dict_dbm.c from snapshot-20000309 with the updated + dict_delete() behaviour (key not found is not considered fatal). + Maintained dict_sdbm.c accordingly. + +2000/04/18 == Released 0.6.5 == + - Important: + * New session cache mechanism SDBM. Please adapt your main.cf and delete + any old ".db" session cache files manually. + +2000/04/18 + - I am using the SDBM session cache for a week right now and did not have + any trouble, so I think its worth pushing it out. + - I am not completely happy with the dict_del() behaviour of considering + a not-found key fatal. It might happen when the smtp[d] processes would + be allowed to delete themselves. They are not as of now, so I accept it + for now but will reconsider it. + - Updated documentation accordingly. + +2000/04/17 + - Received corrections for the HTML-docs from Ralf Hildebrandt + . + +2000/04/11 + - Transfered SDBM from home (Linux-testbed :-) to work [found and fixed some + small items when compiling on HP-UX]. Started running it under + "real life" conditions. + +2000/04/07 + - Implemented "SDBM" Simple Database Management routines as also utilized in + ModSSL. Of course, it requires reopening of the databases, so the + routines are changed, that the _file_descriptors_ are left open, but + the _in_memory_ database stuff (especially the cached data) is closed + and reopened on access. This is what is really needed. The pagesize + is increased from standard DBM compatibility to hold the session + information. + Additionally, this software is in the public domain, so no additional + license problems arise. + - The access goes through the dict_* interface, hence the locking is + performed by myflock(). + +2000/04/01 == Released 0.6.4 == + +2000/04/01 + - Updated to the new patchlevel of Postfix (19991231-pl06), some parts of + the patch were rejected due to changes in smtpd. + - Changed patch name with respect of today's release of OpenSSL-0.9.5a. + The code remained unchanged. + +2000/03/25-31 + - The cached informations are not deleted by "tlsmgr" even though stored + and retrieved by the smtp[d] processess. Strange. + - Spend some large amount of time digging through the Berkeley DB + documentation and code. + * It claims that Berkeley DB is multi-process capable. Caveat: it takes + the very complicated "transaction model", that I did not use until now. + Hence the session cache does not work as is. + * Even with transaction model, Berkeley DB requires re-opening of the + databases to get rid of cached information. F*ck. + - Finally, I give up on Berkeley DB for session caching. It will never + work for us. Even if it would, it requires a large amount of helper files + and it seems, that the transaction environment is somewhat fragile when it + comes to some problem. I won't rely on it. + +2000/03/28 == Released 0.6.3 == + +2000/03/28 + - As has been pointed out to me, the TLS information in the Received: + header is not conform to RFC822. + - The TLS protocol and peer CN information is now included in '()', so + that it is a comment. + +2000/03/21 == Released 0.6.2 == + +2000/03/21 + - I have been running DB based session caching with the changes for some + more time now without problems. Am I really confident? No, not really. + I remember the trouble I had with Berkeley DB and sendmail on HP-UX. + I don't think I really trust it. + - Realized single "smtp_tls_per_site" lookup. I cannot use the more or + less comfortable "domain_list" lookups as before, since these do not + return the value, just found or not :-(. + Hence the lookup is realized with maps and exact lookup. I never tried + regexp. But if I understand the docs correctly, it should be possible to + use it here to realize wildcard lookups, if it would not have been + disabled :-(. + - Summary: + * Session Cache will be cleaned at "postfix reload" or "postfix start" + * New table "smtp_tls_per_site" + * Gone: "smtp_tls_[use/enforce]_[recipients/sites]" + + +2000/03/16 + - Changed pfixtls.c, so that it will only open Session Cache databases, + that are already available. tlsmgr is responsible for creation. + - Change tlsmgr.c, such that session cache databases will be removed before + opening, so that fresh databases are used whenever postfix is restarted. + This means, that session information is not kept over a postfix stop/start + or reload sequence, but it also means, that issuing a postfix reload will + clean the session cache. + I don't use simple dict_open with O_TRUNC, because this would not help + against database files, that are locked by hanging smtp[d] processes. + If you think it will also solve the "hang" problem described for + 2000/03/15: in a certain sense it can, since tlsmgr will be killed by + the watchdog and new, fresh cache files are installed, but that is not + more than an ugly hack. It must be solved in a clean manner. + +2000/03/15 + - Experienced some strange problem with Berkeley DB based session cache. + The DB routines hang while trying to delete an entry. I did save the + corresponding "hash:" file and could reproduce it (and walk through + the endless loop with a debugger), but I didn't find the reason why. + Since during "db->del" the database is exclusively locked all other + processes hang however, so this is really bad!!!!!!!! + +2000/03/12 == Released 0.6.1 == + +2000/03/12 + - Created tls_info_t structure to hold all information about the active + TLS connection. Remove all global variables except those for the + running client/server engines (those might be replaced with global + variables in smtpd/smtp, though). + - Added field "dNSName" to the structure (still unused). This will be + used with X503v3 extensions. + - Cleaned up TODO, since some items are now done... + +2000/03/11 + - Added missing #include to tlsmgr.c. (Worked without on HP-UX, + showed up on Linux.) + - Bug: removal of server side sessions from the cache in case of trouble + failed, because uppercase hex was used instead of lowercase for the key. + This does not affect removal of expired sessions by tlsmgr. + - Stepped up to postfix-19991231-pl05. + +2000/03/09 == Released 0.6.0 == + - Important: + * This release features an additional daemon, the "tlsmgr", please update + your master.cf accordingly. + * This release does not use the /var/spool/postfix/TLS* directories + anymore. Remove them and re-install the original postfix-script. + * Check the new/changed configuration parameters tls_random* and + smtp[d]_tls_session_cache*. + * This release will only work with OpenSSL >= 0.9.5!!!!! + +2000/03/09 + - Testcompilation of Postfix/TLS without -DSSL and the OpenSSL includes and + libraries passed. + - Worked through tlsmgr.c to remove unneeded header files. + - Wrote documentation for tlsmgr.c. + - Updated documentation on top of pfixtls.c. + - Put (char *) casts into the myfree() calls, where necessary, to make the + HP compiler happy. + - Updated html PRNG documentation in Postfix/TLS. + +2000/03/08 + - Finished first version of "tlsmgr". Does run through session cache + databases and detects and deletes (*) old sessions. + * Had to realize SYNC_UPDATES for the dict_db_delete() function and patch + the flag handling within the function. Changes sent to Wietse. + - Restored qmgr to its original state. + - Extended pfixtls.c to need an additional "needs_095_or_later()" function + when compiled with an older version of postfix. + - The session cache is now enabled, when a database filename is given. + smtp[d]_tls_use_session_cache configuration parameters removed, + updated documenation accordingly. + - Moved the PRNG handling to tlsmgr, applying the new model. tlsmgr will + query external sources at startup and will then feed a PRNG exchange + file with random data in intervals of configurable (but random driven) + length. + If running outside chroot, tlsmgr can query the entropy source (e.g. + EGD or /dev/urandom) again and so increase entropy with time. If the + entropy sources don't limit access, the tlsmgr can run with "postfix" + privileges. Mine does. + -> master.cf became a new entry. + - tlsmgr is realized as a trigger server and has the "fifo" entry. Actually, + it does not take any input. One could utilize it to feed back some entropy + from running smtp[d] processes, but I think this would overload the + issue. + - I will release a 0.6.0 pre-version as is. tlsmgr still lacks the detailed + information in the header and the interface description in pfixtls.c + probably is also not longer up do date. + +2000/03/07 + - Since defective session data can cause SEGFAULTs, it is now armored + by a leading structure that does contain a session cache version and + the postfix library version before the timestamp. If a session does + not match exactly the version numbers, it is immediately discarded + and deleted to avoid harm. + - Removed the seperate storage of the peer's certificate verify_result, + so starting from this moment, Postfix/TLS will only work safely with + OpenSSL >= 0.9.5!!! + - Ported server side session cache routines to the client side; works. + - Analyzed structure of "qmgr" to understand consequences for the planned + "tlsmgr" daemon. Transferred the sceleton. + - Received word from sendmail, a (at least preliminary) TLS enabled test + address is "bounce@esmtp.org". + +2000/03/06 + - Wietse supplied a change to the dict/dict_db mechanism to allow for + synchronous updates. + Session cache updates for the server side seem to work now, removal of + old sessions (when called from the client) integrated. + +2000/03/05 + - Got the database style session cache to run for the server side (at least + partial). The removal of old sessions is not yet realized. + [There are several man pages for OpenSSL as of 0.9.5, but the i2d etc + interfaces are not belong them, so I had to study the source code instead.] + * What is not working by now is the synchronization of the memory database + to disk. It only is synchronized automatically upon close. It would be + necessary to sync after each update or delete, but this is not implemented + in Wietse's dict library. I will post an according proposal. + +2000/03/04 + - Wietse posts a patch to select "EHLO" negotiation even if ESMTP is + not recognized from the 220 greeting. Activating this flag will however + break compatibility with mailers, that simply close the connection + upon EHLO. I don't know how the large the number of these broken mailers + is, but activating "smtp_always_send_ehlo" is a tradeoff. + - Integrated Wietse's patch into Postfix/TLS. + +2000/03/03 + - Received update from Matti Aarnio (Zmailer) is now for some time able + to do server _and_ client side TLS. Updated documenation accordingly. + When testing, Postfix client to Zmailer server failed, because + Zmailer announces with "ESMTP+IDENT" and Postfix does not recognize + the ESMTP token (must be seperate), so only HELO is used and STARTTLS + is not offered by the Zmailer server. Informed Matti accordingly, + will wait until the problem is resolved before actually publishing + the update. + - Enhanced the documentation by listing automatic reply services at which + interoperability can be tested. + +2000/03/02 + - Went through the Postfix source to check out the database routines. + It should be possible to move session caching from directory/file- + based to database. Since DBM only allows blocks (key+contents) of + 1024 bytes and a session is larger, only Berkeley DB can be used. + Put some first bits into Postfix/TLS. + +2000/02/29 == Released 0.5.5 == + +2000/02/29 + - OpenSSL 0.9.5 has been released. Since I want to promote 0.9.5, as it + contains several bugfixes and enhancements, I release a new version + of Postfix/TLS. My personal highlights: + * The bug with Win32 Netscape not commencing after certificate storage + unlocking should be fixed. (I will leave the not in however, as long + as I have not positively checked it myself. Reproducibility...) + * The bug, that the certificate verifiation result is not stored in the + session cache (discovered for Postfix/TLS 0.4.4) is fixed. I will leave + the Postfix/TLS workaround in as long as it will run with older versions + of OpenSSL. + * The OpenSSL commandline tools like "openssl gendh" now support EGD, so + that the examples for generating the DH parameters now will really work + with high quality random data :-) + * The support of 56bit ciphers has lost its importance since 128bit + versions of Netscape etc are now easily available... + - This version does not feature source code changes but updated documenation + when compared with 0.5.4: + * List examples on how to generate good entropy for the PRNG seed in + /etc/postfix/random_file. + - Update the TODO document with respect to the discussion about session + caching and other security items. This document is a very short summary, + for the full discussion check the mail archive at + http://www.aet.tu-cottbus.de/mailman/listinfo/postfix_tls/ + +2000/02/26-28 + - Wietse considers including Postfix/TLS into the main release. A discussion + about security relevant features, especially the session cache inside + the chroot jail takes place. + The discussion will definetely lead to some changes; I have however not + decided on the first step, yet :-) + +2000/02/21 == RELEASED 0.5.4 == + - Important: Another directoy is created in /var/spool/postfix, so don't + forget to install the new versions of conf/postfix-script-*sgid. + +2000/02/21 + - Finished the seed-exchange architecture by saving the random seed at exit + of smtp and smtpd. + - Wrote documentation for the PRNG handling to the documentation. + - Tested on HP-UX (with a current OpenSSL-pre-0.9.5 snapshot and 0.9.4) + and on SuSE-Linux (with 0.9.4). + * THIS VERSION WILL STILL RUN WITH OPENSSL-0.9.4, but it will also run + with OpenSSL-0.9.5. Older versions of Postfix/TLS will not, because the + PRNG is not seeded! + +2000/02/19 + - Start to implement my own model of collecting entropy. All smtp and smtpd + processes will record some items (mainly the time of actions) to add + some entropy into the PRNG. The state is saved and used to re-seed by the + smtp and smtpd processes, so that entropy adds up into the pool. + The seeding by external file is additionally kept in order to be able + to inject additional entropy. + +2000/02/18 + - Included routines to add random seed from a configurable file + "rand_file_name". I don't want to retrieve the entropy from a real + random system source, because the amount of entropy that can be collected + is limited. We might hence stall. Let's think about this problem. + - The SSL_CTX_load_verify_locations() has been fixed in the latest + OpenSSL snapshot. + +2000/02/17 + - Tracked down the SSL_CTX_load_verify_locations() problem in the OpenSSL + library. If more than one CA-certificate is loaded, a bogus return value 0 + is created, because the count of certs is checked to be "1" instead of + allowing ">=1". Reported to openssl-dev. + +2000/02/16 + - Downloaded the latest openssl-SNAPSHOT-20000215 and installed it on + my development machine, then recompiled Postfix/TLS and try to run it. + * Failure: SSL_CTX_load_verify_locations() fails on reading the CAfile with + return value 0, but no actual error is displayed. + If the return value is not checked, the CA-certificates work, so that + they are loaded and the error indicator seems to be bogus. + Reported to openssl-dev mailing list. + * Failure: OpenSSL has become picky about correct seeding of the PRNG + Pseudo Random Number Generator. Installed some "testseed" that is + actually not random, but then Postfix/TLS starts to work again. We + will need some good random seed setup, probably reading from either + /dev/random (if available) or from EGD. + Found out during the experiments, that EGD is not that simple to use + as described in some of my Postfix/TLS docs. Must be upgraded. + Asked in the openssl-dev mailing list about the recommended amount + of random data needed for seeding the PRNG. Ulf Moeller recommends + a minimum of 128bit. + +2000/02/14 == Released 0.5.3 == + +2000/02/14 + - OpenSSL 0.9.5 is to be released within the next hours/days. Since I intend + to use some of its new features soon, I will re-release 0.5.2 as the last + version that will run with 0.9.4 but for the latest postfix patchlevel. + - No functional changes. + - Updated patch for postfix-19991231-pl04. + +2000/01/28 == Released 0.5.2 == + +2000/01/28 + - Stepped up the next postfix patchlevel postfix-19991231-pl03. + No functional changes. + +2000/01/03 == Released 0.5.1 == + +2000/01/03 + - Bug fixed: Don't specify a default value for "smtpd_tls_dcert_file", + assuming that typically a DSA certificate is not used. + Otherwise smtpd will try to read it on startup and the TLS engine won't + start since it is not found. + I didn't note this bug before today, because I could not install this + release in a larger scale on my own servers due to a network failure + of our campus backbone lastring from Dec 31 until today. + - Stepped up to the just released postfix-19991231-pl01. + +2000/01/01 == Released 0.5.0 == + +2000/01/01 + - Upgraded to the new postfix release 19991231. + +1999/12/30 + - Enabled support for DSA certificate and key for the server side. One + can have both at the same time, the selected cipher decides which one + is used. OpenSSL clients (like Postfix/TLS) will prefer the RSA cipher + suites, if not especially changed in the cipher selection list. + Netscape will only use the RSA cert. + - The client side can only have one certificate. There is a way out by using + a callback function, that will receive the list of acceptable CAs and + then do some clever selection: SSL_CTX_set_client_cert_cb(). + I will however have to figure out, how it has to be prepared, it seems, + that there is no example available. + - I have been able to successfully generate a DSA CA and certificates for + some Postfix hosts and to do authentication and relaying as expected. + So now I have to document how it is done in a practical manner... + - Moved up prerelease 0.5.0pre02 to the download site. + +1999/12/28 + - Moved up to SNAPSHOT-19991227. + - Don't forget to check the return value when calling + SSL_CTX_set_cipherlist(). + - Add code to load DH-parameters from disk. + - Add configuration information for the new functionality: DH paramter + support, possibility to influence the cipherlist. + - Moved up prerelease 0.5.0pre01 to the download site. + +1999/12/25 + - Found some minutes to relax from the christmas business. + - Applied the 0.4.7 patch to SNAPSHOT-19991223 and included the new changes + of 1999/12/19. + Once the new stable release of postfix is out, this minimum state will be + the new Postfix/TLS patch: the new functionality will not influence + stability, so it can stay in even if still unfinished. + +1999/12/23 + - Wietse announces SNAPSHOT-19991223: if no severe bugs are found, it will + be promoted as next stable release soon. Good to have kept everything + from yesterday. + +1999/12/22 + - Got a query from a Postfix/TLS user: the patch does not apply cleanly to + SNAPSHOT-19991216 and he somehow messed up to integrate the rejected + parts (it later turned out he just forgot on reject). + Applied the patch myself and generated a diff, sent it to the user + and of course kept a copy for myself, since I will have to apply it + myself eventually once the next "stable" release of postfix is out. + +1999/12/19 + - Began modifications for 0.5.x: + * Added configuration variables for specifying the cipherlist to be used + smtpd_tls_cipherlist and smtp_tls_cipherlist. For the format, there + is some (however sparse) documentation in the openssl package. + * Call SSL_CTX_set_cipherlist() with these data. + * Added default temporary DH parameters to pfixtls.c (only server side is + necessary) and configuration variables to specify user generated + parameters; they are however not used, yet. + The default parameters were generated using the presumably good + /dev/random source. + +1999/12/13 == Released 0.4.7 == + +1999/12/13 + - Addendum to the last change: do also remove sessions, that could _not_ + be reused. + - Updated configuration information: + * As of OpenSSL 0.9.4, certificate chain verification is not sufficient, + since the certificate purpose is not checked, so I recommend to add + all intermediate CAs the the list of CAs and stay with a verification + depth of 1. + Work is in progress for 0.9.5. + - Stepped up to the just released new patchlevel postfix-19990906-pl09. + +1999/12/10 == Released 0.4.6 == + +1999/12/10 + - Realized changes implied below: Removed SSL_CTX_add_session() in the + client startup; remove session on stop with SSL_SESSION_free(). + - In the morning there is a mail on the list, that Postfix might be + crashed with a single "\" on the "CC:" line. Hence, we should expect + a new patchlevel soon. Release the actual change anyway. + +1999/12/09 + - Read in the "openssl-users" mailing list, that SSL_CTX_add_session() + is only intended for servers. On the client side, SSL_set_session() + is sufficient. + Additionally, the session should be explicitely freed, since + SSL_set_session() will increment the usage count for the session. + Explained by Bodo Moeller. + +1999/12/xx + - Had a discussion (by email) with Bodo Moeller about DH/DSS. It seems + I understand better now (after the discussion) how it works :-). + Implementing it should not be too difficult but might take some more + hours. Mentally scheduled it for Version "0.5.0" whenever this might + be (rough guess: christmas vacation). + Decided to hence not discuss this topic in the docs, since it might + change in the near future anyway. + +1999/11/23 + - Discussion with rch@writeme.com (Richard) about implementing DH ciphers + and DSA keys and certificates on the Postfix/TLS list: It does not work + as of now. + +1999/11/15 == Released 0.4.5 == + +1999/11/15 + - Applied patch to postfix-19990906-pl07 without problems. Well, let's + release new version of Postfix/TLS, so that we look up to date. + - Add the "DO NOT EDIT THIS FILE" to conf/sample-tls.cf. + +1999/11/08 + - Applied patch to the fresh release of postfix-19990906-pl06 without + problems. Nothing else, so no new release of Postfix/TLS. + +1999/11/07 == Released 0.4.4 == + +1999/11/07 + - Played around some more with the X509_verify_cert() function: when saving + a session, neither the verify_result is saved nor the certificate chain + necessary to re-verify. So there were two possibilities left: do a full + renegotiation negating the benefit of session caching or + - save the verify_result into to the session cache file and set the value + when rereading from disk. This way the positive result of session caching + is kept. + - Make sure, the verify_result value is propagated as pfixtls_peer_verified + and used where needed. + - After experiencing some failures at TLS connection setup, the SSL_sessions + are now freed again when closing. It seems, something is left over in the + session structures, even though SSL_clear() is called. + +1999/11/06 + - When not asking for a client certificate, the "Received:" header will show + the protocol and cipher, but silently omit the client CN (because they + where not supplied). Noted by Craig Sanders . + The same holds, if a certificate is asked for, but none supplied. + Now, in any case an appropriate information is added in the "Received:" + header. + - Added a hint to remove sessions from the cache during testing, since + old information may still be in the cache. Also proposed by Craig + Sanders . + - While at it: client CN and issuer CN are printed, but the verification + state is not, so that the trust value of this data is not known. + * Added (verify OK/not verified) to the Received: header. + * Obtained information using the SSL_get_verify_result(SSL *con) call. + * Learned, that the state is not saved in the session information, so + that a recalled old session will always return "OK" even if the + certificate failed the verification! Call it a bug in OpenSSL. + Still investigating on a good way to work around this problem. + - Fixed a bug in the syslog entries: The client CN is logged, but the + issuer CN is not, because of a missing "%s" in the format string. + +1999/11/03 == Released 0.4.3 == + +1999/11/03 + - Added some hints about security to the html documentation. + - Tested the changes made two weeks ago at home in the large university + setup. I was to a conference in between and didn't want to release + the new version without having done some more tests. + +1999/10/17 + - Added another half a ton of comments (this time for the client side), + yielding one ton alltogether... + +1999/10/16 + - Rearranged some of the TLS-engine initialization to improve readability. + - Do not "free" the SSL connection, when it is not really necessary. Do only + reset information about the TLS connection, when there was one. This is + the better way instead of the quick fix applied for 0.4.2. + - Added half a ton of comments to the TLS code (server side) to document + what is done when and why, since there is no real documentation about + the OpenSSL library. + +1999/10/11 == Released 0.4.2 == + +1999/10/11 + - Fixed a severe bug introduced in 0.4.0: smtpd and smtp tried to flush + old session from the session cache even when TLS was not enabled. Since + no SSL-context was allocated, smtp would segfault on connection close. + +1999/10/10 == Released 0.4.1 == + +1999/10/10 + - Added a long description of the session cache handling to the top of + global/pfixtls.c. + - There is a race condition when cleaning up the session cache in qmgr, that + might lead to lost sessions in client mode. The worst consequence is an + additional session negotiation, so we can live with it as of now. + Bug described in qmgr/qmgr_tls.c. + - Implemented immediate removal of session cache files with expired sessions + when these are called. No need to first load and then discard them. + - Implemented the requirement from RFC2246 to remove sessions, when + connection failures occure (well actually, when TLS layer failures + occur, but I cannot seperate this from another) for the server side. + the client side is under work. + +1999/10/09 + - Set an absolut maximum length of 32 for the IDs used for session caching. + This matches the default in OpenSSL, but I don´t want to see surprises + when somebody sometimes will run into a longer session id. + +1999/10/05 == Released 0.4.0 == + - The new disk based session cache is a major step, so the minor release + number is pushed to 0.4. + - By now I think all necessary bells and whistles are in the code. What + is left is a big code cleanup and some more testing before calling this + patchkit "1.0.0". + - Initiated Mailing List at + http://www.aet.tu-cottbus.de/mailman/listinfo/postfix_tls + +1999/10/05 + - Some code cleanup. + - Added new options to the documentation and the hint to update + "postfix-script", because otherwise qmgr might fail! + +1999/10/03 + - Realized disc based session caching also for the Postfix/TLS client. + Must go to real world testing now between hosts. + And, of course, tune up the documentation, because users will have to + install a new postfix-script, too. + +1999/10/02 + - The old sessions must be removed once they have timed out, so a process + is needed that will scan through the list of old sessions and remove + once they have expired. + Lucky me: this is what qmgr usually does with deferred messages, so + qmgr is extended only a little bit and will now also clean up the + old sessions from the cache directory. + And hey: it is good to see how easily this thing can be extended and + functions can easily be reused. Postfix is an excellent peace of + software engineering and there is no line of C++ or other "object + oriented modern junk" in it. It should be recommended as an example + to computer sience students. + +1999/09/28 + - I cannot use the mod_ssl way for session caching and I don´t want to + spend an extra "gcache" daemon as ApacheSSL does. So I follow Wietse´s + idea realized for his mail queues and create hash level based subdirectory + structures. The good thing: I can cannibalize the mail_queue code. + The bad thing: there is a path length of 100 chars fix coded in Wietse´s + routines. It does hold for 32byte session ideas. + Status: can save sessions to disk and recall them (server side). + +1999/09/26 + - Created new call backs for external session caching for the server side. + In a first step, they can print out the session ids for the newly created + session and when recalling a session. + As the OpenSSL documentation on this is pretty sparse, Ben Laurie´s + ApacheSSL code is very helpful, Ralph Engelschall´s Mod_SSL code for + session caching is far more complicated. + +1999/09/23 == Released 0.3.10 == + +1999/09/23 + - Debugging for 0.3.8/0.3.9 would have been so much easier, if the error + messages put onto the error message stack from the OpenSSL library would + have been printed out. The error was clearly stated from the library, I + just didn't print it. Added pfixtls_print_errors() calls where missing + after calls to the OpenSSL library. + Sometimes I feel so old... + - Used opportunity to upgrade to the latest postfix patchlevel 05: + postfix-19990906-pl05. + +1999/09/19 == Released 0.3.9 == + +1999/09/19 + - Added a "smtp_no_tls_sites" table to allow people to enable TLS negotiation + globally and only omit it on a per site basis. + +1999/09/18 + - Finally found the bug described for 0.3.8: In the server setup, the + SSL_CTX_set_session_id_context() call was missing. To find this, I + had to trace through the OpenSSL library and when I finally found it + in ssl/ssl_sess.c, there was an appropriate comment about this. I however + have to find out why I didn´t receive the appropriate error message... + - This bug was hidden during the first developing stages, as the shutdown + sequence was not working correct, so the session was not cached. + +1999/09/17 == Released 0.3.8 == + +1999/09/17 + - Something is strange with the session caching in smtpd server mode + with Netscape 4.61 client. The first connection is fine, the next + one hangs after the server fails with errors while reading the + SSLv3 client hello C. (Found by Michael Stroeder ) + Reproducable with OpenSSL 0.9.3a, 0.9.4 and SNAPSHOT 19990915, so + the problem seems to be persistent. I will try to figure out the + problem myself before reporting it to the developers. If I don't find + it, maybe they do :-) + Workaround: the cached session is removed after connection is closed. + This will impose some time penalty on the negotiation. As the caching + is local in the smtp processes and they time out anyway, the penalty + should not be significant. + The problem does not occure with Postfix/TLS clients. + +1999/09/13 == Released 0.3.7 == + +1999/09/13 + - Ran tests, seems no further conflicts between Wietse's changes and my + extensions. + +1999/09/09 + - Applied the patchkit 0.3.6 to postfix-19990906-pl02 and worked out + the rejected part of the patch. From this point of view the patch + is included. Now everything has to be retested. + +1999/09/09 == Released 0.3.6 == + +1999/09/09 + - Added a missing ´#ifdef HAS_SSL #endif´ in smtp_connect.c. + Noted by Jeff Johnson . + - HINT: + On 1999/09/06 a new "stable" version of postfix was released. + Future Postfix/TLS enhancements will be against this new version 19990906. + +1999/08/25 == Released 0.3.5 == + +1999/08/25 + - Added Wietse's patch for postfix-19990601 to prevent crashing smtpd when + VRFY is called without setting the sender with "MAIL FROM:" first. + +1999/08/13 + - Small changes to global/pfixtls.[ch]: Since we also support client STARTLS, + we check the peers certificate, which may also be a "server" certificate + (not just client). Hence I renamed "*ccert*" to "*peer*". + - global/pfixtls.c: add some "const" to "char *" for OpenSSL library calls, + to make gcc happy. + - Extended comments in pfixtls.[ch] to better match Wietse's style. + +1999/08/12 == Released 0.3.4 == + +1999/08/12 + - Enabled workarounds for known bugs in SSL-engines. + - Tested with OpenSSL 0.9.4. + - Windows95/NT: Problem with Netscape hanging on first connection when + the client certificate database has to be unlocked cannot be reproduced + anymore. + I am happy, but I am also not sure what caused the problem to go away + and I cannot figure out the security settings manually from the files... + +1999/08/11 + - Corrected loglevel handling: At some points smtpd_tls_loglevel was used + instead of smtp_tls_loglevel (only noted at loglevels >= 2). + +1999/08/09 == Released 0.3.3 == + +1999/08/09 + - Removed SSL_CTX_set_quiet_shutdown() as it does prevent the shutdown + from actually being performed. In order to remove the annoying + "SSL3 alert write:warning:close notify" it is now explicitly handled + in apps_ssl_info_callback(). + Bug found by Bodo Moeller . + +1999/08/06 == Released 0.3.2 == + +1999/08/06 + - Add option "smtp_tls_note_starttls_offer" to collect information about + hosts, that offered the STARTTLS feature without using it. + - Shut up smtpd. Only print information about relaying based on certs + when msg_verbose is true. + +1999/07/20 + - Added missing "const" in pfixtls.h (found by Juergen Scheiderer + ). HP-UX ANSI-C didn't complain. + +1999/07/08 == Released 0.3.1 == + +1999/07/08 + - New config variable "smtpd_tls_received_header". When "true", the protocol + and cipher data as well as subject and issuer CN of the client certificate + are included into the "Received:" header. + +1999/07/07 + - "starting TLS engine" message will only be printed when loglevel >=2 + to reduce unnecessary noise in the log files. + - Added code to fetch the protocol (e.g. TLSv1) and the cipher used (by name + and bits). Information is printed to the logfile. + +1999/07/01 == Released 0.3.0 == + +1999/07/01 + - (Client mode) Bug fix: Don't try to use STARTTLS if it is not offered. The + server we are connected to might not understand it and respond with a + "500 command not understood", causing the email to bounce back, even + when the lack of STARTTLS is just a temporary problem. + - Updated documentation for the new per recipient/site TLS decisions. + +1999/06/30 + - Client mode: Added variables and routines to decide "per recipient" or + "per host/site" whether to use/enforce TLS or not. + +1999/06/18 == Released 0.2.8 == + +1999/06/18 + - In client mode the "use_tls" and "enforce_tls" internal variables were + not initialized correctly, such that the client could try to use the + STARTTLS negotiation even if not wanted. This error was introduced + in 0.2.7. + Noted by "Cerebus" . + +1999/06/08 == Released 0.2.7 == + +1999/06/08 + - Studied discussions in the IETF-apps-TLS mailing list: MS Exchange + seems to offer STARTTLS even if not configured. Added this info to the + documentation. + - Updated Documentation regarding the changes made. + +1999/06/03 + - The subject-CommonName (CN) of the server certificate is extracted when + connecting to a TLS server. + - In "smtp_*_tls" mode, this subject-CommonName is matched against the + hostname of the server. In "enforce" mode, the connection is droppend + when the certified server name and the real hostname differ. + - Added missing dependencies in smtp/Makefile.in (missing pfixtls.h since + 0.2.0). + +1999/06/02 == Released 0.2.6 == + +1999/06/02 + - Adapted patchkit to postfix-19990601. + +1999/06/01 == Released 0.2.5 == + +1999/06/01 + - Updated OpenSSL API to 0.9.3a -> position of include files has changed + from to . No functional changes. + - pkcs12 utility is now part of OpenSSL -> changed documentation + accordingly. + +1999/05/20 == Released 0.2.4 == + +1999/05/20 + - Updated postfix base 19990317 from pl04 to pl05. + +1999/05/14 == Released 0.2.3 == + +1999/05/14 + - Fixed a bug in pfixtls_stop_*(): there was a ";" to much directly + after "if (con);". This check is only done as a safety measure: + When SSL is not started you should not stop it. This case could however + only happen when the code in smtp[d] would be wrong, so it should never + be necessary. (Bug found by Uwe Ohse ) + +1999/05/11 == Released 0.2.2 == + +1999/05/11 + - Matti Aarnio: Reworked pfixtls_dump() to use fewer strcpy and strcat calls. + - Added information about Matti Aarnio (author/maintainer of ZMailer) + working on RFC2487 for ZMailer. + +1999/05/04 == Released 0.2.1 == + +1999/05/04 + - Stuffed up the documenation to reflect the actual status. No change + in functionality. + +1999/04/30 == Released 0.2.0 == + +1999/04/30 + - Adjusted the changes in smtp*.c to Wietse's indentation style. + - Sorry, the documentation about the client side has by now to be + taken from sample-tls.conf. The documenation has to be rearranged + in a larger scale. + +1999/04/29 + - Finished client support for STARTTLS in smtp; some testing done. + - Fixed a race condition in smtpd: When in PIPELINE mode, the connection + was switched back from SSL to normal mode before the buffers were + flashed. + - Adjusted the code in pfixtls.[ch] and additions in smtpd*.c to + Wietse's indentation style. + +1999/04/28 + - Incorporated skeleton of STARTTLS support into smtp. + - Introduced variables to control client STARTTLS to configuration. + +1999/04/15 == Released 0.1.5 == + +1999/04/15 + - Adjusted pfixtls.diff to postfix-19990317-pl04. + +1999/04/14 + - Ported from OpenSSL the BIO_callback functions to dump out the negotiation + and transmission for debugging purposes. The functions are triggered + by the the new loglevels 3 and 4. + - Call SSL_free() to get rid of the SSL connection structure not used + anymore. + +1999/04/13 == Released 0.1.4 == + +1999/04/13 + - Based on a hint in the openssl-users list added an SSL_set_accept_state() + before the actual SSL_accept(). I don't really understand why, but the + documentation of SSL is a bit short anyway. + +1999/04/11 + - Some more comments on certificates in the documentation. + +1999/04/10 + - Moved initialization of the pfixtls_server_engine to the pre_jail_init() + section of smtpd, so that it is called with root privileges to read the + key and cert information. The secret key of the server can now be protected + by "chown root secretkey.pem; chmod 400 secretkey.pem". + Additionally, this makes it possible to run smtpd in chroot jail, even + though I didn't test that, yet. All information is read at smtpd startup + time except the CAcerts in tls_CApath, which are checked at runtime. + I have to look into that. + - Updated documentation accordingly. + - Rewrote the documentation with regard to the certificate setup and + explaining the different types of certificates. + +1999/04/09 + - Introduced pfixtls_print_errors() which imitates BIO_print_errors() + (the typical way to print error information in OpenSSL) but writes + to syslog instead of a file handle. + Hence we can get more informative error information. + +1999/04/08 == Released 0.1.3 == + +1999/04/08 + - Stuffed up the documentation by reworking the references. + - Added contributed script for automatic addition of fingerprints. + - Added ACKNOWLEDGEMENTS file + +1999/04/06 == Released 0.1.2 == + +1999/04/06 + - Portability: removed call of "snprintf()", as it is not available on + some (older) UNIX versions (in this case Solaris 2.5). + - Removed calls to "select()" when in TLS mode: Even though no new bytes + arrive, there might be bytes left in the SSL buffer -> possible hang. + +1999/03/30 == Released 0.1.1 == + +1999/03/30 + - Added disclaimer about export restrictions. + - Fixed a bug in util/match_ops.c: + When using dictionary lookup the compare was case sensitive by accident. + Effect: Fingerprint matching did not work with databases, only for plain + file. + Bug report submitted to postfix author. + +1999/03/29 == Released first version 0.1.0 == diff -Pur postfix-2.1.5/pfixtls/INSTALL postfix-2.1.5-ti1.25/pfixtls/INSTALL --- postfix-2.1.5/pfixtls/INSTALL Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/INSTALL Mon Sep 20 15:01:53 2004 @@ -0,0 +1,2 @@ +For installation instructions please read the HTML documentation in the +"doc/" subdirectory. diff -Pur postfix-2.1.5/pfixtls/README postfix-2.1.5-ti1.25/pfixtls/README --- postfix-2.1.5/pfixtls/README Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/README Mon Sep 20 15:01:53 2004 @@ -0,0 +1,42 @@ +Overview: +========= + +- This is an SSL/TLS enhancement package for postfix. + It realizes (well, or at least should, once it is finished) the + STARTTLS extension to SMTP as described in RFC2487 and used + by Netscape 4.5x. +- For instructions on how to install the kit, please read the installation + section in the "html" manual in the "doc/" subdirectory. + +License: +======== +- This software is free. You can do with it whatever you want. + I would however kindly ask you to acknowledge the use of this + package, if you are going use it in your software, which you might + be going to distribute. I would also like to receive a note if you + are a satisfied user :-) + +Acknowledgements: +================= +- This package is based on the OpenSSL package as provided by the + ``OpenSSL Project''. + +Disclaimer: +=========== +- This software is provided ``as is''. You are using it at your own risk. + I will take no liability in any case. +- This software package uses strong cryptography, so even if it is created, + maintained and distributed from liberal countries in Europe (where it is + legal to do this), it falls under certain export/import and/or use + restrictions in some other parts of the world. +- 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 + PFIXTLS IS NOT LIABLE FOR ANY VIOLATIONS YOU MAKE HERE. SO BE + CAREFULLY YOURSELF, IT IS YOUR RESPONSIBILITY. + diff -Pur postfix-2.1.5/pfixtls/TODO postfix-2.1.5-ti1.25/pfixtls/TODO --- postfix-2.1.5/pfixtls/TODO Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/TODO Mon Sep 20 15:01:53 2004 @@ -0,0 +1,36 @@ +This list does not really follow priority. + +* Implement support of CRL checking. OpenSSL 0.9.7 finally supports CRLs, + so Postfix/TLS should support loading CRLs. + +* Cleanup the "pfixtls" special logging, so that it fits Wietses original + "per site" decision to make debugging easier. + +* Move TLS based information from separate lines into Postfix's smtpd + logging lines to make logfile analysis easier. + +* Check the "info_callback" for sensitive use. I already had to remove the + "warning alert" issued on normal shutdown. Why is a warning issued for + a normal shutdown?? + +* Allow to specify the protocol used globally: SSLv2, SSLv3, TLSv1. + +* Enhance tls_per_site feature, such that not only MAY, MUST, NONE flags + are supported. It should also be possible to influence the behaviour: + choose the SSLv2/SSLv3/TLSv1 protocols. + [A compatible way to upgrad the tls_per_site table would be to add the + keywords: + MUST,SSLv2 + MAY,NO_TLSv1 + ] + +* Introduce new tls_per_client table to achieve the same selective behaviour + for incoming connections. + +* Introduce better support for "opportunistic" encryption: collect information + about peers connecting; log warnings when the key changed etc. + [I am not sure that I already have the best answers available.] + +* Find a way to use the certificates themselves instead of the fingerprints + to allow certificate based relaying. The maintenance of the fingerprints + is a nightmare. diff -Pur postfix-2.1.5/pfixtls/contributed/00README postfix-2.1.5-ti1.25/pfixtls/contributed/00README --- postfix-2.1.5/pfixtls/contributed/00README Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/contributed/00README Mon Sep 20 15:01:53 2004 @@ -0,0 +1,22 @@ +All entries in this directory have been contributed from other sources: + +- Frederic J. Hirsch + * loadcacert.pl: + I "took" this one from his excellent introduction + "Introducing SSL and Certificates using SSLeay" + http://www.camb.opengroup.org/RI/www/prism/wwwj/index.html + +- Walcir Fontanini + * fp.csh: + add fingerprints to the list of client certs; + be carefull to a adjust filenames and maptype as necessary + +- Craig Sanders + * make-postfix-cert.sh: + automatically create certificates for postfix usage. + +- Justin Davies + * SSL_CA-HOWTO.pdf/sgml + SSL CA howto + * Postfix_SSL-HOWTO.pdf/sgml + Postfix/TLS howto diff -Pur postfix-2.1.5/pfixtls/contributed/fp.csh postfix-2.1.5-ti1.25/pfixtls/contributed/fp.csh --- postfix-2.1.5/pfixtls/contributed/fp.csh Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/contributed/fp.csh Mon Sep 20 15:01:53 2004 @@ -0,0 +1,20 @@ +#!/bin/csh -f + +## fp.csh +# Generate a fingerprint from a X509 certificate +# and updates /etc/postfix/relay_clientcerts +# It presumes a user certificate in /etc/postfix/certs/ +# with name -cert.pem +# author: walcir fontanini (walcir@densis.fee.unicamp.br) Apr-08-1999 + +set USER=$1 +set FP=`/usr/local/ssl/bin/openssl x509 -fingerprint -in /etc/postfix/certs/$USER-cert.pem | grep Fingerprint | awk -F= '{print $2}' | tr ":" "_"` + +cat >> /etc/postfix/relay_clientcerts <param('FORMAT'); +if($kind eq 'DER') { $cert_file = "CAcert.der"; } + +my $cert_path = "$cert_dir/$cert_file"; + +open(CERT, "<$cert_path"); +my $data = join '', ; +close(CERT); +print "Content-Type: application/x-x509-ca-cert\n"; +print "Content-Length: ", length($data), "\n\n$data"; + +1; diff -Pur postfix-2.1.5/pfixtls/contributed/make-postfix-cert.sh postfix-2.1.5-ti1.25/pfixtls/contributed/make-postfix-cert.sh --- postfix-2.1.5/pfixtls/contributed/make-postfix-cert.sh Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/contributed/make-postfix-cert.sh Mon Sep 20 15:01:53 2004 @@ -0,0 +1,78 @@ +#! /bin/sh + +# make-postfix-cert.sh +# by Craig Sanders 2000-09-02 +# this script is hereby placed in the public domain. + +# this script assumes that you already have a CA set up, as the openssl +# default "demoCA" under the current directory. if you haven't done it +# already, run "/usr/lib/ssl/misc/CA.pl -newca" (or where the path to +# openssl's CA.pl script is on your system). +# +# then run this script like so: +# +# ./make-postfix-cert.sh hostname.your.domain.com +# +# it will create the certificate and key files for that host and put +# them into a subdirectory. + +site="$1" + +# edit these values to suit your site. + +COUNTRY="??" # ISO country code +PROVINCE="YOUR STATE OR PROVINCE" +LOCALITY="YOUR CITY" +ORGANISATION="YOUR ORG NAME" +ORG_UNIT="" +COMMON_NAME=$site +EMAIL="someone@your.domain.com" + +OPTIONAL_COMPANY_NAME="" + +# leave challenge password blank +CHALLENGE_PASSWORD="" + +# generate a certificate valid for 10 years +# (probably not a good idea if you care about authentication, but should +# be fine if you only care about encryption of the smtp session) +DAYS="-days 1825" + +# alternatively, make one valid for one year +#DAYS="-days 365" + +# create the certificate request +cat <<__EOF__ | openssl req -new -nodes -keyout newreq.pem -out newreq.pem $DAYS +$COUNTRY +$PROVINCE +$LOCALITY +$ORGANISATION +$ORG_UNIT +$COMMON_NAME +$EMAIL +$CHALLENGE_PASSWORD +$OPTIONAL_COMPANY_NAME +__EOF__ + +# sign it +openssl ca -policy policy_anything -out newcert.pem -infiles newreq.pem + +# move it +mkdir -p $site +mv newreq.pem $site/key.pem +chmod 400 $site/key.pem +mv newcert.pem $site/cert.pem +cd $site + +# create server.pem for smtpd +cat cert.pem ../demoCA/cacert.pem key.pem >server.pem +chmod 400 server.pem + +# create fingerprint file +openssl x509 -fingerprint -in cert.pem -noout > fingerprint + +# create pkcs12 certificate for netscape (probably not needed) +#openssl pkcs12 -export -in cert.pem -inkey key.pem \ +# -certfile ../demoCA/cacert.pem -name "$site" -out cert.p12 + +cd .. diff -Pur postfix-2.1.5/pfixtls/doc/conf.html postfix-2.1.5-ti1.25/pfixtls/doc/conf.html --- postfix-2.1.5/pfixtls/doc/conf.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/conf.html Mon Sep 20 15:01:53 2004 @@ -0,0 +1,604 @@ + + + + +Postfix/TLS - Configuring main.cf and master.cf + + +

Postfix/TLS - Configuring main.cf and master.cf

+ +To use the TLS extension you need to feed some information to +postfix. Please see also the conf/sample-tls.cf file. + +

main.cf: smtpd (server) specific variables

+ +
+# 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 using "smtpd_use_tls". (Note: when invoked
+# via "sendmail -bs", STARTTLS is never offered due to insufficient
+# privileges to access the private key. This is intended behaviour.)
+#
+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. (Note: when invoked via "sendmail -bs", STARTTLS
+# is never offered due to insufficient privileges to access the private key.
+# This is intended behaviour.)
+#
+# 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
+
+ +

main.cf: smtp (client) specific variables

+ +
+# 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). Checks are performed against
+# all names provided as dNSNames in the SubjectAlternativeName. If no
+# dNSNames are specified, the CommonName is checked.
+# 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
+
+ +

SASL related variables

+ +
+# The smtpd_sasl_tls_security_options parameter controls what authentication
+# mechanism the Postfix SMTP server will offer to the client, in case the
+# connection is protected by a TLS encrypted session.
+# This parameter allows to provide for example plaintext authentication that
+# otherwise would not be allowed without encryption.
+# The default is to use the same settings as in the unencrypted case.
+#
+# Warning: this option only works against passive (eavesdropping) attackes.
+# An active attacker (man in the middle) may modify the AUTH options offered
+# and/or remove the STARTTLS offer from the EHLO response. Protection against
+# active attackers is only possible by enforcing TLS at the client side.
+#
+#smtpd_sasl_tls_security_options = noanonymous
+smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
+
+# Sending AUTH data over an unencrypted channel poses a security risk. When
+# smtpd_tls_enforce_tls is set, AUTH will only be announced and accepted,
+# once the TLS layer has been activated via the STARTTLS protocol. If
+# TLS layer encryption is optional, it may however still be useful to only
+# offer AUTH, if TLS is active. To not break compatiblity with unpatched
+# postfix versions, the default is to accept AUTH without encryption. In
+# order to change this behaviour, set smtpd_tls_auth_only = yes.
+# THIS OPTION ONLY WORKS WITH SSL/TLS SUPPORT COMPILED IN.
+#
+#smtpd_tls_auth_only = yes
+smtpd_tls_auth_only = no
+
+# The smtp_sasl_tls_security_options parameter controls, what authentication
+# mechanisms the local Postfix SMTP client is allowed to use, if the session
+# is encrypted via TLS. This provides the option to permit plaintext passwords
+# that otherwise could not be used.
+#
+# The settings allowed are the same as for the non-encrypted sessions
+# (smtp_sasl_security_options).
+#
+# Warning, Warning, Warning: This option only works against passive
+# (eavesdropping) attacks. An active attacker (man in the middle) may provide
+# a TLS capabable server (proxy) and in such way obtain the password
+# information. The only way to prevent a man in the middle attack is to check
+# the hostname of the server presented in the certificate. This is assured
+# in the (preferrably used) smtp_sasl_tls_verified_security_options case.
+#
+#smtp_sasl_tls_security_options =
+smtp_sasl_tls_security_options = $smtp_sasl_security_options
+
+# The smtp_sasl_tls_verified_security_options parameter controls, what
+# authentication mechanisms the local Postfix SMTP client is allowed to use,
+# if the session is encrypted via TLS _and_ the server has proven its
+# identity (expected hostname matches certificate, verification successfull).
+# This provides the option to permit plaintext passwords that otherwise could
+# not be used.
+#
+# The settings allowed are the same as for the non-encrypted sessions
+# (smtp_sasl_security_options).
+#
+#smtp_sasl_tls_verified_security_options =
+smtp_sasl_tls_verified_security_options = $smtp_sasl_tls_security_options
+
+ +

main.cf: general variables

+ +
+# 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
+
+ +

master.cf: tlsmgr daemon

+ +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 +will contact entropy sources on startup and keep the connection open, +so that it can be chrooted and can drop privileges. + +
+# ==========================================================================
+# service type  private unpriv  chroot  wakeup  maxproc command + args
+#               (yes)   (yes)   (yes)   (never) (50)
+# ==========================================================================
+tlsmgr    fifo  -       -       y       300     1       tlsmgr
+
+ +

master.cf: additional services

+ +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). + +

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.)

+ +
+# ==========================================================================
+# 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
+
+ + + diff -Pur postfix-2.1.5/pfixtls/doc/index.html postfix-2.1.5-ti1.25/pfixtls/doc/index.html --- postfix-2.1.5/pfixtls/doc/index.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/index.html Mon Sep 20 15:01:53 2004 @@ -0,0 +1,53 @@ + + + + +Postfix/TLS - A TLS extension for POSTFIX + + +

Postfix/TLS - A TLS extension for POSTFIX

+ +

Contents

+ + + +Please check also the contents of the contributions folder +including useful scripts and some HOWTO documents. + +
+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.
+
+ +Lutz Jänicke, Homepage, +Email: +Lutz.Jaenicke@aet.TU-Cottbus.DE + + + diff -Pur postfix-2.1.5/pfixtls/doc/install.html postfix-2.1.5-ti1.25/pfixtls/doc/install.html --- postfix-2.1.5/pfixtls/doc/install.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/install.html Mon Sep 20 15:01:53 2004 @@ -0,0 +1,93 @@ + + + + +Postfix/TLS - Installation + + +

Postfix/TLS - Installing the patchkit

+ +

Prerequisits

+ +This patchkit is prepared for + +
    +
  • Postfix Version 2.0.18-20040122
    + http://www.postfix.org/ [POSTFIX]
    + The use of other versions might lead to patch conflicts or silent +failures, as we directly change the source code.
  • + +
  • OpenSSL Version 0.9.7c (>=0.9.5)
    + http://www.openssl.org/ [OPENSSL]
    +We use OpenSSL as library (and some command line tools to create +the certificates, if necessary). OpenSSL is the successor of +SSLeay. +

    Postfix/TLS uses properties that are only available starting with +version 0.9.5 of the OpenSSL library. 0.9.5a and 0.9.6x have proven +stability over several months. + +The release 0.9.7 contains several enhancemants and bugfixes. + +OpenSSL 0.9.7c is the latest release and the recommended version. +

  • +
+ +You may also need to update your "patch" utility (see below). + +

Patching

+ +The changes to the postfix source code as well as the additional +files are included in the "pfixtls.diff" in the main +directory of the patch kit. It is a unified diff. + +

To apply the patches, go to the directory one level below the +original postfix source tree (you should see +"postfix-xxxxxxx" or "snapshot-xxxxxxx" +when doing an "ls -al" +at this point. The patch is then applied with:

+ +
+patch -p0 < path-to/pfixtls.diff
+
+ +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. + +

If you need to apply the patchkit to a different version of +patchlevel of postfix, you might try the following:

+ +
+cd postfix-directory ; patch -p1 < path-to/pfixtls.diff
+
+ +Since the patch is in unified form, it might also apply to a mildly +changed source, as long as no conflicts appear. + +

Compiling

+ +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 USE_SSL. Your command for configuration +might then be: + +
+make makefiles CCARGS="-DUSE_SSL -I/usr/local/ssl/include" AUXLIBS="-L/usr/local/ssl/lib -lssl -lcrypto"
+
+ +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: + +
+make
+
+ +and then follow the instructions in the postfix INSTALL file. + + + + diff -Pur postfix-2.1.5/pfixtls/doc/intro.html postfix-2.1.5-ti1.25/pfixtls/doc/intro.html --- postfix-2.1.5/pfixtls/doc/intro.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/intro.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,194 @@ + + + + +Postfix/TLS - Introduction + + +

Postfix/TLS - Introduction

+ +Postfix/TLS is an extension of the Postfix [POSTFIX] MTA software to support the +TLS protocol. + +

A note about the start of the project

+ +When I started writing this software, I had a sophisticated way to +allow relaying for roaming users in +mind. In the meantime, this project is living on its own. + +

RFC2246: The TLS (former SSL) protocol

+ +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. + +

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 RFC2246. 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).

+ +

Postfix/TLS does not realize the TLS protocol itself; it rather +uses the OpenSSL package [OPENSSL] 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.)

+ +

RFC2487: Introducing TLS to SMTP

+ +The integration of the TLS protocol to Internet mail, SMTP (Simple +Mail Transport Protocol) is described in +RFC2487. + +

Unlike the first incarnations of SSL as a wrapper +around normal network communications [STUNNEL] [JONAMA], the TLS protocol is now +completely integrated into the ESMTP: during the startup +negotiation (EHLO) the server offers the support of TLS by +advertising the STARTTLS feature. The client can +now send the STARTTLS command to do authentication +and switch to encrypted communication.

+ +

Postfix/TLS: what can it do for you

+ +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. + +
    +
  • Encrypted email transfer from one host to another.
    +Status: realized.
    +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.
  • + +
  • Authentication of the receiving host to prevent +interception.
    +Status: realized.
    +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.
  • + +
  • Authentication of the sending host to prevent forgery.
    +Status: Difficult to do.
    +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 and reliable solution is hardly possible (do +you want your users' email bounce without reason?), so it has least +priority.
  • + +
  • Authentication of the sending host to allow relaying.
    +Status: realized.
    +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.
  • + +
  • Any more ideas???
    +Status: Send me an email.
  • +
+ +

Postfix/TLS: what it cannot do for you

+ +There is one thing that I explicitly want to point out: + +
    +
  • Securing the privacy of your email.
    +Status: Cannot be done.
    +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 + +
      +
    • all of the mailhubs in between are enforcing TLS.
    • + +
    • all mailhubs themselves are trustworthy, as the email is only +encrypted during transport, not when queued or spooled.
    • + +
    • 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!
    • +
    + +Hence, if you want privacy, you have to send out your +email encrypted, e.g. using S/MIME or the traditional PGP +package.
  • + +
  • Authenticate the sender of an email.
    +Status: Cannot be done.
    +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.
    +To ensure the identity of the sender and the integrity of the +email, you can again use S/MIME or PGP.
  • +
+ +

Support by Mail User Agents

+ +The following MUAs are known to work with RFC2487: +
    +
  • Netscape >= 4.5 supports STARTTLS and client certificates. +
  • Outlook (Express) >= 5 supports STARTTLS (only on port 25) and traditional +SSL-wrapping style (on all other ports). No support for client certificates. +
  • Eudora >= 5.1 supports STARTTLS. Client certificate status unknown. +
+ +

Other OpenSource packages

+ +As of version sendmail-8.11, sendmail includes RFC2487 support [SENDMAIL]. + +

Frederik Vermeulen has realized an RFC2487 extension [QMAILTLS] for the Qmail [QMAIL] MTA.

+ +

Matti Aarnio has integrated RFC2487 into ZMailer [ZMAILER].

+ +

Michal Trojnara is currently integrating basic SMTP support into +his stunnel software, starting with stunnel-3.3 [STUNNEL].

+ +

Trey Childs is also working on a "wrapper" solution [SMTPS].

+ +

Commercial implementations

+ +The commercial version of sendmail includes RFC2487 support [SENDMAIL.INC]. + +

Netscape Enterprise Server and Microsoft Exchange Server do offer +RFC2487 functionality.

+ +

The CommunigatePro mailserver software also supports RFC2487 +[COMMUNIGATE].

+ + + + diff -Pur postfix-2.1.5/pfixtls/doc/loadCAcert.pl postfix-2.1.5-ti1.25/pfixtls/doc/loadCAcert.pl --- postfix-2.1.5/pfixtls/doc/loadCAcert.pl Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/loadCAcert.pl Mon Sep 20 15:01:54 2004 @@ -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 '', ; +close(CERT); +print "Content-Type: application/x-x509-ca-cert\n"; +print "Content-Length: ", length($data), "\n\n$data"; + +1; diff -Pur postfix-2.1.5/pfixtls/doc/myownca.html postfix-2.1.5-ti1.25/pfixtls/doc/myownca.html --- postfix-2.1.5/pfixtls/doc/myownca.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/myownca.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,175 @@ + + + + +Postfix/TLS - Being your on CA + + +

Postfix/TLS - Lutz's very short course on being your own +CA

+ +This section is kept quite short as there are already a lot of +pages explaining these things (e.g. [INTROCERT]). There are also +projects under way to make this task easier [OPENCA], so I wont't waste your time +(and mine) by writing a book about it. + +

Be your own CA

+ +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). + + +

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.

+ +

Using OpenSSL it is quite simple to become your own CA. Just +run

+ +
+CA.pl -newca
+
+ +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 openssl.cnf file, especially the comment. + +

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 +loadCAcert.pl script to your cgi-bin directory. If +you call it from Netscape (or Internet Explorer), you can load the +certificate! (Taken from [6])

+ +

Create your site certificate

+ +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. + +

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 -nodes option +in CA.pl to the line with the -newcert +and/or -newreq command:

+ +
+*** 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$/) {
+
+ +For sslwrap or stunnel the authors propose to use self signed certs +created with -newcert. I rather propose to create an +ordinary certificate request with + +
+CA.pl -newreq
+
+ +and then sign it with your CA: + +
+CA.pl -sign
+
+ +Now you can install the cert from cacert.pem to +/etc/postfix/CAcert.pem, the created certificate from +newcert.pem to /etc/postfix/cert.pem and the +key part form newreq.pem to +/etc/postfix/key.pem. Please be aware, that the +key.pem 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 + +
+chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
+
+ +

Create a client certificate

+ +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: + +
+CA.pl -newreq
+CA.pl -sign
+
+ +If you want to do client certificate based relaying, you do need +the fingerprint of the certificate, which can be obtained with + +
+openssl x509 -fingerprint -in newcert.pem
+
+ +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 pkcs12 utility [PKCS12], which is included in the +OpenSSL package as of version 0.9.3. The necessary command is: + +
+pkcs12 -export -in newcert.pem -inkey newreq.pem \
+  -certfile /usr/local/ssl/CAcert.pem -name "Name" -out newcert.p12
+
+ +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)"). +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? + + + diff -Pur postfix-2.1.5/pfixtls/doc/prng.html postfix-2.1.5-ti1.25/pfixtls/doc/prng.html --- postfix-2.1.5/pfixtls/doc/prng.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/prng.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,97 @@ + + + + +Postfix/TLS - PRNG Pseudo Random Number Generator + + +

Postfix/TLS - PRNG Pseudo Random Number Generator

+ +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. + +

Included PRNG

+ +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. + +

Obtaining Entropy

+ +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". + +

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.

+ +

External sources

+ +Only few operating systems provide good entropy collection. + +

/dev/random and /dev/urandom

+ +Linux offers the /dev/random and /dev/urandom +devices, some BSD derivatives as well. + +

/dev/random will provide high quality random data, but +it will block until enough entropy is available, if too much random +data is requested to fast. /dev/urandom 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 +/dev/urandom.

+ +

Entropy Gathering Daemon

+ +A replacement for operating systems without good random number +collection is the EGD Entropy +Gathering Daemon. It will also extract entropy from a lot of +sources. + +

EGD has a command driven interface, there is a command for +blocking and one for non-blocking read. Unlike +/dev/urandom 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.

+ +

EGD should hence not be used for direct feeding of smtp[d] +processes. Again, imagine 50 smtp processes starting delivery at +the same time.

+ +

To circumvent this problem, I have witten my own daemon, +that has a EGD compatible interface but can never run dry, just +like /dev/urandom. Check out PRNGD for details.

+ +

Intermediate File

+ +Hence, Postfix/TLS maintains its own pool of entropy by means +of the tlsmgr 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. + +

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. + + + + diff -Pur postfix-2.1.5/pfixtls/doc/references.html postfix-2.1.5-ti1.25/pfixtls/doc/references.html --- postfix-2.1.5/pfixtls/doc/references.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/references.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,105 @@ + + + + +Postfix/TLS - References + + +

Postfix/TLS - References

+ +
    +
  1. [POSTFIX] The Postfix (formerly VMailer) Home +Page: +http://www.postfix.org/.
  2. + +
  3. [OPENSSL] OpenSSL: The Open Source +toolkit for SSL/TLS: +http://www.openssl.org/.
  4. + +
  5. [PKCS12]OpenSSL PKCS#12 Program FAQ: +http://www.drh-consultancy.demon.co.uk/pkcs12faq.html.
  6. + +
  7. [SSLWRAP] SSLwrap Homepage: +http://www.rickk.com/sslwrap/.
  8. + +
  9. [STUNNEL] Stunnel Homepage: +http://stunnel.mirt.net/.
  10. + +
  11. [INTROCERT] Introducing SSL and +Certificates using SSLeay: +http://www.ultranet.com/~fhirsch/Papers/wwwj/.
  12. + +
  13. [IMC] Internet Mail Consortium: http://www.imc.org/.
  14. + +
  15. [IETF-APPS-TLS] ietf-apps-tls +mailing list: +http://www.imc.org/ietf-apps-tls/
  16. + +
  17. [OPENCA] The OpenCA Project: http://www.openca.org/.
  18. + +
  19. [DFNPCA] DFN-PCA: http://www.dfn-pca.de/.
  20. + +
  21. [SENDMAIL] Sendmail: http://www.sendmail.org/.
  22. + +
  23. [SENDMAIL.INC] Sendmail Inc: http://www.sendmail.com/.
  24. + +
  25. [QMAIL] Qmail: http://www.qmail.org/.
  26. + +
  27. [QMAILTLS] Qmail/TLS: +http://www.esat.kuleuven.ac.be/~vermeule/qmail/tls.patch.
  28. + +
  29. [ZMAILER] ZMailer: http://www.zmailer.org/.
  30. + +
  31. [JONAMA] Jonama: +http://www.multimania.com/jonama/.
  32. + +
  33. [SMTPS] Trey Child's STARTTLS wrapper: +http://blueice.shopkeeper.de/~tchilds/.
  34. + +
  35. [SAFEGOSSIP] Safegossip universal +TLS-wrapper: +http://www.skygate.co.uk/safegossip/.
  36. + +
  37. [SENDMAIL-TLS] Jeremy Beker's +sendmail-tls wrapper: +http://opensource.3gi.com/.
  38. + +
  39. [COMMUNIGATE] Stalker Software's +CommunigatePro mailserver product: +http://www.stalker.com/.
  40. + +
  41. [EGD] Entropy Gathering Daemon: +http://www.lothar.com/tech/crypto/.
  42. + +
  43. [PRNGD] Pseudo Random Number Generator +Daemon: +http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html.
  44. + +
  45. [Outlook/SSL] Outlook (Express) and +STARTTLS info: +http://support.microsoft.com/support/kb/articles/Q218/4/30.ASP.
  46. + +
  47. [TLS/CA Howto] Justin Davis TLS and CA Howtos: + +http://palmcoder.net/files/howtos/.
  48. +
+ + + diff -Pur postfix-2.1.5/pfixtls/doc/relaycert.html postfix-2.1.5-ti1.25/pfixtls/doc/relaycert.html --- postfix-2.1.5/pfixtls/doc/relaycert.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/relaycert.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,124 @@ + + + + +Postfix/TLS - Initial Motivation + + +

Postfix/TLS - Initial Motivation

+ +This introduction shall point out the motivation, why I spend my +time writing this TLS extension for postfix. + +

Roaming users problem

+ +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. + +

UCE control

+ +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. + + +

Passwords and insecure networks

+ +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. + +

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.

+ +

Encryption via SSL

+ +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 SSLwrap [SSLWRAP] or stunnel +[STUNNEL]. + +

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.

+ +

Netscape 4.5

+ +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 RFC 2487 [IMC]. + +

RFC 2487 - SMTP Service Extension for Secure SMTP over TLS

+ +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. + +

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.

+ +

Postfix

+ +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. + +

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.

+ +

Postfix/TLS

+ +Some time after having done this I finally found the time to write +my TLS extensions for postfix. I took the source of the +s_server 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! + +

Summary

+ +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. + + + diff -Pur postfix-2.1.5/pfixtls/doc/rfc2246.txt postfix-2.1.5-ti1.25/pfixtls/doc/rfc2246.txt --- postfix-2.1.5/pfixtls/doc/rfc2246.txt Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/rfc2246.txt Mon Sep 20 15:01:54 2004 @@ -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] + +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] + +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] + +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] + +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] + +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] + +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 . 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'; + + 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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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] + +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 . Information on the + group and information on how to subscribe to the list is at + . + + + +Dierks & Allen Standards Track [Page 78] + +RFC 2246 The TLS Protocol Version 1.0 January 1999 + + + Archives of the list can be found at: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Dierks & Allen Standards Track [Page 79] + +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] + diff -Pur postfix-2.1.5/pfixtls/doc/rfc2487.txt postfix-2.1.5-ti1.25/pfixtls/doc/rfc2487.txt --- postfix-2.1.5/pfixtls/doc/rfc2487.txt Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/rfc2487.txt Mon Sep 20 15:01:54 2004 @@ -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] + +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] + +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] + +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: + C: + 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: + + + +Hoffman Standards Track [Page 4] + +RFC 2487 SMTP Service Extension January 1999 + + + C & S: + C & S: + C: + . . . + +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] + +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] + +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] + +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] + diff -Pur postfix-2.1.5/pfixtls/doc/rfc3207.txt postfix-2.1.5-ti1.25/pfixtls/doc/rfc3207.txt --- postfix-2.1.5/pfixtls/doc/rfc3207.txt Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/rfc3207.txt Mon Sep 20 15:01:54 2004 @@ -0,0 +1,507 @@ + + + + + + +Network Working Group P. Hoffman +Request for Comments: 3207 Internet Mail Consortium +Obsoletes: 2487 February 2002 +Category: Standards Track + + + SMTP Service Extension for + Secure SMTP over Transport Layer Security + +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 (2002). All Rights Reserved. + +Abstract + + This document describes an extension to the SMTP (Simple Mail + Transfer Protocol) service that allows an SMTP server and client to + use TLS (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. + +1. Introduction + + SMTP [RFC2821] 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. + + + + + + + + +Hoffman Standards Track [Page 1] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + + 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. + + This document obsoletes RFC 2487. + +1.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 [RFC2119]. + +2. 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. + +3. The STARTTLS Keyword + + The STARTTLS keyword is used to tell the SMTP client that the SMTP + server is currently able to negotiate the use of TLS. It takes no + parameters. + +4. 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 + + + + +Hoffman Standards Track [Page 2] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + + If the client receives the 454 response, the client must decide + whether or not to continue the SMTP session. Such a decision is + based on local policy. For instance, if TLS was being used for + client authentication, the client might try to continue the session, + in case the server allows it even with no authentication. However, + if TLS was being negotiated for encryption, a client that gets a 454 + response needs to decide whether to send the message anyway with no + TLS encryption, whether to wait and try again later, or whether to + give up and notify the sender of the error. + + 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. + + 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 + [RFC2034], the status code to be returned SHOULD be 5.7.0. + + After receiving a 220 response to a STARTTLS command, the client MUST + start the TLS negotiation before giving any other SMTP commands. If, + after having issued the STARTTLS command, the client finds out that + some failure prevents it from actually starting a TLS handshake, then + it SHOULD abort the connection. + + If the SMTP client is using pipelining as defined in RFC 2920, the + STARTTLS command must be the last command in a group. + + + + + + + + +Hoffman Standards Track [Page 3] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + +4.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: + + - 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 verifiable 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. + +4.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 + + + +Hoffman Standards Track [Page 4] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + + 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 STARTTLS + extension in response to an EHLO command received after a TLS + handshake has completed. + +4.3 STARTTLS on the Submission Port + + STARTTLS is a valid ESMTP extension when used on the Submission port, + as defined in [RFC2476]. In fact, since the submission port is by + definition not a publicly referenced SMTP server, the STARTTLS + extension can be particularly useful by providing security and + authentication for this service. + +5. Usage Example + + The following dialog illustrates how a client and server can start a + TLS session: + + S: + C: + S: 220 mail.imc.org SMTP service ready + C: EHLO mail.example.com + S: 250-mail.imc.org offers a warm hug of welcome + S: 250-8BITMIME + S: 250-STARTTLS + S: 250 DSN + C: STARTTLS + S: 220 Go ahead + C: + C & S: + C & S: + C: EHLO mail.example.com + S: 250-mail.imc.org touches your hand gently for a moment + S: 250-8BITMIME + S: 250 DSN + +6. 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 + + + +Hoffman Standards Track [Page 5] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + + 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 SMTP client and server must check the result of the TLS + negotiation to see whether an acceptable degree of authentication and + 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-dependent, 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 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. Another man-in-the-middle attack is + to allow the server to announce its STARTTLS capability, but to alter + the client's request to start TLS and the server's response. In + order to defend against such attacks both clients and servers MUST be + able to be configured to require successful TLS negotiation of an + appropriate cipher suite for selected hosts before messages can be + successfully transferred. The additional option of using TLS when + possible SHOULD also be provided. An implementation MAY provide the + ability to record that TLS was used in communicating with a given + peer and generating a warning if it is not used in a later session. + + If the TLS negotiation fails or if the client receives a 454 + response, the client has to decide what to do next. There are three + main choices: go ahead with the rest of the SMTP session, retry TLS + at a later time, or give up and return the mail to the sender. If a + failure or error occurs, the client can assume that the server may be + able to negotiate TLS in the future, and should try negotiate TLS in + a later session, until some locally-chosen timeout occurs, at which + point, the client should return the mail to the sender. However, if + the client and server were only using TLS for authentication, the + client may want to proceed with the SMTP session, in case some of the + operations the client wanted to perform are accepted by the server + even if the client is unauthenticated. + + Before the TLS handshake has begun, any protocol interactions are + performed in the clear and may be modified by an active attacker. + + + +Hoffman Standards Track [Page 6] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + + 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. + +7. References + + [RFC2821] Klensin, J., "Simple Mail Transfer Protocol", RFC 2821, + April 2001. + + [RFC2034] Freed, N., "SMTP Service Extension for Returning Enhanced + Error Codes", RFC 2034, October 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2476] Gellens, R. and J. Klensin, "Message Submission", RFC + 2476, December 1998. + + [SASL] Myers, J., "Simple Authentication and Security Layer + (SASL)", RFC 2222, October 1997. + + [SMTP-AUTH] Myers, J., "SMTP Service Extension for Authentication", + RFC 2554, March 1999. + + [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", + RFC 2246, January 1999. + + + + + + + + + + + + + + + +Hoffman Standards Track [Page 7] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + +Appendix + + This document is a revision of RFC 2487, which is a Proposed + Standard. The changes from that document are: + + - Section 5 and 7: More discussion of the man-in-the-middle attacks + - Section 5: Additional discussion of when a server should and + should not advertise the STARTTLS extension + - Section 5: Changed the requirements on SMTP clients after + receiving a 220 response. + - Section 5.1: Clarified description of verifying certificates. + - Section 5.3: Added the section on "STARTTLS on the Submission + Port" + - Section 6: Bug fix in the example to indicate that the client + needs to issue a new EHLO command, as already is described in + section 5.2. + - Section 7: Clarification of the paragraph on acceptable degree of + privacy. Significant change to the discussion of how to avoid a + man-in-the-middle attack. + - Section A: Update reference from RFC 821 to RFC 2821. + +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 8] + +RFC 3207 SMTP Service Extension - Secure SMTP over TLS February 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). 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. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Hoffman Standards Track [Page 9] + diff -Pur postfix-2.1.5/pfixtls/doc/security.html postfix-2.1.5-ti1.25/pfixtls/doc/security.html --- postfix-2.1.5/pfixtls/doc/security.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/security.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,78 @@ + + + + +Postfix/TLS - Security Considerations + + +

Postfix/TLS - Security Considerations

+ +The following sections cover some (possible) security issues with +regard to Postfix/TLS. + +

Server/Client private key file

+ +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. + +

The only protection can therefore come from filesystem access +rights, which should be set to 'owner root' and 'readable for owner +only':

+ +
+-rw-------   1 root       sys            887 Apr 29  1999 /etc/postfix/key.pem
+
+ +

This protection is only as good as your host is protected +against root exploits.

+ +

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.)

+ +

Disk based session cache

+ +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. + +

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.

+ +

DNS issues

+ +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! + +

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.

+ +

The only way to protect against this problem is that for those +recipients, for which we want to enforce +encryption and authentication, the MX lookup must be overridden +with an appropriate entry in the /etc/postfix/transport table:

+ +
+important.dom.ain smtp:[mailserver.important.dom.ain]
+
+ + + diff -Pur postfix-2.1.5/pfixtls/doc/setup.html postfix-2.1.5-ti1.25/pfixtls/doc/setup.html --- postfix-2.1.5/pfixtls/doc/setup.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/setup.html Mon Sep 20 15:01:54 2004 @@ -0,0 +1,220 @@ + + + + +Postfix/TLS - Setting up the certificates + + +

Postfix/TLS - Setting up the certificates

+ +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. + +

Server certificate

+ +To run SMTP with TLS in server mode, your server +must have a pair of private key and public +key. + +

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 +certificate from a certificate authority (CA), that is sent +combined with the public key. This server certificate +contains the name.of.your.host. The client will then +check the signature of the CA on the public key to decide, +whether the certificate (and public key) are authentic.

+ +

So for the server we do need:

+ +
    +
  • 1 server private key
  • + +
  • 1 server public key signed by a CA, a server +certificate, certifying that the public key belongs to +name.of.your.host.
  • + +
  • 1 CA certificate with the public key of the CA
  • +
+ +For this list I definitely want point out the number of components +used to be 1, because you must have +1, you cannot have less, you cannot have more! + +

Server certificate policy

+ +At this point you have to decide about policy. The client which is +going to connect to your host will check the names in the server +certificate, the dNSName entries in the SubjectAlternativeName +or the CN (Common Name) if no dNSName is found, against the FQDN (Fully +Qualified Domain Name) of your server. If both agree, your server's +identity is proved. + +

To see, whether the certificate itself is authentic, the client +itself must have the CA certificate. 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.

+ +

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 +Research Network (DFN) has started a program for universities [DFNPCA].

+ +

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.
+Lutz's very short course on being your own +CA.

+ +

Using the certificates with Postfix/TLS

+ +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: + +
    +
  • The private key: + +
    +smtpd_tls_key_file = /etc/postfix/key.pem
    +
    + +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: + +
    +chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
    +
    + +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.
  • + +
  • The server certificate: This certificate is not secret, as it +will be presented to every client anyhow, so you just name it to +postfix: + +
    +smtpd_tls_cert_file = /etc/postfix/cert.pem
    +
    + +If you like, you can put private key and cert into one file.
  • + +
  • 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. + +
    +smtpd_tls_CAfile = /etc/postfix/CAcert.pem
    +
    +
  • +
+ +With these certificates you should already have enough to get +Postfix/TLS running. + +

Postfix/TLS client mode

+ +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: + +
+smtp_tls_key_file = /etc/postfix/key.pem
+chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
+
+ +
+smtp_tls_cert_file = /etc/postfix/cert.pem
+
+ +
+smtp_tls_CAfile = /etc/postfix/CAcert.pem
+
+ +

Client certificates

+ +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. + +

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.

+ +

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).

+ +

Listing CA certificates

+ +

You have two possibilities to perform this task.

+ +
    +
  1. You just add the CA certificates to the +smtp[d]_tls_CAfile 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.
  2. + +
  3. You can add the CA certificates in single files with adequate +names to a certificate directory specified in: + +
    +smtpd_tls_CApath = /etc/postfix/certs
    +
    + +Please don't forget to issue a $OPENSSL_HOME/bin/c_rehash +/etc/postfix/certs after you have made changes, as the +hashes are use to find the right CA certificate. This method should +not work in chroot mode.
  4. +
+ +

Adding client certificates

+ +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. + +

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 chmod 400).

+ + + diff -Pur postfix-2.1.5/pfixtls/doc/test.html postfix-2.1.5-ti1.25/pfixtls/doc/test.html --- postfix-2.1.5/pfixtls/doc/test.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc/test.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,167 @@ + + + + +Postfix/TLS - Testing + + +

Postfix/TLS - Testing

+ +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 :-). + +

Included debugging aids

+ +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). + +

As a first step set smpt[d]_tls_loglevel=2 and +watch the logfile. Typically you will have problems with the access +to the keys or certificates, so you will find error messages +here.

+ +

You can always try to send an email to +postfix_tls-bounce@serv01.aet.tu-cottbus.de with TLS enabled +at your side and watch, what is going to happen :-)

+ +

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.

+ +

Platforms

+ +
    +
  • Development Platform: + +
      +
    • OS: HP-UX 10.20
    • + +
    • OS: Linux 2.x (SuSE Linux)
    • +
    +
  • + +
  • Test Client: + +
      +
    • Software: Netscape 4.5x, Netscape 4.6x, Netscape 4.7x
    • + +
    • OS: HP-UX 10.20, Linux 2.x, Win95
    • +
    +
  • +
+ +Please don't comment on the stability of Netscape, especially not +on HP-UX... + +

Interoperability

+ +Besides support by generic wrapper solutions, there exist specially +crafted extensions for other MTAs: + +
    +
  • Qmail There is an OpenSource patch available, +extending the Qmail [QMAIL] MTA +to support RFC2487, written by Frederik Vermeulen [QMAILTLS]. Sending and receiving is +working from both sides. + +

    Testing: send mail to ping@linux.student.kuleuven.ac.be +(will send back complete email including headers).

    +
  • + +
  • Zmailer The author/maintainer of ZMailer, +Matti Aarnio, has incorporated both server and client side TLS +support [ZMAILER]. + +

    Zmailer -> Postfix works fine,
    +Postfix -> Zmailer does not work, since ESMTP is not recognized +(problem reported).

    + +

    Testing: send mail to autoanswer@mea.tmt.tele.fi (will +send back headers).

    +
  • + +
  • Sendmail 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 [SENDMAIL]. + +

    Testing: send mail to bounce@esmtp.org (will bounce +error message including old headers).

    +
  • + +
  • Postfix Can send emails to itself :-). + +

    Testing: send mail to +postfix_tls-bounce@serv01.aet.tu-cottbus.de (will bounce back, +includes old headers).

    +
  • +
+ +Other reports are welcome. + +

Known interoperability problems

+ +
    +
  • Postfix/TLS server: 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.
    +Remark: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...
    +Workarounds: kill this connection, the next one will work +immediately or use SSLv2 only (second workaround +not recommended). + +

    Should finally be fixed with OpenSSL 0.9.5.

    +
  • + +
  • Postfix/TLS server: 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. [Microsoft +Knowledgebase]
  • + +
  • Postfix/TLS server: Outlook Express as of Internet Explorer 4 does not +support RFC2487. Use smtpd_tls_wrappermode=yes on a different +port(!) (465=smpts?) instead.
  • + +
  • Postfix/TLS server: Outlook Express (Mac) seems not to support +RFC2487, you must use smtpd_tls_wrappermode on a different port(!) +(465=smtps?) instead.
  • + +
  • Postfix/TLS client: MS Exchange also in recent versions (5.5) offers +STARTTLS even if not configured (from the mailing list [IETF-APPS-TLS]). I could not +test this without access to such server, so I cannot predict what +is going to happen.
  • + +
  • Postfix/TLS client: 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.
    +This problem has been fixed in CommunigatePro 3.3b?? (don't know +the exact numbering) around June 09, 2000.
  • +
+ + + diff -Pur postfix-2.1.5/pfixtls/doc_french/conf.html postfix-2.1.5-ti1.25/pfixtls/doc_french/conf.html --- postfix-2.1.5/pfixtls/doc_french/conf.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/conf.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,600 @@ + + +Untitled Document + + + + +

Postfix/TLS - Configurer main.cf et master.cf

+

Afin d'utiliser les extensions TLS vous devez renseigner quelques informations + a Postfix. Regardez également le fichier conf/sample-tls.cf

+

main.cf: smtpd (serveur) variables spécifiques
+ # pour utiliser TLS nous avons besoin d'un certificat et d'une clef privée. Tous + les deux doivent ętre
+ # au format "PEM ",la clé privée ne doit pas ętre chiffrée, ce qui signifie: +
+ # elle doit ętre accessible sans mot de passe. Les deux pičces (certificat et
+ # clé privée) peuvent ętre dans le męme fichier
+ #
+ # RSA et DSA sont des formats de certificats supportées
+ # Typiquement vous pouvez seulement vous faire délivrer des certificats de RSA + par un CA commercial
+ # Les outils OpenSSL vont, par defaut, générer des certificats + RSA
+ # Vous pouvez avoir les deux en męme temps, dans ce cas-ci le chiffrage du client + utilisé décide
+ # Pour les clients Netscape et OpenSSL le certificat + de RSA est préféré.
+ #
+ # Afin de contrôler les certificats, le certificat CA (dans le cas d'une chaine + de certificats, tous les certificats CA) doit être disponible
+ # Vous devez ajouter ces certificats aux certificat du serveur, ce dernier en + premier puis ceux émis par par le(s) CA(s)
+ #
+ # exemple: le certificat pour "serveur.chez.moi" a été + émis par "Intermediate CA"
+ # qui lui même a un certificat de "root CA". Creez le fichier + server.pem en faisant 'cat server_cert.pem intermediate.pem > server.pem'
+ #
+ # Si vous voulez accepter des certificats délivrés par ces derniers en tant + que vous-męme, vous pouvez aussi ajouter les certificats CA
+ # au fichier smtpd_tls_CAfile, dans ce cas ce n'et pas nécessaire de les + avoir dans le fichier smtpd_tls_[d]cert_file
+ #
+ # Un certificat fourni ici doit être utilisable comme SSL certificat serveur + et par conséquent passer le test
+ # "openssl verify -purpose sslserver ..."
+ #
+ smtpd_tls_cert_file = /etc/postfix/server.pem
+ smtpd_tls_key_file = $smtpd_tls_cert_file
+ #
+ # Les équivalents DSA
+ smtpd_tls_dcert_file = /etc/postfix/server-dsa.pem
+ smtpd_tls_dkey_file = $smtpd_tls_dcert_file
+ #
+ # le certificat a été délivré par une autorité de certification (CA) le certificat + CA de celui-ci doit être disponible
+ # si il n'est pas dans le fichier de certificats.
+ # Ce fichier peut également contenir les les certificats de CA d'autres CA de + confiance.
+ # Vous devez utiliser ce fichier pour la liste de CA de confiance si vous voulez + utiliser le mode chroot.
+ # Il n'y a pas de valeurs par defaut
+ #
+ # smtpd_tls_CAfile = /etc/postfix/CAcert.pem
+
+ # pour vérifier le certificat de pair, nous devons connaître les certificats des + autorités de certification. Ces certificats sont au format PEM
+ # et sont rassemblés dans un répertoire. Les mêmes CA sont offerts aux + clients pour la vérification. N'oubliez pas de créer
+ # les tables de hachages nécessaires avec $OPENSSL_HOME/bin/c_rehash + /etc/postfix/certs. Une place classique
+ # pour les certificats CA peut être aussi $OPENSSL_HOME/certs, il n'y + a donc aucune valeur par défaut et vous avez à
+ # le spécifier ici
+ #
+ # Pour utiliser cette option en mode chrooté, ce répertoire ou + une copie de celui-ci doit être dans la 'cage'. Veuillez noter également
+ # que les CA listés dans ce répertoire ne sont pas listés + aux clients, Netscape ne peut donc pas offrir de certificats émis par + ceux ci.
+ #
+ # Je n'encourage pas à l'utilisation de cette option
+
+ smtpd_tls_CApath = /etc/postfix/certs
+
+ # Pour obtenir des informations supplémentaires pendant la mise en place + et les négociations TLS
+ # vous pouvez augmenter le niveau de journalisation de 0 à 4:
+ # 0 : rien a propos du TLS
+ # 1 : Notification de mise en route et information de certificat
+ # 2 : 1 + impression des niveaux pendant la négociation
+ # 3 : 2 + hexa et vidage mémoire Ascii du processus de négociation
+ # 4 : 4: 3 + hexa et vidage mémoire Ascii de transmission complčte aprčs STARTTLS +
+ # utilisez le niveau 3 uniquement en cas de problémes. L'utilisation + du niveau 4 est fortement déconseillée.
+ #
+ # smtpd_tls_loglevel = 0
+ # Afin d'inclure des informations sur le protocole et le cryptage utilisé + aussi bien que le client et l'émetteur
+ # dans l'entête "Received:", positionnez la variable smtpd_tls_received_header + à true. Par défaut elle est a no,
+ # du fait que cette information n'est pas forcément authentique. Seulement + la destination finale est fiable,
+ # puisque les en-tętes pourraient avoir été modifiées entre temps.
+ #
+ # smtpd_tls_received_header = yes
+
+ # Vous pouvez IMPOSER l'utilisation de TLS, de sorte qu'on ne permette aucune + commande (excepté QUIT naturellement)
+ # sans TLS. Selon la RFC2487 ceci NE DOIT PAS ętre appliquée dans le cas d'un + serveur SMTP public. Cette option est
+ # donc inactive par defaut et ne doit être utilisée que rarement. + Cette fonction implique
+ # smtpd_use_tls = yes
+ #
+ #smtpd_enforce_tls = no
+ #
+ # Sans compter que quelques clients, comme outlook express prefère utiliser + un mode d'emballage non-standard et non les
+ # améliorations STARTTLS de SMTP.
+ # Ceci est vrai pour outlook express ( Win32 < 5.0 et Win 32 >= 5.0 quand + on l'utilise sur un port differents de 25
+ # et sur 5.01 pour Mac sur tous les ports
+ # Il est strictement découragé d'utiliser utiliser ce mode depuis main.cf. Si + vous voulez
+ # supporter ce service, rajoutez un port spécial dans master.cf. Le port 465 + (smtps) a été choisi pour ce dispositif.
+ # smtpd_tls_wrappermode = no
+
+ # Pour recevoir un certificat de client, le serveur doit explicitement en demander + un. Par conséquent Netscape se plaindra
+ # si aucun certificat n'est disponible (pour la liste des CA dans /etc/postfix/certs) + ou vous offrira des certificats clients
+ # pour choisir. Ceci peut ętre ennuyeux, ainsi cette option est "Off" par défaut + .
+ # Vous aurez peut être besoin du certificat si vous voulez faire du relayage + à partir des certificats
+ #
+ # smtpd_tls_ask_ccert = no
+
+ # Vous pouvez également décider D'EXIGER d'un certificat de client afin de permettre + des connexions de TLS.
+ # Je ne pense pas que ce sera nécessaire souvent, il est cependant inclus ici. + Cette option smtpd_tls_ask_ccert = yes
+ #
+ # Notez bien que ceci empęchera des connexions TLS sans un certificat approprié, + et n'a de sens que dans le cas
+ # de soumission normal desactivée (smtpd_enforce_tls). Autrement les + clients peuvent éviter ceci en n'utilisant pas du tout
+ # STARTTLS. Quand TLS n'est pas imposé, la connexion ne sera traitée comme + si smtpd_tls_ask_ccert = yes
+ # était activé et une information est journalisée.
+
+ # smtpd_tls_req_ccert = no
+
+ # la profondeur de vérification pour des certificats de client. Une profondeur + de 1 est suffisante si le certificat
+ # est émis directement par un CA listé dans la liste des CA.
+ # La valeur par defaut (5) suffit également pour de plus longues chaînes (le + root CA émet le CA spécial
+ # qui délivre alors le certificat réel...)
+
+ # smtpd_tls_ccert_verifydepth = 5
+
+ # le serveur et le client négocient une session, qui prend un certain temps + machine et une largeur de bande passante.
+ # La session est cachée seulement dans le processus de smtpd réellement en utilisant + cette session et est détruite
+ # quand le processus meurt pour partager l'information de session entre les + processus de smtpd,
+ # antémémoire de session peut ętre utilisée avec des bases de données + SDBM (sous-programmes inclus dans Postfix/TLS)
+ # Puisque l'écriture concourante doit ętre supportée seulement SDBM peut ętre + utilisé.
+
+ smtpd_tls_session_cache_database = sdbm:/etc/postfix/smtpd_scache
+
+ # les sessions cachées ont un delais d'attente. Je n'utilise pas le défaut d'OpenSSL + de 300sec, mais un plus long temps
+ # de 3600sec (= 1 heure). RFC2246 recommande un maximum de 24 heures
+
+ # smtpd_tls_session_cache_timeout = 3600s
+
+ # deux options supplémentaires a été ajoutées pour la commande de relais aux + rčgles d'UCE
+ # permit_tls_clientcerts (a)
+ # et
+ # permit_tls_all_clientcerts. (b)
+ #
+ # Si une de ces options est ajoutée
+ # smtpd_recipient_restrictions
+ # postfix va relayer si
+ # (a) Un client valide (vérification faite) est présenté + et que son empreinte est inscrite dans la liste des certificats clients
+ # (relay_clientcerts),
+ # (b) n'importe quel client valide (vérification faite) est présenté.
+ #
+ # L'option (b) doit seulement ętre utilisée, si un CA spécial délivre les certificats + et seulement ce CA
+ # est énuméré en tant que CA de confiance. Si on fait confiance à d'autres + CA tout propriétaire d'un certificat client valide
+ # peut être relayé. L'option (b) peut ętre pratique pour un relais + spécialement créé. Il est recommande cependant de rester +
+ # avec l'option (a) et d'énumérer tous les certificats, car (b) ne permet aucun + contrôle quand un certificat ne doit
+ # plus ętre utilisé (par exemple un employé partant).
+
+ # smtpd_recipient_restrictions = ... permit_tls_clientcerts ...
+
+ # La liste de certificats de client pour lesquels le relais sera permis.
+ # Malheureusement les sous-programmes pour des listes utilise des espaces comme + séparateurs
+ # et s'emmèle sur les caractères spéciaux
+ # Ainsi l'utilisation du certificat # du X509ONELINES est tout ŕ fait impraticable. + Nous utiliserons donc
+ # les empreintes digitales ŕ ce point, car il est difficile de les truquer mais + facile ŕ utiliser pour la consultation
+ # pendant que le postmap (en utilisant par exemple le DB) exige d'avoir une + paire de clé et de valeur,
+ # mais nous avons besoin seulement de la clef, la valeur pouvant ętre choisie + librement, par exemple le nom
+ # de l'utilisateur ou de l'hôte:
+ # 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
+
+ # Pour influencer la sélection du cryptage, vous pouvez donner une liste + de cryptage.
+ # Une description complète irait troin loin ici, allez voir la documentation + sur le site d'OpenSSL
+ # Si vous ne savez pas quoi faire avec, n'y touchez pas et laissez celui d'openssl + par defaut
+ # N'UTILISEZ PAS " pour entourer la chaîne de caractčres, juste la chaîne de + caractčres!!!
+ #
+ # smtpd_tls_cipherlist = default
+
+ # Si vous voulez tirer profit du chiffrage avec EDH, les paramčtres de DH sont + nécessaires.
+ # Ils sont construits dans les paramètres DH pour à la fois le + 1025éme et le 512éme bit disponible
+ # Il vaut mieux cependant avoir ses "propres" paramètres, puisqu'autrement + ce serait "payant" pour un
+ # 'pirates' d'attaquer en brute force ces paramètres qui sont utilisés + communément.
+ # Pour cette raison, les paramčtres choisis sont déjŕ différents de ceux distribués + avec le package TLS
+
+ # Pour produire de votre propre ensemble de paramčtres, faites :
+ # 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 +
+ # Votre source pour la génération aléatoire peut varier; + sur des ystèmes linux c'est /dev/random
+ # Pour d'autres systèmes vous pouvez consulter "Entropy Gathering Daemon + EGD",
+ # disponible sur 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
+
+ # le smtpd_starttls_timeout paramètre la limite de temps en secondes pour + lire et écrire
+ # les opérations pendant les procédures de 'serrages de mains' + (SSL handshake)
+ #
+ # smtpd_starttls_timeout = 300s
+
+ # Main.cf smtp (client) variables spécifiques
+ # Pendant la négociation de démarrage nous pourrions présenter un certificat + au serveur. Netscape
+ # est plutôt intelligent ici et laisse l'utilisateur choisi entre seulement + ceux qui corresipondront à ceux reçus du serveur
+ # Comme j'utilise simplement la commande "SSL_connect()" du package OpenSSL, + ceci n'est pas encore possible
+ # et nous ne devons choisir qu'un certificat.
+ # Le paramètre par defaut est de n'utiliser aucun certificat/clef a moins + de de le définir ici.
+ # Si un certificat est présent il doit être au format PEM, la clef + privée ne doit pas être encryptée : concrétement
+ # cela veut dire qu'elle doit être accessible sans mot de passe. LA clef + et le certificats peuvent être dans le même fichier.
+
+ # Afin de contrôler les certificats, le certificat CA doit être + disponible (dans le cas d'une chaine de certificats, tous les
+ # certificats CA).
+ # Exemple: le certificat pour "moi.chez.moi.fr" a été + émis par "intermedaire CA" qui lui-même
+ # a un certificat de "racine CA". Créez le client.pem par : +
+ # 'cat client_cert.pem intermediaire_CA.pem racine_CA.pem > client.pem'
+ #
+ # Si vous voulez accepter vous mêmes les certificats émis par ces + CA, vous pouvez également ajouter
+ # les certificats CA au fichier smtp_tls_CAfile, dans ce cas il n'est pas nécessaire + de les avoir
+ # dans le fichier smtp_tls_[d]cert_file
+
+ # Un certificat fourni ici doit ętre utilisable en tant que certificat de client + de SSL et passer le test
+ # "openssl verify -purpose sslclient ..."
+
+ smtp_tls_cert_file = /etc/postfix/client.pem
+ smtp_tls_key_file = $smtp_tls_cert_file
+
+ # Le certificat a été délivré par une autorité de certification (CA), son certificat + CA doit être disponible, si il n'est
+ # pas dans le fichier de certificat
+ # Ce fichier peut aussi contenir les certificats CA d'autres CA de confiance.
+ # Vous devez utiliser ce fichier pour lister les CA de confiance si voulez utiiser + le mode chroot
+ # Cette variable n'a aucune valeur fixče par défaut
+
+ smtp_tls_CAfile = /etc/postfix/CAcert.pem
+
+ # Pour vérifier le certificat de pair, nous devons connaître les certificats des + autorités de certification. Ces certificats
+ # au format PEM sont rassemblés en répertoire. N'oubliez pas de créer + les tables de hachage nécessaires avec
+ # un $OPENSSL_RACINE/bin/c_rehash /etc/postfix/certs, il n'y a pas de valeurs + par defaut et vous devez en
+ # renseigner une ici
+ # Pour utiliser cette option en mode chroot, ce repertoire ou une copie de celui-ci + doit être dans la cage
+
+ smtp_tls_CApath = /etc/postfix/certs
+
+ # Pour obtenir des informations suplémentaires pendant la mise en place + et les négociations TLS
+ # vous pouvez augmenter le niveau de journalisation de 0 à 4:
+ # 0 : rien a propos du TLS
+ # 1 : Notification de mise en route et information de certificat
+ # 2 : 1 + impression des niveaux pendant la négociation
+ # 3 : 2 + hexa et vidage mémoire Ascii du processus de négociation
+ # 4 : 4: 3 + hexa et vidage mémoire Ascii de transmission complčte aprčs STARTTLS +
+ # utilisez le niveau 3 uniquement en cas de problémes. L'utilisation + du niveau 4 est fortement déconseillée.
+
+ smtp_tls_loglevel = 0
+
+ # le serveur et le client négocient une session, qui prend un certain temps + machine machine et une certaine bande passante.
+ # La session est cachée seulement dans le processus de smtpd réellement en utilisant + cette session et est détruite
+ # quand le processus meurt pour partager l'information de session entre les + processus de smtpd,
+ # antémémoire de session peut ętre utilisée avec des bases de données + SDBM (sous-programmes inclus dans Postfix/TLS)
+ # Puisque l'écriture concourante doit ętre supportée, seulement SDBM peut ętre + utilisé.
+
+ smtp_tls_session_cache_database = sdbm:/etc/postfix/smtp_scache
+
+ # les sessions cachées ont un delais d'attente. Je n'utilise pas le défaut d'OpenSSL + de 300sec, mais un plus long temps
+ # de 3600sec (= 1 heure). RFC2246 recommande un maximum de 24 heures
+
+ # Par defaut TLS est désactivé, ainsi aucune différence au Postfix + ordinaire n'est visible. Si vous l'activez
+ # TLS sera utilisé quand le serveur l'offrira.
+ # ATTENTION : Je n'ai pas eu accčs ŕ d'autres logiciels (autres que ceux énumérés) + pour tester l'interaction.
+ # Sur certaines listes de diffusions il y a eu une discussion a propos des serveurs + MS EXCHANGE qui offre TLS
+ # même si il n'est pas configuré, ainsi il pourrait ętre sage de + ne pas utiliser ceci sur votre serveur central de messagerie
+ # car vous ne savez pas à l'avance si vous allez rencontrer ce genre + de serveur. Utilisez les options de recipient/site ŕ la place .
+ # Conseil: je l'ai activé sur mes serveurs de courrier et je n'a eu qu'une + panne depuis que la version client de TLS
+ # est implémentée (c'était un serveur EXCHANGE mal configuré, + j'ai contacté l'administrateur).
+ # Par conséquent j'en suis satisfait de l'utiliser tout le temps, mais + je suis toutefois intéressé par des tests.
+ # Cependant vous aurez été prévenu ;-)
+
+ # Dans le cas d'un echec, un code "4xx" (ndt: erreur temporaire) est + émis et le message reste dans la file d'attente
+ # Spécifiez le ici si vous le voulez
+
+ smtp_use_tls = yes
+
+ # Vous pouvez IMPOSER l'utilisation de TLS, de sorte que seulement des connexions + avec TLS soient acceptées
+ # De plus, le nom de l'hôte doit être identique au nom contenu dans + le certificat. En outre, le certtificat doit
+ # passer avec succès la vérification, le client doit faire confiance + à l'entité de certification qui a émis le certificat.
+ # Si le certificat ne correspond pas au nom de la machine ou si le test de vérification + échoue un code "4xx"
+ # va être envoyé et le message va rester en file d'attente.
+ # Le nom d'hôte utilisé est évident, en effet il doit être + le nom principal de la machine (pas de CNAME ici).
+ # Le comportement peut ętre changé avec l'option de smtp_tls_enforce_peername +
+
+ # smtp_tls_enforce_peername = yes
+
+ # Comme offrir TLS par défaut peut être une mauvaise idéee + (quelques machines offre STARTTLS mais
+ # la négociation va échouer avec des erreurs inexpliquables, il + peut être une bonne idée de décider selon
+ # le destinataire ou la machine distante sur laquelle vous vous connectez
+
+ # Décider par destinataire peut être difficile, car un seul message + peut avoir plusieurs destinataires.
+ # Nous allons utiliser le mécanisme "nexthop" (prochain saut) + interne de Postfix.
+ # Quand un message va être délivré, the "nexthop" + est obtenu. Si il correspond à une entrée
+ # dans la liste smtp_tls_per_site, une action appropriée est effectuée
+ # Une entrée dans la table de transport ou l'utilisation de relay_host + réecrivent le paramètre "nexthop"
+ # dans ce cas l'hôte de relayage doit être indiqué dans la + liste. Dans tous les cas le nom
+ # de l'hote à contacter est résolu (en fait l'enregistrement MX + ou le nom de la machine si il n'y a pas de MX)
+ # Conseil spécial pour le renforcement:
+ # puisqu'il n'y a aucun moyen disponible pour sécuriser les résolutions + DNS , le paramètrage recommandé est:
+ # mettez les domaines sensibles dans une table de transport (vous pouvez ainsi + vous assurer de la sécurité
+ # de cette table à la différence de DNS), puis paramétrez + à MUST cet hôte de messagerie.
+
+ # Format de la table:
+ # Le entrées clefs sont sur le coté gauche, les jokers ne sont + pas autorisés. Sur la partie droite
+ # les mots clefs NONE (n'utilise pas TLS), MAY (essaye d'utiliser TLS si il + est offert, sinon pas de problèmes)
+ # MUST (force l'usage de TLS, vérifie le nom du certificat server avec + le nom du serveur), MUST_NOPEERMATCH
+ # (force l'usage de TLS et vérifie le certificat, mais ignore les différences + entre le nom commun du certificat et le nom
+ # de la machine).
+ # dom.ain NONE
+ # host.dom.ain MAY
+ # important.host MUST
+ # some.host.dom.ain MUST_NOPEERMATCH

+

# Si une entrée ne correspond pas la politique par défaut est + appliquée; si la politique par défaut est "enforce",
+ # NONE la désactive explicitement, sinon le mode "enforce" + est utilisé même pour les entrées "MAY"
+ #
+ smtp_tls_per_site = hash:/etc/postfix/tls_per_site
+
+ # la profondeur de vérification pour des certificats de client. Une profondeur + de 1 est suffisante si le certificat
+ # est émis directement par un CA listé dans la liste des CA.
+ # La valeur par defaut (5) suffit également pour de plus longues chaînes (le + root CA émet le CA spécial
+ # qui délivre alors le certificat réel...)
+
+ # smtp_tls_scert_verifydepth = 5
+
+ # Comme nous avons décidé d'opter pour une politique "par site" + afin d'utiliser ou non TLS, il serait interessant
+ # d'avoir une liste de sites offrant STARTTLS. Nous pouvons la récupérer + nous mêmes avec cette option:
+ # Si ce paramètre est activé et que TLS n'est pas activé + pour cet hôte, une ligne est ajouté dans le fichier
+ # de journalisation:
+ # postfix/smtp[pid]: Host offered STARTTLS: [nom.de.la.machine]
+ # smtp_tls_note_starttls_offer = yes
+
+ # Pour influencer la sélection du cryptage, vous pouvez donner une liste + de cryptage.
+ # Une description complète irait troin loin ici, allez voir la documentation + sur le site d'OpenSSL
+ # Si vous ne savez pas quoi faire avec, n'y touchez pas et laissez celui d'openssl + par defaut
+ # N'UTILISEZ PAS " pour entourer la chaîne de caractčres, juste la chaîne de + caractčres!!!
+ #
+ # smtp_tls_cipherlist = DEFAULT
+
+ # le smtp_starttls_timeout paramètre limite le temps en secondes pour + lire et écrire
+ # les opérations pendant les procédures de 'serrages de mains' + (SSL handshake)
+ #
+ # smtp_starttls_timeout = 300s
+

+

main.cf : variables générales

+

# Afin d'alimenter le PRNG Pseude Random Number Generator (pseudo générateur + de nombres aléatoires),
+ # des données aléatoires sont nécéssaires. Le 'stock' + de PRNG est mis à jour par le démon "tlsmgr" et est + utilisé (lu)
+ # par les process smtp(d) aprčs avoir ajouté encore plus d'entropie par l'agitation + du temps et de l'identifiant du process.
+ # le fichier, qui est de temps en temps réécrit par tlsmgr, est + créé si il n'existe pas. Une valeur par défaut est donnée
+ # et doit sûrement être dans la partition /var mais PAS dans la + cage de chroot.
+
+ # tls_random_exchange_name = /etc/postfix/prng_exch
+
+ # Pour alimenter le stock PRNG, l'entropie est lue depuis une source externe, + à la fois au démarrage et pendant l'éxecution
+ # Spécifiez ici une bonne source, comme EGD ou /dev/urandom, soyez certains + de ne pas utiliser des sources bloquantes
+ # Dans les deux cas, 32 octets sont lus à chaque 'alimentation' (qui + est une quantité de 256 bits et par conséquent
+ # assez bon pour des clefs symétriques de 128bits)
+ # Vous devez spécifier la type de sources : "dev:" pour un + pour un fichier spécial de périphérique ou "egd:" pour
+ # une source avec un port de communication (socket) compatible avec l'interface + EGD. Un maximum de 255 octets
+ # est lu depuis ces sources à chaque étape.
+ # Si vous spécifiez un fichier normal, un plus grand nombre de données + peut être lu.
+
+ # La source d'entropie est interrogée de nouveau après un certains + temps. ce temps est calculé en utilisant le PRNG,
+ # il est compris entre 0 et le temps spécifié, un defaut est spécifié + à 1 heure
+
+ # tls_random_source = dev:/dev/urandom
+ tls_random_source = egd:/var/run/egd-pool
+ # tls_random_bytes = 32
+ # tls_random_reseed_period = 3600s
+
+ # Le stock PRNG dans tlsmgr est utilisé pour regénérer + le fichier de 1024 octets qui est lu par smtp(d). Le temps, après lequel
+ # le fichier d'échange se trouve regénéré est calculé + en utilisant le PRNG, il est compris entre 0 et le temps spécifié, +
+ # le defaut est un maximum de 60 secondes
+
+ # tls_random_upd_period = 60s
+
+ # Si vous avez une source d'entropie disponible, qui n'est pas facilement vidée + (comme /dev/urandom), les démons
+ # peuvent aussi charger une entropie supplémentaire au démarrage + depuis une source spécifiée. Par défaut une quantité
+ # de 32 octets est lue, équivalent ŕ 256 bits. Ceci est plus que suffisant pour + générer une clef de session de 128 (ou 168) bits
+ # mais nous avons à en générer plus d'une. L'utilisation + de cette option peut vider EGD (en prenant le cas de 50 smtp
+ # démarrant avec une file d'attente pleine en faisant "postfix start", + ceci devrait requérir 1600 octets d'entropie). Ceci
+ # n'est cependant pas une cause d'arrêt, du fait que les données + d'entropie peuvent être lues depuis le fichier d'échange.
+
+ # tls_daemon_random_source = dev:/dev/urandom
+ tls_daemon_random_source = egd:/var/run/egd-pool
+ # tls_daemon_random_bytes = 32

+

master.cf: le démon tlsmgr

+

Si vous n'avez pas de périphérique /dev/urandom ou si vous n'utilisez + pas le système de cache de session, vous devez lancer
+ le démon tlsmgr (voir conf/master.cf). Tlsmgr a besoin d'avoir accés + à la source d'entropie et ne peut (encore) être éxécuté +
+ dans une cage. Il peut restreindre ses privilčges, si les sources d'entropie + (par exemple /dev/urandom ou un port de communication
+ (socket) EGD) n'ont pas des restrictions d'accčs.
+
+ # ========================================================================== +
+ # service type private unpriv chroot wakeup maxproc command + args
+ # (yes) (yes) (yes) (never) (50)
+ # ========================================================================== +
+ tlsmgr fifo - - n 300 1 tlsmgr

+

master.cf: services supplémenentaires

+

Il peut être pratique d'avoir postfix écoutant sur des ports supplémentaires, + nommés "submission"=587 pour la
+ soumission d'email comme défini dans la RFC2476; c'est particuličrement utile + si vous voulez permettre une authentification
+ avec des mots de passes en clair (PLAIN,LOGIN) et par conséquent exécuter sur + un port avec l'application de
+ chiffrement. Un autre port utile peut ętre "smtps"=465 qui a été destiné pour + l'emballage TLS et qui est toujours
+ utlisé par outlook (express)
+
+ Les deux entrées d'exemple contiennent déjŕ les indicateurs pour permettre l'authentification + de SASL (qui peut ętre
+ desactivé sur le port normal). Puisque les noms réels de service sont + utilisés, les smtps et la soumission doivent ętre définis
+ dans /etc/services (et probablement aussi dans / var/spool/postfix/etc/services + si éxecuté dans une cage)!!!
+ (utilisez les numéros de ports autrement.)
+
+ # ========================================================================== +
+ # 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 +

+ + diff -Pur postfix-2.1.5/pfixtls/doc_french/index.html postfix-2.1.5-ti1.25/pfixtls/doc_french/index.html --- postfix-2.1.5/pfixtls/doc_french/index.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/index.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,35 @@ + + +Untitled Document + + + + +

Postfix/tls - Une extension TLS pour Postfix

+

Contenu :

+

Introduction

+

Installation de la mise ŕ jour

+

Configurer les certificats

+

Configurer main.cf

+

Considérations de sécurité

+

Tester

+

RAPPELEZ VOUS QU'IMPORTER/EXPORTER ET/OU L'USAGE DE LOGICIELS USANT
+ DE CHIFFREMENT FORT, FOURNIR DES POINTS D'ENTREE POUR DES FONCTIONS
+ CRYPTOGRAPHIQUES OU DIVULGUER DES TECHNIQUES DE CRYPTOGRAPHIE EST
+ ILLEGAL DANS CERTAINES PARTIES DU MONDE. DONC SI VOUS IMPORTEZ CE
+ PAQUET DANS VOTRE PAYS, LE REDISTRIBUEZ DEPUIS ICI OU MEME JUSTE
+ ENVOYER DES SUGGESTIONS TECHNIQUES PAR COURRIER ELECTRONIQUE OU
+ MEME DES CORRECTIONS DE SOURCES A L'AUTEUR OU D'AUTRES PERSONNES
+ VOUS ETES LARGEMENT INVITE A FAIRE ATTENTION A TOUTES LES LOIS
+ CONCERNANT L'IMPORT/EXPORT QUI S'APPLIQUENT DANS VOTRE PAYS.
+ L'AUTEUR DE POSTFIX/TLS NE PEUT PAS ETRE TENU POUR RESPONSABLE EN CAS
+ DE VIOLATION. DONC FAITES TRES ATTENTION, IL EN VA DE VOTRE RESPONSABILITE.

+

 

+

Lutz Jänicke, Homepage, + Email: Lutz.Jaenicke@aet.TU-Cottbus.DE +

+Merci a tous ceux qui m'ont aidé sur #linuxfr ;-) + + + + diff -Pur postfix-2.1.5/pfixtls/doc_french/install.html postfix-2.1.5-ti1.25/pfixtls/doc_french/install.html --- postfix-2.1.5/pfixtls/doc_french/install.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/install.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,57 @@ + + +Untitled Document + + + + +

postfix/TLS - Installation de la mise a jour

+

Prérequis:
+ Postfix Version 2.0.18-20040122
+ http://www.postfix.org

+

L'utilisation d'autres versions pourrait mener ŕ des conflits ou ŕ des pannes + silencieuses du fait que nous intervenons directement sur le code source.
+ OpenSSL Version 0.9.5 ou plus (0.9.7c recommandée)
+ http://www.openssl.org

+

Nous utilisons OpenSSL comme bibliothčque (et quelques outils en ligne de commande + pour créer les certificats, au besoin). OpenSSL est le successeur de SSLeay. +

+

Postfix/TLS utilise les propriétés qui sont seulement disponibles à + partir de la version 0.9.5 des bibliothčque OpenSSL. 0.9.5a a prouvé une stabilité + au delà de plusieurs mois. La derničre version 0.9.7c contient plusieurs + améliorations et a prouvé sa stabilité jusqu'ici.
+ Vous pouvez également avoir ŕ mettre ŕ jour votre utilitaire 'patch'(voir ci-dessous). +

+

Mettre ŕ jour:

+

Les modifications du code source de Postfix tout comme les fichiers supplementaires + sont inclus dans le fichier "pfixtls.diff" dans le répertoire + principal du kit de mise ŕ jour.
+ Pour appliquer la mise ŕ jour, allez dans le répertoire parent de l'arborescence + des sources originales de Postfix (vous devez voir "postfix-xxxxxx" + ou "snapshot-xxxxxx" quand vous faites un "ls -al" depuis + ce repertoire. La mise ŕ jour est alors appliquee par:

+

patch -p0 < chemin-de/pfixtls.diff

+

Si vous avez des problčmes pendant le processus de mise ŕ jour (par exemple avec les + includes de HP-UX 10.20), vous devriez mettre ŕ jour votre utilitaire de patch, + par exemple un GNU-patch plus récent.
+ Si vous avez besoin d'appliquer la mise ŕ jour sur une autre version de postfix, vous + pouvez essayer:
+ cd repertoire-postfix; patch -p1 < chemin-de/pfixtls.diff
+ Puisque la mise ŕ jour est sous forme unifiée, elle peut être également + appliqué à un code source modérément modifié + sans que des conflits apparaissent.

+

Compiler

+

Apres être mis ŕ jour; postfix va se configurer et se compiler comme + avant. Dans le but d'activer les fonctions TLS, vous devez spécifier + le chemin des headers OpenSSL ainsi que les bibliothéques appropriées, + et vous devez définir USE_SSL. Votre commande pour la configuration doit + être :
+ make makefiles CCARGS="-DUSE_SSL -I/usr/local/ssl/include" AUXLIBS="-L/usr/local/ssl/lib + -lssl -lcrypto"
+ Vous pourriez avoir besoin de personnalisation supplémentaire par exemple pour + l'usage des Berkeley-DB comme énuméré dans les instructions INSTALL de postfix + . Vous pouvez alors continuer de la manière habituelle avec:
+ make

+

et ensuite suivre les instructions du fichier INSTALL de postfix

+ + diff -Pur postfix-2.1.5/pfixtls/doc_french/intro.html postfix-2.1.5-ti1.25/pfixtls/doc_french/intro.html --- postfix-2.1.5/pfixtls/doc_french/intro.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/intro.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,116 @@ + + +Untitled Document + + + + +

Postfix/TLS - Introduction

+

Postfix/PLS est une extension du MTA Postfix dans le but de supporter le protocole + TLS

+

Une note à propos du démarrage du projet

+

Quand j'ai commencé a écrire ce programme, j'avais en tête un un moyen sophistiqué + pour autoriser le relayage de mes utilisateurs itinérants. En + attendant ce projet vit de lui-même.

+

RFC2246 : le protocol TLS (anciennement SSL)

+

Par défaut toutes les communications sur internet sont faites sans cryptage + et sans authentification forte. Cela signifie que toute personne avec un accès + physique au chemin de communication qu'emprunte un paquet peut écouter vos communications. + Pire, il est même possible de rediriger ou de modifier vos communications donc + l'information que vous voulez envoyer à quelqu'un peut être perdue ou modifiée + à votre insu.

+

Dans le but de résoudre ces problèmes de sécurité, le protocole SSL (Secure + Socket Layers), présenté par Netscape inc., + a maintenant évolué en protocole TLS (Transportation Layer Security) + standardisé par la RFC2246. + Cela permet à la fois le cryptage de la communication (arrêt des + écoutes) et l'authentification forte (être sûr que les deux parties de + la communication sont correctement identifiées et que la communication + ne peut pas être altérée)

+

Postfix/TLS ne réalise pas le protocole TLS lui-même, il utilise + plutôt le package OpenSSL pour cette tâche. Sur le site d'OpenSSL, vous + trouverez aussi des liens vers une documentation plus approfondie sur le + protocole et ses dispositifs, il n'est donc pas nécessaire de les inclure + ici. (Et, bien sûr il n'y a aucune utilité de réécrire ce + que d'autres ont déjŕ ecrits, cela présente juste l'intérêt + de rajouter des erreurs)

+

 

+

RFC2487: Présentation de TLS a SMTP

+

L'intégration du protocole TLS au protocole SMTP (Simple Mail Transport Protocol) + est décrit dans la RFC2487

+

Ŕ la différence des premières incarnations du SSL comme 'emballage' + d'une communication normale [STUNNEL] [JONAMA], le protocole TLS est maintenant + complétement intégré dans SMTP : pendant la négociation + de départ (EHLO) le serveur offre le support de TLS avec la commande + STARTTLS. Le client peut maintenant envoyer la commande STARTTLS pour permettre + l'authentification et passer en mode crypté.

+

Postfix/TLS : Ce qu'il peut faire pour vous

+

La liste de fonctions présentée ici doit être comprise + comme une liste d'idées. Toutes ne sont pas encore réalisées, + regardez bien les notes pour chaque fonction.

+

Encryption de message d'une machine à une autre:
+ Etat: Fait
+ Commentaire: une fois que la negociation STARTTLS est réalisée, + la communication entre les deux machines est cryptée. Ceci inclue aussi + les enveloppes MAIL FROM: et RCPT TO:, les 'sniffeurs' ne seront pas capables + d'avoir ces informations.

+

Authentification de l'hôte récepteur afin d'éviter une interception
+ Etat: Fait
+ Commentaire: Ceci est une fonction importante qui n'est pas difficile a implementer. + Le problème est en fait que toutes les machines (en fait presque aucune) ne + supportent pas ce protocole. L'expéditeur doit par conséquent mettre ŕ jour une liste + de récepteurs qui doivent s'identifier par TLS, sinon quelqu'un peut intercepter + la session et ne pas prèsenter la commande STARTTLS, dans ce cas, aucune authentification + n'est faite. On doit également faire attention à utiliser le nom correct du + serveur (voir le CNAME), mais ce problème est le męme pour des serveurs HTTP.

+

Authentification de l'hote émetteur afin d'éviter la contrefaçon
+ Etat: Fait
+ Commentaire: Ceci est l'idée à l'origine de ce projet, ce fut + donc la première réalisation. Basé sur le certificat du + client MTA (ou MUA) présenté au serveur, le relayage peut être + ainsi autorisé.

+

D'autres idées:
+ Etat: envoyez moi un message

+

Postfix/TLS: ce qu'il ne peut pas faire pour vous

+

Voici un point sur lequel je veux insister:

+

Garantir l'intimité de votre correspondance
+ Etat: ne peut pas etre fait
+ Commentaire: La RFC2487 ne prend en compte uniquement le transport entre deux + serveurs de courrier. Pour vous assurer que personne ne peut 'sniffer' votre + correspondance il faudrait que:
+ - Tous les serveurs de courrier soient forcés en TLS
+ - Tous les serveurs eux-mêmes soient dignes de confiance, car l'email est seulement + chiffré pendant le transport, pas en spool ni en queue.
+ - La destination soit digne de confiance, car le courrier est spoolé en + clair et toute personne pouvant accéder à votre boite aux lettres (root par exemple) + peut lire votre courrier!
+ Par conséquent, si vous voulez une intimité plus conséquente, vous devez + envoyer votre email chiffré, par exemple en utilisant S/MIME ou le module traditionnel + de PGP

+

Authentifier l'émetteur du message
+ Etat: ne peut être fait
+ Commentaire: Beaucoup de MUA envoient les messages juste en se connectant sur + le port SMTP de l'hôte local ou du mailhub le plus proche. il n'y a aucun moyen + de s'assurer que l'émetteur listé dans le message est bien l'émetteur + réel. Et même si il était possible d'identifier l'émetteur, + le contenu du message pourrait avoir été modifié entre + temps.
+ Pour assurer l'identité de l'expéditeur et l'intégrité de l'email, vous pouvez + encore employer S/MIME ou PGP.

+

D'autres packages Opensource:
+ Depuis la version 8.11 sendmail intègre le support de la RFC2487.
+ Frederik Vermeulen a réalisé une extension de la RFC2487 pour + le MTA Qmail.
+ Matti Aarnio a intégré la RFC2487 dans ZMailer.
+ Michal Trojnara est actuellement en train d'intégrer un système basique + d'authentification SMTP dans son logiciel stunnel depuis la version stunnel-3.3.
+ Trey Childs travaille sur une solution d'emballage.

+

Implémentations commerciales:

+

La version commerciale de sendmail supporte la RFC2487.
+ Netscape Enterprise Server et Microsoft exchange server supportent aussi la + RFC 2487.
+ CommunigatePro mailserver software supporte aussi la RFC2487.

+

 

+

 

+ + diff -Pur postfix-2.1.5/pfixtls/doc_french/security.html postfix-2.1.5-ti1.25/pfixtls/doc_french/security.html --- postfix-2.1.5/pfixtls/doc_french/security.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/security.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,67 @@ + + +Untitled Document + + + + +

Postfix/TLS - Considérations de Sécurité

+

Les sections suivantes couvrent quelques considérations de sécurités + (possibles) en ce qui concerne Postfix/TLS.

+

Clef privée du client/serveur
+ Postfix/TLS utilise l'authentification du côté serveur (obligatoire) et du côté + client (facultatif). Afin de s'authentifier,
+ le processus défini (smptd/smtp) doit pouvoir accéder ŕ la clef privée, + qui doit cependant ętre maintenue secrčte.
+ Car ces processus sont lancés ŕ partir de 'master' sans possibilité d'interaction + d'utilisateur, il n'est pas possible
+ de fournir un mot de passe, de sorte que la clef privée ne puisse pas ętre chiffrée. +

+

La seule protection peut donc venu des droits d'accčs de systéme de + fichiers, qui devraient ętre placés
+ ŕ 'root' et ' lisible pour le propriétaire seulement
+ -rw------- 1 root sys 887 Apr 29 1999 /etc/postfix/key.pem
+
+ Cette protection n'est valable que si votre système est protégé + contre les failles de sécurités concernant root
+
+ Vous devez aussi vous rendre compte que des personnes ayant un accés physique + à la machine peuvent voler
+ la clef privée si ils peuvent démarrer la machine en mode 'superutilisateur' + (single-user) sans mot de passe
+ ou peuvent voler le disque et le monter sur un autre système où + ils sont super-utilisateur. (Oui je sais qu'il existe
+ des systémes de fichiers encryptés mais ils n'ont pas encore une + large diffusion)

+

Antémemoire de session sur le disque

+

Si vous utilisez l'antémemoire de session sur le disque (par défaut) + des personnes capables mettre la main sur les fichiers
+ devraient pouvoir éviter les paramètres de transmission sécurisée. + Cette situation n'est cependant pas plus grave que le cas
+ de la clef privée décrit ci-dessus, ainsi je ne considčre aucun + danger supplémentaire venant de l'enregistrement information
+ de session sur un peripherique de stockage
+
+ Casser le cryptage avec un système de clefs n'est qu'une affaire de temps + (même si ce temps peut être très long), les sessions
+ ne devraient pas être utilisées indéfiniment. La valeur par défaut + pour Postfix/TLS est 1 heure, la RFC 2246 recommande
+ de ne pas utiliser les sessions plus de 24 heures

+

Solutions pour le DNS
+ Un point faible dans l'authentification est l'utilisation du DNS pour découvrir + le MX. Comme nous faisons du (E)SMTP
+ nous avons à utiliser les enregistrements MX.
+ Comme nous avons à authentifier le server découvert par le MX, + quelqu'un est capable d'usurper un faux enregistrement MX
+ pour être capable de recevoir le mail, si son serveur peut présenter un + certificat délivré par un CA acceptable. La dernière
+ partie n'est pas difficile si les certificat 'standarts' sont inclus (Verisign, + Thawte,...)
+ Le seul moyen de se protéger contre ce problème est que, pour + les destinataires pour lesquels nous voulons imposer le
+ chiffrement et l'authentification, la consultation de MX doit ętre ignorée avec + une entrée appropriée dans la table /etc/postfix/transport
+
+ domaine.tres.important smtp:[server.du.domaine.important]

+ + diff -Pur postfix-2.1.5/pfixtls/doc_french/setup.html postfix-2.1.5-ti1.25/pfixtls/doc_french/setup.html --- postfix-2.1.5/pfixtls/doc_french/setup.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/setup.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,162 @@ + + +Untitled Document + + + + +

Postfix/TLS - Paramétrer les certificats

+

Ce paragraphe explique quels types de certificats sont nécessaires pour utiliser + postfix avec TLS. Les certificats (et peut être les clefs) peuvent être + obtenus auprčs de tierces parties, qui peuvent être une autorité + de certification commerciale ou votre FAI. Tout le long vous aurez besoin de + certificats acceptés par d'autres entités sur internet, vous avez + donc à être d'accord sur les entités de certifications, + quelque soit leurs types.

+

certificat serveur

+

Pour utiliser SMTP avec TLS en mode serveur, votre serveur DOIT avoir une paire + de clefs (privée et publique).
+ Puisque la clé publique doit ętre distribuée de façon ou d'autre au client, + elle est envoyée du serveur au client pendant la négociation de départ. + Cependant,au début de la négociation, le client ne peut pas savoir que + la clef publique appartient réellement au serveur et n'est pas contrefaite. + Par conséquent un troisičme composant est nécessaire : le certificat d'une autorité + de certification (CA), qui est envoyé combiné avec la clef publique. Ce certificat + de serveur contient le nom de votre hote. Le client contrôlera alors la signature + du CA sur la clef publique pour décider si le certificat (et la clef publique) + sont authentiques.
+ Ainsi pour le serveur nous avons besoin:
+ - 1 clef privée de serveur
+ - 1 clef publique de serveur signée par une autorité de certification, + certifiant que la clef publique appartient ŕ votre hôte +
+ - 1 certificat CA avec la clef publique du CA
+ Pour cette liste je veux absolument préciser que le nombre de composants utilisés + est 1, parce que vous devez en avoir 1, vous ne pouvez pas en avoir ni moins + ni plus!

+

Politique de certificat serveur

+

A partir de maintenant vous avez à vous décider sur la politique. + Le client qui va se connecter sur votre hôte va comparer le nom dans le + certificat de votre serveur ŕ son FQDN (Fully Qualified Domain Name). Si ils + correspondent, l'identité de votre serveur est prouvée.
+ Pour voir, si le certificat lui-męme est authentique, le client lui-męme doit + avoir le certificat du CA. Ainsi, si vous voulez le rendre facilement accessible + ŕ d'autres, parties inconnues, vous devez avoir un certificat issu d'un CA connu + et digne de confiance. Rappelez vous que votre serveur ne peut avoir qu'un certificat + à la fois.
+ Il y a des fournisseurs commerciaux (Thawte, Verisign, pour n'en citer que quelques + uns), leurs certificats CA sont bien distribués. Je ne sais pas pour + les autres pays mais en Allemagne le organisation de la recherche reseaux (DFN) a commencé + un programme pour les universités.
+ Si vous ne portez pas d'importance ŕ ceci (vous pourrez le changer plus + tard), vous pouvez devenir votre propre CA et distribuer vos certificat de CA + aux parties qui devront le connaitre, et vous êtes prêts. Ce n'est + pas difficile de le faire.
+ Le + cours tres bref de Lutz pour être votre propre CA (toujours en anglais ..)

+

Utiliser les certificats

+

Pour rendre la clef et les certificats utilisables par Postfix/TLS, ils doivent + être au format "PEM". Puis vous avez à indiquer à + postfix où les trouver:
+ - La clef privée:
+
+ smtpd_tls_key_file = /etc/postfix/key.pem
+
+ comme la clef publique est publique y compris le certificat (tout le monde peut + la récupérer), une personne disposant d'une copie de votre clef + privée peut usurper votre identitée. Ce n'est pas si facile que + ça, du fait qu'il doit être capable d'intercepter ou de rediriger + les paquets envoyés vers votre serveur, mais j'ai déja vu bien + de choses arriver. Donc protégez cette clef avec :
+
+ chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
+
+ Une autre possibilité de protection est la 'phrase clef'. Ceci est toutefois + un problème, du fait que vous ayez à le taper ŕ chaque fois que + le server est démarré. Ceci a des inconvenients : premièrement + vous devez le taper dans postfix à chaque fois que vous le redémarrez. + Deuxièmement les process smtpd sont lancés indépendamment + à partir de master, dans ce cas master doit passer la 'phrase clef' aux + clients d'une façon ou d'une autre. Tout cela fait que je pense que cette + méthode n'est pas pratique et donc n'est pas supportée par le programme.
+
+ - Le certificat serveur : ce certificat n'est pas secret, du fait qu'il est + présenté à chaque client de toutes façons, ainsi + nommez le juste a postfix :
+
+ smtpd_tls_cert_file = /etc/postfix/cert.pem
+
+ Si vous voulez vous pouvez concaténer la clef privée et le certificat + dans le même fichier.
+
+ - Le certificat CA: pour avoir également le certificat CA disponible, +écrivez le dans un fichier et donnez le nom ŕ postfix/TLS. Nous reviendrons + plus tard sur ce fichier.
+
+ smtpd_tls_CAfile = /etc/postfix/CAcert.pem
+
+ Avec ces certificats vous devez être en mesure de faire tourner Postfix/TLS.

+

Postfix/TLS en mode client
+
+ Quand il se connecte à un serveur offrant TLS postfix peut présenter + un certificat client de lui même. Du fait de la réalisation actuelle, + seulement un certificat ne peut ętre contrôlé, ainsi il devrait ętre émis depuis + votre propre nom d'hôte. Par défaut aucun certificat n'est présenté, + ŕ moins que vous placiez explicitement le certificat dans la configuration. + Vous pouvez utiliser le męme certificat que pour le serveur:
+
+ smtp_tls_key_file = /etc/postfix/key.pem
+ chown root /etc/postfix/key.pem ; chmod 400 /etc/postfix/key.pem
+
+ smtp_tls_cert_file = /etc/postfix/cert.pem
+ smtp_tls_CAfile = /etc/postfix/CAcert.pem
+

+

Certificats clients:
+
+ Une des raisons pour laquelle j'ai fait ce travail est que je voulais faire + du relayage basé sur les certificats clients. Le client présente + un certificat d'un CA, qui est unique et ne peut être usurpé.
+ Des clients peuvent avoir plusieus certificats émis par diffčrents CA. + Lors de la connexion le serveur passera au client la liste de CA qu'il connait + (les certificats de CA) et le client peut alors choisir le certificat à + passer. Avec Netscape cela signifie qu'une fenêtre est ouverte et seulement + le certificat client est listé.
+ Donc si vos clients ont déjà des certificats émanant de + sources de confiances ce n'est pas nécessaire de se créer des + problémes. Vous avez juste à récupérer les certificats + CA et les rendre disponibles à Postfix/TLS. Si ce n'est pas suffisant, + vous pouvez toujours devenir votre propre CA pour créer facilement vos + certificats clients pour vos usagers (qui sont naturellement inutiles en dehors + de votre portée)

+

Lister les certificats CA
+
+ Vous avez deux possibilité de faire ceci:
+ 1- Concaténez les certificats CA au fichier smtp[d]_tls_CAfile que vous + avez créé. Ce fichier n'est certainement pas très lisible + mais a l'avantage d'être lu par smtpd avant le changement dans la cage + chroot et par conséquent fonctionne en mode chrooté.
+ 2- Vous pouvez ajouter les certificats CA dans plusieurs fichiers avec des noms + adéquats dans un répertoire de certificats spécifié + par:
+ smtpd_tls_CApath = /etc/postfix/certs
+ N'oubliez pas de faire un $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs après + tout changement, car les tables de hachages sont utilisées pour trouver + le bon certificat CA. Cette methode ne doit pas fonctionner en mode chrooté.

+

Ajouter des certificats client:
+
+ Les certificats de client sont délivrés pour un DN (Distinguished Name) (Nom + Complet) composé de la compagnie, service, le nom, l'email... Du fait qu'ils + peuvent contenir des blancs, des @, des signes et des colonnes, il est tout ŕ fait + difficile de les manipuler avec les outils standards de postfix.
+ Une chose tout ŕ fait pratique est que chaque certificat de client a une " empreinte + digitale " il est extręmement difficile truquer que (à ma connaissance, + elle pourrait prendre des années męme sur les ordinateurs rapides). Je dois + faire encore plus de recherche au sujet de la sécurité de l'empreinte digitale, + mais au moins pour relayer cela doit être suffisament sécurisé. + Je trouverai plus facilement une machine avec une mauvaise sécurité + pour envoyer mon spam au lieu de truquer un certificat de client avec une empreinte + digitale assortie (que d'ailleurs je ne connais pas depuis l'extérieur, + même depuis l'interieur vous pouvez protéger la base "d'empreintes + digitales" par un chmod 400)

+ + diff -Pur postfix-2.1.5/pfixtls/doc_french/test.html postfix-2.1.5-ti1.25/pfixtls/doc_french/test.html --- postfix-2.1.5/pfixtls/doc_french/test.html Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/pfixtls/doc_french/test.html Mon Sep 20 15:01:55 2004 @@ -0,0 +1,118 @@ + + +Untitled Document + + + + +

tester Postfix/TLS

+

Le test du module est un peu difficile, car la transmission est chiffrée, de + sorte que vous ne puissiez pas "imiter" la
+ conversation juste par un telnet sur le port smtp. Vous ne pouvez pas également + capturer les paquets (vous pouvez,
+ mais si tout fonctionne comme annoncé, cela ne vous aidera pas :-).
+
+ Outils de mise au point inclus:
+ Comme tous les messages générés par postfix sont envoyés + au système de journalisation, la mise au point doit être faite
+ en utilisant vos fichier de journalisation. Postfix/TLS supporte les niveaux + de journalisation de 0 (très calme) à 4 (vidange
+ mémoire de la conversation complčte, non recommandé). Dans un premier temps + placez smpt[d]_tls_loglevel=2 et
+ observez le fichier journal. Typiquement vous aurez des problčmes avec l'accčs + aux clés ou aux certificats, ainsi vous
+ trouverez des messages d'erreur ici. Vous pouvez toujours essayer d'envoyer + un email ŕ postfix_tls-bounce@serv01.aet.tu-cottbus.de
+ avec le TLS activé de votre côté et regardez ce qui se produit + :-).
+ Tout en testant l'interopérabilité avec ZMailer nous avons appris qu'un certificat + incorrect (qui doit ętre le serveur pour le serveur :-) peut
+ mener à des erreurs de connexions sans messages clairs. cela peut nous + aider d'utiliser Netscape 4.5x en tant que client et d'étudier
+ soigneusement les informations ainsi que les boites de dialogue.
+ Je n'ai pas encore trouvé comment identifier le problème de postfix + à afficher un message approprié dans le fichier de journalisation.
+ Si tout va bien ce sera possible sans modifier les bibliothèques d'OpenSSL.

+

Plateformes:

+

Plateformes de développement:
+ OS: HP-UX 10.20
+ OS: Linux 2.x (SuSE Linux)
+
+ Succés enregistrés:
+ OS: Solaris 2.5 - Walcir Fontanini

+

Clients de test:
+ Software: Netscape 4.5x, Netscape 4.6x, Netscape 4.7x
+ OS: HP-UX 10.20, Linux 2.x, Win95

+

Intéropérabilité:
+ Sans compter le support par les solutions génériques d'emballage, il existe + des extensions particulièrement travaillés pour
+ d'autres MTA:

+

Qmail il y a un patch en sources libres disponible, étendant le MTA de Qmail + pour supporter la RFC2487,
+ écrit par Frederik Vermeulen . L'envoi et la réception fonctionne des deux côtés.
+ Test: envoyez le courrier ŕ ping@linux.student.kuleuven.ac.be (renverra l'email + complet comprenant des en-tętes).
+ Zmailer l'autheur/développeur de ZMailer, Matti Aarnio, a incorporé le + support serveur et client de TLS .
+ Zmailer - > Postfix trčs bien,
+ Postfix - > Zmailer ne fonctionne pas, puisqu'Esmtp n'est pas identifié (problčme + signalé).
+ Test: envoyez un courrier ŕ autoanswer@mea.tmt.tele.fi (renverra des en-tętes). +
+ Sendmail la verson commerciale supporte le client et le serveur TLS, + les deux côtés fonctionnent avec Postfix/TLS.
+ En date de sendmail-8.11, TLS est également inclus avec la version opensource + .
+ Test: envoyez le courrier ŕ bounce@esmtp.org (reverra le message d'erreur comprenant + de vieux en-tętes).
+ Postfix: peut s'envoyer des messages à lui-même :-)
+ Test: envoyez le courrier ŕ postfix_tls-bounce@serv01.aet.tu-cottbus.de (reviendra, + en incluant de vieux en-tętes).
+
+ D'autres retour sont les bienvenus

+

Problèmes connus:
+ Ce logiciel en est qu'à ses débuts, soyez donc patients. Ŕ ce + jour j'ai ces points:

+

Côté de serveur: Sous Win95/NT j'ai quelques problčmes avec les certificats + de client. En ouvrant la premičre connexion
+ (Netscape demande le mot de passe pour accéder ŕ la base de données de certificat), + la connexion s'arręte. Ceci semble
+ ętre provoqué par Netscape: une vidange mémoire de la transmission montre que + Netscape ne reprend pas la poignée de main
+ (TLS handshake) de TLS.
+ Remarque: je n'ai pas pu reproduire cette anomalie récemment aprčs évolution + d'OpenSSL 0.9.4. J'espčre qu'elle a disparue,
+ mais peut-ętre est elle juste une conséquence du jeu autour avec les options + de la sécurité de Netscape. Plus de test exigé...
+ Solution: détruisez cette connexion, la prochaine fonctionnera immédiatement + ou utilisez SSLv2 seulement (deuxičme solution
+ non recommandée).

+

Doit être résolu avec OpenSSL 0.9.5
+ Coté serveur: Outlook Express tout comme Internet explorer 5 fonctionneront + avec Postfix/TLS mais aucun certificat
+ client ne seront présentés. Ainsi vous pouvez chiffrer votre transfert + de courrier mais vous ne pouvez pas vous authentifier
+ (et relayer) avec des certificats clients. Cela fonctionne seulement sur le + port 25 (smtp); sur d'autres ports vous devez
+ utiliser le smtpd_tls_wrappermode ŕ la place.
+ Coté serveur: Outlook Express tout comme Internet explorer 4 semble + ne pas supporter la RFC2487. Utilisez
+ smtpd_tls_wrappermode=yes sur un autre port.
+ Coté serveur: Outlook Express (Mac) semble ne pas supporter la RFC2487. + Utilisez smtpd_tls_wrappermode=yes
+ sur un autre port.
+ Coté client: MS Exchange même en version récente offre STARTTLS + même si ce dernier n'est pas configuré (la liste
+ de diffusion[IETF-APPS-TLS]). Je ne pourrais pas tester ceci sans accčs ŕ un + tel serveur, je ne peux donc pas prévoir
+ ce qui va se produire.
+ Coté client: Les connexions de TLS ŕ un serveur de CommunigatePro échouent + avec une erreur de poignée de main
+ avec des versions plus anciennes de CommunigatePro. La raison est une violation + de protocole de CommunigatePro
+ en ce qui concerne la numérotation de version de protocole SSL. (cf RFC 2246 + section 7.4.7.1)
+ Ce problčme a été fixé dans CommunigatePro 3.3b?? (je ne connais pas la numérotation + exacte) autour du 9 juin 2000. .

+ + diff -Pur postfix-2.1.5/src/global/Makefile.in postfix-2.1.5-ti1.25/src/global/Makefile.in --- postfix-2.1.5/src/global/Makefile.in Thu Apr 22 21:37:34 2004 +++ postfix-2.1.5-ti1.25/src/global/Makefile.in Mon Sep 20 15:01:55 2004 @@ -22,7 +22,9 @@ sent.c smtp_stream.c split_addr.c string_list.c strip_addr.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 trace.c verify.c \ - verify_clnt.c verp_sender.c virtual8_maps.c xtext.c + verify_clnt.c verp_sender.c virtual8_maps.c xtext.c \ + wildcard_inet_addr.c inet_interfaces_to_af.c \ + pfixtls.c OBJS = abounce.o been_here.o bounce.o bounce_log.o \ canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \ clnt_stream.o debug_peer.o debug_process.o defer.o \ @@ -46,7 +48,9 @@ sent.o smtp_stream.o split_addr.o string_list.o strip_addr.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 trace.o verify.o \ - verify_clnt.o verp_sender.o virtual8_maps.o xtext.o + verify_clnt.o verp_sender.o virtual8_maps.o xtext.o \ + wildcard_inet_addr.o inet_interfaces_to_af.o \ + pfixtls.o HDRS = abounce.h been_here.h bounce.h bounce_log.h \ canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \ debug_peer.h debug_process.h defer.h deliver_completed.h \ @@ -67,7 +71,9 @@ resolve_local.h rewrite_clnt.h sent.h smtp_stream.h split_addr.h \ string_list.h strip_addr.h sys_exits.h timed_ipc.h tok822.h \ trace.h verify.h verify_clnt.h verp_sender.h virtual8_maps.h \ - xtext.h + xtext.h \ + wildcard_inet_addr.h inet_interfaces_to_af.h \ + pfixtls.h TESTSRC = rec2stream.c stream2rec.c recdump.c DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) CFLAGS = $(DEBUG) $(OPT) $(DEFS) @@ -643,6 +649,10 @@ hold_message.o: ../../include/vstream.h hold_message.o: mail_params.h hold_message.o: hold_message.h +inet_interfaces_to_af.o: inet_interfaces_to_af.c +inet_interfaces_to_af.o: ../../include/sys_defs.h +inet_interfaces_to_af.o: mail_params.h +inet_interfaces_to_af.o: inet_interfaces_to_af.h input_transp.o: input_transp.c input_transp.o: ../../include/sys_defs.h input_transp.o: ../../include/name_mask.h @@ -862,6 +872,7 @@ mail_params.o: ../../include/attr.h mail_params.o: verp_sender.h mail_params.o: mail_params.h +mail_params.o: pfixtls.h mail_pathname.o: mail_pathname.c mail_pathname.o: ../../include/sys_defs.h mail_pathname.o: ../../include/stringops.h @@ -1088,6 +1099,7 @@ own_inet_addr.o: ../../include/vbuf.h own_inet_addr.o: mail_params.h own_inet_addr.o: own_inet_addr.h +own_inet_addr.o: inet_interfaces_to_af.h pipe_command.o: pipe_command.c pipe_command.o: ../../include/sys_defs.h pipe_command.o: ../../include/msg.h @@ -1394,3 +1406,16 @@ xtext.o: ../../include/vstring.h xtext.o: ../../include/vbuf.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: ../../include/msg.h +pfixtls.o: ../../include/connect.h +pfixtls.o: mail_params.h +pfixtls.o: pfixtls.h diff -Pur postfix-2.1.5/src/global/inet_interfaces_to_af.c postfix-2.1.5-ti1.25/src/global/inet_interfaces_to_af.c --- postfix-2.1.5/src/global/inet_interfaces_to_af.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/inet_interfaces_to_af.c Mon Sep 20 15:01:56 2004 @@ -0,0 +1,26 @@ +#include +#include +#include +#include +#include + +int inet_interfaces_to_af (char *inet_interfaces) +{ + int af = -1; + + if (inet_interfaces == NULL || *inet_interfaces == '\0') + return (af); + if (strcasecmp(inet_interfaces, DEF_INET_INTERFACES) == 0) + af = AF_UNSPEC; + else if (strcasecmp(inet_interfaces, "IPv6:" DEF_INET_INTERFACES) == 0) +#ifdef INET6 + af = AF_INET6; +#else + msg_fatal("unable to bind to IPv6 only (%s=%s): IPv6 not compiled in", + VAR_INET_INTERFACES, inet_interfaces); +#endif + else if (strcasecmp(inet_interfaces, "IPv4:" DEF_INET_INTERFACES) == 0) + af = AF_INET; + + return (af); +} diff -Pur postfix-2.1.5/src/global/inet_interfaces_to_af.h postfix-2.1.5-ti1.25/src/global/inet_interfaces_to_af.h --- postfix-2.1.5/src/global/inet_interfaces_to_af.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/inet_interfaces_to_af.h Mon Sep 20 15:01:56 2004 @@ -0,0 +1,6 @@ +#ifndef _INET_INTERFACES_TO_AF_H_INCLUDED_ +#define _INET_INTERFACES_TO_AF_H_INCLUDED_ + +extern int inet_interfaces_to_af (char *); + +#endif diff -Pur postfix-2.1.5/src/global/mail_params.c postfix-2.1.5-ti1.25/src/global/mail_params.c --- postfix-2.1.5/src/global/mail_params.c Mon Jan 26 16:43:42 2004 +++ postfix-2.1.5-ti1.25/src/global/mail_params.c Mon Sep 20 15:01:56 2004 @@ -46,6 +46,7 @@ /* int var_message_limit; /* char *var_mail_release; /* char *var_mail_version; +/* char *var_tlsipv6_version; /* int var_ipc_idle_limit; /* int var_ipc_ttl_limit; /* char *var_db_type; @@ -161,6 +162,7 @@ #include "mail_proto.h" #include "verp_sender.h" #include "mail_params.h" +#include "pfixtls.h" /* * Special configuration variables. @@ -205,6 +207,9 @@ int var_message_limit; char *var_mail_release; char *var_mail_version; +#ifdef INET6 +char *var_tlsipv6_version; +#endif int var_ipc_idle_limit; int var_ipc_ttl_limit; char *var_db_type; @@ -231,6 +236,33 @@ int var_in_flow_delay; char *var_par_dom_match; char *var_config_dirs; +#ifdef USE_SSL +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; +#endif char *var_import_environ; char *var_export_environ; @@ -454,6 +486,9 @@ VAR_ALIAS_DB_MAP, DEF_ALIAS_DB_MAP, &var_alias_db_map, 0, 0, VAR_MAIL_RELEASE, DEF_MAIL_RELEASE, &var_mail_release, 1, 0, VAR_MAIL_VERSION, DEF_MAIL_VERSION, &var_mail_version, 1, 0, +#ifdef INET6 + VAR_TLSIPV6_VERSION, DEF_TLSIPV6_VERSION, &var_tlsipv6_version, 1, 0, +#endif VAR_DB_TYPE, DEF_DB_TYPE, &var_db_type, 1, 0, VAR_HASH_QUEUE_NAMES, DEF_HASH_QUEUE_NAMES, &var_hash_queue_names, 1, 0, VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim, 0, 1, @@ -478,6 +513,28 @@ VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0, VAR_VERIFY_SERVICE, DEF_VERIFY_SERVICE, &var_verify_service, 1, 0, VAR_TRACE_SERVICE, DEF_TRACE_SERVICE, &var_trace_service, 1, 0, +#ifdef USE_SSL + 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, +#endif 0, }; static CONFIG_STR_FN_TABLE function_str_defaults_2[] = { @@ -500,6 +557,11 @@ VAR_TOKEN_LIMIT, DEF_TOKEN_LIMIT, &var_token_limit, 1, 0, VAR_MIME_MAXDEPTH, DEF_MIME_MAXDEPTH, &var_mime_maxdepth, 1, 0, VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0, +#ifdef USE_SSL + 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, +#endif 0, }; static CONFIG_TIME_TABLE time_defaults[] = { @@ -512,6 +574,10 @@ 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, +#ifdef USE_SSL + 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, +#endif VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0, VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10, 0, diff -Pur postfix-2.1.5/src/global/mail_params.h postfix-2.1.5-ti1.25/src/global/mail_params.h --- postfix-2.1.5/src/global/mail_params.h Wed Apr 21 20:56:04 2004 +++ postfix-2.1.5-ti1.25/src/global/mail_params.h Mon Sep 20 15:01:56 2004 @@ -519,6 +519,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. */ @@ -768,6 +796,10 @@ #define DEF_SMTP_XFWD_TMOUT "300s" extern int var_smtp_xfwd_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; @@ -828,6 +860,10 @@ #define DEF_SMTP_BIND_ADDR "" extern char *var_smtp_bind_addr; +#define VAR_SMTP_BIND_ADDR6 "smtp_bind_address6" +#define DEF_SMTP_BIND_ADDR6 "" +extern char *var_smtp_bind_addr6; + #define VAR_SMTP_HELO_NAME "smtp_helo_name" #define DEF_SMTP_HELO_NAME "$myhostname" extern char *var_smtp_helo_name; @@ -869,6 +905,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; @@ -901,6 +941,150 @@ #define DEF_SMTPD_NOOP_CMDS "" extern char *var_smtpd_noop_cmds; +#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_AUTH_ONLY "smtpd_tls_auth_only" +#define DEF_SMTPD_TLS_AUTH_ONLY 0 +extern bool var_smtpd_tls_auth_only; + +#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. */ @@ -916,6 +1100,10 @@ #define DEF_SMTPD_SASL_APPNAME "smtpd" extern char *var_smtpd_sasl_appname; +#define VAR_SMTPD_SASL_TLS_OPTS "smtpd_sasl_tls_security_options" +#define DEF_SMTPD_SASL_TLS_OPTS "$smtpd_sasl_security_options" +extern char *var_smtpd_sasl_opts; + #define VAR_SMTPD_SASL_REALM "smtpd_sasl_local_domain" #define DEF_SMTPD_SASL_REALM "" extern char *var_smtpd_sasl_realm; @@ -945,6 +1133,14 @@ #define DEF_SMTP_SASL_OPTS "noplaintext, noanonymous" extern char *var_smtp_sasl_opts; +#define VAR_SMTP_SASL_TLS_OPTS "smtp_sasl_tls_security_options" +#define DEF_SMTP_SASL_TLS_OPTS "$var_smtp_sasl_opts" +extern char *var_smtp_sasl_tls_opts; + +#define VAR_SMTP_SASL_TLSV_OPTS "smtp_sasl_tls_verified_security_options" +#define DEF_SMTP_SASL_TLSV_OPTS "$var_smtp_sasl_tls_opts" +extern char *var_smtp_sasl_tls_verified_opts; + /* * LMTP server. The soft error limit determines how many errors an LMTP * client may make before we start to slow down; the hard error limit @@ -1075,6 +1271,14 @@ #define DEF_LMTP_QUIT_TMOUT "300s" extern int var_lmtp_quit_tmout; +#define VAR_LMTP_BIND_ADDR "lmtp_bind_address" +#define DEF_LMTP_BIND_ADDR "" +extern char *var_lmtp_bind_addr; + +#define VAR_LMTP_BIND_ADDR6 "lmtp_bind_address6" +#define DEF_LMTP_BIND_ADDR6 "" +extern char *var_lmtp_bind_addr6; + #define VAR_LMTP_SEND_XFORWARD "lmtp_send_xforward_command" #define DEF_LMTP_SEND_XFORWARD 0 extern bool var_lmtp_send_xforward; @@ -1234,6 +1438,10 @@ #define DEF_RELAY_RCPT_CODE 550 extern int var_relay_rcpt_code; +#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; @@ -1352,6 +1560,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 -Pur postfix-2.1.5/src/global/mail_proto.h postfix-2.1.5-ti1.25/src/global/mail_proto.h --- postfix-2.1.5/src/global/mail_proto.h Sun Feb 1 19:51:03 2004 +++ postfix-2.1.5-ti1.25/src/global/mail_proto.h Mon Sep 20 15:01:56 2004 @@ -42,6 +42,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 -Pur postfix-2.1.5/src/global/mail_version.h postfix-2.1.5-ti1.25/src/global/mail_version.h --- postfix-2.1.5/src/global/mail_version.h Wed Sep 15 17:32:11 2004 +++ postfix-2.1.5-ti1.25/src/global/mail_version.h Mon Sep 20 15:01:56 2004 @@ -31,6 +31,14 @@ #endif extern char *var_mail_version; +#define VAR_TLSIPV6_VERSION "tls_ipv6_version" +#ifdef INET6 +#define DEF_TLSIPV6_VERSION "1.25" +#else +#define DEF_TLSIPV6_VERSION "" +#endif +extern char *var_tlsipv6_version; + /* * Release date. */ diff -Pur postfix-2.1.5/src/global/mynetworks.c postfix-2.1.5-ti1.25/src/global/mynetworks.c --- postfix-2.1.5/src/global/mynetworks.c Wed Jun 16 20:01:14 2004 +++ postfix-2.1.5-ti1.25/src/global/mynetworks.c Mon Sep 20 15:01:56 2004 @@ -28,6 +28,13 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Dean C. Strik +/* Department ICT Services +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven, Netherlands +/* E-mail: /*--*/ /* System library. */ @@ -42,7 +49,8 @@ #define IN_CLASSD_NSHIFT 28 #endif -#define BITS_PER_ADDR 32 +#define BITS_PER_ADDR_V4 32 +#define BITS_PER_ADDR_V6 128 /* Utility library. */ @@ -50,6 +58,12 @@ #include #include #include +#ifdef INET6 +#include +#include +#include +#include +#endif /* Global library. */ @@ -75,18 +89,25 @@ const char *mynetworks(void) { static VSTRING *result; + int bits_per_addr; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#endif if (result == 0) { char *myname = "mynetworks"; INET_ADDR_LIST *my_addr_list; INET_ADDR_LIST *my_mask_list; - unsigned long addr; - unsigned long mask; + unsigned long addr = 0; + unsigned long mask = 0; struct in_addr net; - int shift; + int shift = 0; int junk; int i; int mask_style; +#ifdef INET6 + struct sockaddr *sa; +#endif mask_style = name_mask("mynetworks mask style", mask_styles, var_mynetworks_style); @@ -107,8 +128,23 @@ my_mask_list = own_inet_mask_list(); for (i = 0; i < my_addr_list->used; i++) { +#ifdef INET6 + sa = (struct sockaddr *)&my_addr_list->addrs[i]; + if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) { + msg_warn("%s: unknown family in address list", myname); + continue; + } + if (sa->sa_family == AF_INET) { + bits_per_addr = BITS_PER_ADDR_V4; + addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); + mask = ntohl(((struct sockaddr_in *) + &my_mask_list->addrs[i])->sin_addr.s_addr); + } else + bits_per_addr = BITS_PER_ADDR_V6; +#else addr = ntohl(my_addr_list->addrs[i].s_addr); mask = ntohl(my_mask_list->addrs[i].s_addr); +#endif switch (mask_style) { @@ -117,6 +153,9 @@ * ISP who gave you a small portion of their network. */ case MASK_STYLE_CLASS: +#ifdef INET6 + if (sa->sa_family == AF_INET) { +#endif if (IN_CLASSA(addr)) { mask = IN_CLASSA_NET; shift = IN_CLASSA_NSHIFT; @@ -130,24 +169,73 @@ mask = IN_CLASSD_NET; shift = IN_CLASSD_NSHIFT; } else { +#ifdef INET6 + if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST)) + strncpy(hbuf, "???", sizeof(hbuf)); + msg_fatal("%s: bad address class: %s", myname, hbuf); +#else msg_fatal("%s: bad address class: %s", myname, inet_ntoa(my_addr_list->addrs[i])); +#endif } break; +#ifdef INET6 + } /* if AF_INET */ + /* + * There are no classes for IPv6, we default to subnets instead. + */ + /* FALLTHROUGH */ +#endif /* * Subnet mask. This is safe, but breaks backwards * compatibility when used as default setting. */ case MASK_STYLE_SUBNET: - for (junk = mask, shift = BITS_PER_ADDR; junk != 0; shift--, (junk <<= 1)) - /* void */ ; +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + unsigned char *ac, *end; + ac = (unsigned char *)&(((struct sockaddr_in6 *)&my_mask_list->addrs[i])->sin6_addr); + end = ac + bits_per_addr / 8; + shift = bits_per_addr; + while (ac < end) { + switch (*(ac++)) { + case 0xff: shift -= 8; break; + case 0xfe: shift -= 7; break; + case 0xfc: shift -= 6; break; + case 0xf8: shift -= 5; break; + case 0xf0: shift -= 4; break; + case 0xe0: shift -= 3; break; + case 0xc0: shift -= 2; break; + case 0x80: shift -= 1; break; + case 0x00: break; + default: msg_fatal("%s: inconsistent prefixlen", + myname); + } + } + break; + } +#endif + /* AF_INET */ + junk = mask; + shift = bits_per_addr; + while (junk != 0) { + shift--; + junk <<= 1; + } break; /* * Host only. Do not relay authorize other hosts. */ case MASK_STYLE_HOST: +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + shift = 0; + break; + } +#endif mask = ~0; shift = 0; break; @@ -156,9 +244,20 @@ msg_panic("unknown mynetworks mask style: %s", var_mynetworks_style); } +#ifdef INET6 + if (sa->sa_family == AF_INET6) { + if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) + msg_fatal("%s: bad address to getnameinfo()", myname); + vstring_sprintf_append(result, "[%s]/%d ", + hbuf, bits_per_addr - shift); + continue; + } +#endif + /* AF_INET */ net.s_addr = htonl(addr & mask); vstring_sprintf_append(result, "%s/%d ", - inet_ntoa(net), BITS_PER_ADDR - shift); + inet_ntoa(net), bits_per_addr - shift); } if (msg_verbose) msg_info("%s: %s", myname, vstring_str(result)); diff -Pur postfix-2.1.5/src/global/own_inet_addr.c postfix-2.1.5-ti1.25/src/global/own_inet_addr.c --- postfix-2.1.5/src/global/own_inet_addr.c Fri Oct 25 01:19:19 2002 +++ postfix-2.1.5-ti1.25/src/global/own_inet_addr.c Mon Sep 20 15:01:56 2004 @@ -50,6 +50,8 @@ #include #include #include +#include +#include #ifdef STRCASECMP_IN_STRINGS_H #include @@ -68,6 +70,7 @@ #include #include +#include /* Application-specific. */ @@ -88,6 +91,8 @@ char *bufp; int nvirtual; int nlocal; + int done = 0; + int af; inet_addr_list_init(addr_list); inet_addr_list_init(mask_list); @@ -96,14 +101,10 @@ * If we are listening on all interfaces (default), ask the system what * the interfaces are. */ - if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) { - if (inet_addr_local(addr_list, mask_list) == 0) + af = inet_interfaces_to_af(var_inet_interfaces); + if (af > -1) { + if (inet_addr_local(addr_list, mask_list, af) == 0) msg_fatal("could not find any active network interfaces"); -#if 0 - if (addr_list->used == 1) - msg_warn("found only one active network interface: %s", - inet_ntoa(addr_list->addrs[0])); -#endif } /* @@ -113,10 +114,11 @@ */ else { bufp = hosts = mystrdup(var_inet_interfaces); - while ((host = mystrtok(&bufp, sep)) != 0) + while ((host = mystrtok(&bufp, sep)) != 0) { if (inet_addr_host(addr_list, host) == 0) msg_fatal("config variable %s: host not found: %s", VAR_INET_INTERFACES, host); + } myfree(hosts); /* @@ -129,19 +131,44 @@ inet_addr_list_init(&local_addrs); inet_addr_list_init(&local_masks); - if (inet_addr_local(&local_addrs, &local_masks) == 0) + if (inet_addr_local(&local_addrs, &local_masks, AF_UNSPEC) == 0) msg_fatal("could not find any active network interfaces"); for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) { for (nlocal = 0; /* see below */ ; nlocal++) { - if (nlocal >= local_addrs.used) + if (nlocal >= local_addrs.used) { +#ifdef INET6 + char hbuf[NI_MAXHOST]; + if (getnameinfo((struct sockaddr *)&addr_list->addrs[nvirtual], + SS_LEN(addr_list->addrs[nvirtual]), hbuf, + sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) + strncpy(hbuf, "???", sizeof(hbuf)); + msg_fatal("parameter %s: no local interface found for %s", + VAR_INET_INTERFACES, hbuf); +#else msg_fatal("parameter %s: no local interface found for %s", VAR_INET_INTERFACES, inet_ntoa(addr_list->addrs[nvirtual])); +#endif + } +#ifdef INET6 + if (addr_list->addrs[nvirtual].ss_family == + local_addrs.addrs[nlocal].ss_family && + SS_LEN(addr_list->addrs[nvirtual]) == + SS_LEN(local_addrs.addrs[nlocal]) && + memcmp(&addr_list->addrs[nvirtual], + &local_addrs.addrs[nlocal], + SS_LEN(local_addrs.addrs[nlocal])) == 0) { + inet_addr_list_append(mask_list, (struct sockaddr *) + &local_masks.addrs[nlocal]); + break; + } +#else if (addr_list->addrs[nvirtual].s_addr == local_addrs.addrs[nlocal].s_addr) { inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]); break; } +#endif } } inet_addr_list_free(&local_addrs); @@ -151,6 +178,49 @@ /* own_inet_addr - is this my own internet address */ +#ifdef INET6 + +#ifdef INET6_KAME +#define SA6_ARE_ADDR_EQUAL(a, b) ( \ + ((a)->sin6_scope_id == 0 || (b)->sin6_scope_id == 0 || \ + (a)->sin6_scope_id == (b)->sin6_scope_id) && \ + (memcmp(&(a)->sin6_addr, &(b)->sin6_addr, \ + sizeof(struct in6_addr)) == 0)) +#else +#define SA6_ARE_ADDR_EQUAL(a, b) \ + (memcmp(&(a)->sin6_addr, &(b)->sin6_addr, \ + sizeof(struct in6_addr)) == 0) +#endif + +int own_inet_addr(struct sockaddr *addr) +{ + int i; + + if (addr_list.used == 0) + own_inet_addr_init(&addr_list, &mask_list); + + for (i = 0; i < addr_list.used; i++) { + if (((struct sockaddr *)&addr_list.addrs[i])->sa_family != + addr->sa_family) + continue; + switch (addr->sa_family) { + case AF_INET: + if (((struct sockaddr_in *)addr)->sin_addr.s_addr == + ((struct sockaddr_in *)&addr_list.addrs[i])->sin_addr.s_addr) + return (1); + break; + case AF_INET6: + if (SA6_ARE_ADDR_EQUAL((struct sockaddr_in6 *)addr, + (struct sockaddr_in6 *)&addr_list.addrs[i])) + return (1); + break; + default: + continue; + } + return (0); + } +} +#else int own_inet_addr(struct in_addr * addr) { int i; @@ -163,6 +233,7 @@ return (1); return (0); } +#endif /* own_inet_addr_list - return list of addresses */ @@ -224,8 +295,15 @@ proxy_inet_addr_init(&proxy_list); for (i = 0; i < proxy_list.used; i++) +#ifdef INET6 + if (proxy_list.addrs[i].ss_family == AF_INET && addr->s_addr == + ((struct sockaddr_in *)&(proxy_list.addrs[i]))-> + sin_addr.s_addr) + return (1); +#else if (addr->s_addr == proxy_list.addrs[i].s_addr) return (1); +#endif return (0); } diff -Pur postfix-2.1.5/src/global/own_inet_addr.h postfix-2.1.5-ti1.25/src/global/own_inet_addr.h --- postfix-2.1.5/src/global/own_inet_addr.h Fri Oct 25 01:07:05 2002 +++ postfix-2.1.5-ti1.25/src/global/own_inet_addr.h Mon Sep 20 15:01:56 2004 @@ -15,11 +15,18 @@ * System library. */ #include +#ifdef INET6 +#include +#endif /* * External interface. */ +#ifdef INET6 +extern int own_inet_addr(struct sockaddr *); +#else extern int own_inet_addr(struct in_addr *); +#endif extern struct INET_ADDR_LIST *own_inet_addr_list(void); extern struct INET_ADDR_LIST *own_inet_mask_list(void); extern int proxy_inet_addr(struct in_addr *); diff -Pur postfix-2.1.5/src/global/pfixtls.c postfix-2.1.5-ti1.25/src/global/pfixtls.c --- postfix-2.1.5/src/global/pfixtls.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/pfixtls.c Mon Sep 20 15:01:56 2004 @@ -0,0 +1,2822 @@ +/*++ +/* NAME +/* pfixtls +/* SUMMARY +/* interface to openssl routines +/* SYNOPSIS +/* #include +/* +/* const long scache_db_version; +/* const long openssl_version; +/* +/* int pfixtls_serverengine; +/* +/* int pfixtls_clientengine; +/* +/* 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 +#include +#include +#include /* gettimeofday, not in POSIX */ +#include +#include +#include +#include +#include + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Application-specific. */ + +#include "mail_params.h" +#include "pfixtls.h" + +#define STR vstring_str + +const tls_info_t tls_info_zero = { + 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0 +}; + +#ifdef USE_SSL + +/* OpenSSL library. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 is used + * as key. According to HP-UX 10.20, MAXHOSTNAMELEN=64. Maybe new standards + * will increase this value, but as this will break compatiblity with existing + * implementations, we won't see this for long. We therefore choose a limit + * of 64 bytes. + * The length of the (TLS) session id can be up to 32 bytes according to + * RFC2246, so it fits well into the 64bytes limit. + */ +#define 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 TLSpeername_index = -1; +static int do_dump = 0; +static DH *dh_512 = NULL, *dh_1024 = NULL; +static SSL_CTX *ctx = NULL; + +static int rand_exch_fd = -1; + +static DICT *scache_db = NULL; +const long scache_db_version = 0x00000003L; +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; + int hostname_matched; +} TLScontext_t; + +typedef struct { + int pid; + struct timeval tv; +} randseed_t; + +static randseed_t randseed; + +/* + * 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 size_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) { + if ((num_write < 0) && (timeout > 0) && (errno == EAGAIN)) { + msg_warn("write() returns EAGAIN on a writable file descriptor!"); + msg_warn("pausing to avoid going into a tight select/write loop!"); + sleep(1); + } else { + msg_warn("Write failed in network_biopair_interop with errno=%d: num_write=%d, provided=%d", errno, num_write, from_bio - write_pos); + return (-1); /* something happened to the socket */ + } + } else + 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) { + if ((num_write < 0) && (timeout > 0) && (errno == EAGAIN)) { + msg_warn("read() returns EAGAIN on a readable file descriptor!"); + msg_warn("pausing to avoid going into a tight select/write loop!"); + sleep(1); + } else { + msg_warn("Read failed in network_biopair_interop with errno=%d: num_read=%d, want_read=%d", errno, num_read, want_read); + return (-1); /* something happened to the socket */ + } + } else { + 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 *, void *, int), + int (*wfunc)(SSL *, const void *, int), + char *buf, int num) +{ + int status; + int err; + int retval = 0; + 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); +} + + +/* + * match_hostname: match name provided in "buf" against the expected + * hostname. Comparison is case-insensitive, wildcard certificates are + * supported. + * "buf" may be come from some OpenSSL data structures, so we copy before + * modifying. + */ +static int match_hostname(const char *buf, TLScontext_t *TLScontext) +{ + char *hostname_lowercase; + char *peername_left; + int hostname_matched = 0; + int buf_len; + + buf_len = strlen(buf); + if (!(hostname_lowercase = (char *)mymalloc(buf_len + 1))) + return 0; + memcpy(hostname_lowercase, buf, buf_len + 1); + + hostname_lowercase = lowercase(hostname_lowercase); + if (!strcmp(TLScontext->peername_save, hostname_lowercase)) { + hostname_matched = 1; + } else { + if ((buf_len > 2) && + (hostname_lowercase[0] == '*') && (hostname_lowercase[1] == '.')) { + /* + * Allow wildcard certificate matching. The proposed rules in + * RFCs (2818: HTTP/TLS, 2830: LDAP/TLS) are different, RFC2874 + * does not specify a rule, so here the strict rule is applied. + * An asterisk '*' is allowed as the leftmost component and may + * replace the left most part of the hostname. Matching is done + * by removing '*.' from the wildcard name and the Name. from + * the peername and compare what is left. + */ + peername_left = strchr(TLScontext->peername_save, '.'); + if (peername_left) { + if (!strcmp(peername_left + 1, hostname_lowercase + 2)) + hostname_matched = 1; + } + } + } + myfree(hostname_lowercase); + return hostname_matched; +} + +/* + * 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 *peername_left; + 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) && pfixtls_clientengine) { + int i, r; + int hostname_matched; + int dNSName_found; + STACK_OF(GENERAL_NAME) *gens; + + /* + * Check out the name certified against the hostname expected. + * In case it does not match, print an information about the result. + * If a matching is enforced, bump out with a verification error + * immediately. + * Standards are not always clear with respect to the handling of + * dNSNames. RFC3207 does not specify the handling. We therefore follow + * the strict rules in RFC2818 (HTTP over TLS), Section 3.1: + * The Subject Alternative Name/dNSName has precedence over CommonName + * (CN). If dNSName entries are provided, CN is not checked anymore. + */ + hostname_matched = dNSName_found = 0; + + gens = X509_get_ext_d2i(err_cert, NID_subject_alt_name, 0, 0); + if (gens) { + for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i) { + const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); + if (gn->type == GEN_DNS) { + dNSName_found++; + if ((hostname_matched = + match_hostname((char *)gn->d.ia5->data, TLScontext))) + break; + } + } + sk_GENERAL_NAME_free(gens); + } + if (dNSName_found) { + if (!hostname_matched) + msg_info("Peer verification: %d dNSNames in certificate found, but no one does match %s", dNSName_found, TLScontext->peername_save); + } else { + buf[0] = '\0'; + if (!X509_NAME_get_text_by_NID(X509_get_subject_name(err_cert), + NID_commonName, buf, 256)) { + msg_info("Could not parse server's subject CN"); + pfixtls_print_errors(); + } + else { + hostname_matched = match_hostname(buf, TLScontext); + if (!hostname_matched) + msg_info("Peer verification: CommonName in certificate does not match: %s != %s", buf, TLScontext->peername_save); + } + } + + if (!hostname_matched) { + if (TLScontext->enforce_verify_errors && TLScontext->enforce_CN) { + err = X509_V_ERR_CERT_REJECTED; + X509_STORE_CTX_set_error(ctx, err); + msg_info("Verify failure: Hostname mismatch"); + ok = 0; + } + } + else + TLScontext->hostname_matched = 1; + } + + 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 - \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))", + (unsigned int)bio, (unsigned long)argp, argi, + ret, (unsigned int)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))", + (unsigned int)bio, (unsigned long)argp, argi, + ret, (unsigned int)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[2 * ID_MAXLENGTH + 1]; + 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; + + 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"); + 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"); + + return (session); +} + + +static SSL_SESSION *load_clnt_session(const char *hostname, + int enforce_peername) +{ + SSL_SESSION *session = NULL; + char idstring[ID_MAXLENGTH + 1]; + 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; + + 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"); + 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. + * When we enforce_peername, we may find an old session, that was + * saved when enforcement was not set. In this case the session will + * be removed and a fresh session will be negotiated. + */ + 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 if (enforce_peername && (!scache_info.enforce_peername)) + 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)); + strncpy(SSL_SESSION_get_ex_data(session, TLSpeername_index), + idstring, ID_MAXLENGTH + 1); + if (!session) + pfixtls_print_errors(); + } + myfree((char *)data); + } + + if (session && (var_smtp_tls_loglevel >= 3)) + msg_info("Successfully reloaded session from disc"); + + return (session); +} + + +static void create_client_lookup_id(char *idstring, char *hostname) +{ + int n, len, uselength; + + len = strlen(hostname); + if (len > ID_MAXLENGTH) + uselength = ID_MAXLENGTH; /* Limit length of ID */ + else + uselength = len; + + for (n = 0 ; n < uselength ; n++) + idstring[n] = tolower(hostname[n]); + idstring[uselength] = '\0'; +} + + +static void create_server_lookup_id(char *idstring, SSL_SESSION *session) +{ + int n, uselength; + + if (session->session_id_length > ID_MAXLENGTH) + uselength = ID_MAXLENGTH; /* Limit length of ID */ + else + uselength = session->session_id_length; + + for(n = 0; n < uselength ; n++) + sprintf(idstring + 2 * n, "%02x", session->session_id[n]); +} + + +static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *session) +{ + char idstring[2 * ID_MAXLENGTH + 1]; + char *hostname; + + if (pfixtls_clientengine) { + hostname = SSL_SESSION_get_ex_data(session, TLSpeername_index); + create_client_lookup_id(idstring, hostname); + if (var_smtp_tls_loglevel >= 3) + msg_info("Trying to remove session from disc: %s", idstring); + } + else { + create_server_lookup_id(idstring, session); + if (var_smtpd_tls_loglevel >= 3) + msg_info("Trying to remove session from disc: %s", idstring); + } + + if (scache_db) + dict_del(scache_db, idstring); +} + + +/* + * We need space to save the peername into the SSL_SESSION, as we must + * look up the external database for client sessions by peername, not + * by session id. We therefore allocate place for the peername string, + * when a new SSL_SESSION is generated. It is filled later. + */ +static int new_peername_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp) +{ + char *peername; + + peername = (char *)mymalloc(ID_MAXLENGTH + 1); + if (!peername) + return 0; + peername[0] = '\0'; /* initialize */ + return CRYPTO_set_ex_data(ad, idx, peername); +} + +/* + * When the SSL_SESSION is removed again, we must free the memory to avoid + * leaks. + */ +static void free_peername_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, + int idx, long argl, void *argp) +{ + myfree(CRYPTO_get_ex_data(ad, idx)); +} + +/* + * Duplicate application data, when a SSL_SESSION is duplicated + */ +static int dup_peername_func(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, + void *from_d, int idx, long argl, void *argp) +{ + char *peername_old, *peername_new; + + peername_old = CRYPTO_get_ex_data(from, idx); + peername_new = CRYPTO_get_ex_data(to, idx); + if (!peername_old || !peername_new) + return 0; + memcpy(peername_new, peername_old, ID_MAXLENGTH + 1); + return 1; +} + + + /* + * Save a new session to the external cache + */ +static int new_session_cb(SSL *ssl, SSL_SESSION *session) +{ + char idstring[2 * ID_MAXLENGTH + 1]; + int n; + int dsize; + int len; + unsigned char *data, *sess_data; + pfixtls_scache_info_t scache_info; + char *hexdata, *hostname; + TLScontext_t *TLScontext; + + if (pfixtls_clientengine) { + TLScontext = SSL_get_ex_data(ssl, TLScontext_index); + hostname = TLScontext->peername_save; + create_client_lookup_id(idstring, hostname); + strncpy(SSL_SESSION_get_ex_data(session, TLSpeername_index), + hostname, ID_MAXLENGTH + 1); + /* + * Remember, whether peername matching was enforced when the session + * was created. If later enforce mode is enabled, we do not want to + * reuse a session that was not sufficiently checked. + */ + scache_info.enforce_peername = + (TLScontext->enforce_verify_errors && TLScontext->enforce_CN); + + if (var_smtp_tls_loglevel >= 3) + msg_info("Trying to save session for hostID to disc: %s", idstring); + +#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) + /* + * Ugly Hack: OpenSSL before 0.9.6a 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 + + } + else { + create_server_lookup_id(idstring, session); + 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"); + 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); + 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); + return (1); +} + + + /* + * 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_set_session_cache_mode(ctx, + SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_AUTO_CLEAR); + SSL_CTX_sess_set_get_cb(ctx, get_session_cb); + SSL_CTX_sess_set_new_cb(ctx, new_session_cb); + SSL_CTX_sess_set_remove_cb(ctx, remove_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(); + 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; + } + + TLScontext->peer_CN[0] = '\0'; + if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer), + NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse client's subject CN"); + pfixtls_print_errors(); + } + tls_info->peer_CN = TLScontext->peer_CN; + + TLScontext->issuer_CN[0] = '\0'; + if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), + NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse client's issuer CN"); + pfixtls_print_errors(); + } + if (!TLScontext->issuer_CN[0]) { + /* No issuer CN field, use Organization instead */ + if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), + NID_organizationName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse client's issuer Organization"); + pfixtls_print_errors(); + } + } + tls_info->issuer_CN = TLScontext->issuer_CN; + + if (var_smtpd_tls_loglevel >= 1) { + if (tls_info->peer_verified) + msg_info("Verified: subject_CN=%s, issuer=%s", + TLScontext->peer_CN, TLScontext->issuer_CN); + else + msg_info("Unverified: subject_CN=%s, issuer=%s", + TLScontext->peer_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"); + session = SSL_get_session(TLScontext->con); + SSL_CTX_remove_session(ctx, session); + 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); + + if (var_smtpd_tls_loglevel >= 1) + 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) +{ + TLScontext_t *TLScontext; + int retval; + + if (pfixtls_serveractive) { + TLScontext = (TLScontext_t *)vstream_context(stream); + /* + * Perform SSL_shutdown() twice, as the first attempt may return + * to early: it will only send out the shutdown alert but it will + * not wait for the peer's shutdown alert. Therefore, when we are + * the first party to send the alert, we must call SSL_shutdown() + * again. + * On failure we don't want to resume the session, so we will not + * perform SSL_shutdown() and the session will be removed as being + * bad. + */ + if (!failure) { + retval = do_tls_operation(vstream_fileno(stream), timeout, + TLScontext, SSL_shutdown, NULL, NULL, NULL, 0); + if (retval == 0) + do_tls_operation(vstream_fileno(stream), timeout, TLScontext, + SSL_shutdown, NULL, NULL, NULL, 0); + } + /* + * 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); + /* + * It is practical to have OpenSSL automatically save newly created + * sessions for us by callback. Therefore we have to enable the + * internal session cache for the client side. Disable automatic + * clearing, as smtp has limited lifetime anyway and we can call + * the cleanup routine at will. + */ + SSL_CTX_set_session_cache_mode(ctx, + SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_NO_AUTO_CLEAR); + SSL_CTX_sess_set_new_cb(ctx, new_session_cb); + } + + /* + * 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); + TLSpeername_index = SSL_SESSION_get_ex_new_index(0, + "TLSpeername ex_data index", + new_peername_func, + dup_peername_func, + free_peername_func); + + 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; + SSL_SESSION *session, *old_session; + SSL_CIPHER *cipher; + X509 *peer; + int verify_flags; + 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; + } + TLScontext->hostname_matched = 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 = NULL; + + /* + * Find out the hashed HostID for the client cache and try to + * load the session from the cache. + */ + strncpy(TLScontext->peername_save, peername, ID_MAXLENGTH + 1); + TLScontext->peername_save[ID_MAXLENGTH] = '\0'; /* just in case */ + (void)lowercase(TLScontext->peername_save); + if (scache_db) { + old_session = load_clnt_session(peername, enforce_peername); + if (old_session) { + SSL_set_session(TLScontext->con, old_session); +#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) + /* + * Ugly Hack: OpenSSL before 0.9.6a 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) { + SSL_CTX_remove_session(ctx, session); + if (var_smtp_tls_loglevel >= 2) + msg_info("SSL session removed"); + } + if ((old_session) && (!SSL_session_reused(TLScontext->con))) + SSL_SESSION_free(old_session); /* Must also be removed */ + SSL_free(TLScontext->con); + myfree((char *)TLScontext); + return (-1); + } + + if (!SSL_session_reused(TLScontext->con)) { + SSL_SESSION_free(old_session); /* Remove unused session */ + } + else if (var_smtp_tls_loglevel >= 3) + msg_info("Reusing old 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; + + tls_info->hostname_matched = TLScontext->hostname_matched; + TLScontext->peer_CN[0] = '\0'; + if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer), + NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse server's subject CN"); + pfixtls_print_errors(); + } + tls_info->peer_CN = TLScontext->peer_CN; + + TLScontext->issuer_CN[0] = '\0'; + if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), + NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse server's issuer CN"); + pfixtls_print_errors(); + } + if (!TLScontext->issuer_CN[0]) { + /* No issuer CN field, use Organization instead */ + if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), + NID_organizationName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { + msg_info("Could not parse server's issuer Organization"); + pfixtls_print_errors(); + } + } + tls_info->issuer_CN = TLScontext->issuer_CN; + + if (var_smtp_tls_loglevel >= 1) { + if (tls_info->peer_verified) + msg_info("Verified: subject_CN=%s, issuer=%s", + TLScontext->peer_CN, TLScontext->issuer_CN); + else + msg_info("Unverified: subject_CN=%s, issuer=%s", + TLScontext->peer_CN, TLScontext->issuer_CN); + } + X509_free(peer); + } + + /* + * 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); + + if (var_smtp_tls_loglevel >= 1) + 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) +{ + TLScontext_t *TLScontext; + int retval; + + if (pfixtls_clientactive) { + TLScontext = (TLScontext_t *)vstream_context(stream); + /* + * Perform SSL_shutdown() twice, as the first attempt may return + * to early: it will only send out the shutdown alert but it will + * not wait for the peer's shutdown alert. Therefore, when we are + * the first party to send the alert, we must call SSL_shutdown() + * again. + * On failure we don't want to resume the session, so we will not + * perform SSL_shutdown() and the session will be removed as being + * bad. + */ + if (!failure) { + retval = do_tls_operation(vstream_fileno(stream), timeout, + TLScontext, SSL_shutdown, NULL, NULL, NULL, 0); + if (retval == 0) + do_tls_operation(vstream_fileno(stream), timeout, TLScontext, + SSL_shutdown, NULL, NULL, NULL, 0); + } + /* + * 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 /* USE_SSL */ diff -Pur postfix-2.1.5/src/global/pfixtls.h postfix-2.1.5-ti1.25/src/global/pfixtls.h --- postfix-2.1.5/src/global/pfixtls.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/pfixtls.h Mon Sep 20 15:01:56 2004 @@ -0,0 +1,81 @@ +/*++ +/* NAME +/* pfixtls 3h +/* SUMMARY +/* TLS routines +/* SYNOPSIS +/* include "pfixtls.h" +/* DESCRIPTION +/* .nf +/*--*/ + +#ifndef PFIXTLS_H_INCLUDED +#define PFIXTLS_H_INCLUDED + +#if defined(HAS_SSL) && !defined(USE_SSL) +#define USE_SSL +#endif + +typedef struct { + int peer_verified; + int hostname_matched; + char *peer_subject; + char *peer_issuer; + char *peer_fingerprint; + char *peer_CN; + char *issuer_CN; + 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 USE_SSL + +typedef struct { + long scache_db_version; + long openssl_version; + time_t timestamp; /* We could add other info here... */ + int enforce_peername; +} 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 -Pur postfix-2.1.5/src/global/resolve_local.c postfix-2.1.5-ti1.25/src/global/resolve_local.c --- postfix-2.1.5/src/global/resolve_local.c Fri Oct 25 01:21:20 2002 +++ postfix-2.1.5-ti1.25/src/global/resolve_local.c Mon Sep 20 15:01:57 2004 @@ -43,6 +43,7 @@ #include #include #include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -80,7 +81,12 @@ { char *saved_addr = mystrdup(addr); char *dest; +#ifdef INET6 + struct addrinfo hints, *res, *res0; + int error; +#else struct in_addr ipaddr; +#endif int len; #define RETURN(x) { myfree(saved_addr); return(x); } @@ -118,9 +124,28 @@ if (*dest == '[' && dest[len - 1] == ']') { dest++; dest[len -= 2] = 0; +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(dest, NULL, &hints, &res0); + if (!error) { + for (res = res0; res; res = res->ai_next) { + if (own_inet_addr(res->ai_addr) || + (res->ai_family == AF_INET && + proxy_inet_addr((struct in_addr *)&res->ai_addr))) { + freeaddrinfo(res0); + RETURN(1); + } + } + freeaddrinfo(res0); + } +#else if ((ipaddr.s_addr = inet_addr(dest)) != INADDR_NONE && (own_inet_addr(&ipaddr) || proxy_inet_addr(&ipaddr))) RETURN(1); +#endif } /* diff -Pur postfix-2.1.5/src/global/wildcard_inet_addr.c postfix-2.1.5-ti1.25/src/global/wildcard_inet_addr.c --- postfix-2.1.5/src/global/wildcard_inet_addr.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/wildcard_inet_addr.c Mon Sep 20 15:01:57 2004 @@ -0,0 +1,81 @@ +/* System library. */ + +#include +#include +#include +#include +#ifdef INET6 +#include +#endif +#include + +#ifdef STRCASECMP_IN_STRINGS_H +#include +#endif + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include + +/* Application-specific. */ +static INET_ADDR_LIST addr_list; + +/* wildcard_inet_addr_init - initialize my own address list */ + +static void wildcard_inet_addr_init(INET_ADDR_LIST *addr_list, int addr_family) +{ +#ifdef INET6 + struct addrinfo hints, *res, *res0; + char hbuf[NI_MAXHOST]; + int error; + const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; + + inet_addr_list_init(addr_list); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + error = getaddrinfo(NULL, "0", &hints, &res0); + if (error) + msg_fatal("could not get list of wildcard addresses"); + for (res = res0; res; res = res->ai_next) { + if (addr_family > 0 && res->ai_family != addr_family) + continue; + if (addr_family <= 0 && res->ai_family != AF_INET + && res->ai_family != AF_INET6) + continue; + if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, niflags) != 0) + continue; + if (inet_addr_host(addr_list, hbuf) == 0) + continue; /* msg_fatal("config variable %s: host not found: %s", + VAR_INET_INTERFACES, hbuf); */ + } + freeaddrinfo(res0); +#else + if (inet_addr_host(addr_list, "0.0.0.0") == 0) + msg_fatal("config variable %s: host not found: %s", + VAR_INET_INTERFACES, "0.0.0.0"); +#endif +} + +/* wildcard_inet_addr_list - return list of addresses */ + +INET_ADDR_LIST *wildcard_inet_addr_list(int addr_family) +{ + if (addr_list.used == 0) + wildcard_inet_addr_init(&addr_list, addr_family); + + return (&addr_list); +} diff -Pur postfix-2.1.5/src/global/wildcard_inet_addr.h postfix-2.1.5-ti1.25/src/global/wildcard_inet_addr.h --- postfix-2.1.5/src/global/wildcard_inet_addr.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/global/wildcard_inet_addr.h Mon Sep 20 15:01:57 2004 @@ -0,0 +1,36 @@ +#ifndef _WILDCARD_INET_ADDR_H_INCLUDED_ +#define _WILDCARD_INET_ADDR_H_INCLUDED_ + +/*++ +/* NAME +/* wildcard_inet_addr_list 3h +/* SUMMARY +/* grab the list of wildcard IP addresses. +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf +/*--*/ + + /* + * System library. + */ +#include +#ifdef INET6 +#include +#endif + + /* + * External interface. + */ +extern struct INET_ADDR_LIST *wildcard_inet_addr_list(int); + +/* LICENSE +/* .ad +/* .fi +/* foo +/* AUTHOR(S) +/* Jun-ichiro itojun Hagino +/*--*/ + +#endif diff -Pur postfix-2.1.5/src/lmtp/lmtp.c postfix-2.1.5-ti1.25/src/lmtp/lmtp.c --- postfix-2.1.5/src/lmtp/lmtp.c Sun Jun 20 01:06:39 2004 +++ postfix-2.1.5-ti1.25/src/lmtp/lmtp.c Mon Sep 20 15:01:57 2004 @@ -196,6 +196,12 @@ /* .IP "\fBsyslog_name (postfix)\fR" /* The mail system name that is prepended to the process name in syslog /* records, so that "smtpd" becomes, for example, "postfix/smtpd". +/* .IP \fBlmtp_bind_address\fR +/* Numerical source network address (IPv4) to bind to when making +/* a connection. +/* .IP \fBlmtp_bind_address6\fR +/* Numerical source network address (IPv6) to bind to when making +/* a connection. /* SEE ALSO /* bounce(8), delivery status reports /* qmgr(8), queue manager @@ -293,6 +299,8 @@ char *var_lmtp_sasl_passwd; bool var_lmtp_sasl_enable; bool var_lmtp_send_xforward; +char *var_lmtp_bind_addr; +char *var_lmtp_bind_addr6; /* * Global variables. @@ -554,6 +562,8 @@ VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0, VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_lmtp_sasl_opts, 0, 0, + VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_lmtp_bind_addr, 0, 0, + VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_lmtp_bind_addr6, 0, 0, 0, }; static CONFIG_INT_TABLE int_table[] = { diff -Pur postfix-2.1.5/src/lmtp/lmtp_addr.c postfix-2.1.5-ti1.25/src/lmtp/lmtp_addr.c --- postfix-2.1.5/src/lmtp/lmtp_addr.c Mon Nov 20 19:05:33 2000 +++ postfix-2.1.5-ti1.25/src/lmtp/lmtp_addr.c Mon Sep 20 15:01:57 2004 @@ -166,7 +166,11 @@ /* * Append the addresses for this host to the address list. */ +#ifdef INET6 + switch (dns_lookup_types(host, RES_DEFNAMES, &addr, (VSTRING *) 0, why, T_AAAA, T_A, NULL)) { +#else switch (dns_lookup(host, T_A, RES_DEFNAMES, &addr, (VSTRING *) 0, why)) { +#endif case DNS_OK: for (rr = addr; rr; rr = rr->next) rr->pref = pref; diff -Pur postfix-2.1.5/src/lmtp/lmtp_connect.c postfix-2.1.5-ti1.25/src/lmtp/lmtp_connect.c --- postfix-2.1.5/src/lmtp/lmtp_connect.c Sat Sep 13 02:05:07 2003 +++ postfix-2.1.5-ti1.25/src/lmtp/lmtp_connect.c Mon Sep 20 15:01:57 2004 @@ -94,16 +94,23 @@ #include #include #include +#include /* Global library. */ #include #include +#include /* DNS library. */ #include +#ifdef INET6 +#define GAI_STRERROR(error) \ + ((error == EAI_SYSTEM) ? strerror(errno) : gai_strerror(error)) +#endif + /* Application-specific. */ #include "lmtp.h" @@ -162,19 +169,221 @@ addr, addr, destination, why)); } +/* lmtp_force_bind: bind() address */ + +static void lmtp_force_bind(const char *bind_addr, + const char *bind_var, + int sock, + int af) +{ + /* + * If the bind() call fails, this is considered a non-fatal error. + * All address conversion errors are fatal. + */ + char *myname = "lmtp_force_bind"; +#ifdef INET6 + char hbuf[NI_MAXHOST]; + int aierr; + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + snprintf(hbuf, sizeof(hbuf), "%s", bind_addr); + aierr = getaddrinfo(hbuf, NULL, &hints, &res); + if (aierr == EAI_NONAME) + msg_fatal("%s: bad %s parameter: \"%s\"", + myname, bind_var, bind_addr); + if (aierr != 0) { + if (msg_verbose) + msg_warn("%s: getaddrinfo(%s): %s", + myname, hbuf, GAI_STRERROR(aierr)); + return; + } + aierr = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); + if (aierr != 0) { + msg_warn("%s: getnameinfo(): %s", + myname, GAI_STRERROR(aierr)); + freeaddrinfo(res); + return; + } + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbuf); + else if (msg_verbose) + msg_info("%s: bind %s", myname, hbuf); + freeaddrinfo(res); +#else /* INET6 */ + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif + sin.sin_addr.s_addr = inet_addr(bind_addr); + if (sin.sin_addr.s_addr == INADDR_NONE) { + msg_fatal("%s: bad %s parameter: \"%s\"", + myname, bind_var, bind_addr); + return; + } + if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); + else if (msg_verbose) + msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); +#endif /* INET6 */ +} + +/* lmtp_virtual_bind - bind() when acting as virtual host */ + +static void lmtp_virtual_bind(int sock, int af) +{ + char *myname = "lmtp_virtual_bind"; + INET_ADDR_LIST *addr_list; + int count; + +#ifdef INET6 + int i; + char hbuf[NI_MAXHOST]; + int aierr; + struct sockaddr *sa; + struct addrinfo hints, *loopback = NULL, *res = NULL; + + /* + * Check whether we are acting as a virtual host + */ + count = 0; + addr_list = own_inet_addr_list(); + for (i = 0; count < 2 && i < addr_list->used; i++) + if (((struct sockaddr *)&addr_list->addrs[i])->sa_family == af) + count++; + if (count != 1) + return; + + /* + * Bind the source address. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + aierr = getaddrinfo(NULL, "0", &hints, &loopback); + if (aierr != 0) { + loopback = NULL; + msg_warn("%s: getaddrinfo(\"0\"): %s", + myname, GAI_STRERROR(aierr)); + } + + sa = (struct sockaddr *)&addr_list->addrs[i - 1]; + aierr = getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); + if (aierr != 0) + msg_fatal("%s: getnameinfo() (AF=%d): %s", + myname, af, GAI_STRERROR(aierr)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; + aierr = getaddrinfo(hbuf, NULL, &hints, &res); + if (aierr != 0) + msg_fatal("%s: getaddrinfo(\"%s\"): %s", + myname, hbuf, GAI_STRERROR(aierr)); + + if (res->ai_addrlen != loopback->ai_addrlen + || memcmp(res->ai_addr, loopback->ai_addr, res->ai_addrlen) != 0) { + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbuf); + else if (msg_verbose) + msg_info("%s: bind %s", myname, hbuf); + } else if (msg_verbose) { + msg_info("%s: not calling bind(): unusable source " + "address from \"%s\"", myname, hbuf); + } + if (res) + freeaddrinfo(res); + if (loopback) + freeaddrinfo(loopback); + +#else /* INET6 */ + + struct sockaddr_in sin; + unsigned long inaddr; /*XXX BAD!*/ + + /* + * Check whether we are acting as a virtual host + */ + addr_list = own_inet_addr_list(); + count = addr_list->used; + if (count != 1) + return; + + /* + * Bind the source address. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif + memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); + inaddr = (unsigned long)ntohl(sin.sin_addr.s_addr); + if (!IN_CLASSA(inaddr) + || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { + if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) + msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); + else if (msg_verbose) + msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); + } +#endif /* INET6 */ +} + /* lmtp_connect_addr - connect to explicit address */ static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port, const char *destination, VSTRING *why) { char *myname = "lmtp_connect_addr"; - struct sockaddr_in sin; - int sock; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; +#endif + struct sockaddr *sa; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + SOCKADDR_SIZE salen; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; +#endif + int sock = -1; + INET_ADDR_LIST *addr_list; + char *bind_addr; + char *bind_var; +#ifdef INET6 + char *addr6_ptr = NULL; +#endif + + sa = (struct sockaddr *)&ss; + sin = (struct sockaddr_in *)&ss; +#ifdef INET6 + sin6 = (struct sockaddr_in6 *)&ss; +#endif /* * Sanity checks. */ - if (addr->data_len > sizeof(sin.sin_addr)) { +#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); lmtp_errno = LMTP_RETRY; return (0); @@ -183,25 +392,93 @@ /* * Initialize. */ - memset((char *) &sin, 0, sizeof(sin)); - sin.sin_family = AF_INET; + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + bind_addr = ""; + bind_var = VAR_LMTP_BIND_ADDR6; + if (*var_lmtp_bind_addr6) { + addr6_ptr = mystrdup(var_lmtp_bind_addr6); + if (*addr6_ptr == '[' && addr6_ptr[strlen(addr6_ptr) - 1] == ']') { + addr6_ptr[strlen(addr6_ptr) - 1] = 0; + bind_addr = addr6_ptr + 1; + } else { + msg_warn("%s: skip incorrectly bracketed IPv6 address in %s", + myname, VAR_LMTP_BIND_ADDR6); + } + } + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + break; +#endif + default: /* T_A: */ + bind_addr = var_lmtp_bind_addr; + bind_var = VAR_SMTP_BIND_ADDR; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + salen = sizeof(*sin); + break; + }; +#ifdef HAS_SALEN + sa->sa_len = salen; +#endif - if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) + if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) msg_fatal("%s: socket: %m", myname); /* + * Allow the sysadmin to specify the source address + */ + + if (bind_addr && *bind_addr) { + lmtp_force_bind(bind_addr, bind_var, sock, sa->sa_family); +#ifdef INET6 + if (addr6_ptr) + myfree(addr6_ptr); +#endif + } else { + /* + * When running as a virtual host, bind to the virtual interface so that + * the mail appears to come from the "right" machine address. + */ + lmtp_virtual_bind(sock, sa->sa_family); + } + + /* * Connect to the LMTP server. */ - sin.sin_port = port; - memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr)); + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + /* XXX scope-unfriendly */ + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_port = port; + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); + inet_ntop(AF_INET6, &sin6->sin6_addr, hbuf, sizeof(hbuf)); + break; +#endif + default: /* T_A: */ + memset(sin, 0, sizeof(*sin)); + sin->sin_port = port; + sin->sin_family = AF_INET; + salen = sizeof(*sin); + memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); + inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); + break; + } +#ifdef HAS_SA_LEN + sa->sa_len = salen; +#endif if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", - myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); + myname, addr->name, hbuf, ntohs(port)); - return (lmtp_connect_sock(sock, (struct sockaddr *) & sin, sizeof(sin), - addr->name, inet_ntoa(sin.sin_addr), - destination, why)); + return (lmtp_connect_sock(sock, (struct sockaddr *)sa, salen, + addr->name, hbuf, destination, why)); } /* lmtp_connect_sock - connect a socket over some transport */ diff -Pur postfix-2.1.5/src/master/master_ent.c postfix-2.1.5-ti1.25/src/master/master_ent.c --- postfix-2.1.5/src/master/master_ent.c Wed Nov 26 16:52:56 2003 +++ postfix-2.1.5-ti1.25/src/master/master_ent.c Mon Sep 20 15:01:57 2004 @@ -86,6 +86,10 @@ #include #include #include +#include +#ifdef INET6 +#include +#endif /* Global library. */ @@ -235,6 +239,7 @@ char *bufp; char *atmp; static char *saved_interfaces = 0; + int af; if (master_fp == 0) msg_panic("get_master_ent: config file not open"); @@ -308,9 +313,14 @@ VSTREAM_PATH(master_fp), master_line, host); inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; - } else if (strcasecmp(saved_interfaces, DEF_INET_INTERFACES) == 0) { + } else if ((af = inet_interfaces_to_af (saved_interfaces)) > -1) { +#ifdef INET6 + MASTER_INET_ADDRLIST(serv) = wildcard_inet_addr_list(af); + serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; +#else MASTER_INET_ADDRLIST(serv) = 0; /* wild-card */ serv->listen_fd_count = 1; +#endif } else { MASTER_INET_ADDRLIST(serv) = own_inet_addr_list(); /* virtual */ inet_addr_list_uniq(MASTER_INET_ADDRLIST(serv)); diff -Pur postfix-2.1.5/src/master/master_listen.c postfix-2.1.5-ti1.25/src/master/master_listen.c --- postfix-2.1.5/src/master/master_listen.c Tue May 1 00:47:57 2001 +++ postfix-2.1.5-ti1.25/src/master/master_listen.c Mon Sep 20 15:01:57 2004 @@ -64,13 +64,22 @@ #include "master.h" +#ifdef INET6 +#include +#include +#endif + /* master_listen_init - enable connection requests */ void master_listen_init(MASTER_SERV *serv) { char *myname = "master_listen_init"; char *end_point; - int n; + int n,m,tmpfd; +#ifdef INET6 + char hbuf[NI_MAXHOST]; + SOCKADDR_SIZE salen; +#endif /* * Find out what transport we should use, then create one or more @@ -111,18 +120,31 @@ serv->listen_fd[0] = inet_listen(MASTER_INET_PORT(serv), serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING); + serv->max_proc : var_proc_limit, NON_BLOCKING, 1); close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC); } else { /* virtual or host:port */ - for (n = 0; n < serv->listen_fd_count; n++) { + for (m = n = 0; n < serv->listen_fd_count; n++) { +#ifdef INET6 + if (getnameinfo((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n], + SA_LEN((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n]), + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) { + strncpy(hbuf, "?????", sizeof(hbuf)); + } + end_point = concatenate(hbuf, ":", MASTER_INET_PORT(serv), (char *) 0); +#else end_point = concatenate(inet_ntoa(MASTER_INET_ADDRLIST(serv)->addrs[n]), ":", MASTER_INET_PORT(serv), (char *) 0); - serv->listen_fd[n] +#endif + tmpfd = inet_listen(end_point, serv->max_proc > var_proc_limit ? - serv->max_proc : var_proc_limit, NON_BLOCKING); - close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC); + serv->max_proc : var_proc_limit, NON_BLOCKING, 0); + if (tmpfd >= 0) { + serv->listen_fd[m] = tmpfd; + close_on_exec(serv->listen_fd[m++], CLOSE_ON_EXEC); + } myfree(end_point); } + serv->listen_fd_count=m; } break; default: diff -Pur postfix-2.1.5/src/qmqpd/qmqpd_peer.c postfix-2.1.5-ti1.25/src/qmqpd/qmqpd_peer.c --- postfix-2.1.5/src/qmqpd/qmqpd_peer.c Sat Dec 13 17:31:59 2003 +++ postfix-2.1.5-ti1.25/src/qmqpd/qmqpd_peer.c Mon Sep 20 15:01:57 2004 @@ -70,16 +70,23 @@ ) #endif +#ifdef INET6 +#define GAI_STRERROR(error) \ + ((error = EAI_SYSTEM) ? gai_strerror(error) : strerror(errno)) +#endif + /* Utility library. */ #include #include #include #include +#ifdef INET6 +#include /* for NI_WITHSCOPEID */ +#endif /* Global library. */ - /* Application-specific. */ #include "qmqpd.h" @@ -88,16 +95,24 @@ void qmqpd_peer_init(QMQPD_STATE *state) { - struct sockaddr_in sin; - SOCKADDR_SIZE len = sizeof(sin); + char *myname = "qmqpd_peer_init"; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; + struct in_addr *in; struct hostent *hp; - int i; +#endif + struct sockaddr *sa; + SOCKADDR_SIZE len; + + sa = (struct sockaddr *)&ss; + len = sizeof(ss); /* * Look up the peer address information. */ - if (getpeername(vstream_fileno(state->client), - (struct sockaddr *) & sin, &len) >= 0) { + if (getpeername(vstream_fileno(state->client), sa, &len) >= 0) { errno = 0; } @@ -112,16 +127,71 @@ /* * Look up and "verify" the client hostname. */ - else if (errno == 0 && sin.sin_family == AF_INET) { - state->addr = mystrdup(inet_ntoa(sin.sin_addr)); - hp = gethostbyaddr((char *) &(sin.sin_addr), - sizeof(sin.sin_addr), AF_INET); - if (hp == 0) { + else if (errno == 0 && (sa->sa_family == AF_INET +#ifdef INET6 + || sa->sa_family == AF_INET6 +#endif + )) { +#ifdef INET6 + char hbuf[NI_MAXHOST]; + char abuf[NI_MAXHOST]; + char rabuf[NI_MAXHOST]; + struct addrinfo hints, *res0 = NULL, *res; + char *colonp; +#else + char abuf[sizeof("255.255.255.255") + 1]; + char *hbuf; +#endif + int error = -1; + +#ifdef INET6 + error = getnameinfo(sa, len, abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + if (error) + msg_fatal("%s: numeric getnameinfo lookup for peer: error %s", + myname, GAI_STRERROR(error)); + /* + * Convert IPv4-mapped IPv6 address to 'true' IPv4 address + * early on. We have no need for the mapped form in logging + * or access checks. + */ + if (sa->sa_family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr) + && (colonp = strrchr(abuf, ':')) != NULL) { + if (msg_verbose > 1) + msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", + myname, abuf, colonp + 1); + state->addr = mystrdup(colonp + 1); + } else { + state->addr = mystrdup(abuf); + } + + error = getnameinfo(sa, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD); +#else + in = &((struct sockaddr_in *)sa)->sin_addr; + inet_ntop(AF_INET, in, abuf, sizeof(abuf)); + state->addr = mystrdup(abuf); + hbuf = NULL; + hp = gethostbyaddr((char *)in, sizeof(*in), AF_INET); + if (hp) { + error = 0; + hbuf = mystrdup(hp->h_name); + state->name = mystrdup(CLIENT_ATTR_UNKNOWN); + } else { + error = 1; + } +#endif + if (error) { state->name = mystrdup(CLIENT_ATTR_UNKNOWN); - } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { +#ifdef INET6 + if (error != EAI_NONAME) + msg_warn("%s: getnameinfo(%s,,,,,,NI_NAMEREQD) error %s", + myname, abuf, GAI_STRERROR(error)); +#endif + } else if (!valid_hostname(hbuf, DONT_GRIPE)) { state->name = mystrdup(CLIENT_ATTR_UNKNOWN); } else { - state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ + state->name = mystrdup(hbuf); /* * Reject the hostname if it does not list the peer address. @@ -131,16 +201,52 @@ state->name = mystrdup(CLIENT_ATTR_UNKNOWN); \ } +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(state->name, NULL, &hints, &res0); + if (error) { + msg_warn("%s: hostname %s verification failed: %s", + state->addr, state->name, GAI_STRERROR(error)); + REJECT_PEER_NAME(state); + } else { + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != sa->sa_family) + continue; + error = getnameinfo(res->ai_addr, res->ai_addrlen, + rabuf, sizeof(rabuf), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + if (error) { + msg_warn("%s: %s: hostname %s verification failed: %s", + myname, state->addr, state->name, + GAI_STRERROR(error)); + REJECT_PEER_NAME(state); + break; + } + if (strcmp(state->addr, rabuf) == 0) + break; /* keep peer name */ + } + if (res == NULL) { + msg_warn("%s: %s: address not listed for hostname %s", + myname, state->addr, state->name); + REJECT_PEER_NAME(state); + } + } + if (res0) + freeaddrinfo(res0); +#else hp = gethostbyname(state->name); /* clobbers hp->name!! */ if (hp == 0) { msg_warn("%s: hostname %s verification failed: %s", state->addr, state->name, HSTRERROR(h_errno)); REJECT_PEER_NAME(state); - } else if (hp->h_length != sizeof(sin.sin_addr)) { + } else if (hp->h_length != sizeof(*in)) { msg_warn("%s: hostname %s verification failed: bad address size %d", state->addr, state->name, hp->h_length); REJECT_PEER_NAME(state); } else { + int i; for (i = 0; /* void */ ; i++) { if (hp->h_addr_list[i] == 0) { msg_warn("%s: address not listed for hostname %s", @@ -148,12 +254,12 @@ REJECT_PEER_NAME(state); break; } - if (memcmp(hp->h_addr_list[i], - (char *) &sin.sin_addr, - sizeof(sin.sin_addr)) == 0) + if (memcmp(hp->h_addr_list[i], (char *)in, + sizeof(*in)) == 0) break; /* keep peer name */ } } +#endif } } diff -Pur postfix-2.1.5/src/smtp/Makefile.in postfix-2.1.5-ti1.25/src/smtp/Makefile.in --- postfix-2.1.5/src/smtp/Makefile.in Thu Apr 22 21:37:45 2004 +++ postfix-2.1.5-ti1.25/src/smtp/Makefile.in Mon Sep 20 15:01:57 2004 @@ -77,6 +77,7 @@ smtp.o: ../../include/debug_peer.h smtp.o: ../../include/flush_clnt.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 @@ -96,6 +97,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 @@ -116,6 +118,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 @@ -142,6 +145,8 @@ smtp_connect.o: ../../include/mail_error.h smtp_connect.o: ../../include/name_mask.h smtp_connect.o: ../../include/dns.h +smtp_connect.o: ../../include/get_port.h +smtp_connect.o: ../../include/pfixtls.h smtp_connect.o: smtp.h smtp_connect.o: ../../include/argv.h smtp_connect.o: smtp_addr.h @@ -174,6 +179,7 @@ smtp_proto.o: ../../include/attr.h smtp_proto.o: ../../include/mime_state.h smtp_proto.o: ../../include/header_opts.h +smtp_proto.o: ../../include/pfixtls.h smtp_proto.o: smtp.h smtp_proto.o: ../../include/argv.h smtp_proto.o: smtp_sasl.h @@ -231,9 +237,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 @@ -243,6 +252,7 @@ smtp_state.o: ../../include/mail_conf.h smtp_state.o: ../../include/mime_state.h smtp_state.o: ../../include/header_opts.h +smtp_state.o: ../../include/pfixtls.h smtp_state.o: smtp.h smtp_state.o: ../../include/argv.h smtp_state.o: ../../include/deliver_request.h @@ -264,6 +274,7 @@ smtp_trouble.o: ../../include/defer.h smtp_trouble.o: ../../include/mail_error.h smtp_trouble.o: ../../include/name_mask.h +smtp_trouble.o: ../../include/pfixtls.h smtp_trouble.o: smtp.h smtp_trouble.o: ../../include/argv.h smtp_unalias.o: smtp_unalias.c @@ -278,3 +289,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 -Pur postfix-2.1.5/src/smtp/smtp.c postfix-2.1.5-ti1.25/src/smtp/smtp.c --- postfix-2.1.5/src/smtp/smtp.c Wed Apr 14 16:25:42 2004 +++ postfix-2.1.5-ti1.25/src/smtp/smtp.c Mon Sep 20 15:01:57 2004 @@ -89,6 +89,12 @@ /* not try again later). /* .IP "\fBsmtp_skip_quit_response (yes)\fR" /* Do not wait for the response to the SMTP QUIT command. +/* .IP \fBsmtp_bind_address\fR +/* Numerical source network address (IPv4) to bind to when making +/* a connection. +/* .IP \fBsmtp_bind_address6\fR +/* Numerical source network address (IPv6) to bind to when making +/* a connection. /* .PP /* Available in Postfix version 2.0 and earlier: /* .IP "\fBsmtp_skip_4xx_greeting (yes)\fR" @@ -284,6 +290,7 @@ #include #include #include +#include /* Single server skeleton. */ @@ -322,6 +329,7 @@ char *var_smtp_sasl_passwd; bool var_smtp_sasl_enable; char *var_smtp_bind_addr; +char *var_smtp_bind_addr6; bool var_smtp_rand_addr; int var_smtp_pix_thresh; int var_smtp_pix_delay; @@ -333,6 +341,17 @@ bool var_smtp_send_xforward; int var_smtp_mxaddr_limit; int var_smtp_mxsess_limit; +bool var_smtp_use_tls; +bool var_smtp_enforce_tls; +char *var_smtp_tls_per_site; +#ifdef USE_SSL +int var_smtp_starttls_tmout; +char *var_smtp_sasl_tls_opts; +char *var_smtp_sasl_tls_verified_opts; +bool var_smtp_tls_enforce_peername; +int var_smtp_tls_scert_vd; +bool var_smtp_tls_note_starttls_offer; +#endif /* * Global variables. smtp_errno is set by the address lookup routines and by @@ -453,6 +472,16 @@ 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 + */ + if (var_smtp_use_tls || var_smtp_enforce_tls || var_smtp_tls_per_site[0]) +#ifdef USE_SSL + pfixtls_init_clientengine(var_smtp_tls_scert_vd); +#else + msg_warn("TLS has been selected, but TLS support is not compiled in"); +#endif + smtp_tls_list_init(); /* * Flush client. @@ -493,9 +522,15 @@ VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, 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, +#ifdef USE_SSL + VAR_SMTP_SASL_TLS_OPTS, DEF_SMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0, + VAR_SMTP_SASL_TLSV_OPTS, DEF_SMTP_SASL_TLSV_OPTS, &var_smtp_sasl_tls_verified_opts, 0, 0, +#endif VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0, + VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0, VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0, VAR_SMTP_HOST_LOOKUP, DEF_SMTP_HOST_LOOKUP, &var_smtp_host_lookup, 1, 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[] = { @@ -511,12 +546,18 @@ VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0, VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0, VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0, +#ifdef USE_SSL + VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0, +#endif 0, }; static CONFIG_INT_TABLE int_table[] = { VAR_SMTP_LINE_LIMIT, DEF_SMTP_LINE_LIMIT, &var_smtp_line_limit, 0, 0, VAR_SMTP_MXADDR_LIMIT, DEF_SMTP_MXADDR_LIMIT, &var_smtp_mxaddr_limit, 0, 0, VAR_SMTP_MXSESS_LIMIT, DEF_SMTP_MXSESS_LIMIT, &var_smtp_mxsess_limit, 0, 0, +#ifdef USE_SSL + VAR_SMTP_TLS_SCERT_VD, DEF_SMTP_TLS_SCERT_VD, &var_smtp_tls_scert_vd, 0, 0, +#endif 0, }; static CONFIG_BOOL_TABLE bool_table[] = { @@ -530,6 +571,12 @@ VAR_SMTP_QUOTE_821_ENV, DEF_SMTP_QUOTE_821_ENV, &var_smtp_quote_821_env, VAR_SMTP_DEFER_MXADDR, DEF_SMTP_DEFER_MXADDR, &var_smtp_defer_mxaddr, VAR_SMTP_SEND_XFORWARD, DEF_SMTP_SEND_XFORWARD, &var_smtp_send_xforward, + VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls, + VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls, +#ifdef USE_SSL + 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, +#endif 0, }; diff -Pur postfix-2.1.5/src/smtp/smtp.h postfix-2.1.5-ti1.25/src/smtp/smtp.h --- postfix-2.1.5/src/smtp/smtp.h Fri Dec 26 20:17:29 2003 +++ postfix-2.1.5-ti1.25/src/smtp/smtp.h Mon Sep 20 15:01:57 2004 @@ -27,6 +27,7 @@ * Global library. */ #include +#include /* * State information associated with each SMTP delivery. We're bundling the @@ -113,9 +114,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 -Pur postfix-2.1.5/src/smtp/smtp_addr.c postfix-2.1.5-ti1.25/src/smtp/smtp_addr.c --- postfix-2.1.5/src/smtp/smtp_addr.c Wed Jul 14 18:49:45 2004 +++ postfix-2.1.5-ti1.25/src/smtp/smtp_addr.c Mon Sep 20 15:17:31 2004 @@ -46,11 +46,11 @@ /* /* All routines either return a DNS_RR pointer, or return a null /* pointer and set the \fIsmtp_errno\fR global variable accordingly: -/* .IP SMTP_RETRY +/* .IP SMTP_ERR_RETRY /* The request failed due to a soft error, and should be retried later. -/* .IP SMTP_FAIL +/* .IP SMTP_ERR_FAIL /* The request attempt failed due to a hard error. -/* .IP SMTP_LOOP +/* .IP SMTP_ERR_LOOP /* The local machine is the best mail exchanger. /* .PP /* In addition, a textual description of the problem is made available @@ -132,18 +132,74 @@ static void smtp_print_addr(char *what, DNS_RR *addr_list) { DNS_RR *addr; - struct in_addr in_addr; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; +#endif + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; + char hbuf[NI_MAXHOST]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; +#endif msg_info("begin %s address list", what); for (addr = addr_list; addr; addr = addr->next) { - if (addr->data_len > sizeof(addr)) { - msg_warn("skipping address length %d", addr->data_len); - } else { - memcpy((char *) &in_addr, addr->data, sizeof(in_addr)); - msg_info("pref %4d host %s/%s", - addr->pref, addr->name, - inet_ntoa(in_addr)); + if ( +#ifdef INET6 + addr->class && addr->class != C_IN +#else + addr->class != C_IN +#endif + ) { + msg_warn("skipping unsupported address (class=%u)", addr->class); + continue; + } + switch (addr->type) { + case T_A: + if (addr->data_len != sizeof(sin->sin_addr)) { + msg_warn("skipping invalid address (AAAA, len=%u)", + addr->data_len); + continue; + } + sin = (struct sockaddr_in *)&ss; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin->sin_len = sizeof(*sin); +#endif + memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); + break; +#ifdef INET6 + case T_AAAA: + if (addr->data_len != sizeof(sin6->sin6_addr)) { + msg_warn("skipping invalid address (AAAA, len=%u)", + addr->data_len); + continue; + } + sin6 = (struct sockaddr_in6 *)&ss; + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; +#ifdef HAS_SA_LEN + sin6->sin6_len = sizeof(*sin6); +#endif + memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); + break; +#endif + default: + msg_warn("skipping unsupported address (type=%u)", addr->type); + continue; } + +#ifdef INET6 + (void)getnameinfo((struct sockaddr *)&ss, SS_LEN(ss), + hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); +#else + (void)inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); +#endif + msg_info("pref %4d host %s/%s", addr->pref, addr->name, hbuf); } msg_info("end %s address list", what); } @@ -153,15 +209,23 @@ static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why) { char *myname = "smtp_addr_one"; +#ifndef INET6 struct in_addr inaddr; - DNS_FIXED fixed; DNS_RR *addr = 0; DNS_RR *rr; struct hostent *hp; +#else + struct addrinfo hints, *res0, *res; + int error = -1; + char *addr; + size_t addrlen; +#endif + DNS_FIXED fixed; if (msg_verbose) msg_info("%s: host %s", myname, host); +#ifndef INET6 /* * Interpret a numerical name as an address. */ @@ -228,6 +292,49 @@ /* * No further alternatives for host lookup. */ +#else + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + switch (error) { + case EAI_AGAIN: + smtp_errno = SMTP_ERR_RETRY; + break; + default: + vstring_sprintf(why, "[%s]: %s", host,gai_strerror(error)); + if (smtp_errno != SMTP_ERR_RETRY) + smtp_errno = SMTP_ERR_FAIL; + break; + } + return (addr_list); + } + for (res = res0; res; res = res->ai_next) { + memset((char *) &fixed, 0, sizeof(fixed)); + switch (res->ai_family) { + case AF_INET6: + /* XXX not scope friendly */ + fixed.type = T_AAAA; + addr = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + addrlen = sizeof(struct in6_addr); + break; + case AF_INET: + fixed.type = T_A; + addr = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr; + addrlen = sizeof(struct in_addr); + break; + default: + msg_warn("%s: unknown address family %d for %s", + myname, res->ai_family, host); + continue; + } + addr_list = dns_rr_append(addr_list, + dns_rr_create(host, &fixed, pref, addr, addrlen)); + } + if (res0) + freeaddrinfo(res0); +#endif return (addr_list); } @@ -265,6 +372,9 @@ INET_ADDR_LIST *proxy; DNS_RR *addr; int i; +#ifdef INET6 + struct sockaddr *sa; +#endif #define INADDRP(x) ((struct in_addr *) (x)) @@ -276,23 +386,75 @@ /* * Find out if this mail system is listening on this address. */ - for (i = 0; i < self->used; i++) + for (i = 0; i < self->used; i++) { +#ifdef INET6 + sa = (struct sockaddr *)&self->addrs[i]; + switch(addr->type) { + case T_AAAA: + /* XXX scope */ + if (sa->sa_family != AF_INET6) + break; + if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr, + addr->data, sizeof(struct in6_addr)) != 0) + break; + if (msg_verbose) + msg_info("%s: found self at pref %d", myname, addr->pref); + return (addr); + case T_A: + if (sa->sa_family != AF_INET) + break; + if (memcmp(&((struct sockaddr_in *)sa)->sin_addr, + addr->data, sizeof(struct in_addr)) != 0) + break; + if (msg_verbose) + msg_info("%s: found self at pref %d", myname, addr->pref); + return(addr); + } +#else if (INADDRP(addr->data)->s_addr == self->addrs[i].s_addr) { if (msg_verbose) msg_info("%s: found self at pref %d", myname, addr->pref); return (addr); } +#endif + } /* * Find out if this mail system has a proxy listening on this * address. */ - for (i = 0; i < proxy->used; i++) + for (i = 0; i < proxy->used; i++) { +#ifdef INET6 + sa = (struct sockaddr *)&self->addrs[i]; + switch(addr->type) { + case T_AAAA: + /* XXX scope */ + if (sa->sa_family != AF_INET6) + break; + if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr, + addr->data, sizeof(struct in6_addr)) != 0) + break; + if (msg_verbose) + msg_info("%s: found proxy at pref %d", myname, addr->pref); + return (addr); + case T_A: + if (sa->sa_family != AF_INET) + break; + if (memcmp(&((struct sockaddr_in *)sa)->sin_addr, + addr->data, sizeof(struct in_addr)) != 0) + break; + if (msg_verbose) + msg_info("%s: found proxy at pref %d", myname, addr->pref); + return(addr); + } +#else if (INADDRP(addr->data)->s_addr == proxy->addrs[i].s_addr) { if (msg_verbose) msg_info("%s: found proxy at pref %d", myname, addr->pref); return (addr); } +#endif + } } /* @@ -333,6 +495,29 @@ return (a->pref - b->pref); } +#ifdef INET6 +static int smtp_compare_pref_aaaa_first(DNS_RR *a, DNS_RR *b) +{ + if (a->pref != b->pref) + return (a->pref - b->pref); + if (a->type == T_AAAA) + return -1; + else if (b->type == T_AAAA) + return 1; + return 0; +} + +static int smtp_compare_host_aaaa_first(DNS_RR *a, DNS_RR *b) +{ + if (a->type == b->type) + return 0; + if (a->type == T_AAAA) + return -1; + return 1; +} + +#endif + /* smtp_domain_addr - mail exchanger address lookup */ DNS_RR *smtp_domain_addr(char *name, int misc_flags, VSTRING *why) @@ -440,7 +625,11 @@ } if (addr_list && addr_list->next && var_smtp_rand_addr) { addr_list = dns_rr_shuffle(addr_list); +#ifdef INET6 + addr_list = dns_rr_sort(addr_list, smtp_compare_pref_aaaa_first); +#else addr_list = dns_rr_sort(addr_list, smtp_compare_pref); +#endif } break; case DNS_NOTFOUND: @@ -478,6 +667,10 @@ } if (addr_list && addr_list->next && var_smtp_rand_addr) addr_list = dns_rr_shuffle(addr_list); +#ifdef INET6 + if (addr_list && addr_list->next) + addr_list = dns_rr_sort(addr_list, smtp_compare_host_aaaa_first); +#endif if (msg_verbose) smtp_print_addr(host, addr_list); return (addr_list); diff -Pur postfix-2.1.5/src/smtp/smtp_connect.c postfix-2.1.5-ti1.25/src/smtp/smtp_connect.c --- postfix-2.1.5/src/smtp/smtp_connect.c Sat Jun 19 18:23:33 2004 +++ postfix-2.1.5-ti1.25/src/smtp/smtp_connect.c Mon Sep 20 15:01:57 2004 @@ -46,6 +46,7 @@ /* System library. */ #include +#include #include #include #include @@ -86,37 +87,244 @@ #include #include #include +#include /* DNS library. */ #include +#ifdef INET6 +#define GAI_STRERROR(error) \ + ((error == EAI_SYSTEM) ? strerror(errno) : gai_strerror(error)) +#endif + /* Application-specific. */ #include "smtp.h" #include "smtp_addr.h" +/* smtp_force_bind: bind() address */ + +static void smtp_force_bind(const char *bind_addr, + const char *bind_var, + int sock, + int af) +{ + /* + * If the bind() call fails, this is considered a non-fatal error. + * All address conversion errors are fatal. + */ + char *myname = "smtp_force_bind"; +#ifdef INET6 + char hbuf[NI_MAXHOST]; + int aierr; + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + snprintf(hbuf, sizeof(hbuf), "%s", bind_addr); + aierr = getaddrinfo(hbuf, NULL, &hints, &res); + if (aierr == EAI_NONAME) + msg_fatal("%s: bad %s parameter: \"%s\"", + myname, bind_var, bind_addr); + if (aierr != 0) { + if (msg_verbose) + msg_warn("%s: getaddrinfo(%s): %s", + myname, hbuf, GAI_STRERROR(aierr)); + return; + } + aierr = getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); + if (aierr != 0) { + msg_warn("%s: getnameinfo(): %s", + myname, GAI_STRERROR(aierr)); + freeaddrinfo(res); + return; + } + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbuf); + else if (msg_verbose) + msg_info("%s: bind %s", myname, hbuf); + freeaddrinfo(res); +#else /* INET6 */ + struct sockaddr_in sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif + sin.sin_addr.s_addr = inet_addr(bind_addr); + if (sin.sin_addr.s_addr == INADDR_NONE) { + msg_fatal("%s: bad %s parameter: \"%s\"", + myname, bind_var, bind_addr); + return; + } + if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) + msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); + else if (msg_verbose) + msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); +#endif /* INET6 */ +} + +/* smtp_virtual_bind - bind() when acting as virtual host */ + +static void smtp_virtual_bind(int sock, int af) +{ + char *myname = "smtp_virtual_bind"; + INET_ADDR_LIST *addr_list; + int count; + +#ifdef INET6 + int i, pos; + char hbuf[NI_MAXHOST]; + int aierr; + struct sockaddr *sa; + struct addrinfo hints, *loopback = NULL, *res = NULL; + + /* + * Check whether we are acting as a virtual host + */ + count = 0; + pos = 0; + addr_list = own_inet_addr_list(); + for (i = 0; count < 2 && i < addr_list->used; i++) + if (((struct sockaddr *)&addr_list->addrs[i])->sa_family == af) + count++, pos = i; + if (count != 1) + return; + + /* + * Bind the source address. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + aierr = getaddrinfo(NULL, "0", &hints, &loopback); + if (aierr != 0) { + loopback = NULL; + msg_warn("%s: getaddrinfo(\"0\"): %s", + myname, GAI_STRERROR(aierr)); + } + + sa = (struct sockaddr *)&addr_list->addrs[pos]; + aierr = getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST | NI_WITHSCOPEID); + if (aierr != 0) + msg_fatal("%s: getnameinfo() (AF=%d): %s", + myname, af, GAI_STRERROR(aierr)); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = af; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; + aierr = getaddrinfo(hbuf, NULL, &hints, &res); + if (aierr != 0) + msg_fatal("%s: getaddrinfo(\"%s\"): %s", + myname, hbuf, GAI_STRERROR(aierr)); + + if (res->ai_addrlen != loopback->ai_addrlen + || memcmp(res->ai_addr, loopback->ai_addr, res->ai_addrlen) != 0) { + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) + msg_warn("%s: bind %s: %m", myname, hbuf); + else if (msg_verbose) + msg_info("%s: bind %s", myname, hbuf); + } else if (msg_verbose) { + msg_info("%s: not calling bind(): unusable source " + "address from \"%s\"", myname, hbuf); + } + if (res) + freeaddrinfo(res); + if (loopback) + freeaddrinfo(loopback); + +#else /* INET6 */ + + struct sockaddr_in sin; + unsigned long inaddr; /*XXX BAD!*/ + + /* + * Check whether we are acting as a virtual host + */ + addr_list = own_inet_addr_list(); + count = addr_list->used; + if (count != 1) + return; + + /* + * Bind the source address. + */ + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif + memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); + inaddr = (unsigned long)ntohl(sin.sin_addr.s_addr); + if (!IN_CLASSA(inaddr) + || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { + if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) + msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); + else if (msg_verbose) + msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); + } +#endif /* INET6 */ +} + /* 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"; - struct sockaddr_in sin; - int sock; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; +#endif + struct sockaddr *sa; + struct sockaddr_in *sin; +#ifdef INET6 + struct sockaddr_in6 *sin6; +#endif + SOCKADDR_SIZE salen; +#ifdef INET6 + char hbuf[NI_MAXHOST]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; +#endif + int sock = -1; INET_ADDR_LIST *addr_list; int conn_stat; int saved_errno; VSTREAM *stream; int ch; - unsigned long inaddr; + char *bind_addr; + char *bind_var; +#ifdef INET6 + char *addr6_ptr = NULL; +#endif + + sa = (struct sockaddr *)&ss; + sin = (struct sockaddr_in *)&ss; +#ifdef INET6 + sin6 = (struct sockaddr_in6 *)&ss; +#endif smtp_errno = SMTP_ERR_NONE; /* Paranoia */ /* * Sanity checks. */ - if (addr->data_len > sizeof(sin.sin_addr)) { +#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_ERR_RETRY; return (0); @@ -125,65 +333,104 @@ /* * Initialize. */ - 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); - + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + bind_addr = ""; + bind_var = VAR_SMTP_BIND_ADDR6; + if (*var_smtp_bind_addr6) { + addr6_ptr = mystrdup(var_smtp_bind_addr6); + if (*addr6_ptr == '[' && addr6_ptr[strlen(addr6_ptr) - 1] == ']') { + addr6_ptr[strlen(addr6_ptr) - 1] = 0; + bind_addr = addr6_ptr + 1; + } else { + msg_warn("%s: skip incorrectly bracketed IPv6 address in %s", + myname, VAR_SMTP_BIND_ADDR6); + } + } + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + break; +#endif + default: /* T_A: */ + bind_addr = var_smtp_bind_addr; + bind_var = VAR_SMTP_BIND_ADDR; + memset(sin, 0, sizeof(*sin)); + sin->sin_family = AF_INET; + salen = sizeof(*sin); + break; + } +#ifdef HAS_SA_LEN + sa->sa_len = salen; +#endif + if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) { + msg_warn("%s: socket: %m", myname); + smtp_errno = SMTP_ERR_RETRY; + return (0); + } + /* * Allow the sysadmin to specify the source address, for example, as "-o * smtp_bind_address=x.x.x.x" in the master.cf file. */ - if (*var_smtp_bind_addr) { - sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr); - if (sin.sin_addr.s_addr == INADDR_NONE) - msg_fatal("%s: bad %s parameter: %s", - myname, VAR_SMTP_BIND_ADDR, var_smtp_bind_addr); - if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) - msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); - if (msg_verbose) - msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); - } - - /* - * When running as a virtual host, bind to the virtual interface so that - * the mail appears to come from the "right" machine address. - */ - else if ((addr_list = own_inet_addr_list())->used == 1) { - memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); - inaddr = ntohl(sin.sin_addr.s_addr); - if (!IN_CLASSA(inaddr) - || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { - if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) - msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); - if (msg_verbose) - msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); - } + if (bind_addr && *bind_addr) { + smtp_force_bind(bind_addr, bind_var, sock, sa->sa_family); +#ifdef INET6 + if (addr6_ptr) + myfree(addr6_ptr); +#endif + } else { + /* + * When running as a virtual host, bind to the virtual interface so that + * the mail appears to come from the "right" machine address. + */ + smtp_virtual_bind(sock, sa->sa_family); } /* * Connect to the SMTP server. */ - sin.sin_port = port; - memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr)); + switch (addr->type) { +#ifdef INET6 + case T_AAAA: + /* XXX scope unfriendly */ + memset(sin6, 0, sizeof(*sin6)); + sin6->sin6_port = port; + sin6->sin6_family = AF_INET6; + salen = sizeof(*sin6); + memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); + inet_ntop(AF_INET6, &sin6->sin6_addr, hbuf, sizeof(hbuf)); + break; +#endif + default: /* T_A */ + memset(sin, 0, sizeof(*sin)); + sin->sin_port = port; + sin->sin_family = AF_INET; + salen = sizeof(*sin); + memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); + inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); + break; + } +#ifdef HAS_SA_LEN + sa->sa_len = salen; +#endif if (msg_verbose) msg_info("%s: trying: %s[%s] port %d...", - myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); + myname, addr->name, hbuf, 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); + conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout); saved_errno = errno; non_blocking(sock, BLOCKING); errno = saved_errno; } else { - conn_stat = sane_connect(sock, (struct sockaddr *) & sin, sizeof(sin)); + conn_stat = sane_connect(sock, sa, salen); } if (conn_stat < 0) { vstring_sprintf(why, "connect to %s[%s]: %m", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_ERR_RETRY; close(sock); return (0); @@ -193,8 +440,8 @@ * Skip this host if it takes no action within some time limit. */ if (read_wait(sock, var_smtp_helo_tmout) < 0) { - vstring_sprintf(why, "connect to %s[%s]: read timeout", - addr->name, inet_ntoa(sin.sin_addr)); + vstring_sprintf(why, "connect to %s [%s]: read timeout", + addr->name, hbuf); smtp_errno = SMTP_ERR_RETRY; close(sock); return (0); @@ -206,13 +453,13 @@ stream = vstream_fdopen(sock, O_RDWR); if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { vstring_sprintf(why, "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting", - addr->name, inet_ntoa(sin.sin_addr)); + addr->name, hbuf); smtp_errno = SMTP_ERR_RETRY; vstream_fclose(stream); return (0); } vstream_ungetc(stream, ch); - return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr))); + return (smtp_session_alloc(dest, stream, addr->name, hbuf)); } /* smtp_parse_destination - parse destination */ @@ -247,6 +494,7 @@ msg_fatal("unknown service: %s/%s", service, protocol); *portp = sp->s_port; } + return (buf); } @@ -348,7 +596,7 @@ next = addr->next; if (++addr_count == var_smtp_mxaddr_limit) next = 0; - if ((state->session = smtp_connect_addr(addr, port, why)) != 0) { + if ((state->session = smtp_connect_addr(host, addr, port, why)) != 0) { state->features = 0; /* XXX should be SESSION info */ if (++sess_count == var_smtp_mxsess_limit) next = 0; diff -Pur postfix-2.1.5/src/smtp/smtp_proto.c postfix-2.1.5-ti1.25/src/smtp/smtp_proto.c --- postfix-2.1.5/src/smtp/smtp_proto.c Wed Apr 14 22:02:20 2004 +++ postfix-2.1.5-ti1.25/src/smtp/smtp_proto.c Mon Sep 20 15:01:57 2004 @@ -102,6 +102,7 @@ #include #include #include +#include /* Application-specific. */ @@ -184,6 +185,8 @@ XFORWARD_HELO, SMTP_FEATURE_XFORWARD_HELO, 0, 0, }; + int oldfeatures; + int rval; /* * Prepare for disaster. @@ -256,7 +259,8 @@ translit(resp->str, "\n", " "))); return (0); } - + 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 @@ -268,6 +272,7 @@ * MicroSoft implemented AUTH based on an old draft. */ 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) @@ -288,6 +293,8 @@ state->size_limit = off_cvt_string(word); } } + 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); @@ -307,6 +314,128 @@ msg_info("server features: 0x%x size %.0f", state->features, (double) state->size_limit); +#ifdef USE_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. + * 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")); + } + } + } 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; +#ifdef USE_SASL_AUTH + if (state->sasl_mechanism_list) { + myfree(state->sasl_mechanism_list); + state->sasl_mechanism_list = 0; + } +#endif + 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 -Pur postfix-2.1.5/src/smtp/smtp_session.c postfix-2.1.5-ti1.25/src/smtp/smtp_session.c --- postfix-2.1.5/src/smtp/smtp_session.c Mon Nov 20 19:06:05 2000 +++ postfix-2.1.5-ti1.25/src/smtp/smtp_session.c Mon Sep 20 15:01:57 2004 @@ -42,15 +42,40 @@ #include #include +#include +#include +#include + /* Application-specific. */ #include "smtp.h" +/* 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); +} + /* 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 +83,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 USE_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 && !recipient_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 && !recipient_dont_use) || host_use || recipient_use) + session->tls_use_tls = 1; +#endif + session->tls_info = tls_info_zero; return (session); } @@ -65,6 +145,11 @@ void smtp_session_free(SMTP_SESSION *session) { +#ifdef USE_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 -Pur postfix-2.1.5/src/smtp/smtp_unalias.c postfix-2.1.5-ti1.25/src/smtp/smtp_unalias.c --- postfix-2.1.5/src/smtp/smtp_unalias.c Thu Sep 28 19:06:09 2000 +++ postfix-2.1.5-ti1.25/src/smtp/smtp_unalias.c Mon Sep 20 15:01:57 2004 @@ -86,7 +86,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)); } diff -Pur postfix-2.1.5/src/smtpd/smtpd.c postfix-2.1.5-ti1.25/src/smtpd/smtpd.c --- postfix-2.1.5/src/smtpd/smtpd.c Sat Aug 14 00:28:41 2004 +++ postfix-2.1.5-ti1.25/src/smtpd/smtpd.c Mon Sep 20 15:01:57 2004 @@ -652,6 +652,7 @@ #include #endif #include +#include /* Single-threaded server skeleton. */ @@ -677,6 +678,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 */ @@ -759,7 +761,19 @@ int var_smtpd_crate_limit; int var_smtpd_cconn_limit; char *var_smtpd_hoggers; +#endif +bool var_smtpd_use_tls; +bool var_smtpd_enforce_tls; +bool var_smtpd_tls_wrappermode; +#ifdef USE_SSL +int var_smtpd_starttls_tmout; +bool var_smtpd_tls_auth_only; +bool var_smtpd_tls_ask_ccert; +bool var_smtpd_tls_req_ccert; +int var_smtpd_tls_ccert_vd; +bool var_smtpd_tls_received_header; +char *var_smtpd_sasl_tls_opts; #endif /* @@ -814,7 +828,7 @@ /* * This filter is applied after printable(). */ -#define NEUTER_CHARACTERS " <>()\\\";:@" +#define NEUTER_CHARACTERS " <>()\\\";@" #ifdef USE_SASL_AUTH @@ -943,11 +957,21 @@ if (var_disable_vrfy_cmd == 0) smtpd_chat_reply(state, "250-VRFY"); smtpd_chat_reply(state, "250-ETRN"); +#ifdef USE_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 && !sasl_client_exception(state)) { +#ifdef USE_SSL + if (!state->tls_auth_only || 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 USE_SSL + } +#endif } #endif if (namadr_list_match(verp_clients, state->name, state->addr)) @@ -1505,12 +1529,77 @@ state->rcpt_overshoot = 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 *err; char *start; + char *peer_CN; + char *issuer_CN; int len; int curr_rec_type; int prev_rec_type; @@ -1601,9 +1690,40 @@ */ if (!state->proxy || state->xforward.flags == 0) { out_fprintf(out_stream, REC_TYPE_NORM, - "Received: from %s (%s [%s])", + "Received: from %s (%s [%s%s])", state->helo_name ? state->helo_name : state->name, - state->name, state->addr); + state->name, state->addr_tag, state->addr); +#ifdef USE_SSL + if (var_smtpd_tls_received_header && state->tls_active) { + out_fprintf(out_stream, 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) + out_fprintf(out_stream, REC_TYPE_NORM, + "\t(Client CN \"%s\", Issuer \"%s\" (verified OK))", + peer_CN, issuer_CN); + else + out_fprintf(out_stream, REC_TYPE_NORM, + "\t(Client CN \"%s\", Issuer \"%s\" (not verified))", + peer_CN, issuer_CN); + myfree(issuer_CN); + myfree(peer_CN); + } + else if (var_smtpd_tls_ask_ccert) + out_fprintf(out_stream, REC_TYPE_NORM, + "\t(Client did not present a certificate)"); + else + out_fprintf(out_stream, REC_TYPE_NORM, + "\t(No client certificate requested)"); + } +#endif if (state->rcpt_count == 1 && state->recipient) { out_fprintf(out_stream, REC_TYPE_NORM, state->cleanup ? "\tby %s (%s) with %s id %s" : @@ -2310,6 +2430,90 @@ } } +static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) +{ + char *err; + +#ifdef USE_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); +#ifdef USE_SASL_AUTH + if (var_smtpd_sasl_enable) { + /* + * When TLS is enabled, another set of AUTH methods may be offered, + * for example plain text methods that would not be offered without + * encryption protection. Reconnect with a different set of options. + */ + smtpd_sasl_disconnect(state); + smtpd_sasl_connect(state, VAR_SMTPD_SASL_TLS_OPTS, + var_smtpd_sasl_tls_opts); + smtpd_sasl_auth_reset(state); + } +#endif + 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 USE_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 @@ -2328,6 +2532,10 @@ "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT, "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT, +#ifdef USE_SSL + "STARTTLS", starttls_cmd, 0, +#endif + #ifdef USE_SASL_AUTH "AUTH", smtpd_sasl_auth_cmd, 0, #endif @@ -2488,9 +2696,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++; @@ -2530,6 +2757,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) @@ -2562,6 +2790,58 @@ * machines. */ smtpd_state_init(&state, stream); + +#ifdef USE_SSL + if (SMTPD_STAND_ALONE((&state))) { + state.tls_use_tls = 0; + state.tls_enforce_tls = 0; + state.tls_auth_only = 0; + } + else { + 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; +#ifdef USE_SASL_AUTH + if (var_smtpd_sasl_enable) { + /* + * When TLS is enabled, another set of AUTH methods may be + * offered, for example plain text methods that would not be + * offered without encryption protection. Reconnect with a + * different set of options. + */ + smtpd_sasl_disconnect(&state); + smtpd_sasl_connect(&state, VAR_SMTPD_SASL_TLS_OPTS, + var_smtpd_sasl_tls_opts); + smtpd_sasl_auth_reset(&state); + } +#endif + } + if (var_smtpd_tls_auth_only || state.tls_enforce_tls) + state.tls_auth_only = 1; + } +#else + state.tls_use_tls = 0; + state.tls_enforce_tls = 0; + state.tls_auth_only = 0; +#endif + msg_info("connect from %s[%s]", state.name, state.addr); /* @@ -2611,7 +2891,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. @@ -2639,6 +2918,21 @@ msg_warn("%s is true, but SASL support is not compiled in", VAR_SMTPD_SASL_ENABLE); #endif + /* + * Keys can only be loaded when running with superuser permissions. + * When called from "sendmail -bs" this is not the case, but STARTTLS + * is not used in this scenario anyhow. + */ + if (geteuid() == 0) { + if (var_smtpd_use_tls || var_smtpd_enforce_tls + || var_smtpd_tls_wrappermode) +#ifdef USE_SSL + pfixtls_init_serverengine(var_smtpd_tls_ccert_vd, + var_smtpd_tls_ask_ccert); +#else + msg_warn("TLS has been selected but TLS support is not compiled in"); +#endif + } /* * flush client. @@ -2677,6 +2971,7 @@ if (var_smtpd_crate_limit || var_smtpd_cconn_limit) anvil_clnt = anvil_clnt_create(); #endif + } /* main - the main program */ @@ -2713,6 +3008,9 @@ VAR_SMTPD_CRATE_LIMIT, DEF_SMTPD_CRATE_LIMIT, &var_smtpd_crate_limit, 0, 0, VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0, #endif +#ifdef USE_SSL + VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0, +#endif 0, }; static CONFIG_TIME_TABLE time_table[] = { @@ -2723,6 +3021,9 @@ VAR_SMTPD_POLICY_TMOUT, DEF_SMTPD_POLICY_TMOUT, &var_smtpd_policy_tmout, 1, 0, VAR_SMTPD_POLICY_IDLE, DEF_SMTPD_POLICY_IDLE, &var_smtpd_policy_idle, 1, 0, VAR_SMTPD_POLICY_TTL, DEF_SMTPD_POLICY_TTL, &var_smtpd_policy_ttl, 1, 0, +#ifdef USE_SSL + VAR_SMTPD_STARTTLS_TMOUT, DEF_SMTPD_STARTTLS_TMOUT, &var_smtpd_starttls_tmout, 1, 0, +#endif 0, }; static CONFIG_BOOL_TABLE bool_table[] = { @@ -2736,6 +3037,15 @@ VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table, VAR_SMTPD_REJ_UNL_FROM, DEF_SMTPD_REJ_UNL_FROM, &var_smtpd_rej_unl_from, VAR_SMTPD_REJ_UNL_RCPT, DEF_SMTPD_REJ_UNL_RCPT, &var_smtpd_rej_unl_rcpt, + 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_WRAPPER, DEF_SMTPD_TLS_WRAPPER, &var_smtpd_tls_wrappermode, +#ifdef USE_SSL + VAR_SMTPD_TLS_AUTH_ONLY, DEF_SMTPD_TLS_AUTH_ONLY, &var_smtpd_tls_auth_only, + 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, +#endif 0, }; static CONFIG_STR_TABLE str_table[] = { @@ -2777,6 +3087,10 @@ #ifdef SNAPSHOT VAR_SMTPD_HOGGERS, DEF_SMTPD_HOGGERS, &var_smtpd_hoggers, 0, 0, #endif +#ifdef USE_SSL + VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_relay_ccerts, 0, 0, + VAR_SMTPD_SASL_TLS_OPTS, DEF_SMTPD_SASL_TLS_OPTS, &var_smtpd_sasl_tls_opts, 0, 0, +#endif 0, }; static CONFIG_RAW_TABLE raw_table[] = { @@ -2799,3 +3113,4 @@ MAIL_SERVER_POST_INIT, post_jail_init, 0); } + diff -Pur postfix-2.1.5/src/smtpd/smtpd.h postfix-2.1.5-ti1.25/src/smtpd/smtpd.h --- postfix-2.1.5/src/smtpd/smtpd.h Wed Apr 21 20:23:33 2004 +++ postfix-2.1.5-ti1.25/src/smtpd/smtpd.h Mon Sep 20 15:01:58 2004 @@ -32,6 +32,7 @@ * Global library. */ #include +#include /* * Variables that keep track of conversation state. There is only one SMTP @@ -62,6 +63,7 @@ time_t time; /* start of MAIL FROM transaction */ char *name; /* client hostname */ char *addr; /* client host address string */ + char *addr_tag; /* address family prefix */ char *namaddr; /* combined name and address */ int peer_code; /* 2=ok, 4=soft, 5=hard */ int error_count; /* reset after DOT */ @@ -136,6 +138,12 @@ * XFORWARD server state. */ SMTPD_XFORWARD_ATTR xforward; /* up-stream logging info */ + + int tls_active; + int tls_use_tls; + int tls_enforce_tls; + int tls_auth_only; + tls_info_t tls_info; } SMTPD_STATE; #define SMTPD_STATE_XFORWARD_INIT (1<<0) /* xforward preset done */ diff -Pur postfix-2.1.5/src/smtpd/smtpd_check.c postfix-2.1.5-ti1.25/src/smtpd/smtpd_check.c --- postfix-2.1.5/src/smtpd/smtpd_check.c Sun Aug 1 23:08:32 2004 +++ postfix-2.1.5-ti1.25/src/smtpd/smtpd_check.c Mon Sep 20 15:01:58 2004 @@ -151,6 +151,7 @@ #include #include #include +#include #ifdef STRCASECMP_IN_STRINGS_H #include @@ -185,6 +186,7 @@ #include #include #include +#include #include #include #include @@ -269,6 +271,9 @@ static DOMAIN_LIST *relay_domains; static NAMADR_LIST *mynetworks; static NAMADR_LIST *perm_mx_networks; +#ifdef USE_SSL +static MAPS *relay_ccerts; +#endif /* * How to do parent domain wildcard matching, if any. @@ -352,6 +357,8 @@ defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2)) #define DEFER_IF_REJECT3(state, class, fmt, a1, a2, a3) \ defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3)) +#define DEFER_IF_REJECT4(state, class, fmt, a1, a2, a3, a4) \ + defer_if(&(state)->defer_if_reject, (class), (fmt), (a1), (a2), (a3), (a4)) #define DEFER_IF_PERMIT2(state, class, fmt, a1, a2) do { \ if ((state)->warn_if_reject == 0) \ defer_if(&(state)->defer_if_permit, (class), (fmt), (a1), (a2)); \ @@ -563,6 +570,10 @@ perm_mx_networks = namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS), var_perm_mx_networks); +#ifdef USE_SSL + relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_relay_ccerts, + DICT_FLAG_LOCK); +#endif /* * Pre-parse and pre-open the recipient maps. @@ -1056,6 +1067,36 @@ static int permit_auth_destination(SMTPD_STATE *state, char *recipient); +/* permit_tls_clientcerts - OK/DUNNO for message relaying */ + +#ifdef USE_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, @@ -1196,8 +1237,16 @@ static int all_auth_mx_addr(SMTPD_STATE *state, char *host, const char *reply_name, const char *reply_class) { + size_t len; char *myname = "all_auth_mx_addr"; - struct in_addr addr; + char *addr; + struct in_addr addr4; +#ifdef INET6 + struct in6_addr addr6; + char hbuf[NI_MAXHOST]; +#else + char *hbuf; +#endif DNS_RR *rr; DNS_RR *addr_list; int dns_status; @@ -1214,7 +1263,9 @@ /* * Verify that all host addresses are within permit_mx_backup_networks. */ - dns_status = dns_lookup(host, T_A, 0, &addr_list, (VSTRING *) 0, (VSTRING *) 0); + dns_status = dns_lookup_types(host, 0, (DNS_RR **) &addr_list, + (VSTRING *) 0, + (VSTRING *) 0, RR_ADDR_TYPES, 0); if (dns_status != DNS_OK) { DEFER_IF_REJECT3(state, MAIL_ERROR_POLICY, "450 <%s>: %s rejected: Unable to look up host %s as mail exchanger", @@ -1222,16 +1273,28 @@ return (NOPE); } for (rr = addr_list; rr != 0; rr = rr->next) { - if (rr->data_len > sizeof(addr)) { +#ifdef INET6 + if (rr->type == T_AAAA) + len = sizeof(addr6), addr = (char *) &addr6; + else /* T_A */ +#endif + len = sizeof(addr4), addr = (char *) &addr4; + if (rr->data_len > len) { msg_warn("%s: skipping address length %d for host %s", state->queue_id, rr->data_len, host); continue; } - memcpy((char *) &addr, rr->data, sizeof(addr)); + memcpy(addr, rr->data, len); +#ifdef INET6 + inet_ntop(rr->type == T_AAAA ? AF_INET6 : AF_INET, + addr, hbuf, sizeof(hbuf)); +#else + hbuf = inet_ntoa(*(struct in_addr *)addr); +#endif if (msg_verbose) - msg_info("%s: checking: %s", myname, inet_ntoa(addr)); + msg_info("%s: checking: %s", myname, hbuf); - if (!namadr_list_match(perm_mx_networks, host, inet_ntoa(addr))) { + if (!namadr_list_match(perm_mx_networks, host, hbuf)) { /* * Reject: at least one IP address is not listed in @@ -1239,7 +1302,7 @@ */ if (msg_verbose) msg_info("%s: address %s for %s does not match %s", - myname, inet_ntoa(addr), host, VAR_PERM_MX_NETWORKS); + myname, hbuf, host, VAR_PERM_MX_NETWORKS); dns_rr_free(addr_list); return (NOPE); } @@ -1253,6 +1316,50 @@ static int has_my_addr(SMTPD_STATE *state, const char *host, const char *reply_name, const char *reply_class) { +#ifdef INET6 + char *myname = "has_my_addr"; + struct addrinfo hints, *res, *res0; + int error; + char hbuf[NI_MAXHOST]; + + if (msg_verbose) + msg_info("%s: host %s", myname, host); + + /* + * If we can't lookup the host, defer rather than reject + */ +#define YUP 1 +#define NOPE 0 + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(host, NULL, &hints, &res0); + if (error) { + DEFER_IF_REJECT4(state, MAIL_ERROR_POLICY, + "450 <%s>: %s rejected: Mail exchanger lookup error for %s: %s", + reply_name, reply_class, host, gai_strerror(error)); + return (NOPE); + } + for (res = res0; res; res = res->ai_next) { + if (msg_verbose) { + if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), + NULL, 0, NI_NUMERICHOST)) { + strncpy(hbuf, "???", sizeof(hbuf)); + } + msg_info("%s: addr %s", myname, hbuf); + } + if (own_inet_addr(res->ai_addr)) { + freeaddrinfo(res0); + return (YUP); + } + } + freeaddrinfo(res0); + if (msg_verbose) + msg_info("%s: host %s: no match", myname, host); + + return (NOPE); +#else char *myname = "has_my_addr"; struct in_addr addr; char **cpp; @@ -1291,6 +1398,7 @@ msg_info("%s: host %s: no match", myname, host); return (NOPE); +#endif } /* i_am_mx - is this machine listed as MX relay */ @@ -2029,6 +2137,10 @@ char *addr; const char *value; DICT *dict; + int delim; +#ifdef INET6 + struct in6_addr a6; +#endif if (msg_verbose) msg_info("%s: %s", myname, address); @@ -2039,6 +2151,12 @@ #define CHK_ADDR_RETURN(x,y) { *found = y; return(x); } addr = STR(vstring_strcpy(error_text, address)); +#ifdef INET6 + if (inet_pton(AF_INET6, addr, &a6) == 1) + delim = ':'; + else +#endif + delim = '.'; if ((dict = dict_handle(table)) == 0) msg_panic("%s: dictionary not found: %s", myname, table); @@ -2052,7 +2170,7 @@ msg_fatal("%s: table lookup problem", table); } flags = PARTIAL; - } while (split_at_right(addr, '.')); + } while (split_at_right(addr, delim)); CHK_ADDR_RETURN(SMTPD_CHECK_DUNNO, MISSED); } @@ -2110,11 +2228,17 @@ DNS_RR *server_list; DNS_RR *server; int found = 0; +#ifdef INET6 + int error; + char *addr; + struct addrinfo hints, *res, *res0; +#else struct in_addr addr; struct hostent *hp; + char **cpp; +#endif char *addr_string; int status; - char **cpp; static DNS_FIXED fixed; /* @@ -2175,6 +2299,50 @@ /* * Check the hostnames first, then the addresses. */ +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_CANONNAME; + for (server = server_list; server != 0; server = server->next) { + error = getaddrinfo((char *)server->data, NULL, &hints, &res0); + if (error) { + msg_warn("Unable to look up %s host %s for %s %s: %s", + dns_strtype(type), (char *) server->data, + reply_class, reply_name, GAI_STRERROR(error)); + continue; + } + if (msg_verbose) + msg_info("%s: %s hostname check: %s", + myname, dns_strtype(type), (char *) server->data); + if ((status = check_domain_access(state, table, (char *) server->data, + FULL, &found, reply_name, reply_class, + def_acl)) != 0 || found) + CHECK_SERVER_RETURN(status); + for (res = res0; res; res = res->ai_next) { + switch (res->ai_family) { + case AF_INET6: + addr = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; + break; + case AF_INET: + addr = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr; + break; + default: + msg_warn("%s: unknown address family %d for %s", + myname, res->ai_family, (char *) server->data); + continue; + } + addr_string = mymalloc(NI_MAXHOST); + inet_ntop(res->ai_family, addr, addr_string, NI_MAXHOST); + status = check_addr_access(state, table, addr_string, FULL, + &found, reply_name, reply_class, + def_acl); + myfree(addr_string); + if (status != 0 || found) + CHECK_SERVER_RETURN(status); + } + } +#else for (server = server_list; server != 0; server = server->next) { if (msg_verbose) msg_info("%s: %s hostname check: %s", @@ -2210,6 +2378,7 @@ CHECK_SERVER_RETURN(status); } } +#endif CHECK_SERVER_RETURN(SMTPD_CHECK_DUNNO); } @@ -2475,6 +2644,7 @@ * Do the query. If the DNS lookup produces no definitive reply, give the * requestor the benefit of the doubt. We can't block all email simply * because an RBL server is unavailable. + * Don't do this for AAAA records. Yet. */ why = vstring_alloc(10); dns_status = dns_lookup(query, T_A, 0, &addr_list, (VSTRING *) 0, why); @@ -2644,12 +2814,15 @@ int i; SMTPD_RBL_STATE *rbl; const char *reply_addr; +#ifdef INET6 + struct in_addr a; +#endif if (msg_verbose) msg_info("%s: %s %s", myname, reply_class, addr); /* - * IPv4 only for now + * IPv4 / IPv6-mapped IPv4 (if supported) only for now */ #ifdef INET6 if (inet_pton(AF_INET, addr, &a) != 1) @@ -3238,6 +3411,12 @@ #else msg_warn("restriction `%s' ignored: no SASL support", name); #endif +#ifdef USE_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, @@ -3948,6 +4127,7 @@ char *var_etrn_checks = ""; char *var_data_checks = ""; char *var_relay_domains = ""; +char *var_relay_ccerts = ""; char *var_mynetworks = ""; char *var_notify_classes = ""; diff -Pur postfix-2.1.5/src/smtpd/smtpd_peer.c postfix-2.1.5-ti1.25/src/smtpd/smtpd_peer.c --- postfix-2.1.5/src/smtpd/smtpd_peer.c Thu Dec 4 01:44:28 2003 +++ postfix-2.1.5-ti1.25/src/smtpd/smtpd_peer.c Mon Sep 20 15:01:58 2004 @@ -63,6 +63,20 @@ #include #include +/* Utility library. */ + +#include +#include +#include +#include +#ifdef INET6 +#include /* for NI_WITHSCOPEID */ +#endif + +/* Global library. */ + +#include + /* * Older systems don't have h_errno. Even modern systems don't have * hstrerror(). @@ -84,17 +98,11 @@ ) #endif -/* Utility library. */ - -#include -#include -#include -#include - -/* Global library. */ - -#include - +#ifdef INET6 +#define GAI_STRERROR(error) \ + ((error == EAI_SYSTEM) ? strerror(errno) : gai_strerror(error)) +#endif + /* Application-specific. */ #include "smtpd.h" @@ -103,21 +111,24 @@ void smtpd_peer_init(SMTPD_STATE *state) { - struct sockaddr_in sin; - SOCKADDR_SIZE len = sizeof(sin); + char *myname = "smtpd_peer_init"; +#ifdef INET6 + struct sockaddr_storage ss; +#else + struct sockaddr ss; + struct in_addr *in; struct hostent *hp; - int i; +#endif + struct sockaddr *sa; + SOCKADDR_SIZE len; - /* - * Avoid suprious complaints from Purify on Solaris. - */ - memset((char *) &sin, 0, len); + sa = (struct sockaddr *)&ss; + len = sizeof(ss); /* * Look up the peer address information. */ - if (getpeername(vstream_fileno(state->client), - (struct sockaddr *) & sin, &len) >= 0) { + if (getpeername(vstream_fileno(state->client), sa, &len) >= 0) { errno = 0; } @@ -133,24 +144,111 @@ /* * Look up and "verify" the client hostname. */ - else if (errno == 0 && sin.sin_family == AF_INET) { - state->addr = mystrdup(inet_ntoa(sin.sin_addr)); - hp = gethostbyaddr((char *) &(sin.sin_addr), - sizeof(sin.sin_addr), AF_INET); - if (hp == 0) { + else if (errno == 0 && (sa->sa_family == AF_INET +#ifdef INET6 + || sa->sa_family == AF_INET6 +#endif + )) { +#ifdef INET6 + char hbuf[NI_MAXHOST]; + char abuf[NI_MAXHOST]; + char rabuf[NI_MAXHOST]; + struct addrinfo hints, *res0 = NULL, *res; + char *colonp; +#else + char abuf[sizeof("255.255.255.255") + 1]; + char *hbuf; +#endif + int error = -1; + +#ifdef INET6 + error = getnameinfo(sa, len, abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + if (error) + msg_fatal("%s: numeric getnameinfo lookup for peer: error %s", + myname, GAI_STRERROR(error)); + + /* + * Convert an IPv4-mapped IPv6-address to 'true' IPv4 address + * early on. We have no need for the mapped form in logging, + * hostname verification and access checks. + */ + if (sa->sa_family == AF_INET6 + && IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr) + && (colonp = strrchr(abuf, ':')) != NULL) { + struct addrinfo hints, *res0; + if (msg_verbose > 1) + msg_info("%s: rewriting V4-mapped address \"%s\" to \"%s\"", + myname, abuf, colonp + 1); + state->addr = mystrdup(colonp + 1); + /* + * We create new socket information so getnameinfo() will be + * performed on the rewritten IPv4 address. + */ + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + error = getaddrinfo(state->addr, NULL, &hints, &res0); + if (error) + msg_panic("%s: getaddrinfo(\"%s\", NULL, " + "{AF_INET,SOCK_STREAM,AI_NUMERICHOST}, " + "&res0): %s", myname, state->addr, + GAI_STRERROR(error)); + len = res0->ai_addrlen; + memcpy((char *)sa, res0->ai_addr, len); + } else { + state->addr = mystrdup(abuf); + } + + /* + * RFC 2821 section 4.1.3: IPv6 address literals in SMTP + * mail headers are prepended with tag 'IPv6' and a colon. + */ + if (sa->sa_family == AF_INET6) + state->addr_tag = "IPv6:"; + + error = getnameinfo(sa, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD); +#else + in = &((struct sockaddr_in *)sa)->sin_addr; + inet_ntop(AF_INET, in, abuf, sizeof(abuf)); + state->addr = mystrdup(abuf); + hbuf = NULL; + hp = gethostbyaddr((char *)in, sizeof(*in), AF_INET); + if (hp) { + error = 0; + hbuf = mystrdup(hp->h_name); + } else + error = 1; +#endif + if (error) { state->name = mystrdup(CLIENT_NAME_UNKNOWN); +#ifdef INET6 + if (error != EAI_NONAME) + msg_warn("%s: getnameinfo(%s,,,,,,NI_NAMEREQD) error %s", + myname, abuf, GAI_STRERROR(error)); + /* + * XXX: There are other error codes from GAI that should + * result in only a temporary error code from this daemon. + * This also applies to get{addr,name}info() results + * below. + */ + state->peer_code = (error == EAI_AGAIN ? + SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); +#else state->peer_code = (h_errno == TRY_AGAIN ? SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM); - } else if (valid_hostaddr(hp->h_name, DONT_GRIPE)) { +#endif + } else if (valid_hostaddr(hbuf, DONT_GRIPE)) { msg_warn("numeric result %s in address->name lookup for %s", - hp->h_name, state->addr); + hbuf, state->addr); state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->peer_code = SMTPD_PEER_CODE_PERM; - } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { + } else if (!valid_hostname(hbuf, DONT_GRIPE)) { state->name = mystrdup(CLIENT_NAME_UNKNOWN); state->peer_code = SMTPD_PEER_CODE_PERM; } else { - state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ + state->name = mystrdup(hbuf); state->peer_code = SMTPD_PEER_CODE_OK; /* @@ -162,17 +260,55 @@ state->peer_code = code; \ } - hp = gethostbyname(state->name); /* clobbers hp->name!! */ +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(state->name, NULL, &hints, &res0); + if (error) { + msg_warn("%s: %s: hostname %s verification failed: %s", + myname, state->addr, state->name, + GAI_STRERROR(error)); + REJECT_PEER_NAME(state, (error == EAI_AGAIN ? + SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM)); + } else { + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != sa->sa_family) + continue; + error = getnameinfo(res->ai_addr, res->ai_addrlen, + rabuf, sizeof(rabuf), NULL, 0, + NI_NUMERICHOST | NI_WITHSCOPEID); + if (error) { + msg_warn("%s: %s: hostname %s verification failed: %s", + myname, state->addr, state->name, + GAI_STRERROR(error)); + REJECT_PEER_NAME(state, SMTPD_PEER_CODE_TEMP); + break; + } + if (strcmp(state->addr, rabuf) == 0) + break; /* keep peer name */ + } + if (res == NULL) { + msg_warn("%s: %s: address not listed for hostname %s", + myname, state->addr, state->name); + REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM); + } + } + if (res0) + freeaddrinfo(res0); +#else + hp = gethostbyname(state->name); if (hp == 0) { msg_warn("%s: hostname %s verification failed: %s", state->addr, state->name, HSTRERROR(h_errno)); REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ? - SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM)); - } else if (hp->h_length != sizeof(sin.sin_addr)) { + SMTPD_PEER_CODE_TEMP : SMTPD_PEER_CODE_PERM)); + } else if (hp->h_length != sizeof(*in)) { msg_warn("%s: hostname %s verification failed: bad address size %d", state->addr, state->name, hp->h_length); REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM); } else { + int i; for (i = 0; /* void */ ; i++) { if (hp->h_addr_list[i] == 0) { msg_warn("%s: address not listed for hostname %s", @@ -180,12 +316,11 @@ REJECT_PEER_NAME(state, SMTPD_PEER_CODE_PERM); break; } - if (memcmp(hp->h_addr_list[i], - (char *) &sin.sin_addr, - sizeof(sin.sin_addr)) == 0) + if (memcmp(hp->h_addr_list[i], (char *)in, sizeof(*in)) == 0) break; /* keep peer name */ } } +#endif } } diff -Pur postfix-2.1.5/src/smtpd/smtpd_state.c postfix-2.1.5-ti1.25/src/smtpd/smtpd_state.c --- postfix-2.1.5/src/smtpd/smtpd_state.c Wed Apr 21 20:23:49 2004 +++ postfix-2.1.5-ti1.25/src/smtpd/smtpd_state.c Mon Sep 20 15:01:58 2004 @@ -77,6 +77,7 @@ state->notify_mask = name_mask(VAR_NOTIFY_CLASSES, mail_error_masks, var_notify_classes); state->helo_name = 0; + state->addr_tag = ""; state->queue_id = 0; state->cleanup = 0; state->dest = 0; @@ -111,6 +112,11 @@ state->saved_flags = 0; state->instance = vstring_alloc(10); state->seqno = 0; + state->tls_active = 0; + state->tls_use_tls = 0; + state->tls_enforce_tls = 0; + state->tls_info = tls_info_zero; + state->tls_auth_only = 0; #ifdef USE_SASL_AUTH if (SMTPD_STAND_ALONE(state)) diff -Pur postfix-2.1.5/src/smtpstone/qmqp-sink.c postfix-2.1.5-ti1.25/src/smtpstone/qmqp-sink.c --- postfix-2.1.5/src/smtpstone/qmqp-sink.c Thu Apr 22 01:44:09 2004 +++ postfix-2.1.5-ti1.25/src/smtpstone/qmqp-sink.c Mon Sep 20 15:01:58 2004 @@ -275,7 +275,7 @@ } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; - sock = inet_listen(argv[optind], backlog, BLOCKING); + sock = inet_listen(argv[optind], backlog, BLOCKING, 1); } /* diff -Pur postfix-2.1.5/src/smtpstone/smtp-sink.c postfix-2.1.5-ti1.25/src/smtpstone/smtp-sink.c --- postfix-2.1.5/src/smtpstone/smtp-sink.c Thu Apr 22 01:44:38 2004 +++ postfix-2.1.5-ti1.25/src/smtpstone/smtp-sink.c Mon Sep 20 15:01:58 2004 @@ -692,7 +692,7 @@ } else { if (strncmp(argv[optind], "inet:", 5) == 0) argv[optind] += 5; - sock = inet_listen(argv[optind], backlog, BLOCKING); + sock = inet_listen(argv[optind], backlog, BLOCKING, 1); } /* diff -Pur postfix-2.1.5/src/tlsmgr/Makefile.in postfix-2.1.5-ti1.25/src/tlsmgr/Makefile.in --- postfix-2.1.5/src/tlsmgr/Makefile.in Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/tlsmgr/Makefile.in Mon Sep 20 15:01:58 2004 @@ -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 -Pur postfix-2.1.5/src/tlsmgr/tlsmgr.c postfix-2.1.5-ti1.25/src/tlsmgr/tlsmgr.c --- postfix-2.1.5/src/tlsmgr/tlsmgr.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/tlsmgr/tlsmgr.c Mon Sep 20 15:01:58 2004 @@ -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 +#include +#include +#include +#include +#include +#include /* gettimeofday, not POSIX */ + +/* OpenSSL library. */ +#ifdef USE_SSL +#include /* For the PRNG */ +#endif + +/* Utility library. */ + +#include +#include +#include +#include +#include +#include +#include + +/* Global library. */ + +#include +#include +#include + +/* Master process interface */ + +#include +#include + +/* Application-specific. */ + +#ifdef USE_SSL + /* + * 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; + + /* + * 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); +} + + +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; + + /* + * 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); +} + + +static int tlsmgr_do_scache_check(DICT *scache_db, int scache_timeout, + int start) +{ + 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; + +} + +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]; + + /* + * 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); + } + } + + /* + * 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; + + /* + * 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); + } + + 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); + trigger_server_main(argc, argv, tlsmgr_trigger_event, + MAIL_SERVER_PRE_INIT, tlsmgr_pre_init, + 0); +} + +#else +int main(int argc, char **argv) +{ + msg_fatal("Do not run tlsmgr with TLS support compiled in\n"); +} +#endif diff -Pur postfix-2.1.5/src/util/Makefile.in postfix-2.1.5-ti1.25/src/util/Makefile.in --- postfix-2.1.5/src/util/Makefile.in Thu Apr 22 21:37:28 2004 +++ postfix-2.1.5-ti1.25/src/util/Makefile.in Mon Sep 20 15:01:59 2004 @@ -28,7 +28,9 @@ vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \ write_buf.c write_wait.c auto_clnt.c attr_clnt.c attr_scan_plain.c \ attr_print_plain.c sane_connect.c neuter.c name_code.c \ - uppercase.c + uppercase.c \ + get_port.c \ + dict_sdbm.c sdbm.c OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \ attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \ chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \ @@ -58,7 +60,9 @@ vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \ write_buf.o write_wait.o auto_clnt.o attr_clnt.o attr_scan_plain.o \ attr_print_plain.o sane_connect.o $(STRCASE) neuter.o name_code.o \ - uppercase.o + uppercase.o \ + get_port.o \ + dict_sdbm.o sdbm.o HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \ dict_cidr.h dict_ht.h dict_ni.h dict_nis.h \ @@ -77,7 +81,9 @@ split_at.h stat_as.h stringops.h sys_defs.h timed_connect.h \ timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \ vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \ - auto_clnt.h attr_clnt.h sane_connect.h name_code.h + auto_clnt.h attr_clnt.h sane_connect.h name_code.h \ + get_port.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 DEFS = -I. -D$(SYSTYPE) @@ -690,6 +696,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 @@ -838,6 +845,7 @@ get_domainname.o: mymalloc.h get_domainname.o: get_hostname.h get_domainname.o: get_domainname.h +get_port.o: sys_defs.h get_hostname.o: get_hostname.c get_hostname.o: sys_defs.h get_hostname.o: mymalloc.h @@ -959,6 +967,7 @@ match_list.o: stringops.h match_list.o: argv.h match_list.o: dict.h +match_list.o: inet_util.h match_list.o: match_ops.h match_list.o: match_list.h match_ops.o: match_ops.c @@ -1365,3 +1374,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 -Pur postfix-2.1.5/src/util/dict_cidr.c postfix-2.1.5-ti1.25/src/util/dict_cidr.c --- postfix-2.1.5/src/util/dict_cidr.c Mon Nov 10 20:28:24 2003 +++ postfix-2.1.5-ti1.25/src/util/dict_cidr.c Mon Sep 20 15:01:59 2004 @@ -27,6 +27,13 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Dean C. Strik +/* Department ICT Services +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven, Netherlands +/* E-mail: /*--*/ /* System library. */ @@ -39,6 +46,13 @@ #include #include +#ifdef INET6 +#include +#include +#include +#include +#endif + #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff #endif @@ -53,17 +67,15 @@ #include #include #include -#include +#include /* Application-specific. */ /* * Each rule in a CIDR table is parsed and stored in a linked list. - * Obviously all this is IPV4 specific and needs to be redone for IPV6. */ typedef struct DICT_CIDR_ENTRY { - unsigned long net_bits; /* network portion of address */ - unsigned long mask_bits; /* network mask */ + ADDR_PATTERN *pattern; /* address pattern structure */ char *value; /* lookup result */ struct DICT_CIDR_ENTRY *next; /* next entry */ } DICT_CIDR_ENTRY; @@ -73,27 +85,71 @@ DICT_CIDR_ENTRY *head; /* first entry */ } DICT_CIDR; -#define BITS_PER_ADDR 32 +#define BITS_PER_ADDR_V4 32 +#define BITS_PER_ADDR_V6 128 /* dict_cidr_lookup - CIDR table lookup */ static const char *dict_cidr_lookup(DICT *dict, const char *key) { + char *myname = "dict_cidr_lookup"; + DICT_CIDR *dict_cidr = (DICT_CIDR *) dict; DICT_CIDR_ENTRY *entry; - unsigned long addr; +#ifdef INET6 + struct addrinfo hints, *res0; + int aierr; +#else + struct sockaddr_in sin; +#endif if (msg_verbose) - msg_info("dict_cidr_lookup: %s: %s", dict_cidr->dict.name, key); + msg_info("%s: %s: %s", myname, dict_cidr->dict.name, key); - if ((addr = inet_addr(key)) == INADDR_NONE) +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + /* + * Since access maps call the CIDR map first with the + * hostname and only then with the addresses, we just + * return 0 when an entry isn't numeric, as expressed + * by the EAI_NONAME error. + */ + aierr = getaddrinfo(key, NULL, &hints, &res0); + if (aierr == EAI_NONAME) { + if (msg_verbose) + msg_info("%s: non-address key \"%s\"", + myname, key); return (0); - + } + if (aierr != 0) + msg_fatal("%s: getaddrinfo(%s): %s", + myname, key, GAI_STRERROR(aierr)); for (entry = dict_cidr->head; entry; entry = entry->next) - if ((addr & entry->mask_bits) == entry->net_bits) + if (match_sockaddr(res0->ai_addr, + entry->pattern->addr, + entry->pattern->masklen)) { + freeaddrinfo(res0); return (entry->value); + } + freeaddrinfo(res0); + return (0); +#else /* INET6 */ + + memset(&sin, 0, sizeof(sin)); + sin.family = AF_INET; + sin.addr = inet_addr(key); + if (sin.addr == INADDR_NONE) + return (0); + for (entry = dict_cidr->head; entry; entry = entry->next) + if (match_sockaddr(&sa, entry->pattern->addr, entry->pattern->masklen)) + return (entry->value); return (0); + +#endif } /* dict_cidr_close - close the CIDR table */ @@ -106,6 +162,7 @@ for (entry = dict_cidr->head; entry; entry = next) { next = entry->next; + addr_pattern_free(entry->pattern); myfree(entry->value); myfree((char *) entry); } @@ -120,11 +177,9 @@ DICT_CIDR_ENTRY *rule; char *key; char *value; - char *mask; - int mask_shift; - unsigned long net_bits; - unsigned long mask_bits; - struct in_addr net_addr; + ADDR_PATTERN *pattern; + VSTRING *lookup_err; + int lookup_res; /* * Split the rule into key and value. We already eliminated leading @@ -152,53 +207,35 @@ } /* - * Parse the key into network and mask, and destroy the key. Treat a bare - * network address as /32. - * - * We need explicit code for /0. The result of << is undefined when the - * shift is greater or equal to the number of bits in the shifted - * operand. + * We rewrite the key to standard notation, and check the validity of + * the pattern. + * We cannot use MATCH_FLAG_STRICT_ADDR since access checks try not only + * the numerical address but the resolved hostname as well. */ - if ((mask = split_at(key, '/')) != 0) { - if (!alldig(mask) || (mask_shift = atoi(mask)) > BITS_PER_ADDR - || (net_bits = inet_addr(key)) == INADDR_NONE) { - msg_warn("cidr map %s, line %d: bad net/mask pattern: \"%s/%s\": " - "skipping this rule", mapname, lineno, key, mask); - return (0); - } - mask_bits = mask_shift > 0 ? - htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)) : 0; - if (net_bits & ~mask_bits) { - net_addr.s_addr = (net_bits & mask_bits); - msg_warn("cidr map %s, line %d: net/mask pattern \"%s/%s\" with " - "non-null host portion: skipping this rule", - mapname, lineno, key, mask); - msg_warn("specify \"%s/%d\" if this is really what you want", - inet_ntoa(net_addr), mask_shift); - return (0); - } - } else { - if ((net_bits = inet_addr(key)) == INADDR_NONE) { - msg_warn("cidr map %s, line %d: bad address pattern: \"%s\": " - "skipping this rule", mapname, lineno, key); - return (0); - } - mask_shift = 32; - mask_bits = htonl(0xffffffff); + lookup_err = vstring_alloc(100); + lookup_res = std_addr_pattern(MATCH_FLAG_NOLOOKUP | + MATCH_FLAG_NONNULL_HOST, + key, &pattern, lookup_err); + if (pattern == NULL) { + if (lookup_res == 0 && VSTRING_LEN(lookup_err) != 0) + msg_warn("cidr map %s, line %d: %s: skipping this rule", + mapname, lineno, vstring_str(lookup_err)); + vstring_free(lookup_err); + return (0); } + vstring_free(lookup_err); /* * Bundle up the result. */ rule = (DICT_CIDR_ENTRY *) mymalloc(sizeof(DICT_CIDR_ENTRY)); - rule->net_bits = net_bits; - rule->mask_bits = mask_bits; + rule->pattern = pattern; rule->value = mystrdup(value); rule->next = 0; if (msg_verbose) - msg_info("dict_cidr_open: %s: %lu/%d %s", - mapname, rule->net_bits, mask_shift, rule->value); + msg_info("dict_cidr_open: %s: %s/%d %s", + mapname, pattern->pattern, pattern->masklen, rule->value); return (rule); } diff -Pur postfix-2.1.5/src/util/dict_open.c postfix-2.1.5-ti1.25/src/util/dict_open.c --- postfix-2.1.5/src/util/dict_open.c Mon Jan 5 21:55:18 2004 +++ postfix-2.1.5-ti1.25/src/util/dict_open.c Mon Sep 20 15:01:59 2004 @@ -167,6 +167,7 @@ #include #include #include +#include #include #include #include @@ -194,6 +195,7 @@ #ifdef SNAPSHOT DICT_TYPE_TCP, dict_tcp_open, #endif + DICT_TYPE_SDBM, dict_sdbm_open, #ifdef HAS_DBM DICT_TYPE_DBM, dict_dbm_open, #endif diff -Pur postfix-2.1.5/src/util/dict_sdbm.c postfix-2.1.5-ti1.25/src/util/dict_sdbm.c --- postfix-2.1.5/src/util/dict_sdbm.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/dict_sdbm.c Mon Sep 20 15:01:59 2004 @@ -0,0 +1,408 @@ +/*++ +/* NAME +/* dict_sdbm 3 +/* SUMMARY +/* dictionary manager interface to SDBM files +/* SYNOPSIS +/* #include +/* +/* 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 +#include +#include + +/* 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->lock_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->lock_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->lock_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->lock_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->lock_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->lock_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->lock_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->lock_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.lock_fd = sdbm_dirfno(dbm); + dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm); + if (fstat(dict_sdbm->dict.stat_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 -Pur postfix-2.1.5/src/util/dict_sdbm.h postfix-2.1.5-ti1.25/src/util/dict_sdbm.h --- postfix-2.1.5/src/util/dict_sdbm.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/dict_sdbm.h Mon Sep 20 15:01:59 2004 @@ -0,0 +1,37 @@ +#ifndef _DICT_SDBM_H_INCLUDED_ +#define _DICT_SDBM_H_INCLUDED_ + +/*++ +/* NAME +/* dict_dbm 3h +/* SUMMARY +/* dictionary manager interface to DBM files +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +#define DICT_TYPE_SDBM "sdbm" + +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 -Pur postfix-2.1.5/src/util/get_port.c postfix-2.1.5-ti1.25/src/util/get_port.c --- postfix-2.1.5/src/util/get_port.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/get_port.c Mon Sep 20 15:01:59 2004 @@ -0,0 +1,65 @@ +/*++ +/* NAME +/* get_port 3 +/* SUMMARY +/* trivial host and port extracter +/* SYNOPSIS +/* #include +/* +/* char *get_port(data) +/* char *data; +/* +/* DESCRIPTION +/* get_port() extract host name or ip address from +/* strings such as [3ffe:902:12::10]:25, [::1] +/* or 192.168.0.1:25, and null-terminates the +/* \fIdata\fR at the first occurrence of port separator. +/* DIAGNOSTICS +/* If port not found return null pointer. +/* LICENSE +/* .ad +/* .fi +/* BSD Style (or BSD like) license. +/* AUTHOR(S) +/* Arkadiusz Mi¶kiewicz +/* Wroclaw, POLAND +/*--*/ + +/* System libraries */ + +#include +#include + +/* Utility library. */ + +#include "get_port.h" + +/* get_port - extract port number from string */ + +char *get_port(char *data) +{ + const char *escl=strchr(data,'['); + const char *sepl=strchr(data,':'); + char *escr=strrchr(data,']'); + char *sepr=strrchr(data,':'); + + /* extract from "[address]:port" or "[address]"*/ + if (escl && escr) + { + memmove(data, data + 1, strlen(data) - strlen(escr)); + data[strlen(data) - strlen(escr) - 1] = 0; + *escr++ = 0; + if (*escr == ':') + escr++; + return (*escr ? escr : NULL); + } + /* extract from "address:port" or "address" */ + if ((sepl == sepr) && sepr && sepl) + { + *sepr++ = 0; + return sepr; + } + + /* return empty string */ + return NULL; +} diff -Pur postfix-2.1.5/src/util/get_port.h postfix-2.1.5-ti1.25/src/util/get_port.h --- postfix-2.1.5/src/util/get_port.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/get_port.h Mon Sep 20 15:01:59 2004 @@ -0,0 +1,28 @@ +#ifndef _GET_PORT_H_INCLUDED_ +#define _GET_PORT_H_INCLUDED_ + +/*++ +/* NAME +/* get_port 3h +/* SUMMARY +/* trivial host and port extracter +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* External interface. */ + +extern char *get_port(char *); + + +/* LICENSE +/* .ad +/* .fi +/* BSD Style (or BSD like) license. +/* AUTHOR(S) +/* Arkadiusz Mi¶kiewicz +/* Wroclaw, POLAND +/*--*/ + +#endif diff -Pur postfix-2.1.5/src/util/inet_addr_host.c postfix-2.1.5-ti1.25/src/util/inet_addr_host.c --- postfix-2.1.5/src/util/inet_addr_host.c Fri Dec 11 19:55:35 1998 +++ postfix-2.1.5-ti1.25/src/util/inet_addr_host.c Mon Sep 20 15:01:59 2004 @@ -38,7 +38,10 @@ #include #include #include +#include #include +#include +#include #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -46,17 +49,68 @@ /* Utility library. */ +#include #include #include +#ifdef TEST +#include +#endif /* inet_addr_host - look up address list for host */ int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname) { +#ifdef INET6 + int s; + struct addrinfo hints, *res0, *res; + int error; + char *hbuf, *hname; +#else struct hostent *hp; struct in_addr addr; +#endif int initial_count = addr_list->used; +#ifdef INET6 + + /* + * The use of square brackets around an IPv6 addresses is + * required, even though we don't enforce it as it'd make + * the code unnecessarily complicated. + */ + hbuf = mystrdup(hostname); + if (*hbuf == '[' && hbuf[strlen(hbuf) - 1] == ']') { + hbuf[strlen(hbuf) - 1] = '\0'; + hname = hbuf + 1; + } else { + hname = hbuf; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + error = getaddrinfo(hname, NULL, &hints, &res0); + + if (error == 0) { + for (res = res0; res; res = res->ai_next) { + if (res->ai_family != AF_INET && res->ai_family != AF_INET6) + continue; + /* + * filter out address families that are not supported + * XXX is this socket necessary? --dean + */ + s = socket(res->ai_family, SOCK_DGRAM, 0); + if (s < 0) + continue; + if (close(s)) + msg_warn("inet_addr_host: close(): %m"); + + inet_addr_list_append(addr_list, res->ai_addr); + } + freeaddrinfo(res0); + } + myfree(hbuf); +#else if ((addr.s_addr = inet_addr(hostname)) != INADDR_NONE) { inet_addr_list_append(addr_list, &addr); } else { @@ -65,9 +119,12 @@ inet_addr_list_append(addr_list, (struct in_addr *) * hp->h_addr_list++); } +#endif + return (addr_list->used - initial_count); } + #ifdef TEST #include @@ -78,6 +135,8 @@ { INET_ADDR_LIST addr_list; int i; + struct sockaddr *sa; + char hbuf[NI_MAXHOST]; msg_vstream_init(argv[0], VSTREAM_ERR); @@ -89,8 +148,12 @@ if (inet_addr_host(&addr_list, *argv) == 0) msg_fatal("not found: %s", *argv); - for (i = 0; i < addr_list.used; i++) - vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i])); + for (i = 0; i < addr_list.used; i++) { + sa = (struct sockaddr *)&addr_list.addrs[i]; + getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + vstream_printf("%s\n", hbuf); + } vstream_fflush(VSTREAM_OUT); } inet_addr_list_free(&addr_list); diff -Pur postfix-2.1.5/src/util/inet_addr_list.c postfix-2.1.5-ti1.25/src/util/inet_addr_list.c --- postfix-2.1.5/src/util/inet_addr_list.c Fri Dec 12 00:40:06 2003 +++ postfix-2.1.5-ti1.25/src/util/inet_addr_list.c Mon Sep 20 15:01:59 2004 @@ -51,6 +51,13 @@ #include #include +#include + +#ifdef INET6 +#include +#include +#endif + /* Utility library. */ #include @@ -64,14 +71,43 @@ int init_size; list->used = 0; - list->size = 0; init_size = 2; - list->addrs = (struct in_addr *) mymalloc(sizeof(*list->addrs) * init_size); +#ifdef INET6 + list->addrs = (struct sockaddr_storage *) +#else + list->addrs = (struct in_addr *) +#endif + mymalloc(sizeof(*list->addrs) * init_size); list->size = init_size; } /* inet_addr_list_append - append address to internet address list */ +#ifdef INET6 +void inet_addr_list_append(INET_ADDR_LIST *list, + struct sockaddr * addr) +{ + char *myname = "inet_addr_list_append"; + char hbuf[NI_MAXHOST]; + int new_size; + + if (msg_verbose > 1) { + if (getnameinfo(addr, SA_LEN(addr), hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(hbuf, "??????", sizeof(hbuf)); + } + msg_info("%s: %s", myname, hbuf); + } + + if (list->used >= list->size) { + new_size = list->size * 2; + list->addrs = (struct sockaddr_storage *) + myrealloc((char *)list->addrs, sizeof(*list->addrs) * new_size); + list->size = new_size; + } + memcpy(&list->addrs[list->used++], addr, SA_LEN(addr)); +} +#else void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr) { char *myname = "inet_addr_list_append"; @@ -83,20 +119,39 @@ if (list->used >= list->size) { new_size = list->size * 2; list->addrs = (struct in_addr *) - myrealloc((char *) list->addrs, sizeof(*list->addrs) * new_size); + myrealloc((char *)list->addrs, sizeof(*list->addrs) * new_size); list->size = new_size; } list->addrs[list->used++] = *addr; } +#endif /* inet_addr_list_comp - compare addresses */ static int inet_addr_list_comp(const void *a, const void *b) { +#ifdef INET6 + char ha[NI_MAXHOST], hb[NI_MAXHOST]; + int nierr; + int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; + struct sockaddr *sa, *sb; + + sa = (struct sockaddr *)a, sb = (struct sockaddr *)b; + if (sa->sa_family != sb->sa_family) + return (sa->sa_family - sb->sa_family); + nierr = getnameinfo(sa, SA_LEN(sa), ha, sizeof(ha), NULL, 0, niflags); + if (nierr) + msg_fatal("inet_addr_list_comp: getnameinfo(ha) error %d", nierr); + nierr = getnameinfo(sb, SA_LEN(sb), hb, sizeof(hb), NULL, 0, niflags); + if (nierr) + msg_fatal("inet_addr_list_comp: getnameinfo(hb) error %d", nierr); + return strcmp(ha, hb); +#else const struct in_addr *a_addr = (const struct in_addr *) a; const struct in_addr *b_addr = (const struct in_addr *) b; return (a_addr->s_addr - b_addr->s_addr); +#endif } /* inet_addr_list_uniq - weed out duplicates */ @@ -141,7 +196,9 @@ */ #include -static void inet_addr_list_print(INET_ADDR_LIST *list) +#ifndef DEBUG6 +static +#endif void inet_addr_list_print(INET_ADDR_LIST *list) { int n; diff -Pur postfix-2.1.5/src/util/inet_addr_list.h postfix-2.1.5-ti1.25/src/util/inet_addr_list.h --- postfix-2.1.5/src/util/inet_addr_list.h Tue Jul 31 19:56:47 2001 +++ postfix-2.1.5-ti1.25/src/util/inet_addr_list.h Mon Sep 20 15:01:59 2004 @@ -16,19 +16,55 @@ */ #include +#ifndef SA_LEN +# ifndef HAS_SA_LEN +# define SA_LEN(x) (((x)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) +# define SS_LEN(x) (((x).ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) +# else +# define SA_LEN(x) ((x)->sa_len) +# define SS_LEN(x) ((x).ss_len) +# endif +#else +# ifndef SS_LEN +# define SS_LEN(x) (((x).ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) +# endif +#endif + /* * External interface. */ 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 *); extern void inet_addr_list_uniq(INET_ADDR_LIST *); +#ifdef INET6 +struct sockaddr; +extern void inet_addr_list_append(INET_ADDR_LIST *, struct sockaddr *); +#else extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *); +#endif + +/* + * NI_WITHSCOPEID is defined on most systems, but usually not implemented. + * Only on KAME? Use without implementation will result in EAI_BADFLAGS. + */ +#ifdef INET6 +# ifndef INET6_KAME +# ifdef NI_WITHSCOPEID +# undef NI_WITHSCOPEID +# endif +# define NI_WITHSCOPEID 0 +# endif +#endif /* LICENSE /* .ad diff -Pur postfix-2.1.5/src/util/inet_addr_local.c postfix-2.1.5-ti1.25/src/util/inet_addr_local.c --- postfix-2.1.5/src/util/inet_addr_local.c Sun Feb 25 19:20:19 2001 +++ postfix-2.1.5-ti1.25/src/util/inet_addr_local.c Mon Sep 20 15:01:59 2004 @@ -6,9 +6,10 @@ /* SYNOPSIS /* #include /* -/* int inet_addr_local(addr_list, mask_list) +/* int inet_addr_local(addr_list, mask_list, addr_family) /* INET_ADDR_LIST *addr_list; /* INET_ADDR_LIST *mask_list; +/* int addr_family; /* DESCRIPTION /* inet_addr_local() determines all active IP interface addresses /* of the local system. Any address found is appended to the @@ -17,6 +18,9 @@ /* /* The mask_list is either a null pointer, or it is a list that /* receives the netmasks of the interface addresses that were found. +/* +/* The addr_family is ether AF_UNSPEC, AF_INET or AF_INET6 +/* /* DIAGNOSTICS /* Fatal errors: out of memory. /* SEE ALSO @@ -30,6 +34,13 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Dean C. Strik +/* Department ICT +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven, Netherlands +/* E-mail: /*--*/ /* System library. */ @@ -47,6 +58,13 @@ #endif #include #include +#ifdef INET6 +#include +#include +#endif +#ifdef HAVE_GETIFADDRS +#include +#endif /* Utility library. */ @@ -57,39 +75,300 @@ #include /* + * IF IPV6 SUPPORT IS ENABLED: + * + * In the non-getifaddrs() version, we determine the interface addresses + * using the SIOCG(L)IFCONF. However, it is operating system dependent + * whether this also results in IPv6 addresses configuration. Another + * issue is that there is no good method to determine the netmask / + * prefixlen for IPv6 addresses. + * We will therefore use OS dependent methods. An overview: + * - Use SIOCGLIFCONF when available -> this supports both IPv4/IPv6 + * addresses. Also, with SIOCGLIFNETMASK we can obtain the netmask / + * prefixlen for either address family. + * - On Linux, read IPv6 addresses / prefixlengths from a file in the + * /proc filesystem. Linux does not return IPv6 addresses in + * SIOCGIFCONF. + * - On other systems without getifaddrs(), we expect SIOCGIFCONF + * to return IPv6 addresses. Since SIOCGIFNETMASK does not work for + * IPv6 addresses, we will always set the prefixlen to 64 (subnet) + * However, it is suggested you set the mynetworks variable(s) + * manually then. + * XXX: We duplicate some code. In this case, I think this is better + * than really drowning in the #ifdefs... + * -- Dean Strik (dcs) + */ + + /* * Support for variable-length addresses. */ +#ifdef HAS_SIOCGLIF +#else /* HAS_SIOCGLIF */ +#endif /* HAS_SIOCGLIF */ + +/* decode_scope - separate scope ID from IPv6 address */ + +#ifdef INET6 +static struct sockaddr *decode_scope(struct sockaddr *sa, + struct sockaddr_in6 *sin6) +{ +#ifdef INET6_KAME + memcpy(sin6, sa, sa->sa_len); /* size sin6 >> size sa */ + /* decode scoped address notation */ + if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || + IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)) && + sin6->sin6_scope_id == 0) { + sin6->sin6_scope_id = ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); + sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; + } + return (struct sockaddr *)sin6; +#else + return (sa); +#endif +} +#endif + +/* ial_socket - make socket for ioctl() operations */ + +static int ial_socket(int af) +{ + char *myname = "inet_addr_local[socket]"; + int sock; + + /* + * The host may not be actually configured with IPv6. When + * IPv6 support is not actually in the kernel, don't consider + * failure to create an IPv6 socket as fatal. This could be + * tuned better though. For other families, the error is fatal. + */ + if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) { +#ifdef INET6 + if (af == AF_INET6) { + if (msg_verbose) + msg_warn("%s: socket: %m", myname); + return (-1); + } +#endif + msg_fatal("%s: socket: %m", myname); + } + return (sock); +} + + +#ifdef HAVE_GETIFADDRS + +/* + * The getifaddrs(3) function, introduced by BSD/OS, provides a + * platform-independent way of requesting interface addresses, + * including IPv6 addresses. The implementation however is not + * present in all major operating systems. + */ + +/* ial_getifaddrs - determine IP addresses using getifaddrs(3) */ + +static int ial_getifaddrs(INET_ADDR_LIST *addr_list, + INET_ADDR_LIST *mask_list, + int af) +{ + char *myname = "inet_addr_local[getifaddrs]"; + struct ifaddrs *ifap, *ifa; + struct sockaddr *sa, *sam; +#ifdef INET6 + struct sockaddr_in6 addr6; +#else + void *addr,*addrm; +#endif + + if (getifaddrs(&ifap) < 0) + msg_fatal("%s: getifaddrs: %m", myname); + + /* + * Get the address of each IP network interface. According to BIND we + * must include interfaces that are down because the machine may still + * receive packets for that address (yes, via some other interface). + * Having no way to verify this claim on every machine, I will give them + * the benefit of the doubt. + */ + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (!(ifa->ifa_flags & IFF_RUNNING) || ifa->ifa_addr == NULL) + continue; + sa = ifa->ifa_addr; + sam = ifa->ifa_netmask; + if (af != AF_UNSPEC && sa->sa_family != af) + continue; + switch (sa->sa_family) { + case AF_INET: +#ifndef INET6 + addr = (void *)&((struct sockaddr_in *)sa)->sin_addr; + addrm = (void *)&((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; +#endif + break; +#ifdef INET6 + case AF_INET6: + sa = decode_scope(sa, &addr6); + break; +#endif + default: + continue; + } + +#ifdef INET6 + inet_addr_list_append(addr_list, sa); + if (mask_list != NULL) { + /* + * Unfortunately, sa_len/sa_family may be broken in + * the netmask sockaddr structure. We must fix this + * manually to have correct addresses. --dcs + */ +#ifdef HAS_SA_LEN + sam->sa_len = sa->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in); +#endif + sam->sa_family = sa->sa_family; + inet_addr_list_append(mask_list, sam); + } +#else + inet_addr_list_append(addr_list, (struct in_addr *)addr); + if (mask_list != NULL) + inet_addr_list_append(mask_list, (struct in_addr *)addrm); +#endif + } + + freeifaddrs(ifap); + return (0); +} +#endif /* HAVE_GETIFADDRS */ + + +#ifdef HAS_SIOCGLIF + +/* + * The SIOCLIF* ioctls are the successors of SIOCGIF* on the Solaris + * and HP/UX operating systems. The data is stored in sockaddr_storage + * structure. Both IPv4 and IPv6 addresses are returned though these + * calls. + */ +#define NEXT_INTERFACE(lifr) (lifr + 1) +#define LIFREQ_SIZE(lifr) sizeof(lifr[0]) +#define ial_generic ial_siocglif + +/* ial_siocglif - determine IP addresses using ioctl(SIOCGLIF*) */ + +static int ial_siocglif(INET_ADDR_LIST *addr_list, + INET_ADDR_LIST *mask_list, + int af) +{ + char *myname = "inet_addr_local[siocglif]"; + struct lifconf lifc; + struct lifreq *lifr; + struct lifreq *lifr_mask; + struct lifreq *the_end; + struct sockaddr *sa; + struct sockaddr_in6 addr6; + int sock; + VSTRING *buf; + + if (af != AF_INET && af != AF_INET6) + msg_fatal("%s: address family was %d, must be AF_INET (%d) or " + "AF_INET6 (%d)", myname, af, AF_INET, AF_INET6); + sock = ial_socket(af); + if (sock < 0) + return (0); + buf = vstring_alloc(1024); + for (;;) { + memset(&lifc, 0, sizeof(lifc)); + lifc.lifc_family = AF_UNSPEC; + lifc.lifc_len = vstring_avail(buf); + lifc.lifc_buf = vstring_str(buf); + if (ioctl(sock, SIOCGLIFCONF, (char *) &lifc) < 0) { + if (errno != EINVAL) + msg_fatal("%s: ioctl SIOCGLIFCONF: %m", myname); + } else if (lifc.lifc_len < vstring_avail(buf) / 2) + break; + VSTRING_SPACE(buf, vstring_avail(buf) * 2); + } + + the_end = (struct lifreq *) (lifc.lifc_buf + lifc.lifc_len); + for (lifr = lifc.lifc_req; lifr < the_end;) { + if (((struct sockaddr *)&lifr->lifr_addr)->sa_family != af) { + lifr = NEXT_INTERFACE(lifr); + continue; + } + if (af == AF_INET) { + if (((struct sockaddr_in *)&lifr->lifr_addr)->sin_addr.s_addr + == INADDR_ANY) { + lifr = NEXT_INTERFACE(lifr); + continue; + } + sa = (struct sockaddr *)&lifr->lifr_addr; + } else if (af == AF_INET6) { + sa = decode_scope((struct sockaddr *)&lifr->lifr_addr, &addr6); + if (IN6_IS_ADDR_UNSPECIFIED(&addr6.sin6_addr)) { + lifr = NEXT_INTERFACE(lifr); + continue; + } + } + inet_addr_list_append(addr_list, sa); + if (mask_list) { + lifr_mask = (struct lifreq *) mymalloc(sizeof(struct lifreq)); + memcpy((char *)lifr_mask, (char *)lifr, sizeof(struct lifreq)); + if (ioctl(sock, SIOCGLIFNETMASK, lifr_mask) < 0) + msg_fatal("%s: ioctl(SIOCGLIFNETMASK): %m", myname); + /* XXX: Check whether sa_len/family are honoured --dcs */ + inet_addr_list_append(mask_list, + (struct sockaddr *)&lifr_mask->lifr_addr); + myfree((char *)lifr_mask); + } + lifr = NEXT_INTERFACE(lifr); + } + vstring_free(buf); + (void) close(sock); + return (0); +} + +#else /* HAVE_SIOCGLIF */ + +/* + * The classic SIOCGIF* ioctls. Modern BSD operating systems will + * also return IPv6 addresses through these structure. Note however + * that recent versions of these operating systems have getifaddrs. + */ +#define ial_generic ial_siocgif #ifdef _SIZEOF_ADDR_IFREQ #define NEXT_INTERFACE(ifr) ((struct ifreq *) \ ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr))) #define IFREQ_SIZE(ifr) _SIZEOF_ADDR_IFREQ(*ifr) -#else +#else /* _SIZEOF_ADDR_IFREQ */ #ifdef HAS_SA_LEN #define NEXT_INTERFACE(ifr) ((struct ifreq *) \ ((char *) ifr + sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len)) #define IFREQ_SIZE(ifr) (sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len) -#else +#else /* HAS_SA_LEN */ #define NEXT_INTERFACE(ifr) (ifr + 1) #define IFREQ_SIZE(ifr) sizeof(ifr[0]) -#endif -#endif +#endif /* HAS_SA_LEN */ +#endif /* _SIZEOF_ADDR_IFREQ */ -/* inet_addr_local - find all IP addresses for this host */ +/* ial_siocgif - determine IP addresses using ioctl(SIOCGIF*) */ -int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list) +static int ial_siocgif(INET_ADDR_LIST *addr_list, + INET_ADDR_LIST *mask_list, + int af) { - char *myname = "inet_addr_local"; + char *myname = "inet_addr_local[siocgif]"; + struct in_addr addr; struct ifconf ifc; struct ifreq *ifr; - struct ifreq *the_end; - int sock; - VSTRING *buf = vstring_alloc(1024); - int initial_count = addr_list->used; - struct in_addr addr; struct ifreq *ifr_mask; - - if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) - msg_fatal("%s: socket: %m", myname); + struct ifreq *the_end; +#ifdef INET6 + struct sockaddr *sa; + struct sockaddr_in6 addr6; +#endif + int sock; + VSTRING *buf; /* * Get the network interface list. XXX The socket API appears to have no @@ -106,6 +385,11 @@ * that the program can run out of memory due to a non-memory problem, * making it more difficult than necessary to diagnose the real problem. */ + + sock = ial_socket(af); + if (sock < 0) + return (0); + buf = vstring_alloc(1024); for (;;) { ifc.ifc_len = vstring_avail(buf); ifc.ifc_buf = vstring_str(buf); @@ -117,39 +401,199 @@ VSTRING_SPACE(buf, vstring_avail(buf) * 2); } - /* - * Get the address of each IP network interface. According to BIND we - * must include interfaces that are down because the machine may still - * receive packets for that address (yes, via some other interface). - * Having no way to verify this claim on every machine, I will give them - * the benefit of the doubt. - */ the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); for (ifr = ifc.ifc_req; ifr < the_end;) { - if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */ - addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr; - if (addr.s_addr != INADDR_ANY) { /* has IP address */ + if (ifr->ifr_addr.sa_family != af) { + ifr = NEXT_INTERFACE(ifr); + continue; + } + if (af == AF_INET) { + addr = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr; + if (addr.s_addr != INADDR_ANY) { +#ifdef INET6 + inet_addr_list_append(addr_list, &ifr->ifr_addr); +#else inet_addr_list_append(addr_list, &addr); +#endif if (mask_list) { ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr)); memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr)); if (ioctl(sock, SIOCGIFNETMASK, ifr_mask) < 0) msg_fatal("%s: ioctl SIOCGIFNETMASK: %m", myname); - addr = ((struct sockaddr_in *) & ifr_mask->ifr_addr)->sin_addr; +#ifdef INET6 + /* + * Note that this SIOCGIFNETMASK has truly screwed up + * the contents of sa_len/sa_family. We must fix this + * manually to have correct addresses. --dcs + */ +#ifdef HAS_SA_LEN + ifr_mask->ifr_addr.sa_len = sizeof(struct sockaddr_in); +#endif + ifr_mask->ifr_addr.sa_family = af; + inet_addr_list_append(mask_list, &ifr_mask->ifr_addr); +#else + addr = ((struct sockaddr_in *) &ifr_mask->ifr_addr)->sin_addr; inet_addr_list_append(mask_list, &addr); +#endif myfree((char *) ifr_mask); } } } +#ifdef INET6 + else if (af == AF_INET6) { + sa = decode_scope(&ifr->ifr_addr, &addr6); + if (!(IN6_IS_ADDR_UNSPECIFIED(&addr6.sin6_addr))) { + inet_addr_list_append(addr_list, sa); + if (mask_list) { + /* We can't know, and assume /64 for everything */ + struct sockaddr_in6 mask6; + struct in6_addr *maddr6; + memcpy((char *)&mask6, (char *)&addr6, + sizeof(struct sockaddr_in6)); + maddr6 = &mask6.sin6_addr; + maddr6->s6_addr[0] = maddr6->s6_addr[1] = + maddr6->s6_addr[2] = maddr6->s6_addr[3] = + maddr6->s6_addr[4] = maddr6->s6_addr[5] = + maddr6->s6_addr[6] = maddr6->s6_addr[7] = 0xff; + maddr6->s6_addr[8] = maddr6->s6_addr[9] = + maddr6->s6_addr[10] = maddr6->s6_addr[11] = + maddr6->s6_addr[12] = maddr6->s6_addr[13] = + maddr6->s6_addr[14] = maddr6->s6_addr[15] = 0x0; + inet_addr_list_append(mask_list, + (struct sockaddr *)&mask6); + } + } + } +#endif /* INET6 */ ifr = NEXT_INTERFACE(ifr); } vstring_free(buf); (void) close(sock); + return (0); +} +#endif /* HAVE_SIOCGLIF */ + + +#ifdef HAS_PROCNET_IFINET6 + +/* + * Linux does not provide proper calls to retrieve IPv6 interface + * addresses. Instead, the addresses can be read from a file in the + * /proc tree. The most important issue with this approach however + * is that the /proc tree may not always be available, for example + * in a chrooted environment or in "hardened" (sic) installations. + */ + +/* ial_procnet_ifinet6 - determine IPv6 addresses using /proc/net/if_inet6 */ + +static int ial_procnet_ifinet6(INET_ADDR_LIST *addr_list, + INET_ADDR_LIST *mask_list) +{ + char *myname = "inet_addr_local[procnet_ifinet6]"; + FILE *f; + char addr6p[8][5], addr6res[40], devname[20]; + int plen, scope, dad_status, if_idx, gaierror; + struct addrinfo hints, *res, *res0; + + if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { + while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], + addr6p[5], addr6p[6], addr6p[7], + &if_idx, &plen, &scope, &dad_status, devname) != EOF) { + sprintf(addr6res, "%s:%s:%s:%s:%s:%s:%s:%s", + addr6p[0], addr6p[1], addr6p[2], addr6p[3], + addr6p[4], addr6p[5], addr6p[6], addr6p[7]); + addr6res[sizeof(addr6res) - 1] = 0; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + gaierror = getaddrinfo(addr6res, NULL, &hints, &res0); + if (!gaierror) { + for (res = res0; res; res = res->ai_next) { + struct sockaddr_in6 mask; + int i, rest; + inet_addr_list_append(addr_list, res->ai_addr); + memcpy((char *)&mask, res->ai_addr, res->ai_addrlen); + /* s6_addr32 is available on linux */ + mask.sin6_addr.s6_addr32[0] = + mask.sin6_addr.s6_addr32[1] = + mask.sin6_addr.s6_addr32[2] = + mask.sin6_addr.s6_addr32[3] = ~0; + for (i = 3, rest = 128 - plen; i > -1; i--) + if (rest > 31) { + mask.sin6_addr.s6_addr32[i] = htonl(0); + rest -= 32; + } else { + mask.sin6_addr.s6_addr32[i] = + htonl(~((1 << rest) - 1)); + break; + } + inet_addr_list_append(mask_list, (struct sockaddr *)&mask); + } + freeaddrinfo(res0); + } + } + } else if (msg_verbose) { + msg_warn("%s: Couldn't open " _PATH_PROCNET_IFINET6 + " for reading: %m", myname); + } + return (0); +} +#endif /* HAS_PROCNET_IFINET6 */ + + +/* inet_addr_local - find all IP addresses for this host */ + +int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list, + int addr_family) +{ + char *myname = "inet_addr_local"; + int initial_count = addr_list->used; + int count; + + /* + * IP Version 4 + */ + if (addr_family == AF_INET || addr_family == AF_UNSPEC) { + count = addr_list->used; +#if defined(HAVE_GETIFADDRS) + ial_getifaddrs(addr_list, mask_list, AF_INET); +#else + ial_generic(addr_list, mask_list, AF_INET); +#endif + if (msg_verbose) + msg_info("%s: configured %d IPv4 addresses", + myname, addr_list->used - count); + } + + /* + * IP Version 6 + */ + if (addr_family == AF_INET6 || addr_family == AF_UNSPEC) { + count = addr_list->used; +#ifdef INET6 +#if defined(HAS_PROCNET_IFINET6) + ial_procnet_ifinet6(addr_list, mask_list); +#elif defined(HAVE_GETIFADDRS) + ial_getifaddrs(addr_list, mask_list, AF_INET6); +#else + ial_generic(addr_list, mask_list, AF_INET6); +#endif + if (msg_verbose) + msg_info("%s: configured %d IPv6 addresses", myname, + addr_list->used - count); +#endif + } + return (addr_list->used - initial_count); } + #ifdef TEST +/* XXX: Requires INET6 for now */ +#include #include #include @@ -158,12 +602,14 @@ INET_ADDR_LIST addr_list; INET_ADDR_LIST mask_list; int i; + char abuf[NI_MAXHOST], mbuf[NI_MAXHOST]; + struct sockaddr *sa; msg_vstream_init(argv[0], VSTREAM_ERR); inet_addr_list_init(&addr_list); inet_addr_list_init(&mask_list); - inet_addr_local(&addr_list, &mask_list); + inet_addr_local(&addr_list, &mask_list, AF_UNSPEC); if (addr_list.used == 0) msg_fatal("cannot find any active network interfaces"); @@ -172,8 +618,17 @@ msg_warn("found only one active network interface"); for (i = 0; i < addr_list.used; i++) { - vstream_printf("%s/", inet_ntoa(addr_list.addrs[i])); - vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i])); + sa = (struct sockaddr *)&addr_list.addrs[i]; + if (getnameinfo(sa, SA_LEN(sa), abuf, sizeof(abuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(abuf, "???", sizeof(abuf)); + } + sa = (struct sockaddr *)&mask_list.addrs[i]; + if (getnameinfo(sa, SA_LEN(sa), mbuf, sizeof(mbuf), NULL, 0, + NI_NUMERICHOST)) { + strncpy(mbuf, "???", sizeof(mbuf)); + } + vstream_printf("%s/%s\n", abuf, mbuf); } vstream_fflush(VSTREAM_OUT); inet_addr_list_free(&addr_list); diff -Pur postfix-2.1.5/src/util/inet_addr_local.h postfix-2.1.5-ti1.25/src/util/inet_addr_local.h --- postfix-2.1.5/src/util/inet_addr_local.h Sat Feb 24 01:28:34 2001 +++ postfix-2.1.5-ti1.25/src/util/inet_addr_local.h Mon Sep 20 15:01:59 2004 @@ -19,7 +19,7 @@ /* * External interface. */ -extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *); +extern int inet_addr_local(INET_ADDR_LIST *, INET_ADDR_LIST *, int); /* LICENSE /* .ad diff -Pur postfix-2.1.5/src/util/inet_connect.c postfix-2.1.5-ti1.25/src/util/inet_connect.c --- postfix-2.1.5/src/util/inet_connect.c Sat Sep 13 03:04:12 2003 +++ postfix-2.1.5-ti1.25/src/util/inet_connect.c Mon Sep 20 15:01:59 2004 @@ -55,6 +55,9 @@ #include #include #include +#ifdef INET6 +#include +#endif /* Utility library. */ @@ -74,7 +77,12 @@ char *buf; char *host; char *port; +#ifdef INET6 + struct addrinfo hints, *res, *res0; + int error; +#else struct sockaddr_in sin; +#endif int sock; /* @@ -82,14 +90,58 @@ * the local host. */ buf = inet_parse(addr, &host, &port); +#ifdef INET6 + if (*host == 0) + host = NULL; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; /* find_inet_addr is numeric only */ + if (getaddrinfo(host, port, &hints, &res0)) + msg_fatal("host not found: %s", host); +#else if (*host == 0) host = "localhost"; memset((char *) &sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = find_inet_addr(host); sin.sin_port = find_inet_port(port, "tcp"); +#endif myfree(buf); +#ifdef INET6 + sock = -1; + for (res = res0; res; res = res->ai_next) { + if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) + continue; + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock < 0) + continue; + if (timeout > 0) { + non_blocking(sock, NON_BLOCKING); + if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) { + close(sock); + sock = -1; + continue; + } + if (block_mode != NON_BLOCKING) + non_blocking(sock, block_mode); + break; + } else { + non_blocking(sock, block_mode); + if (connect(sock, res->ai_addr, res->ai_addrlen) < 0 + && errno != EINPROGRESS) { + close(sock); + sock = -1; + continue; + } + break; + } + } + freeaddrinfo(res0); + return sock; +#else /* * Create a client socket. */ @@ -122,4 +174,5 @@ } return (sock); } +#endif } diff -Pur postfix-2.1.5/src/util/inet_listen.c postfix-2.1.5-ti1.25/src/util/inet_listen.c --- postfix-2.1.5/src/util/inet_listen.c Sat Sep 13 01:50:50 2003 +++ postfix-2.1.5-ti1.25/src/util/inet_listen.c Mon Sep 20 15:01:59 2004 @@ -6,7 +6,7 @@ /* SYNOPSIS /* #include /* -/* int inet_listen(addr, backlog, block_mode) +/* int inet_listen(addr, backlog, block_mode, addinuse_fatal) /* const char *addr; /* int backlog; /* int block_mode; @@ -51,11 +51,17 @@ #include #include #include +#ifdef INET6 +#if (! __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 ) +#include +#endif +#endif #include #include #ifndef MAXHOSTNAMELEN #include #endif +#include #include #include @@ -77,35 +83,116 @@ /* inet_listen - create inet-domain listener */ -int inet_listen(const char *addr, int backlog, int block_mode) +int inet_listen(const char *addr, int backlog, int block_mode, int addrinuse_fatal) { +#ifdef INET6 + struct addrinfo *res, *res0, hints; + int error; +#else + struct ai { + int ai_family; + int ai_socktype; + int ai_protocol; + struct sockaddr *ai_addr; + SOCKADDR_SIZE ai_addrlen; + struct ai *ai_next; + } *res, *res0, resbody; struct sockaddr_in sin; +#endif int sock; int t = 1; + int addrinuse = 0; char *buf; char *host; char *port; +#ifdef INET6 + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; +#else + char hbuf[sizeof("255.255.255.255") + 1]; + char pbuf[sizeof("255.255.255.255") + 1]; +#endif + char *cause = "unknown"; /* * Translate address information to internal form. */ buf = inet_parse(addr, &host, &port); - memset((char *) &sin, 0, sizeof(sin)); +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + error = getaddrinfo(*host ? host : NULL, *port ? port : "0", &hints, &res0); + if (error) { + msg_fatal("getaddrinfo: %s", gai_strerror(error)); + } + myfree(buf); +#else + memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; +#ifdef HAS_SA_LEN + sin.sin_len = sizeof(sin); +#endif sin.sin_port = find_inet_port(port, "tcp"); sin.sin_addr.s_addr = (*host ? find_inet_addr(host) : INADDR_ANY); - myfree(buf); - /* - * Create a listener socket. - */ - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) - msg_fatal("socket: %m"); - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) - msg_fatal("setsockopt: %m"); - 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)); + memset(&resbody, 0, sizeof(resbody)); + resbody.ai_socktype = SOCK_STREAM; + resbody.ai_family = AF_INET; + resbody.ai_addr = (struct sockaddr *)&sin; + resbody.ai_addrlen = sizeof(sin); + + res0 = &resbody; +#endif + + sock = -1; + for (res = res0; res; res = res->ai_next) { + if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) + continue; + + /* + * Create a listener socket. + */ + if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0) { + cause = "socket"; + continue; + } +#ifdef IPV6_V6ONLY + if (res->ai_family == AF_INET6 && setsockopt(sock, + IPPROTO_IPV6, IPV6_V6ONLY, (char *)&t, sizeof(t)) < 0) { +#ifdef DEBUG6 + cause = "setsockopt(IPV6_V6ONLY)"; + close(sock); + sock = -1; + continue; +#endif + ; + } +#endif + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) { + cause = "setsockopt(SO_REUSEADDR)"; + close(sock); + sock = -1; + continue; + } + + if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { + cause = "bind"; + if (errno == EADDRINUSE) + addrinuse = 1; + close(sock); + sock = -1; + continue; + } + break; + } + if (sock < 0 && (addrinuse_fatal || !addrinuse)) + msg_fatal("%s: %m", cause); +#ifdef INET6 + freeaddrinfo(res0); +#endif + if (sock < 0) + return -1; non_blocking(sock, block_mode); if (listen(sock, backlog) < 0) msg_fatal("listen: %m"); diff -Pur postfix-2.1.5/src/util/inet_util.c postfix-2.1.5-ti1.25/src/util/inet_util.c --- postfix-2.1.5/src/util/inet_util.c Fri Dec 11 19:55:34 1998 +++ postfix-2.1.5-ti1.25/src/util/inet_util.c Mon Sep 20 15:01:59 2004 @@ -37,6 +37,7 @@ /* System libraries. */ #include +#include /* Utility library. */ @@ -48,14 +49,26 @@ char *inet_parse(const char *addr, char **hostp, char **portp) { - char *buf; - - buf = mystrdup(addr); - if ((*portp = split_at_right(buf, ':')) != 0) { + char *buf, *brk; +#ifdef INET6 + if (*addr == '[') { + buf = mystrdup(addr + 1); + brk = strchr(buf, ']'); + if (brk == NULL) + brk = buf; + } else +#endif + brk = buf = mystrdup(addr); + if ((*portp = split_at_right(brk, ':')) != 0) { *hostp = buf; +#ifdef INET6 + if (brk > buf) + *brk = '\0'; +#endif } else { *portp = buf; *hostp = ""; } return (buf); } + diff -Pur postfix-2.1.5/src/util/listen.h postfix-2.1.5-ti1.25/src/util/listen.h --- postfix-2.1.5/src/util/listen.h Mon Mar 22 02:57:11 1999 +++ postfix-2.1.5-ti1.25/src/util/listen.h Mon Sep 20 15:01:59 2004 @@ -20,7 +20,7 @@ * Listener external interface. */ extern int unix_listen(const char *, int, int); -extern int inet_listen(const char *, int, int); +extern int inet_listen(const char *, int, int, int); extern int fifo_listen(const char *, int, int); extern int stream_listen(const char *, int, int); diff -Pur postfix-2.1.5/src/util/match_list.c postfix-2.1.5-ti1.25/src/util/match_list.c --- postfix-2.1.5/src/util/match_list.c Thu Jul 3 17:02:19 2003 +++ postfix-2.1.5-ti1.25/src/util/match_list.c Mon Sep 20 15:01:59 2004 @@ -125,7 +125,7 @@ list = match_list_parse(list, vstring_str(buf)); if (vstream_fclose(fp)) msg_fatal("%s: read file %s: %m", myname, pattern); - } else if (strchr(pattern, ':') != 0) { /* type:table */ + } else if ((strchr(pattern, ']') == 0) && (strchr(pattern, ':') != 0)) { /* type:table */ if (buf == 0) buf = vstring_alloc(10); #define OPEN_FLAGS O_RDONLY diff -Pur postfix-2.1.5/src/util/match_ops.c postfix-2.1.5-ti1.25/src/util/match_ops.c --- postfix-2.1.5/src/util/match_ops.c Fri Mar 12 23:39:29 2004 +++ postfix-2.1.5-ti1.25/src/util/match_ops.c Mon Sep 20 15:01:59 2004 @@ -54,6 +54,15 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Takahiro Igarashi +/* +/* Dean C. Strik +/* Department ICT Services +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven, Netherlands +/* E-mail: /*--*/ /* System library. */ @@ -63,6 +72,11 @@ #include #include #include +#include + +#ifdef INT_MAX_IN_LIMITS_H +#include +#endif #ifdef STRCASECMP_IN_STRINGS_H #include @@ -75,12 +89,42 @@ /* Utility library. */ #include +#include #include #include #include #include #include +#define BITS_PER_ADDR_V4 32 +#define BITS_PER_ADDR_V6 128 + +#ifdef INET6 + +/* + * IPv6-enabled code was written by Takahiro Igarashi and Dean Strik. + */ + +#endif /* INET6 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* prototypes */ +static PRINTFLIKE(2,3) void warning_msg(VSTRING *, const char *, ...); +#ifdef INET6 +static int mask_comp(void *, void *, int); +#endif /* INET6 */ + /* match_string - match a string literal */ int match_string(int unused_flags, const char *string, const char *pattern) @@ -177,6 +221,7 @@ return (0); } +#ifndef INET6 /* match_parse_mask - parse net/mask pattern */ static int match_parse_mask(const char *pattern, unsigned long *net_bits, @@ -185,11 +230,9 @@ char *saved_pattern; char *mask; -#define BITS_PER_ADDR 32 - saved_pattern = mystrdup(pattern); if ((mask = split_at(saved_pattern, '/')) != 0) { - if (!alldig(mask) || (*mask_shift = atoi(mask)) > BITS_PER_ADDR + if (!alldig(mask) || (*mask_shift = atoi(mask)) > BITS_PER_ADDR_V4 || (*net_bits = inet_addr(saved_pattern)) == INADDR_NONE) { msg_fatal("bad net/mask pattern: %s", pattern); } @@ -198,11 +241,357 @@ return (mask != 0); } +#endif + +static void PRINTFLIKE(2,3) warning_msg(VSTRING *vp, const char *fmt,...) +{ + va_list ap; + if (vp) { + va_start(ap, fmt); + vstring_vsprintf(vp, fmt, ap); + va_end(ap); + } else { + va_start(ap, fmt); + msg_vprintf(MSG_WARN, fmt, ap); + va_end(ap); + } +} + +/* v6addr_literal - copy IPv6 literal address from bracketed version */ +/* Supports both plain addresses and addr/plen's */ + +static char *v6addr_literal(const char *pattern) +{ + size_t patlen; + char *mypattern, *ptr; + + if (pattern == NULL) + msg_panic("v6_addr_literal: called with NULL pattern pointer"); + if (msg_verbose > 1) + msg_info("v6addr_literal: input pattern %s", pattern); + + patlen = strlen(pattern); + + /* + * Note that we allow two different presentation/configuration + * formats for literal IPv6 (address/prefixlen) combinations. + * These are [v6addr]/plen and [v6addr/plen]. The second should + * be avoided and will be deprecated in later Postfix/v6 versions. + */ + if (*pattern == '[') { + mypattern = mystrdup(pattern + 1); + if (pattern[patlen - 1] == ']') { + /* + * Format: "[v6addr]" or "[v6addr/plen]". + */ + mypattern[patlen - 2] = '\0'; + } else if ((ptr = strchr(mypattern + 1, '/')) != NULL + && *--ptr == ']') { + /* + * Format: "[v6addr]/plen". + */ + while (*ptr) + ptr++[0] = ptr[1]; + } + } else { + mypattern = mystrdup(pattern); + } + + if (msg_verbose > 1) + msg_info("v6addr_literal: debracketed to %s", mypattern); + + return (mypattern); +} + +/* std_addr_pattern - standardize address pattern */ + +int std_addr_pattern(int flags, const char *pattern, + ADDR_PATTERN **result, VSTRING *warnings) +{ + char *myname = "std_addr_pattern"; + ADDR_PATTERN *res; + int mask; +#ifdef INET6 + int pf; + char *mypattern, *plenp; + int bits_per_addr, aierr; + struct addrinfo hints, *res0; + struct sockaddr_storage *ss_pattern; + + pf = PF_UNSPEC; + *result = NULL; + + if (pattern == NULL) + msg_panic("%s: pattern may not be NULL!", myname); + + /* + * IPv6 addresses passed as pattern to match_hostaddr should start + * with a bracket '[' and have a ']' closing. This is as specific + * as it can get. + */ + mypattern = v6addr_literal(pattern); + if (*pattern == '[') { + pf = PF_INET6; + } else if (!(flags & (MATCH_FLAG_STRICT_ADDR|MATCH_FLAG_NOLOOKUP))) { + /* + * Return if we find what appears to be a maptype:file entry. + * It's up to the caller of this function to handle this. + */ + if (strchr(pattern, ':') != NULL) { + myfree(mypattern); + return (1); + } + } + plenp = split_at(mypattern, '/'); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = pf; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + aierr = getaddrinfo(mypattern, NULL, &hints, &res0); + /* + * EAI_NONAME happens when the pattern was not supplied in a + * valid printable form. This is a non-fatal error in strict + * address pattern maps like the CIDR dictionary. + */ + if (aierr == EAI_NONAME) { + if (msg_verbose || (flags & MATCH_FLAG_STRICT_ADDR)) + warning_msg(warnings, + "%s: invalid address pattern \"%s\"", + myname, mypattern); + myfree(mypattern); + return (0); + } + if (aierr != 0 && aierr != EAI_NONAME) + msg_fatal("%s: getaddrinfo(%s): %s", myname, mypattern, + GAI_STRERROR(aierr)); + pf = res0->ai_family; + switch (pf) { + case AF_INET: + bits_per_addr = BITS_PER_ADDR_V4; + break; + case AF_INET6: + bits_per_addr = BITS_PER_ADDR_V6; + break; + default: + warning_msg(warnings, + "%s: unsupported address family %d in lookup result " + "of \"%s\"", myname, pf, pattern); + freeaddrinfo(res0); + myfree(mypattern); + return (0); + } + ss_pattern = (struct sockaddr_storage *) + mymalloc(sizeof(struct sockaddr_storage)); + memcpy(ss_pattern, (const void *)res0->ai_addr, res0->ai_addrlen); + freeaddrinfo(res0); + + if (plenp != NULL) { + /* + * Split the pattern into an address and a prefix length + * We explicitly allow "/0" + */ + if (strcmp(plenp, "0")) { + mask = atoi(plenp); + if (mask <= 0 || mask > bits_per_addr) { + warning_msg(warnings, "%s: bad net/mask pattern: %s", + myname, pattern); + myfree(mypattern); + myfree((char *)ss_pattern); + return (0); + } + } else { + mask = 0; + } + } else { + /* + * A single address is considered a prefix with maximum prefix length. + */ + switch (pf) { + case AF_INET: + mask = BITS_PER_ADDR_V4; + break; + case AF_INET6: + mask = BITS_PER_ADDR_V6; + break; + default: + msg_panic("%s: address family %d should not occur here", + myname, pf); + } + } + + if (flags & MATCH_FLAG_NONNULL_HOST) { + /* + * We require that the host portion of (address/plen) pairs be zero + * to reduce the impact of configuration errors. + */ + int non_null = 0; + + if (mask != 0 && mask != bits_per_addr) { + int bytesl, bits; + char *addr = NULL; + unsigned char ac; + + switch (ss_pattern->ss_family) { + case AF_INET6: + addr = (char *)(&((struct sockaddr_in6 *)ss_pattern)->sin6_addr); + bits_per_addr = BITS_PER_ADDR_V6; + break; + case AF_INET: + addr = (char *)(&((struct sockaddr_in *)ss_pattern)->sin_addr); + bits_per_addr = BITS_PER_ADDR_V4; + break; + default: + msg_panic("%s: address family %d should not occur here", + myname, pf); + } + bytesl = mask / 8; + bits = (bits_per_addr - mask) % 8; + if (bytesl == bits_per_addr / 8) + non_null = 1; + else + ac = addr[bytesl]; + if (bits == 0) + bits = 8; + if (!non_null && ac != (ac & 0xff << bits)) + non_null = 1; + while (!non_null && ++bytesl < bits_per_addr / 8) + non_null = addr[bytesl] != 0; + } + if (non_null) { + warning_msg(warnings, + "%s: net/mask pattern \"%s/%s\" " + "with non-null host pattern", + myname, mypattern, plenp); + myfree(mypattern); + myfree((char *)ss_pattern); + return (0); + } + } + +#else /* INET6 */ + + char *mypattern, *plenp; + int bits; + unsigned long addr, addr0; + struct sockaddr_in *ss_pattern; + + *result = NULL; + + if (!(flags & MATCH_FLAG_STRICT_ADDR) && strchr(pattern, ':') != 0) + return (1); + + mypattern = mystrdup(pattern); + plenp = split_at(mypattern, '/'); + if (plenp == NULL) { + bits = BITS_PER_ADDR_V4; + } else { + bits = atoi(plenp); + if (bits <= 0 || bits > BITS_PER_ADDR_V4) + warning_msg(warnings, + "%s: bad net/mask pattern: %s", + myname, pattern); + myfree(mypattern); + return (0); + } + + addr = inet_addr(mypattern); + addr0 = htonl(0xffffffff << (BITS_PER_ADDR_V4 - bits)); + if ((flags & MATCH_FLAG_NONNULL_HOST) && (addr & ~addr0)) { + warning_msg(warnings, + "%s: net/mask pattern \"%s/%s\" with " + "non-null host portion", + myname, mypattern, plenp); + myfree(mypattern); + return (0); + } + + /* + * We make a sockaddr_in, but we don't use any of the fields + * except the sin_addr member. Sockaddrs are used to create + * an API that's closer to AF-independence. + */ + ss_pattern = (struct sockaddr_in *)mymalloc(sizeof(struct sockaddr_in)); + memset(ss_pattern, 0, sizeof(*ss_pattern)); + ss_pattern->sin_family = AF_INET; + ss_pattern->sin_addr.s_addr = addr; + +#endif /* INET6 */ + + res = addr_pattern_init(); + res->addr = (struct sockaddr *)ss_pattern; + res->masklen = mask; + res->opattern = mystrdup(pattern); + res->pattern = mypattern; + *result = res; + + return (1); +} + /* match_hostaddr - match host by address */ +/* XXX: the IPv4-only version does not yet use std_addr_pattern --dean */ + int match_hostaddr(int unused_flags, const char *addr, const char *pattern) { char *myname = "match_hostaddr"; +#ifdef INET6 + size_t patlen; + char *plenp; + int aierr, res, ret, mask; + struct addrinfo hints, *res0; + struct sockaddr_storage ss_addr, ss_mask; + ADDR_PATTERN *mask_info; + + ret = 0; + if (msg_verbose) + msg_info("%s: %s ~? %s", myname, addr, pattern); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + aierr = getaddrinfo(addr, NULL, &hints, &res0); + /* + * The access maps checks run both hostname and address through this. + * E.g. the CIDR map checks both the hostname and address. Checking the + * hostname in a CIDR map will yield no result but may not give an + * EAI_NONAME error since it is correct that the hostname cannot be + * interpreted numerically. + */ + if (aierr != 0 && aierr != EAI_NONAME) + msg_fatal("%s: getaddrinfo(%s): %s", myname, addr, GAI_STRERROR(aierr)); + memcpy(&ss_addr, (const void *)res0->ai_addr, res0->ai_addrlen); + freeaddrinfo(res0); + + res = std_addr_pattern(MATCH_FLAG_NONE, pattern, &mask_info, NULL); + if (mask_info == NULL) { + /* + * Try dictionary lookup. This can be case insensitive. + */ + if (res && strchr(pattern, ':') != 0) { + if (dict_lookup(pattern, addr) != NULL) + return 1; + } + return 0; + } + + /* + * Try an exact match with the host address (IPv4 only) + */ + if (mask_info->addr->sa_family == AF_INET && + strcasecmp(pattern, addr) == 0) { + addr_pattern_free(mask_info); + return 1; + } + + res = match_sockaddr((struct sockaddr *)&ss_addr, + mask_info->addr, mask_info->masklen); + addr_pattern_free(mask_info); + return (res != 0); + + +#else unsigned int mask_shift; unsigned long mask_bits; unsigned long net_bits; @@ -219,7 +608,8 @@ * Try dictionary lookup. This can be case insensitive. XXX Probably * should also try again after stripping least significant octets. */ - if (strchr(pattern, ':') != 0) { + if (strchr(pattern, ':') != 0) + { if (dict_lookup(pattern, addr) != 0) return (1); if (dict_errno != 0) @@ -238,14 +628,15 @@ * In a net/mask pattern, the mask is specified as the number of bits of * the network part. */ + if (match_parse_mask(pattern, &net_bits, &mask_shift)) { addr_bits = inet_addr(addr); if (addr_bits == INADDR_NONE) msg_fatal("%s: bad address argument: %s", myname, addr); mask_bits = mask_shift > 0 ? - htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)) : 0; + htonl((0xffffffff) << (BITS_PER_ADDR_V4 - mask_shift)) : 0; if ((addr_bits & mask_bits) == net_bits) - return (1); + return 1; if (net_bits & ~mask_bits) { net_addr.s_addr = (net_bits & mask_bits); msg_fatal("net/mask pattern %s has a non-null host portion; " @@ -254,4 +645,120 @@ } } return (0); +#endif +} + +int +match_sockaddr(const struct sockaddr *addr, const struct sockaddr *mask, + int masklen) +{ + /* + * I generally hate to do so, but this function just asks for + * #ifdef INET6... address comparison in the IPv4 only case is + * utterly trivial, completely unlike the mixed AF case. + */ +#ifdef INET6 + if (addr->sa_family == AF_INET) { + if (mask->sa_family == AF_INET6) { + if (IN6_IS_ADDR_V4MAPPED( + &((struct sockaddr_in6 *)mask)->sin6_addr)) { + /* IPv4 address but IPv4-mapped-IPv6 netmask... */ + if (masklen < 0 || masklen > BITS_PER_ADDR_V4) + return 0; + return mask_comp(&((struct sockaddr_in *)addr)->sin_addr.s_addr, + &((struct sockaddr_in6 *)mask)->sin6_addr.s6_addr[12], + masklen); + } + /* IPv4 address yet IPv6 mask. No match */ + return 0; + } + /* IPv4 address, IPv4 netmask */ + if (masklen < 0 || masklen > BITS_PER_ADDR_V4) + return 0; + return mask_comp(&((struct sockaddr_in *)addr)->sin_addr.s_addr, + &((struct sockaddr_in *)mask)->sin_addr.s_addr, + masklen); + } else if (addr->sa_family == AF_INET6) { + /* IPv6 address, IPv6 netmask */ + struct sockaddr_in6 *addr6, *mask6; + addr6 = (struct sockaddr_in6 *)addr; + mask6 = (struct sockaddr_in6 *)mask; + + if (IN6_IS_ADDR_V4MAPPED(&addr6->sin6_addr)) { + /* V4-mapped IPv6 address */ + struct sockaddr_in addr4; + memset(&addr4, 0, sizeof(addr4)); +#ifdef HAS_SA_LEN + addr4.sin_len = sizeof(addr4); +#endif + addr4.sin_family = AF_INET; + memcpy(&addr4.sin_addr.s_addr, &addr6->sin6_addr.s6_addr[12], 4); + if (masklen > BITS_PER_ADDR_V4 && masklen <= BITS_PER_ADDR_V6) + masklen -= BITS_PER_ADDR_V6 - BITS_PER_ADDR_V4; + return match_sockaddr((struct sockaddr *)&addr4, mask, masklen); + } + /* True IPv6, finally... */ + if (masklen < 0 || masklen > BITS_PER_ADDR_V6) + return 0; + if (mask->sa_family != AF_INET6 || + IN6_IS_ADDR_V4MAPPED(&mask6->sin6_addr)) + return 0; +#ifdef INET6_KAME + if (IN6_IS_ADDR_SITELOCAL(&addr6->sin6_addr)) + if (!IN6_IS_ADDR_SITELOCAL(&mask6->sin6_addr) || + addr6->sin6_scope_id != mask6->sin6_scope_id) + return 0; + if (IN6_IS_ADDR_LINKLOCAL(&addr6->sin6_addr)) + if (!IN6_IS_ADDR_LINKLOCAL(&mask6->sin6_addr) || + addr6->sin6_scope_id != mask6->sin6_scope_id) + return 0; +#endif + return mask_comp(&addr6->sin6_addr.s6_addr, + &mask6->sin6_addr.s6_addr, + masklen); + } + /* Unsupported address family */ + return 0; +#else /* INET6 */ + /* + * Trivial for IPv4... + */ + return (addr->sa_family == mask->sa_family && + ((struct sockaddr_in *)addr)->sin_addr.s_addr == + ((struct sockaddr_in *)mask)->sin_addr.s_addr); +#endif /* INET6 */ +} + +static int +mask_comp(void *addr, void *mask, int masklen) +{ + int bytes, bit; + + bytes = masklen / 8; + bit = 8 - masklen % 8; + if (memcmp(addr, mask, bytes) != 0) + return 0; + if (bit != 8) { + char *a = addr, *b = mask; + if ((a[bytes] & (0xff << bit)) != (b[bytes] & (0xff << bit))) + return 0; + } + return 1; +} + +ADDR_PATTERN * +addr_pattern_init() { + ADDR_PATTERN *p; + p = (ADDR_PATTERN *)mymalloc(sizeof(ADDR_PATTERN)); + memset(p, 0, sizeof(ADDR_PATTERN)); + return p; } + +void +addr_pattern_free(ADDR_PATTERN *p) { + if (p->addr) myfree((char *)p->addr); + if (p->pattern) myfree(p->pattern); + if (p->opattern) myfree(p->opattern); + myfree((char *)p); +} + diff -Pur postfix-2.1.5/src/util/match_ops.h postfix-2.1.5-ti1.25/src/util/match_ops.h --- postfix-2.1.5/src/util/match_ops.h Tue Nov 20 21:03:07 2001 +++ postfix-2.1.5-ti1.25/src/util/match_ops.h Mon Sep 20 15:01:59 2004 @@ -11,15 +11,40 @@ /* DESCRIPTION /* .nf + /* + * Utility library. + */ +#include + /* External interface. */ #define MATCH_FLAG_NONE 0 #define MATCH_FLAG_PARENT (1<<0) -#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT) +#define MATCH_FLAG_STRICT_ADDR (1<<1) +#define MATCH_FLAG_NOLOOKUP (1<<2) +#define MATCH_FLAG_NONNULL_HOST (1<<3) +#define MATCH_FLAG_ALL (MATCH_FLAG_PARENT | MATCH_FLAG_NOLOOKUP | MATCH_FLAG_NONNULL_HOST) + +#define GAI_STRERROR(error) \ + ((error == EAI_SYSTEM) ? strerror(errno) : gai_strerror(error)) + + /* Data structures. */ + +typedef struct ADDR_PATTERN { + struct sockaddr *addr; /* pointer to sockaddr(_storage) address */ + size_t masklen; /* prefix length */ + char *pattern; /* modified pattern */ + char *opattern; /* original string pattern */ +} ADDR_PATTERN; extern int match_string(int, const char *, const char *); extern int match_hostname(int, const char *, const char *); extern int match_hostaddr(int, const char *, const char *); +extern int std_addr_pattern(int, const char *, ADDR_PATTERN **, VSTRING *); +extern int match_sockaddr(const struct sockaddr *, const struct sockaddr *, int); + +extern ADDR_PATTERN * addr_pattern_init(void); +extern void addr_pattern_free(ADDR_PATTERN *); /* LICENSE /* .ad @@ -30,6 +55,13 @@ /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA +/* +/* Dean C. Strik +/* Department ICT Services +/* Eindhoven University of Technology +/* P.O. Box 513 +/* 5600 MB Eindhoven, Netherlands +/* E-mail: /*--*/ #endif diff -Pur postfix-2.1.5/src/util/sdbm.c postfix-2.1.5-ti1.25/src/util/sdbm.c --- postfix-2.1.5/src/util/sdbm.c Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/sdbm.c Mon Sep 20 15:02:00 2004 @@ -0,0 +1,971 @@ +/*++ +/* NAME +/* sdbm 3h +/* SUMMARY +/* SDBM Simple DBM: ndbm work-alike hashed database library +/* SYNOPSIS +/* include "sdbm.h" +/* DESCRIPTION +/* This file includes the public domain 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 +/* The file has been patched following the advice of Uwe Ohse +/* : +/* -------------------------------------------------------------- +/* this patch fixes a problem with sdbms .dir file, which arrises when +/* a second .dir block is needed for the first time. read() returns 0 +/* in that case, and the library forgot to initialize that new block. +/* +/* A related problem is that the calculation of db->maxbno is wrong. +/* It just appends 4096*BYTESIZ bits, which is not enough except for +/* small databases (.dir basically doubles everytime it's too small). +/* -------------------------------------------------------------- +/* According to Uwe Ohse, the patch has also been submitted to the +/* author of SDBM. (The 4096*BYTESIZ bits comment may apply with a +/* different size for Postfix/TLS, as the patch was sent against the +/* original SDBM distributiona and for Postfix/TLS I have changed the +/* default sizes. +/* .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 +#include +#ifdef WIN32 +#include +#include +#else +#include +#endif +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#endif + +#include + +/* + * 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) + { + int got; + if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0 + || (got = read(db->dirf, db->dirbuf, DBLKSIZ)) < 0) + return 0; + if (got==0) + memset(db->dirbuf,0,DBLKSIZ); + 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) + { + int got; + if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0 + || (got = read(db->dirf, db->dirbuf, DBLKSIZ)) < 0) + return 0; + if (got==0) + memset(db->dirbuf,0,DBLKSIZ); + db->dirbno = dirb; + } + + db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); + +#if 0 + if (dbit >= db->maxbno) + db->maxbno += DBLKSIZ * BYTESIZ; +#else + if (OFF_DIR((dirb+1))*BYTESIZ > db->maxbno) + db->maxbno=OFF_DIR((dirb+1))*BYTESIZ; +#endif + + 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 -Pur postfix-2.1.5/src/util/sdbm.h postfix-2.1.5-ti1.25/src/util/sdbm.h --- postfix-2.1.5/src/util/sdbm.h Thu Jan 1 01:00:00 1970 +++ postfix-2.1.5-ti1.25/src/util/sdbm.h Mon Sep 20 15:02:00 2004 @@ -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 + +#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 -Pur postfix-2.1.5/src/util/sys_defs.h postfix-2.1.5-ti1.25/src/util/sys_defs.h --- postfix-2.1.5/src/util/sys_defs.h Sun Aug 1 23:05:23 2004 +++ postfix-2.1.5-ti1.25/src/util/sys_defs.h Mon Sep 20 15:02:00 2004 @@ -108,6 +108,14 @@ #define SOCKOPT_SIZE socklen_t #endif +#if !defined(NOGETIFADDRS) && ( \ + (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 105000000) \ + || (defined(__FreeBSD__) && __FreeBSD__ >= 4) \ + || (defined(OpenBSD) && OpenBSD >= 200003) \ + || defined(USAGI_LIBINET6)) +#define HAVE_GETIFADDRS +#endif + /* * UNIX on MAC. */ @@ -293,6 +301,7 @@ #define FIONREAD_IN_SYS_FILIO_H #define USE_STATVFS #define STATVFS_IN_SYS_STATVFS_H +#define INT_MAX_IN_LIMITS_H #define STREAM_CONNECTIONS /* avoid UNIX-domain sockets */ #define LOCAL_LISTEN stream_listen #define LOCAL_ACCEPT stream_accept @@ -300,6 +309,9 @@ #define LOCAL_TRIGGER stream_trigger #define HAS_VOLATILE_LOCKS #define BROKEN_READ_SELECT_ON_TCP_SOCKET +#ifdef INET6 +#define HAS_SIOCGLIF +#endif /* * Allow build environment to override paths. @@ -559,6 +571,10 @@ #define SOCKADDR_SIZE socklen_t #define SOCKOPT_SIZE socklen_t #endif +#ifdef INET6 +#define HAS_PROCNET_IFINET6 +#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" +#endif #endif #ifdef LINUX1 @@ -587,6 +603,10 @@ #define NATIVE_NEWALIAS_PATH "/usr/bin/newaliases" #define NATIVE_COMMAND_DIR "/usr/sbin" #define NATIVE_DAEMON_DIR "/usr/libexec/postfix" +#ifdef INET6 +#define HAS_PROCNET_IFINET6 +#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" +#endif #endif /* diff -Pur postfix-2.1.5/src/util/valid_hostname.c postfix-2.1.5-ti1.25/src/util/valid_hostname.c --- postfix-2.1.5/src/util/valid_hostname.c Wed Oct 22 20:49:43 2003 +++ postfix-2.1.5-ti1.25/src/util/valid_hostname.c Mon Sep 20 15:02:00 2004 @@ -53,6 +53,13 @@ #include #include +#ifdef INET6 +#include +#include +#include +#include +#endif + /* Utility library. */ #include "msg.h" @@ -109,7 +116,23 @@ msg_warn("%s: misplaced hyphen: %.100s", myname, name); return (0); } - } else { + } +#ifdef INET6 + else if (ch == ':') { + struct addrinfo hints, *res; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(name, "0", &hints, &res) == 0) { + freeaddrinfo(res); + return 1; + } else + return 0; + } +#endif + else { if (gripe) msg_warn("%s: invalid character %d(decimal): %.100s", myname, ch, name); @@ -131,6 +154,12 @@ return (1); } +#ifdef INET6_KAME +#define INET6_ADDR_PRES_CHARS ":./0123456789abcdefABCDEF%" +#else +#define INET6_ADDR_PRES_CHARS ":./0123456789abcdefABCDEF" +#endif + /* valid_hostaddr - test dotted quad string for correctness */ int valid_hostaddr(const char *addr, int gripe) @@ -141,6 +170,9 @@ int byte_count = 0; int byte_val = 0; int ch; +#ifdef INET6 + struct addrinfo hints, *res; +#endif #define BYTES_NEEDED 4 @@ -153,11 +185,22 @@ return (0); } +#ifdef INET6 + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_STREAM; /*dummy*/ + hints.ai_flags = AI_NUMERICHOST; + if (getaddrinfo(addr, "0", &hints, &res) == 0) { + freeaddrinfo(res); + return 1; + } +#endif + /* * Preliminary IPV6 support. */ if (strchr(addr, ':')) { - if (*(cp = addr + strspn(addr, ":./0123456789abcdefABCDEF")) != 0) { + if (*(cp = addr + strspn(addr, INET6_ADDR_PRES_CHARS)) != 0) { if (gripe) msg_warn("%s: invalid character %d(decimal): %.100s", myname, *cp, addr);