diff options
| author | Manuel Mausz <manuel@mausz.at> | 2018-06-27 01:06:16 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2018-06-27 01:15:54 +0200 |
| commit | 7ec4ffbdbc562c4a2909d9bf4f3093072e0e3ac1 (patch) | |
| tree | 4552a41d0ff55b69303ca8c6070ec9f6be1819fe | |
| parent | d382146c1145dcd3a4108f1b753fcb1250fd9750 (diff) | |
| download | qmail-7ec4ffbdbc562c4a2909d9bf4f3093072e0e3ac1.tar.gz qmail-7ec4ffbdbc562c4a2909d9bf4f3093072e0e3ac1.tar.bz2 qmail-7ec4ffbdbc562c4a2909d9bf4f3093072e0e3ac1.zip | |
OpenSSL 1.1 compatibility
This adds compatibility for OpenSSL 1.1
Since renegotiation is removed from TLS 1.3 we also removed support for
authentication via client certificates (control/tlsclients). In general
this is still supported by TLS 1.3 however I'm just lazy and we don't
need this feature anyway.
This also adds optional support for OpenSSL configuration commands for
qmail-smtpd and qmail-remote. Commands are loaded from control/opensslconf.
For a list of supported commands see
https://www.openssl.org/docs/man1.0.2/ssl/SSL_CONF_cmd.html#SUPPORTED-CONFIGURATION-FILE-COMMANDS
| -rw-r--r-- | README.starttls | 10 | ||||
| -rw-r--r-- | qmail-control.9 | 1 | ||||
| -rw-r--r-- | qmail-remote.c | 49 | ||||
| -rw-r--r-- | qmail-smtpd.8 | 10 | ||||
| -rw-r--r-- | qmail-smtpd.c | 177 | ||||
| -rw-r--r-- | ssl_timeoutio.c | 13 | ||||
| -rw-r--r-- | ssl_timeoutio.h | 1 | ||||
| -rw-r--r-- | tls.h | 1 |
8 files changed, 125 insertions, 137 deletions
diff --git a/README.starttls b/README.starttls index 07ee275..6168c6d 100644 --- a/README.starttls +++ b/README.starttls | |||
| @@ -42,16 +42,6 @@ Optional: - when DEBUG is defined, some extra TLS info will be logged | |||
| 42 | an exhaustive list of hosts TLS is tried on. | 42 | an exhaustive list of hosts TLS is tried on. |
| 43 | If /var/qmail/control/notlshosts/host.dom.ain is present, | 43 | If /var/qmail/control/notlshosts/host.dom.ain is present, |
| 44 | no TLS is tried on this host. | 44 | no TLS is tried on this host. |
| 45 | - client authentication: | ||
| 46 | when relay rules would reject an incoming mail, | ||
| 47 | qmail-smtpd can allow the mail based on a presented cert. | ||
| 48 | Certs are verified against a CA list in | ||
| 49 | /var/qmail/control/clientca.pem (eg. http://www.modssl.org/ | ||
| 50 | source/cvs/exp/mod_ssl/pkg.mod_ssl/pkg.sslcfg/ca-bundle.crt) | ||
| 51 | and the cert email-address has to match a line in | ||
| 52 | /var/qmail/control/tlsclients. This email-address is logged | ||
| 53 | in the headers. CRLs can be provided through | ||
| 54 | /var/qmail/control/clientcrl.pem. | ||
| 55 | - cipher selection: | 45 | - cipher selection: |
| 56 | qmail-remote: | 46 | qmail-remote: |
| 57 | openssl cipher string (`man ciphers`) read from | 47 | openssl cipher string (`man ciphers`) read from |
diff --git a/qmail-control.9 b/qmail-control.9 index 9c6edd8..6898643 100644 --- a/qmail-control.9 +++ b/qmail-control.9 | |||
| @@ -78,7 +78,6 @@ control default used by | |||
| 78 | .I timeoutconnect \fR60 \fRqmail-remote | 78 | .I timeoutconnect \fR60 \fRqmail-remote |
| 79 | .I timeoutremote \fR1200 \fRqmail-remote | 79 | .I timeoutremote \fR1200 \fRqmail-remote |
| 80 | .I timeoutsmtpd \fR1200 \fRqmail-smtpd | 80 | .I timeoutsmtpd \fR1200 \fRqmail-smtpd |
| 81 | .I tlsclients \fR(none) \fRqmail-smtpd | ||
| 82 | .I tlsclientciphers \fR(none) \fRqmail-remote | 81 | .I tlsclientciphers \fR(none) \fRqmail-remote |
| 83 | .I tlshosts/FQDN.pem \fR(none) \fRqmail-remote | 82 | .I tlshosts/FQDN.pem \fR(none) \fRqmail-remote |
| 84 | .I tlsserverciphers \fR(none) \fRqmail-smtpd | 83 | .I tlsserverciphers \fR(none) \fRqmail-smtpd |
diff --git a/qmail-remote.c b/qmail-remote.c index d2412aa..94bb69f 100644 --- a/qmail-remote.c +++ b/qmail-remote.c | |||
| @@ -302,8 +302,8 @@ void smtp_quit() | |||
| 302 | { | 302 | { |
| 303 | #ifdef TLS | 303 | #ifdef TLS |
| 304 | /* shouldn't talk to the client unless in an appropriate state */ | 304 | /* shouldn't talk to the client unless in an appropriate state */ |
| 305 | int state = ssl ? ssl->state : SSL_ST_BEFORE; | 305 | if ((!smtps && !ssl) || (ssl && SSL_is_init_finished(ssl)) |
| 306 | if (state & SSL_ST_OK || (!smtps && state & SSL_ST_BEFORE)) | 306 | || (!smtps && ssl && SSL_in_before(ssl))) |
| 307 | #endif | 307 | #endif |
| 308 | substdio_putsflush(&smtpto,"QUIT\r\n"); | 308 | substdio_putsflush(&smtpto,"QUIT\r\n"); |
| 309 | /* waiting for remote side is just too ridiculous */ | 309 | /* waiting for remote side is just too ridiculous */ |
| @@ -539,6 +539,41 @@ int tls_init() | |||
| 539 | SSL_set_cipher_list(myssl, ciphers); | 539 | SSL_set_cipher_list(myssl, ciphers); |
| 540 | alloc_free(saciphers.s); | 540 | alloc_free(saciphers.s); |
| 541 | 541 | ||
| 542 | #if OPENSSL_VERSION_NUMBER >= 0x10100005L | ||
| 543 | stralloc opensslconf = {0}; | ||
| 544 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) | ||
| 545 | { SSL_free(myssl); temp_control(); } | ||
| 546 | if (opensslconf.len) { | ||
| 547 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); | ||
| 548 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); | ||
| 549 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CLIENT); | ||
| 550 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); | ||
| 551 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); | ||
| 552 | SSL_CONF_CTX_set_ssl(cctx, myssl); | ||
| 553 | |||
| 554 | int i, j, next = 0; | ||
| 555 | char *cmd, * arg; | ||
| 556 | for (i = 0; i < opensslconf.len; i += next) { | ||
| 557 | cmd = opensslconf.s + i; | ||
| 558 | next = str_len(cmd) + 1; | ||
| 559 | |||
| 560 | j = str_chr(cmd, ' '); | ||
| 561 | arg = cmd + j; | ||
| 562 | while (*arg == ' ') ++arg; | ||
| 563 | cmd[j] = 0; | ||
| 564 | |||
| 565 | if (SSL_CONF_cmd(cctx, cmd, arg) <= 0) { | ||
| 566 | SSL_free(myssl); | ||
| 567 | out("Zopensslconf \""); out(cmd); out(" "); out(arg); | ||
| 568 | out("\" failed: "); out(ssl_error()); | ||
| 569 | TLS_QUIT; | ||
| 570 | } | ||
| 571 | } | ||
| 572 | |||
| 573 | (void)SSL_CONF_CTX_finish(cctx); | ||
| 574 | } | ||
| 575 | #endif | ||
| 576 | |||
| 542 | /* set SNI hostname */ | 577 | /* set SNI hostname */ |
| 543 | if (partner_fqdn) | 578 | if (partner_fqdn) |
| 544 | SSL_set_tlsext_host_name(myssl, partner_fqdn); | 579 | SSL_set_tlsext_host_name(myssl, partner_fqdn); |
| @@ -614,8 +649,12 @@ int tls_init() | |||
| 614 | X509_NAME *subj = X509_get_subject_name(peercert); | 649 | X509_NAME *subj = X509_get_subject_name(peercert); |
| 615 | i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1); | 650 | i = X509_NAME_get_index_by_NID(subj, NID_commonName, -1); |
| 616 | if (i >= 0) { | 651 | if (i >= 0) { |
| 617 | const ASN1_STRING *s = X509_NAME_get_entry(subj, i)->value; | 652 | X509_NAME_ENTRY *entry = X509_NAME_get_entry(subj, i); |
| 618 | if (s) { peer.len = s->length; peer.s = s->data; } | 653 | ASN1_STRING *s = X509_NAME_ENTRY_get_data(entry); |
| 654 | #if OPENSSL_VERSION_NUMBER < 0x10100005L | ||
| 655 | #define ASN1_STRING_get0_data ASN1_STRING_data | ||
| 656 | #endif | ||
| 657 | if (s) { peer.len = ASN1_STRING_length(s); peer.s = (unsigned char *)ASN1_STRING_get0_data(s); } | ||
| 619 | } | 658 | } |
| 620 | if (peer.len <= 0) { | 659 | if (peer.len <= 0) { |
| 621 | out("ZTLS unable to verify server "); | 660 | out("ZTLS unable to verify server "); |
| @@ -668,7 +707,7 @@ int utf8received() | |||
| 668 | if (r == 0) break; | 707 | if (r == 0) break; |
| 669 | if (r == -1) temp_read(); | 708 | if (r == -1) temp_read(); |
| 670 | 709 | ||
| 671 | if (ch == '\n') { | 710 | if (ch == '\n' && receivedline.len) { |
| 672 | if (!stralloc_append(&header,"\r")) temp_nomem(); /* received.c does not add '\r' */ | 711 | if (!stralloc_append(&header,"\r")) temp_nomem(); /* received.c does not add '\r' */ |
| 673 | if (!stralloc_append(&header,"\n")) temp_nomem(); | 712 | if (!stralloc_append(&header,"\n")) temp_nomem(); |
| 674 | if (case_startb(receivedline.s,5,"Date:")) return 0; /* header to quit asap */ | 713 | if (case_startb(receivedline.s,5,"Date:")) return 0; /* header to quit asap */ |
diff --git a/qmail-smtpd.8 b/qmail-smtpd.8 index 05d1239..5920dd9 100644 --- a/qmail-smtpd.8 +++ b/qmail-smtpd.8 | |||
| @@ -295,16 +295,6 @@ will wait for each new buffer of data from the remote SMTP client. | |||
| 295 | Default: 1200. | 295 | Default: 1200. |
| 296 | 296 | ||
| 297 | .TP 5 | 297 | .TP 5 |
| 298 | .I tlsclients | ||
| 299 | A list of email addresses. When relay rules would reject an incoming message, | ||
| 300 | .B qmail-smtpd | ||
| 301 | can allow it if the client presents a certificate that can be verified against | ||
| 302 | the CA list in | ||
| 303 | .I clientca.pem | ||
| 304 | and the certificate email address is in | ||
| 305 | .IR tlsclients . | ||
| 306 | |||
| 307 | .TP 5 | ||
| 308 | .I tlsserverciphers | 298 | .I tlsserverciphers |
| 309 | A set of OpenSSL cipher strings. Multiple ciphers contained in a | 299 | A set of OpenSSL cipher strings. Multiple ciphers contained in a |
| 310 | string should be separated by a colon. If the environment variable | 300 | string should be separated by a colon. If the environment variable |
diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 18795bc..f40a4c5 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c | |||
| @@ -71,7 +71,6 @@ char *relayclient; | |||
| 71 | # define SERVERCERT "control/servercert.pem" | 71 | # define SERVERCERT "control/servercert.pem" |
| 72 | 72 | ||
| 73 | void tls_init(); | 73 | void tls_init(); |
| 74 | int tls_verify(); | ||
| 75 | void tls_nogateway(); | 74 | void tls_nogateway(); |
| 76 | int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */ | 75 | int ssl_rfd = -1, ssl_wfd = -1; /* SSL_get_Xfd() are broken */ |
| 77 | stralloc proto = {0}; | 76 | stralloc proto = {0}; |
| @@ -508,9 +507,6 @@ int addrallowed() | |||
| 508 | int r; | 507 | int r; |
| 509 | r = rcpthosts(addr.s,str_len(addr.s)); | 508 | r = rcpthosts(addr.s,str_len(addr.s)); |
| 510 | if (r == -1) die_control(); | 509 | if (r == -1) die_control(); |
| 511 | #ifdef TLS | ||
| 512 | if (r == 0) if (tls_verify()) r = -2; | ||
| 513 | #endif | ||
| 514 | return r; | 510 | return r; |
| 515 | } | 511 | } |
| 516 | 512 | ||
| @@ -1261,19 +1257,44 @@ void smtp_tls(char *arg) | |||
| 1261 | * Grab well-defined DH parameters from OpenSSL, see the get_rfc* | 1257 | * Grab well-defined DH parameters from OpenSSL, see the get_rfc* |
| 1262 | * functions in <openssl/bn.h> for all available primes. | 1258 | * functions in <openssl/bn.h> for all available primes. |
| 1263 | */ | 1259 | */ |
| 1264 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) | 1260 | #if OPENSSL_VERSION_NUMBER < 0x10100005L |
| 1261 | static int DH_set0_pqg(DH *dh, BIGNUM *p, BIGNUM *q, BIGNUM *g) | ||
| 1265 | { | 1262 | { |
| 1266 | DH *dh = DH_new(); | 1263 | /* q is optional */ |
| 1267 | if (!dh) | 1264 | if (p == NULL || g == NULL) |
| 1268 | return NULL; | 1265 | return 0; |
| 1269 | 1266 | BN_free(dh->p); | |
| 1270 | dh->p = prime(NULL); | 1267 | BN_free(dh->q); |
| 1271 | BN_dec2bn(&dh->g, gen); | 1268 | BN_free(dh->g); |
| 1272 | if (!dh->p || !dh->g) { | 1269 | dh->p = p; |
| 1273 | DH_free(dh); | 1270 | dh->q = q; |
| 1274 | return NULL; | 1271 | dh->g = g; |
| 1275 | } | 1272 | |
| 1276 | return dh; | 1273 | if (q != NULL) |
| 1274 | dh->length = BN_num_bits(q); | ||
| 1275 | |||
| 1276 | return 1; | ||
| 1277 | } | ||
| 1278 | #endif | ||
| 1279 | |||
| 1280 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *)) | ||
| 1281 | { | ||
| 1282 | BIGNUM *p, *g; | ||
| 1283 | DH *dh = DH_new(); | ||
| 1284 | if (!dh) | ||
| 1285 | return NULL; | ||
| 1286 | |||
| 1287 | p = prime(NULL); | ||
| 1288 | g = BN_new(); | ||
| 1289 | if (g != NULL) | ||
| 1290 | BN_set_word(g, 2); | ||
| 1291 | if (!p || !g || !DH_set0_pqg(dh, p, NULL, g)) { | ||
| 1292 | DH_free(dh); | ||
| 1293 | BN_free(p); | ||
| 1294 | BN_free(g); | ||
| 1295 | return NULL; | ||
| 1296 | } | ||
| 1297 | return dh; | ||
| 1277 | } | 1298 | } |
| 1278 | 1299 | ||
| 1279 | /* Storage and initialization for DH parameters. */ | 1300 | /* Storage and initialization for DH parameters. */ |
| @@ -1300,7 +1321,7 @@ static struct dhparam { | |||
| 1300 | static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | 1321 | static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) |
| 1301 | { | 1322 | { |
| 1302 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); | 1323 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); |
| 1303 | int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; | 1324 | int type = pkey ? EVP_PKEY_base_id(pkey) : EVP_PKEY_NONE; |
| 1304 | unsigned n; | 1325 | unsigned n; |
| 1305 | 1326 | ||
| 1306 | /* | 1327 | /* |
| @@ -1321,7 +1342,7 @@ static DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | |||
| 1321 | for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { | 1342 | for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { |
| 1322 | if (keylen >= dhparams[n].min) { | 1343 | if (keylen >= dhparams[n].min) { |
| 1323 | if (dhparams[n].dh == NULL) | 1344 | if (dhparams[n].dh == NULL) |
| 1324 | dhparams[n].dh = make_dh_params(dhparams[n].prime, "2"); | 1345 | dhparams[n].dh = make_dh_params(dhparams[n].prime); |
| 1325 | return dhparams[n].dh; | 1346 | return dhparams[n].dh; |
| 1326 | } | 1347 | } |
| 1327 | } | 1348 | } |
| @@ -1338,6 +1359,8 @@ static DH *ssl_dh_GetParamFromFile(const char *file) | |||
| 1338 | return NULL; | 1359 | return NULL; |
| 1339 | dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); | 1360 | dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); |
| 1340 | BIO_free(bio); | 1361 | BIO_free(bio); |
| 1362 | if (!dh) | ||
| 1363 | (void)ERR_get_error(); | ||
| 1341 | return dh; | 1364 | return dh; |
| 1342 | } | 1365 | } |
| 1343 | 1366 | ||
| @@ -1351,6 +1374,8 @@ static EC_GROUP *ssl_ec_GetParamFromFile(const char *file) | |||
| 1351 | return NULL; | 1374 | return NULL; |
| 1352 | group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); | 1375 | group = PEM_read_bio_ECPKParameters(bio, NULL, NULL, NULL); |
| 1353 | BIO_free(bio); | 1376 | BIO_free(bio); |
| 1377 | if (!group) | ||
| 1378 | (void)ERR_get_error(); | ||
| 1354 | return group; | 1379 | return group; |
| 1355 | } | 1380 | } |
| 1356 | 1381 | ||
| @@ -1378,85 +1403,6 @@ void tls_out(const char *s1, const char *s2) | |||
| 1378 | } | 1403 | } |
| 1379 | void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); } | 1404 | void tls_err(const char *s) { tls_out(s, ssl_error()); if (smtps) die_read(); } |
| 1380 | 1405 | ||
| 1381 | int tls_verify() | ||
| 1382 | { | ||
| 1383 | stralloc clients = {0}; | ||
| 1384 | struct constmap mapclients; | ||
| 1385 | |||
| 1386 | if (!ssl || relayclient || ssl_verified) return 0; | ||
| 1387 | ssl_verified = 1; /* don't do this twice */ | ||
| 1388 | |||
| 1389 | /* request client cert to see if it can be verified by one of our CAs | ||
| 1390 | * and the associated email address matches an entry in tlsclients */ | ||
| 1391 | switch (control_readfile(&clients, "control/tlsclients", 0)) | ||
| 1392 | { | ||
| 1393 | case 1: | ||
| 1394 | if (constmap_init(&mapclients, clients.s, clients.len, 0)) { | ||
| 1395 | /* if CLIENTCA contains all the standard root certificates, a | ||
| 1396 | * 0.9.6b client might fail with SSL_R_EXCESSIVE_MESSAGE_SIZE; | ||
| 1397 | * it is probably due to 0.9.6b supporting only 8k key exchange | ||
| 1398 | * data while the 0.9.6c release increases that limit to 100k */ | ||
| 1399 | STACK_OF(X509_NAME) *sk = SSL_load_client_CA_file(CLIENTCA); | ||
| 1400 | if (sk) { | ||
| 1401 | SSL_set_client_CA_list(ssl, sk); | ||
| 1402 | SSL_set_verify(ssl, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, NULL); | ||
| 1403 | break; | ||
| 1404 | } | ||
| 1405 | constmap_free(&mapclients); | ||
| 1406 | } | ||
| 1407 | case 0: alloc_free(clients.s); return 0; | ||
| 1408 | case -1: die_control(); | ||
| 1409 | } | ||
| 1410 | |||
| 1411 | if (ssl_timeoutrehandshake(timeout, ssl_rfd, ssl_wfd, ssl) <= 0) { | ||
| 1412 | const char *err = ssl_error_str(); | ||
| 1413 | tls_out("rehandshake failed", err); die_read(); | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | do { /* one iteration */ | ||
| 1417 | X509 *peercert; | ||
| 1418 | X509_NAME *subj; | ||
| 1419 | stralloc email = {0}; | ||
| 1420 | |||
| 1421 | int n = SSL_get_verify_result(ssl); | ||
| 1422 | if (n != X509_V_OK) | ||
| 1423 | { ssl_verify_err = X509_verify_cert_error_string(n); break; } | ||
| 1424 | peercert = SSL_get_peer_certificate(ssl); | ||
| 1425 | if (!peercert) break; | ||
| 1426 | |||
| 1427 | subj = X509_get_subject_name(peercert); | ||
| 1428 | n = X509_NAME_get_index_by_NID(subj, NID_pkcs9_emailAddress, -1); | ||
| 1429 | if (n >= 0) { | ||
| 1430 | const ASN1_STRING *s = X509_NAME_get_entry(subj, n)->value; | ||
| 1431 | if (s) { email.len = s->length; email.s = s->data; } | ||
| 1432 | } | ||
| 1433 | |||
| 1434 | if (email.len <= 0) | ||
| 1435 | ssl_verify_err = "contains no email address"; | ||
| 1436 | else if (!constmap(&mapclients, email.s, email.len)) | ||
| 1437 | ssl_verify_err = "email address not in my list of tlsclients"; | ||
| 1438 | else { | ||
| 1439 | /* add the cert email to the proto if it helped allow relaying */ | ||
| 1440 | --proto.len; | ||
| 1441 | if (!stralloc_cats(&proto, "\n (cert ") /* continuation line */ | ||
| 1442 | || !stralloc_catb(&proto, email.s, email.len) | ||
| 1443 | || !stralloc_cats(&proto, ")") | ||
| 1444 | || !stralloc_0(&proto)) die_nomem(); | ||
| 1445 | relayclient = ""; | ||
| 1446 | protocol = proto.s; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | X509_free(peercert); | ||
| 1450 | } while (0); | ||
| 1451 | constmap_free(&mapclients); alloc_free(clients.s); | ||
| 1452 | |||
| 1453 | /* we are not going to need this anymore: free the memory */ | ||
| 1454 | SSL_set_client_CA_list(ssl, NULL); | ||
| 1455 | SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL); | ||
| 1456 | |||
| 1457 | return relayclient ? 1 : 0; | ||
| 1458 | } | ||
| 1459 | |||
| 1460 | void tls_init() | 1406 | void tls_init() |
| 1461 | { | 1407 | { |
| 1462 | SSL *myssl; | 1408 | SSL *myssl; |
| @@ -1525,6 +1471,7 @@ void tls_init() | |||
| 1525 | SSL_set_cipher_list(myssl, ciphers); | 1471 | SSL_set_cipher_list(myssl, ciphers); |
| 1526 | alloc_free(saciphers.s); | 1472 | alloc_free(saciphers.s); |
| 1527 | 1473 | ||
| 1474 | //TODO: we shouldn't use hardcoded DH: see https://weakdh.org/ | ||
| 1528 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); | 1475 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); |
| 1529 | 1476 | ||
| 1530 | /* try to read DH parameters from certificate */ | 1477 | /* try to read DH parameters from certificate */ |
| @@ -1550,6 +1497,42 @@ void tls_init() | |||
| 1550 | EC_KEY_free(eckey); | 1497 | EC_KEY_free(eckey); |
| 1551 | #endif | 1498 | #endif |
| 1552 | 1499 | ||
| 1500 | #if OPENSSL_VERSION_NUMBER >= 0x10100005L | ||
| 1501 | stralloc opensslconf = {0}; | ||
| 1502 | if (control_readfile(&opensslconf, "control/opensslconf", 0) == -1) | ||
| 1503 | { SSL_free(myssl); die_control(); } | ||
| 1504 | if (opensslconf.len) { | ||
| 1505 | SSL_CONF_CTX *cctx = SSL_CONF_CTX_new(); | ||
| 1506 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_FILE); | ||
| 1507 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SERVER); | ||
| 1508 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_CERTIFICATE); | ||
| 1509 | SSL_CONF_CTX_set_flags(cctx, SSL_CONF_FLAG_SHOW_ERRORS); | ||
| 1510 | SSL_CONF_CTX_set_ssl(cctx, myssl); | ||
| 1511 | |||
| 1512 | int i, j, next = 0; | ||
| 1513 | char *cmd, * arg; | ||
| 1514 | for (i = 0; i < opensslconf.len; i += next) { | ||
| 1515 | cmd = opensslconf.s + i; | ||
| 1516 | next = str_len(cmd) + 1; | ||
| 1517 | |||
| 1518 | j = str_chr(cmd, ' '); | ||
| 1519 | arg = cmd + j; | ||
| 1520 | while (*arg == ' ') ++arg; | ||
| 1521 | cmd[j] = 0; | ||
| 1522 | |||
| 1523 | if (SSL_CONF_cmd(cctx, cmd, arg) <= 0) { | ||
| 1524 | enew(); eout("opensslconf \""); eout(cmd); eout(" "); eout(arg); | ||
| 1525 | eout("\" failed: "); eout(ssl_error()); eout("\n"); eflush(); | ||
| 1526 | tls_out("OpenSSL", "unable to initialize ssl"); | ||
| 1527 | SSL_free(myssl); | ||
| 1528 | die_read(); | ||
| 1529 | } | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | (void)SSL_CONF_CTX_finish(cctx); | ||
| 1533 | } | ||
| 1534 | #endif | ||
| 1535 | |||
| 1553 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); | 1536 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); |
| 1554 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); | 1537 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); |
| 1555 | 1538 | ||
diff --git a/ssl_timeoutio.c b/ssl_timeoutio.c index 5b2dc9d..30025d5 100644 --- a/ssl_timeoutio.c +++ b/ssl_timeoutio.c | |||
| @@ -68,19 +68,6 @@ int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl) | |||
| 68 | return r; | 68 | return r; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl) | ||
| 72 | { | ||
| 73 | int r; | ||
| 74 | |||
| 75 | SSL_renegotiate(ssl); | ||
| 76 | r = ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); | ||
| 77 | if (r <= 0 || ssl->type == SSL_ST_CONNECT) return r; | ||
| 78 | |||
| 79 | /* this is for the server only */ | ||
| 80 | ssl->state = SSL_ST_ACCEPT; | ||
| 81 | return ssl_timeoutio(SSL_do_handshake, t, rfd, wfd, ssl, NULL, 0); | ||
| 82 | } | ||
| 83 | |||
| 84 | int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len) | 71 | int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len) |
| 85 | { | 72 | { |
| 86 | if (!buf) return 0; | 73 | if (!buf) return 0; |
diff --git a/ssl_timeoutio.h b/ssl_timeoutio.h index 073cb67..fff3859 100644 --- a/ssl_timeoutio.h +++ b/ssl_timeoutio.h | |||
| @@ -10,7 +10,6 @@ | |||
| 10 | 10 | ||
| 11 | int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl); | 11 | int ssl_timeoutconn(int t, int rfd, int wfd, SSL *ssl); |
| 12 | int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl); | 12 | int ssl_timeoutaccept(int t, int rfd, int wfd, SSL *ssl); |
| 13 | int ssl_timeoutrehandshake(int t, int rfd, int wfd, SSL *ssl); | ||
| 14 | 13 | ||
| 15 | int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); | 14 | int ssl_timeoutread(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); |
| 16 | int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); | 15 | int ssl_timeoutwrite(int t, int rfd, int wfd, SSL *ssl, char *buf, int len); |
| @@ -2,6 +2,7 @@ | |||
| 2 | #define TLS_H | 2 | #define TLS_H |
| 3 | 3 | ||
| 4 | #include <openssl/ssl.h> | 4 | #include <openssl/ssl.h> |
| 5 | #include <openssl/err.h> | ||
| 5 | 6 | ||
| 6 | /* ECC: make sure we have at least 1.0.0 */ | 7 | /* ECC: make sure we have at least 1.0.0 */ |
| 7 | #if !defined(OPENSSL_NO_EC) && defined(TLSEXT_ECPOINTFORMAT_uncompressed) | 8 | #if !defined(OPENSSL_NO_EC) && defined(TLSEXT_ECPOINTFORMAT_uncompressed) |
