7 /* Diffie-Hellman parameter support
9 /* #define TLS_INTERNAL
12 /* void tls_set_dh_from_file(path, bits)
16 /* int tls_set_eecdh_curve(server_ctx, grade)
17 /* SSL_CTX *server_ctx;
20 /* DH *tls_tmp_dh_cb(ssl, export, keylength)
21 /* SSL *ssl; /* unused */
25 /* This module maintains parameters for Diffie-Hellman key generation.
27 /* tls_tmp_dh_cb() is a call-back routine for the
28 /* SSL_CTX_set_tmp_dh_callback() function.
30 /* tls_set_dh_from_file() overrides compiled-in DH parameters
31 /* with those specified in the named files. The file format
32 /* is as expected by the PEM_read_DHparams() routine. The
33 /* "bits" argument must be 512 or 1024.
35 /* tls_set_eecdh_curve() enables ephemeral Elliptic-Curve DH
36 /* key exchange algorithms by instantiating in the server SSL
37 /* context a suitable curve (corresponding to the specified
38 /* EECDH security grade) from the set of named curves in RFC
39 /* 4492 Section 5.1.1. Errors generate warnings, but do not
40 /* disable TLS, rather we continue without EECDH. A zero
41 /* result indicates that the grade is invalid or the corresponding
42 /* curve could not be used.
44 /* In case of error, tls_set_dh_from_file() logs a warning and
45 /* ignores the request.
49 /* This software is free. You can do with it whatever you want.
50 /* The original author kindly requests that you acknowledge
51 /* the use of his software.
53 /* Originally written by:
56 /* Allgemeine Elektrotechnik
57 /* Universitaetsplatz 3-4
58 /* D-03044 Cottbus, Germany
62 /* IBM T.J. Watson Research
64 /* Yorktown Heights, NY 10598, USA
74 /* Utility library. */
81 #include <mail_params.h>
88 /* Application-specific. */
91 * Compiled-in EDH primes (the compiled-in generator is always 2). These are
92 * used when no parameters are explicitly loaded from a site-specific file.
94 * 512-bit parameters are used for export ciphers, and 1024-bit parameters are
95 * used for non-export ciphers. An ~80-bit strong EDH key exchange is really
96 * too weak to protect 128+ bit keys, but larger DH primes are
97 * computationally expensive. When greater security is required, use EECDH.
101 * Generated via "openssl dhparam -2 -noout -C 512 2>/dev/null" TODO:
102 * generate at compile-time.
104 static unsigned char dh512_p
[] = {
105 0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2,
106 0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4,
107 0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E,
108 0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5,
109 0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB,
110 0x4F, 0x70, 0xBA, 0x5B,
114 * Generated via "openssl dhparam -2 -noout -C 1024 2>/dev/null" TODO:
115 * generate at compile-time.
117 static unsigned char dh1024_p
[] = {
118 0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D,
119 0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88,
120 0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51,
121 0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F,
122 0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72,
123 0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76,
124 0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81,
125 0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E,
126 0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6,
127 0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF,
128 0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B,
134 static DH
*dh_1024
= 0;
135 static DH
*dh_512
= 0;
137 /* tls_set_dh_from_file - set Diffie-Hellman parameters from file */
139 void tls_set_dh_from_file(const char *path
, int bits
)
152 msg_panic("Invalid DH parameters size %d, file %s", bits
, path
);
155 if ((paramfile
= fopen(path
, "r")) != 0) {
156 if ((*dhPtr
= PEM_read_DHparams(paramfile
, 0, 0, 0)) == 0) {
157 msg_warn("cannot load %d-bit DH parameters from file %s"
158 " -- using compiled-in defaults", bits
, path
);
161 (void) fclose(paramfile
); /* 200411 */
163 msg_warn("cannot load %d-bit DH parameters from file %s: %m"
164 " -- using compiled-in defaults", bits
, path
);
168 /* tls_get_dh - get compiled-in DH parameters */
170 static DH
*tls_get_dh(const unsigned char *p
, int plen
)
173 static unsigned char g
[] = {0x02,};
175 /* Use the compiled-in parameters. */
176 if ((dh
= DH_new()) == 0) {
177 msg_warn("cannot create DH parameter set: %m"); /* 200411 */
180 dh
->p
= BN_bin2bn(p
, plen
, (BIGNUM
*) 0);
181 dh
->g
= BN_bin2bn(g
, 1, (BIGNUM
*) 0);
182 if ((dh
->p
== 0) || (dh
->g
== 0)) {
183 msg_warn("cannot load compiled-in DH parameters"); /* 200411 */
184 DH_free(dh
); /* 200411 */
190 /* tls_tmp_dh_cb - call-back for Diffie-Hellman parameters */
192 DH
*tls_tmp_dh_cb(SSL
*unused_ssl
, int export
, int keylength
)
196 if (export
&& keylength
== 512) { /* 40-bit export cipher */
198 dh_512
= tls_get_dh(dh512_p
, (int) sizeof(dh512_p
));
200 } else { /* ADH, DHE-RSA or DSA */
202 dh_1024
= tls_get_dh(dh1024_p
, (int) sizeof(dh1024_p
));
208 int tls_set_eecdh_curve(SSL_CTX
*server_ctx
, const char *grade
)
210 #if OPENSSL_VERSION_NUMBER >= 0x00909000 && !defined(OPENSSL_NO_ECDH)
216 #define TLS_EECDH_INVALID 0
217 #define TLS_EECDH_NONE 1
218 #define TLS_EECDH_STRONG 2
219 #define TLS_EECDH_ULTRA 3
220 static NAME_CODE eecdh_table
[] = {
221 "none", TLS_EECDH_NONE
,
222 "strong", TLS_EECDH_STRONG
,
223 "ultra", TLS_EECDH_ULTRA
,
224 0, TLS_EECDH_INVALID
,
227 switch (g
= name_code(eecdh_table
, NAME_CODE_FLAG_NONE
, grade
)) {
229 msg_panic("Invalid eecdh grade code: %d", g
);
230 case TLS_EECDH_INVALID
:
231 msg_warn("Invalid TLS eecdh grade \"%s\": EECDH disabled", grade
);
235 case TLS_EECDH_STRONG
:
236 curve
= var_tls_eecdh_strong
;
238 case TLS_EECDH_ULTRA
:
239 curve
= var_tls_eecdh_ultra
;
244 * Elliptic-Curve Diffie-Hellman parameters are either "named curves"
245 * from RFC 4492 section 5.1.1, or explicitly described curves over
246 * binary fields. OpenSSL only supports the "named curves", which provide
247 * maximum interoperability. The recommended curve for 128-bit
248 * work-factor key exchange is "prime256v1" a.k.a. "secp256r1" from
249 * Section 2.7 of http://www.secg.org/download/aid-386/sec2_final.pdf
252 if ((nid
= OBJ_sn2nid(curve
)) == NID_undef
) {
253 msg_warn("unknown curve \"%s\": disabling EECDH support", curve
);
257 if ((ecdh
= EC_KEY_new_by_curve_name(nid
)) == 0
258 || SSL_CTX_set_tmp_ecdh(server_ctx
, ecdh
) == 0) {
259 msg_warn("unable to use curve \"%s\": disabling EECDH support", curve
);
269 int main(int unused_argc
, char **unused_argv
)
271 tls_tmp_dh_cb(0, 1, 512);
272 tls_tmp_dh_cb(0, 1, 1024);
273 tls_tmp_dh_cb(0, 1, 2048);
274 tls_tmp_dh_cb(0, 0, 512);