diff options
| author | manuel <manuel@mausz.at> | 2015-06-23 00:51:07 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2015-06-23 00:51:07 +0200 |
| commit | 999de3146c7bec7ca9e2c55f1f4143b527ba98c4 (patch) | |
| tree | 500aa356d4e2f06e76a174942506896adbdc57ae | |
| parent | 15a5232629a37b3df8a476f984343375950fa2ff (diff) | |
| download | qmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.tar.gz qmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.tar.bz2 qmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.zip | |
add support for ECDH as well as custom ec+dh params in certificate
| -rw-r--r-- | qmail-smtpd.c | 72 | ||||
| -rw-r--r-- | tls.h | 5 |
2 files changed, 71 insertions, 6 deletions
diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 817524d..fe33249 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c | |||
| @@ -1148,15 +1148,14 @@ void smtp_tls(char *arg) | |||
| 1148 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) | 1148 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) |
| 1149 | { | 1149 | { |
| 1150 | DH *dh = DH_new(); | 1150 | DH *dh = DH_new(); |
| 1151 | if (!dh) | ||
| 1152 | return NULL; | ||
| 1151 | 1153 | ||
| 1152 | if (!dh) { | ||
| 1153 | return NULL; | ||
| 1154 | } | ||
| 1155 | dh->p = prime(NULL); | 1154 | dh->p = prime(NULL); |
| 1156 | BN_dec2bn(&dh->g, gen); | 1155 | BN_dec2bn(&dh->g, gen); |
| 1157 | if (!dh->p || !dh->g) { | 1156 | if (!dh->p || !dh->g) { |
| 1158 | DH_free(dh); | 1157 | DH_free(dh); |
| 1159 | return NULL; | 1158 | return NULL; |
| 1160 | } | 1159 | } |
| 1161 | return dh; | 1160 | return dh; |
| 1162 | } | 1161 | } |
| @@ -1182,7 +1181,7 @@ static struct dhparam { | |||
| 1182 | * contrast to the keys itself) and code safe as the returned structure | 1181 | * contrast to the keys itself) and code safe as the returned structure |
| 1183 | * is duplicated by OpenSSL anyway. Hence no modification happens | 1182 | * is duplicated by OpenSSL anyway. Hence no modification happens |
| 1184 | * to our copy. */ | 1183 | * to our copy. */ |
| 1185 | DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | 1184 | static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) |
| 1186 | { | 1185 | { |
| 1187 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); | 1186 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); |
| 1188 | int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; | 1187 | int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; |
| @@ -1214,6 +1213,37 @@ DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | |||
| 1214 | return NULL; /* impossible to reach. */ | 1213 | return NULL; /* impossible to reach. */ |
| 1215 | } | 1214 | } |
| 1216 | 1215 | ||
| 1216 | static DH *ssl_dh_GetParamFromFile(const char *file) | ||
| 1217 | { | ||
| 1218 | DH *dh = NULL; | ||
| 1219 | BIO *bio; | ||
| 1220 | |||
| 1221 | if ((bio = BIO_new_file(file, "r")) == NULL) | ||
| 1222 | return NULL; | ||
| 1223 | dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); | ||
| 1224 | BIO_free(bio); | ||
| 1225 | return dh; | ||
| 1226 | } | ||
| 1227 | |||
| 1228 | #ifdef HAVE_ECC | ||
| 1229 | static EC_GROUP *ssl_ec_GetParamFromFile(const char *file) | ||
| 1230 | { | ||
| 1231 | EC_GROUP *group = NULL; | ||
| 1232 | BIO *bio; | ||
| 1233 | |||
| 1234 | if ((bio = BIO_new_file(file, "r")) == NULL) | ||
| 1235 | return NULL; | ||
| 1236 | group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); | ||
| 1237 | BIO_free(bio); | ||
| 1238 | return group; | ||
| 1239 | } | ||
| 1240 | |||
| 1241 | static EC_KEY *tmp_ecdh_cb(SSL *ssl, int export, int keylen) | ||
| 1242 | { | ||
| 1243 | return EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | ||
| 1244 | } | ||
| 1245 | #endif | ||
| 1246 | |||
| 1217 | /* don't want to fail handshake if cert isn't verifiable */ | 1247 | /* don't want to fail handshake if cert isn't verifiable */ |
| 1218 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } | 1248 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } |
| 1219 | 1249 | ||
| @@ -1324,6 +1354,12 @@ void tls_init() | |||
| 1324 | X509_STORE *store; | 1354 | X509_STORE *store; |
| 1325 | X509_LOOKUP *lookup; | 1355 | X509_LOOKUP *lookup; |
| 1326 | const char *servercert; | 1356 | const char *servercert; |
| 1357 | DH *dhparams; | ||
| 1358 | #ifdef HAVE_ECC | ||
| 1359 | EC_GROUP *ecparams; | ||
| 1360 | int nid; | ||
| 1361 | EC_KEY *eckey = NULL; | ||
| 1362 | #endif | ||
| 1327 | 1363 | ||
| 1328 | /* if set, use servercert selected through SMTP_SERVERCERT env var */ | 1364 | /* if set, use servercert selected through SMTP_SERVERCERT env var */ |
| 1329 | servercert = env_get("SMTP_SERVERCERT"); | 1365 | servercert = env_get("SMTP_SERVERCERT"); |
| @@ -1376,6 +1412,30 @@ void tls_init() | |||
| 1376 | alloc_free(saciphers.s); | 1412 | alloc_free(saciphers.s); |
| 1377 | 1413 | ||
| 1378 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); | 1414 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); |
| 1415 | |||
| 1416 | /* try to read DH parameters from certificate */ | ||
| 1417 | if ((dhparams = ssl_dh_GetParamFromFile(servercert))) | ||
| 1418 | SSL_set_tmp_dh(myssl, dhparams); | ||
| 1419 | |||
| 1420 | #ifdef HAVE_ECC | ||
| 1421 | /* similarly, try to read the ECDH curve name from certificate... */ | ||
| 1422 | if ((ecparams = ssl_ec_GetParamFromFile(servercert)) && | ||
| 1423 | (nid = EC_GROUP_get_curve_name(ecparams)) && | ||
| 1424 | (eckey = EC_KEY_new_by_curve_name(nid))) { | ||
| 1425 | SSL_set_tmp_ecdh(myssl, eckey); | ||
| 1426 | } | ||
| 1427 | else { | ||
| 1428 | #if defined(SSL_set_ecdh_auto) | ||
| 1429 | /* ...otherwise, enable auto curve selection (OpenSSL 1.0.2 and later) */ | ||
| 1430 | SSL_set_ecdh_auto(myssl, 1); | ||
| 1431 | #else | ||
| 1432 | /* or set callback, which will configure NIST P-256 */ | ||
| 1433 | SSL_set_tmp_ecdh_callback(myssl, tmp_ecdh_cb); | ||
| 1434 | #endif | ||
| 1435 | } | ||
| 1436 | EC_KEY_free(eckey); | ||
| 1437 | #endif | ||
| 1438 | |||
| 1379 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); | 1439 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); |
| 1380 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); | 1440 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); |
| 1381 | 1441 | ||
| @@ -3,6 +3,11 @@ | |||
| 3 | 3 | ||
| 4 | #include <openssl/ssl.h> | 4 | #include <openssl/ssl.h> |
| 5 | 5 | ||
| 6 | /* ECC: make sure we have at least 1.0.0 */ | ||
| 7 | #if !defined(OPENSSL_NO_EC) && defined(TLSEXT_ECPOINTFORMAT_uncompressed) | ||
| 8 | #define HAVE_ECC | ||
| 9 | #endif | ||
| 10 | |||
| 6 | extern int smtps; | 11 | extern int smtps; |
| 7 | extern SSL *ssl; | 12 | extern SSL *ssl; |
| 8 | 13 | ||
