summaryrefslogtreecommitdiffstats
path: root/qmail-smtpd.c
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2015-06-23 00:51:07 +0200
committermanuel <manuel@mausz.at>2015-06-23 00:51:07 +0200
commit999de3146c7bec7ca9e2c55f1f4143b527ba98c4 (patch)
tree500aa356d4e2f06e76a174942506896adbdc57ae /qmail-smtpd.c
parent15a5232629a37b3df8a476f984343375950fa2ff (diff)
downloadqmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.tar.gz
qmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.tar.bz2
qmail-999de3146c7bec7ca9e2c55f1f4143b527ba98c4.zip
add support for ECDH as well as custom ec+dh params in certificate
Diffstat (limited to 'qmail-smtpd.c')
-rw-r--r--qmail-smtpd.c72
1 files changed, 66 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)
1148static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) 1148static 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. */
1185DH *tmp_dh_cb(SSL *ssl, int export, int keylen) 1184static 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
1216static 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
1229static 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
1241static 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 */
1218int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } 1248int 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