|
Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com |
Re: "TLS1_SETUP_KEY_BLOCK:cipher or hash unavailable" problem on Solaris 10 + possible solution
From: Victor Duchovni (Victor.Duchovni
MorganStanley.com)
Date: Mon Jan 22 2007 - 22:53:28 CST
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Mon, Jan 22, 2007 at 03:31:05PM -0500, Victor Duchovni wrote:
[ Cross-posted to postfix-devel, and openssl-users, with a Bcc to
postfix-users where it all began. Please reply only whichever of
openssl-users or postfix-devel you belong to. I'll summarize any
conclusions to both lists at the end as appropriate. ].
> Unfortunately, Wietse's interoperability standards are more stringent
> than yours :-(
>
So I built Postfix+TLS on a SunOS 5.10 system, using the vendor OpenSSL
libraries /usr/sfw/lib, and observed the reported issue:
$ smtp-finger "[localhost]:26"
Connected to localhost[127.0.0.1]:26
< 220 amnesiac.ms.com ESMTP Postfix
> EHLO amnesiac.ms.com
< 250-amnesiac.ms.com
< 250-PIPELINING
< 250-SIZE 10240000
< 250-VRFY
< 250-ETRN
< 250-STARTTLS
< 250-ENHANCEDSTATUSCODES
< 250-8BITMIME
< 250 DSN
> STARTTLS
< 220 2.0.0 Ready to start TLS
SSL_connect error to localhost[127.0.0.1]:26: -1
warning: TLS library problem: 27116:error:140D308A:SSL routines:TLS1_SETUP_KEY_BLOCK:cipher or hash unavailable:../../../../common/openssl/ssl/t1_enc.c:449:
The problem is lack of AES256 support the stock SunOS 5.10 libcrypto. They
only partly fixed the problem by changing the definition of the "DEFAULT"
cipherlist as follows:
$ strings /usr/sfw/lib/libssl.so | grep ':
STRENGTH' | uniq
ALL:!DHE-RSA-AES256-SHA:!DHE-DSS-AES256-SHA:!AES256-SHA:!ADH:+RC4:
STRENGTH
When using "ALL" rather than "DEFAULT", the missing SSL ciphersuites
then the "AES+HIGH" ciphers:
ADH-AES256-SHA SSLv3 Kx=DH Au=None Enc=AES(256) Mac=SHA1
DHE-RSA-AES256-SHA SSLv3 Kx=DH Au=RSA Enc=AES(256) Mac=SHA1
DHE-DSS-AES256-SHA SSLv3 Kx=DH Au=DSS Enc=AES(256) Mac=SHA1
AES256-SHA SSLv3 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA1
The best interim work-around, short of building stock OpenSSL 0.9.8d, is:
lmtp_tls_exclude_ciphers = AES+HIGH
smtp_tls_exclude_ciphers = AES+HIGH
smtpd_tls_exclude_ciphers = AES+HIGH
this removes exactly the unavailable ciphers, without removing all HIGH
ciphers (e.g. 3DES).
$ smtp-finger -o smtp_tls_exclude_ciphers=AES+HIGH "[localhost]:26"
Connected to localhost[127.0.0.1]:26
< 220 amnesiac.ms.com ESMTP Postfix
> EHLO amnesiac.ms.com
< 250-amnesiac.ms.com
< 250-PIPELINING
< 250-SIZE 10240000
< 250-VRFY
< 250-ETRN
< 250-STARTTLS
< 250-ENHANCEDSTATUSCODES
< 250-8BITMIME
< 250 DSN
> STARTTLS
< 220 2.0.0 Ready to start TLS
Untrusted TLS connection established to localhost[127.0.0.1]:26: TLSv1 with cipher ADH-DES-CBC3-SHA (168/168 bits)
Server session id: 1285EC932BD961360AE9827767ADB18BA276D2D9F7CCCA4CC51888B799ED0359
Server is anonymous
So I just have to figure out how to remove unsupported ciphers
automatically, so we don't have to fall back to using "DEFAULT" instead of
"ALL" in:
tls_export_cipherlist = ALL:+RC4:
STRENGTH
tls_high_cipherlist = ALL:!EXPORT:!LOW:!MEDIUM:+RC4:
STRENGTH
tls_low_cipherlist = ALL:!EXPORT:+RC4:
STRENGTH
tls_medium_cipherlist = ALL:!EXPORT:!LOW:+RC4:
STRENGTH
thereby losing support for anonymous ciphers in default Postfix
configurations of all platforms, even those that work (including SunOS
5.10 with 3DES).
Now OpenSSL does not provide a public interface for mapping TLS ciphers
to the underlying symmetric cipher and hash algorithms, this is all
internal magic. What is possible however is:
typedef struct {
char *algorithm;
char *exclusion;
} cipher_probe;
static cipher_probe cipher_probe_list[] = {
/* Check for missing symmetric ciphers */
SN_des_cbc, SSL_TXT_DES,
SN_des_ede3_cbc, SSL_TXT_3DES,
SN_rc4, SSL_TXT_RC4,
SN_rc2_cbc, SSL_TXT_RC2,
SN_idea_cbc, SSL_TXT_IDEA,
SN_aes_128_cbc, SSL_TXT_AES,
SN_aes_256_cbc, SSL_TXT_AES "+HIGH",
/* Check for missing hash algorithms */
SN_md5, SSL_TXT_MD5,
SN_sha1, SSL_TXT_SHA1,
0, 0,
};
ARGV *unavailable_ciphers()
{
ARGV *exclude = 0;
cipher_probe *probe;
for (probe = cipher_probe_list; probe->algorithm; ++probe)
if (!EVP_get_cipherbyname(probe->algorithm))
argv_add(exclude ? exclude : (exclude = argv_alloc(1)),
probe->exclusion);
return exclude;
}
the resulting ARGV vector can be added to the manual cipher exclusion
list.
The above seems very ad-hoc, why are we hard-coding the various symmetric
and hash algorithm names used by OpenSSL? This is not 100% future-proof,
if new ciphers are added to OpenSSL, but some misguided O/S supports it
in libssl and leaves it out of the libcrypto library, don't we still
have a problem?
Well, here's where it gets interesting, it turns out that the above
code is a portable variant of code that is already present in libssl.
OpenSSL performs a run-time check to determine which algorithms are
present when building cipherlists, and takes care to exclude those that
are unimplemented. So all this should be completely unnecessary! So
why do we have a problem???
Well, it takes multiple errors to mess this up:
- The OpenSSL "cipher implemented?" check can only exclude a set
of cipher property bits ORed together (all "MD5 or DES" ciphers, all
"AES, RC4 or SHA1" ciphers, ...). It is not possible without making
the code much more complex to exclude sets of ciphers that match
multiple conditions "AES and HIGH, MD5 and RC4" ...
- The above would be fine if the property bits were sufficiently
orthogonal, so that each is always either completely available,
or completely unavailable. It turns out that due to (IMHO) a design
issue in OpenSSL, "AES" bit violates the rule, there are really three
AES algorithms (only two of which are used by SSL/TLS):
SN_aes_128_cbc
SN_aes_192_cbc /* Not used in SSLv2/SSLv3/TLSv1 */
SN_aes_256_cbc
each of which has a different implementation vector in libcrypto,
so there really should be 2 to 4 separate AES related bits in the
cipher mask, instead of the current:
#define SSL_ENC_MASK 0x0087F000L
#define SSL_DES 0x00001000L
#define SSL_3DES 0x00002000L
#define SSL_RC4 0x00004000L
#define SSL_RC2 0x00008000L
#define SSL_IDEA 0x00010000L
#define SSL_eFZA 0x00020000L
#define SSL_eNULL 0x00040000L
#define SSL_AES 0x00800000L
it should be:
#define SSL_ENC_MASK 0x0087F000L
#define SSL_DES 0x00001000L
#define SSL_3DES 0x00002000L
#define SSL_RC4 0x00004000L
#define SSL_RC2 0x00008000L
#define SSL_IDEA 0x00010000L
#define SSL_eFZA 0x00020000L
#define SSL_eNULL 0x00040000L
#define SSL_AES128 0x00100000L
#define SSL_AES192 0x00200000L /* Unused */
#define SSL_AES256 0x00400000L
#define SSL_AES 0x00800000L /* Desirable */
then the property masks of the AES ciphers would reflect both the
generic "AES" property and the specific variant cipher. Allowing
the code to check with of the AES variants are implemented.
- AES is the only multi-algorithm family among the symmetric
algorithms used by SSL. Its integration into OpenSSL has some warts,
for example the HIGH/MEDIUM classification for AES128 is wrong,
for much the same reasons as above. Most importantly the test for
"AES implemented?" only checks for existence of AES128 and does not
that AES256 is present, and then allows both to enter the cipherlist.
- Finally, Sun hits a home run, by implementing only AES 128 and not
AES 256 (or 192, but that is not important).
Bottom line, we can reasonably expect that future expansion of OpenSSL
to more ciphers will not repeat the AES128/AES256 design issue, and will
accurately filter out unavailable ciphers. With that, and the already
implemented checks inside the OpenSSL library, our exclusion code
simplifies to:
typedef struct {
char *algorithm;
char *exclusion;
} cipher_probe;
static cipher_probe cipher_probe_list[] = {
/* Check for missing AES256 */
SN_aes_256_cbc, SSL_TXT_AES "+HIGH",
0, 0,
};
ARGV *unavailable_ciphers()
{
ARGV *exclude = 0;
cipher_probe *probe;
for (probe = cipher_probe_list; probe->algorithm; ++probe)
if (!EVP_get_cipherbyname(probe->algorithm))
argv_add(exclude ? exclude : (exclude = argv_alloc(1)),
probe->exclusion);
return exclude;
}
In other words, all we need to handle is just this one implementation
oversight in the OpenSSL code so carefully spotted and exposed by Sun.
Fixing this in OpenSSL should also fix any other AES128 vs. AES256
ambiguities (high vs. medium, ...)
Adding just this one extra automatic exclusion to the Postfix
cipherlists is easy, but before I cut new code, I am open to any
additional feedback...
--
Viktor.
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]