| 1 | Using Exim 4.80+ with GnuTLS |
| 2 | ============================ |
| 3 | |
| 4 | (1) I'm having problems building with GnuTLS 1, why? |
| 5 | (2) What changed? Why? |
| 6 | (3) I'm seeing: |
| 7 | "(gnutls_handshake): A TLS packet with unexpected length was received" |
| 8 | Why? |
| 9 | (4) What's the deal with MD5? |
| 10 | (5) What happened to gnutls_require_kx / gnutls_require_mac / |
| 11 | gnutls_require_protocols? |
| 12 | (6) What's the deal with tls_dh_max_bits? What's DH? |
| 13 | (7) What's a Priority String? |
| 14 | (8) How do I use tls_require_ciphers? |
| 15 | (9) How do I test STARTTLS support? |
| 16 | |
| 17 | |
| 18 | |
| 19 | (1): I'm having problems building with GnuTLS 1, why? |
| 20 | ----------------------------------------------------- |
| 21 | |
| 22 | GnuTLS's library interface has changed and Exim uses the more current |
| 23 | interface. Since GnuTLS is security critical code, you should probably update |
| 24 | to a supported release. |
| 25 | |
| 26 | If updating GnuTLS is not an option, then build Exim against OpenSSL instead. |
| 27 | |
| 28 | If neither is an option, then you might build Exim with the rule |
| 29 | "SUPPORT_TLS=yes" commented out in "Local/Makefile", so that your Exim build |
| 30 | no longer has TLS support. |
| 31 | |
| 32 | If you need to keep TLS support, and you can't use OpenSSL, then you'll have |
| 33 | to update the GnuTLS you have installed. Sorry. |
| 34 | |
| 35 | We've tested the build of Exim back as far as GnuTLS 2.8.x; most development |
| 36 | work is done with 2.12 and tested on 2.10 and 3.x. |
| 37 | |
| 38 | If you have to pick a version to upgrade to, use GnuTLS 3.x if available. The |
| 39 | GnuTLS developers took advantage of the version bump to add an error code |
| 40 | return value which makes debugging some problems a lot easier. |
| 41 | |
| 42 | |
| 43 | |
| 44 | (2): What changed? Why? |
| 45 | ------------------------ |
| 46 | |
| 47 | The GnuTLS provider integration in Exim was overhauled, rewritten but with |
| 48 | some copy/paste, because building Exim against more current releases of GnuTLS |
| 49 | was issuing deprecation warnings from the compiler. |
| 50 | |
| 51 | When a library provider marks up the include files so that some function calls |
| 52 | will cause the compiler/linker to emit deprecation warnings, it's time to pay |
| 53 | serious attention. A future release might not work at all. Using the new |
| 54 | APIs may mean that Exim will *stop* working with older releases of GnuTLS. |
| 55 | The GnuTLS support in Exim was overhauled in Exim 4.80. In prior releases, |
| 56 | Exim hard-coded a lot of algorithms and constrained what could happen. In |
| 57 | Exim 4.79, we added to the hard-coded list just enough to let TLSv1.1 and |
| 58 | TLSv1.2 be negotiated, but not actually support the mandatory algorithms of |
| 59 | those protocol versions. When Exim's GnuTLS integration was originally |
| 60 | written, there was no other choice than to make Exim responsible for a lot of |
| 61 | this. In the meantime, GnuTLS has improved. |
| 62 | |
| 63 | With the rewrite, we started using the current API and leaving a lot more |
| 64 | responsibility for TLS decisions to the library. |
| 65 | |
| 66 | The GnuTLS developers added "priority strings" (see Q7), which provide an |
| 67 | interface exposed to the configuration file for a lot of the tuning. |
| 68 | |
| 69 | The GnuTLS policy is to no longer support MD5 in certificates. Exim had |
| 70 | previously been immune to this policy, but no longer. See Q4. |
| 71 | |
| 72 | |
| 73 | |
| 74 | (3): I'm seeing "A TLS packet with unexpected length was received". Why? |
| 75 | ------------------------------------------------------------------------- |
| 76 | |
| 77 | The most likely reason is that the client dropped the connection during |
| 78 | handshake, because their library disliked some aspect of the negotiation. |
| 79 | |
| 80 | In GnuTLS 2, an EOF on the connection is reported with an error code for |
| 81 | packets being too large, and the above is the string returned by the library |
| 82 | for that error code. In GnuTLS 3, there's a specific error code for EOF and |
| 83 | the diagnostic will be less confusing. |
| 84 | |
| 85 | Most likely cause is an MD5 hash used in a certificate. See Q4 below. |
| 86 | Alternatively, the client dislikes the size of the Diffie-Hellman prime |
| 87 | offered by the server; if lowering the value of the "tls_dh_max_bits" Exim |
| 88 | option fixes the problem, this was the cause. See Q6. |
| 89 | |
| 90 | |
| 91 | |
| 92 | (4): What's the deal with MD5? |
| 93 | ------------------------------ |
| 94 | |
| 95 | MD5 is a hash algorithm. Hash algorithms are used to reduce a lot of data |
| 96 | down to a fairly short value, which is supposed to be extremely hard to |
| 97 | manipulate to get a value of someone's choosing. Signatures, used to attest |
| 98 | to identity or integrity, rely upon this manipulation being effectively |
| 99 | impossible, because the signature is the result of math upon the hash result. |
| 100 | Without hash algorithms, signatures would be longer than the text being |
| 101 | signed. |
| 102 | |
| 103 | MD5 was once very popular. It still is far too popular. Real world attacks |
| 104 | have been proven possible against MD5. Including an attack against PKI |
| 105 | (Public Key Infrastructure) certificates used for SSL/TLS. In that attack, |
| 106 | the attackers got a certificate for one identity but were able to then publish |
| 107 | a certificate with the same signature but a different identity. This |
| 108 | undermines the whole purpose of having certificates. |
| 109 | |
| 110 | So GnuTLS stopped trusting any certificate with an MD5-based hash used in it. |
| 111 | The world has been hurriedly moving away from MD5 in certificates for a while. |
| 112 | If you still have such a certificate, you should move too. |
| 113 | |
| 114 | If you paid someone for your certificate, they should be willing to reissue |
| 115 | the certificate with a different algorithm, for no extra money. If they try |
| 116 | to charge money to replace their defective product, buy from someone else |
| 117 | instead. Part of the reason for paying money on a recurring basis is to cover |
| 118 | the ongoing costs of proving a trust relationship, such as providing |
| 119 | revocation protocols. This is just another of those ongoing costs you have |
| 120 | already paid for. |
| 121 | |
| 122 | |
| 123 | |
| 124 | (5): ... gnutls_require_kx / gnutls_require_mac / gnutls_require_protocols? |
| 125 | --------------------------------------------------------------------------- |
| 126 | |
| 127 | These Exim options were used to provide fine-grained control over the TLS |
| 128 | negotiation performed by GnuTLS. They required explicit protocol knowledge |
| 129 | from Exim, which vastly limited what GnuTLS could do and involved the Exim |
| 130 | maintainers in decisions which aren't part of their professional areas of |
| 131 | expertise. The need for Exim to be able to do this went away when GnuTLS |
| 132 | introduced Priority Strings (see Q7). |
| 133 | |
| 134 | If you were using these options before, then you're already an expert user and |
| 135 | should be able to easily craft a priority string to accomplish your goals. |
| 136 | Set the Exim "tls_require_ciphers" value accordingly. There is a main section |
| 137 | option of this name, used for Exim receiving inbound connections, and an SMTP |
| 138 | driver transport option of this name, used for Exim establishing outbound |
| 139 | connections. |
| 140 | |
| 141 | |
| 142 | |
| 143 | (6): What's the deal with tls_dh_max_bits? What's DH? |
| 144 | ------------------------------------------------------ |
| 145 | |
| 146 | You can avoid all of the tls_dh_max_bits issues if you leave "tls_dhparam" |
| 147 | unset, so that you get one of the standard built-in primes used for DH. |
| 148 | |
| 149 | |
| 150 | DH, Diffie-Hellman (or Diffie-Hellman-Merkle, or something naming Williamson) |
| 151 | is the common name for a way for two parties to a communication stream to |
| 152 | exchange some private random data so that both end up with a shared secret |
| 153 | which no eavesdropper can get. It does not provide for proof of the identity |
| 154 | of either party, so on its own is subject to man-in-the-middle attacks, but is |
| 155 | often combined with systems which do provide such proof, improving them by |
| 156 | separating the session key (the shared secret) from the long-term identity, |
| 157 | and so protecting past communications from a break of the long-term identity. |
| 158 | |
| 159 | To do this, the server sends to the client a very large prime number; this is |
| 160 | in the clear, an attacker can see it. This is not a problem; it's so not a |
| 161 | problem, that there are standard named primes which applications can use, and |
| 162 | which Exim now supports. |
| 163 | |
| 164 | The size of the prime number affects how difficult it is to break apart the |
| 165 | shared secret and decrypt the data. As time passes, the size required to |
| 166 | provide protection against an adversary climbs: computers get more powerful, |
| 167 | mathematical advances are made, and so on. |
| 168 | |
| 169 | Estimates of the size needed are published as recommendations by various |
| 170 | groups; a good summary of sizes currently recommended, for various |
| 171 | cryptographic primitives, is available at: |
| 172 | |
| 173 | http://www.keylength.com/en/3/ |
| 174 | |
| 175 | The GnuTLS folks think the ECRYPT II advice is good. They know far more of |
| 176 | such matters than the Exim folks, we just say "er, what they said". |
| 177 | |
| 178 | One of the new pieces of the GnuTLS API is a means for an application to ask |
| 179 | it for guidance and advice on how large some numbers should be. This is not |
| 180 | entirely internal to GnuTLS, since generating the numbers is slow, an |
| 181 | application might want to use a standard prime, etc. So, in an attempt to get |
| 182 | away from being involved in cryptographic policy, and to get rid of a |
| 183 | hard-coded "1024" in Exim's source-code, we switched to asking GnuTLS how many |
| 184 | bits should be in the prime number generated for use for Diffie-Hellman. We |
| 185 | then give this number straight back to GnuTLS when generating a DH prime. |
| 186 | We can ask for various sizes, and did not expose this to the administrator but |
| 187 | instead just asked for "NORMAL" protection. |
| 188 | Literally: |
| 189 | |
| 190 | dh_bits = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, GNUTLS_SEC_PARAM_NORMAL); |
| 191 | |
| 192 | This API is only available as of GnuTLS 2.12. Prior to that release, we stuck |
| 193 | with the old value, for compatibility, so "1024" is still hard-coded. |
| 194 | Reviewing the page above, you'll see that this is described as "Short-term |
| 195 | protection against medium organizations, medium-term protection against small |
| 196 | organizations." |
| 197 | |
| 198 | So if you are using an old release of GnuTLS, you can either add to |
| 199 | Local/Makefile a different value of "EXIM_SERVER_DH_BITS_PRE2_12" or accept |
| 200 | that your protection might not be adequate to your needs. We advise updating |
| 201 | to a more current GnuTLS release and rebuilding Exim against that. |
| 202 | |
| 203 | Unfortunately, some TLS libraries have the client side bound how large a DH |
| 204 | prime they will accept from the server. The larger the number, the more |
| 205 | computation required to work with it and the slower that things get. So they |
| 206 | pick what they believe to be reasonable upper bounds, and then typically |
| 207 | forget about it for several years. |
| 208 | |
| 209 | Worse, in TLS the DH negotiation happens after a ciphersuite has been chosen, |
| 210 | so if the client dislikes the value then a different ciphersuite avoiding DH |
| 211 | can not be negotiated! The client typically drops the connection, resulting |
| 212 | in errors to the user and errors in the Exim logs. With GnuTLS 3, you'll see |
| 213 | the EOF (End-Of-File) error message in Exim's logs, reported as being part of |
| 214 | "gnutls_handshake", but with GnuTLS 2 you'll see a log message about a packet |
| 215 | with an unexpected size. Unless the client software is written intelligently |
| 216 | enough to be able to adapt and reconnect forbidding DH, the client will never |
| 217 | be able to negotiate TLS. |
| 218 | |
| 219 | This time around, we discovered that the NSS library used by various Mozilla |
| 220 | products, Chrome, etc, and most particularly by the Thunderbird mail client, |
| 221 | has the lowest cap. In fact, prior to recent updates, their upper limit was |
| 222 | lower than the value returned by GnuTLS for "NORMAL". The most recent NSS |
| 223 | library release raises this, but the most recent Thunderbird release still has |
| 224 | the old limit. |
| 225 | |
| 226 | So Exim had to get involved in cryptography policy decisions again. We added |
| 227 | the "tls_dh_max_bits" global option, to set a number used in both OpenSSL and |
| 228 | GnuTLS bindings for Exim. In GnuTLS, it clamps the value returned by |
| 229 | gnutls_sec_param_to_pk_bits(), so that if the returned value is larger than |
| 230 | tls_dh_max_bits then tls_dh_max_bits would be used instead. |
| 231 | |
| 232 | Our policy decision was to default the value of tls_dh_max_bits to the maximum |
| 233 | supported in the most recent Thunderbird release, and to make this an |
| 234 | administrator-available option so that administrators can choose to trade off |
| 235 | security versus compatibility by raising it. |
| 236 | |
| 237 | A future release of Exim may even let the administrator tell GnuTLS to ask for |
| 238 | more or less than "NORMAL". |
| 239 | |
| 240 | To add to the fun, the size of the prime returned by GnuTLS when we call |
| 241 | gnutls_dh_params_generate2() is not limited to be the requested size. GnuTLS |
| 242 | has a tendency to overshoot. 2237 bit primes are common when 2236 is |
| 243 | requested, and higher still have been observed. Further, there is no API to |
| 244 | ask how large the prime bundled up inside the parameter is; the most we can do |
| 245 | is ask how large the DH prime used in an active TLS session is. Since we're |
| 246 | not able to use GnuTLS API calls (and exporting to PKCS3 and then calling |
| 247 | OpenSSL routines would be undiplomatic, plus add a library dependency), we're |
| 248 | left with no way to actually know the size of the freshly generated DH prime. |
| 249 | |
| 250 | Thus we check if the the value returned is at least 10 more than the minimum |
| 251 | we'll accept as a client (EXIM_CLIENT_DH_MIN_BITS, see below, defaults to |
| 252 | 1024) and if it is, we subtract 10. Then we reluctantly deploy a strategy |
| 253 | called "hope". This is not guaranteed to be successful; in the first code |
| 254 | pass on this logic, we subtracted 3, asked for 2233 bits and got 2240 in the |
| 255 | first test. |
| 256 | |
| 257 | If you see Thunderbird clients still failing, then as a user who can see into |
| 258 | Exim's spool directory, run: |
| 259 | |
| 260 | $ openssl dhparam -noout -text -in /path/to/spool/gnutls-params-2236 | head |
| 261 | |
| 262 | Ideally, the first line will read "PKCS#3 DH Parameters: (2236 bit)". If the |
| 263 | count is more than 2236, then remove the file and let Exim regenerate it, or |
| 264 | generate one yourself and move it into place. Ideally use "openssl dhparam" |
| 265 | to generate it, and then wait a very long time; at least this way, the size |
| 266 | will be correct. |
| 267 | |
| 268 | The use of "hope" as a strategy was felt to be unacceptable as a default, so |
| 269 | late in the RC series for 4.80, the whole issue was side-stepped. The primes |
| 270 | used for DH are publicly revealed; moreover, there are selection criteria for |
| 271 | what makes a "good" DH prime. As it happens, there are *standard* primes |
| 272 | which can be used, and are specified to be used for certain protocols. So |
| 273 | these primes were built into Exim, and by default exim now uses a 2048 bit |
| 274 | prime from section 2.2 of RFC 5114. |
| 275 | |
| 276 | |
| 277 | A TLS client does not get to choose the DH prime used, but can choose a |
| 278 | minimum acceptable value. For Exim, this is a compile-time constant called |
| 279 | "EXIM_CLIENT_DH_MIN_BITS" of 1024, which can be overruled in "Local/Makefile". |
| 280 | |
| 281 | |
| 282 | |
| 283 | (7): What's a Priority String? |
| 284 | ------------------------------ |
| 285 | |
| 286 | A priority string is a way for a user of GnuTLS to tell GnuTLS how it should |
| 287 | make decisions about what to do in TLS; it includes which algorithms to make |
| 288 | available for various roles, what compatibility trade-offs to make, which |
| 289 | features to enable or disable. |
| 290 | |
| 291 | It is exposed to the Mail Administrator in Exim's configuration file as the |
| 292 | "tls_require_ciphers" option, which exists as a main section option for use in |
| 293 | Exim as a server, accepting connections, and as an option on Transports using |
| 294 | the SMTP driver, for use in Exim as a client. The main section option is |
| 295 | *not* the default for the transport option, they are entirely independent. |
| 296 | For both, the default value used by Exim is the string "NORMAL". (This is not |
| 297 | the same NORMAL as for DH prime bit size selection in Q6, but a different |
| 298 | NORMAL.) See Q8. |
| 299 | |
| 300 | The current documentation, for the most recent release of GnuTLS, is available |
| 301 | online at: |
| 302 | |
| 303 | http://www.gnutls.org/manual/html_node/Priority-Strings.html |
| 304 | |
| 305 | Beware that if you are not using the most recent GnuTLS release then this |
| 306 | documentation will be wrong for you! You should find the "info" documentation |
| 307 | which came with GnuTLS to review the available options. It's under "The TLS |
| 308 | Handshake Protocol". |
| 309 | |
| 310 | $ pinfo --node="Priority Strings" gnutls |
| 311 | |
| 312 | (This author is unable to persuade the "info" command-line tool to jump |
| 313 | straight to the required node, but "pinfo" works.) |
| 314 | |
| 315 | To trade off some security for more compatibility, you might set a value of |
| 316 | "NORMAL:%COMPAT". See the documentation for more, including lowering security |
| 317 | even further for more security, forcing clients to use the server's protocol |
| 318 | suite, and ways to force selection of particular algorithms. |
| 319 | |
| 320 | |
| 321 | |
| 322 | (8): How do I use tls_require_ciphers? |
| 323 | -------------------------------------- |
| 324 | |
| 325 | This is the name of two options in Exim. One is a main section option, used |
| 326 | by Exim as a server when a client initiates SSL/TLS negotiation, the other is |
| 327 | an option on transports which use "driver = smtp", used when Exim initiates |
| 328 | SSL/TLS as a client talking to a remote server. |
| 329 | |
| 330 | The option is expanded and so can take advantage of any variables which have |
| 331 | been set. This includes the IP address of the remote side, the port upon |
| 332 | which a connection was accepted (when a server), and more. Currently it does |
| 333 | not have access to $tls_sni, whether as a client or as a server. |
| 334 | |
| 335 | This example, for the main section's option, will let the library defaults be |
| 336 | permitted on the MX port, where there's probably no identity verification |
| 337 | anyway, and lowers security further by increasing compatibility; but this ups |
| 338 | the ante on the submission ports where the administrator might have some |
| 339 | influence on the choice of clients used: |
| 340 | |
| 341 | tls_require_ciphers = ${if =={$received_port}{25}\ |
| 342 | {NORMAL:%COMPAT}\ |
| 343 | {SECURE128}} |
| 344 | |
| 345 | Note that during Exim start-up, when this option is sanity-checked, there will |
| 346 | be no value of $received_port. In the above example, the checked value will |
| 347 | thus be "SECURE128". Be careful to ensure that it always expands safely. |
| 348 | |
| 349 | |
| 350 | |
| 351 | (9): How do I test STARTTLS support? |
| 352 | ------------------------------------ |
| 353 | |
| 354 | The best command-line client for debugging specifically SSL/TLS which this |
| 355 | author has encountered is part of the GnuTLS suite, and is called |
| 356 | "gnutls-cli". It's best because it's the only interactive tool which lets the |
| 357 | user start TLS handshake exactly when they wish, so can choose to use the |
| 358 | STARTTLS command. |
| 359 | |
| 360 | $ gnutls-cli --starttls --crlf --port 587 mail.example.org |
| 361 | |
| 362 | After EHLO, to see the capabilities, enter STARTTLS, wait for the response, |
| 363 | then send EOF. Typically that's done by typing Ctrl-D at the start of a line. |
| 364 | The "gnutls-cli" tool will take over, set up TLS (or fail) and by the time it |
| 365 | returns to await more user input, you're using a secure connection and should |
| 366 | type your second EHLO. |
| 367 | |
| 368 | The "--x509cafile" option may be helpful for checking certificates and |
| 369 | "--priority" to pass a priority string to the client tool for configuring it. |
| 370 | |
| 371 | The --crlf is for strict protocol correctness, but Exim doesn't really need |
| 372 | it, so "gnutls-cli -s -p 587 mail.example.org" is shorter. |
| 373 | |
| 374 | |
| 375 | For debugging SMTP as a whole, we recommend swaks, "Swiss Army Knife SMTP", by |
| 376 | John Jetmore (one of the Exim Maintainers). This has some TLS tuning options; |
| 377 | it can be found at: |
| 378 | |
| 379 | http://www.jetmore.org/john/code/swaks/ |
| 380 | |
| 381 | |
| 382 | For OpenSSL, the "openssl s_client" command helps; you can either set up Exim |
| 383 | with a listening port which is SSL-on-connect or tell s_client to use |
| 384 | STARTTLS. |
| 385 | |
| 386 | For the former, use the "tls_on_connect_ports" option and the |
| 387 | "daemon_smtp_ports" option. Most clients for SSL-on-connect use the port |
| 388 | which was briefly registered with IANA for this purpose, 465. So you would |
| 389 | set something like: |
| 390 | |
| 391 | daemon_smtp_ports = 25 : 465 : 587 |
| 392 | tls_on_connect_ports = 465 |
| 393 | |
| 394 | To use s_client with STARTTLS support, use "-starttls smtp" on the |
| 395 | command-line. Beware that older versions of OpenSSL did not wait for the SMTP |
| 396 | banner before sending EHLO, which will fall afoul of the protocol |
| 397 | synchronisation checks in Exim (used to trip up pump-and-dump spammers); also |
| 398 | you will not get control of the session until TLS is established. That said, |
| 399 | this tool provides more tuning hooks for adjusting how TLS will be set up than |
| 400 | most. |
| 401 | |
| 402 | *BEWARE* that by default, s_client will take any line starting with a capital |
| 403 | letter "R" to be a request to initiate TLS renegotiation with the server and |
| 404 | the line will not be sent. This may trip up "RCPT TO:<someone@example.org>" |
| 405 | lines in SMTP. SMTP is not case-sensitive, so type "rcpt to" instead. |
| 406 | Alternatively, invoke s_client with the "-ign_eof" option to disable this |
| 407 | R-filtering and a few other features. |
| 408 | |
| 409 | |
| 410 | # END OF FAQ |