diff options
| author | manuel <manuel@mausz.at> | 2015-06-22 21:28:22 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2015-06-22 21:28:22 +0200 |
| commit | 15a5232629a37b3df8a476f984343375950fa2ff (patch) | |
| tree | 790fbad488ef2bc481ae1562ad5949afa4e818b6 /qmail-smtpd.c | |
| parent | 3284e61d7a7a49620e64c7d634776f8bcf4f8119 (diff) | |
| download | qmail-15a5232629a37b3df8a476f984343375950fa2ff.tar.gz qmail-15a5232629a37b3df8a476f984343375950fa2ff.tar.bz2 qmail-15a5232629a37b3df8a476f984343375950fa2ff.zip | |
Use DH parameters from OpenSSL and remove support for ephemeral RSA
This adds support for DH parameters from 1024 to 8192 bits.
Diffstat (limited to 'qmail-smtpd.c')
| -rw-r--r-- | qmail-smtpd.c | 92 |
1 files changed, 64 insertions, 28 deletions
diff --git a/qmail-smtpd.c b/qmail-smtpd.c index 3360cfe..817524d 100644 --- a/qmail-smtpd.c +++ b/qmail-smtpd.c | |||
| @@ -1141,41 +1141,78 @@ void smtp_tls(char *arg) | |||
| 1141 | else tls_init(); | 1141 | else tls_init(); |
| 1142 | } | 1142 | } |
| 1143 | 1143 | ||
| 1144 | RSA *tmp_rsa_cb(SSL *ssl, int export, int keylen) | 1144 | /* |
| 1145 | * Grab well-defined DH parameters from OpenSSL, see the get_rfc* | ||
| 1146 | * functions in <openssl/bn.h> for all available primes. | ||
| 1147 | */ | ||
| 1148 | static DH *make_dh_params(BIGNUM *(*prime)(BIGNUM *), const char *gen) | ||
| 1145 | { | 1149 | { |
| 1146 | if (!export) keylen = 512; | 1150 | DH *dh = DH_new(); |
| 1147 | if (keylen == 512) { | 1151 | |
| 1148 | FILE *in = fopen("control/rsa512.pem", "r"); | 1152 | if (!dh) { |
| 1149 | if (in) { | 1153 | return NULL; |
| 1150 | RSA *rsa = PEM_read_RSAPrivateKey(in, NULL, NULL, NULL); | ||
| 1151 | fclose(in); | ||
| 1152 | if (rsa) return rsa; | ||
| 1153 | } | 1154 | } |
| 1154 | } | 1155 | dh->p = prime(NULL); |
| 1155 | return RSA_generate_key(keylen, RSA_F4, NULL, NULL); | 1156 | BN_dec2bn(&dh->g, gen); |
| 1157 | if (!dh->p || !dh->g) { | ||
| 1158 | DH_free(dh); | ||
| 1159 | return NULL; | ||
| 1160 | } | ||
| 1161 | return dh; | ||
| 1156 | } | 1162 | } |
| 1157 | 1163 | ||
| 1164 | /* Storage and initialization for DH parameters. */ | ||
| 1165 | static struct dhparam { | ||
| 1166 | BIGNUM *(*const prime)(BIGNUM *); /* function to generate... */ | ||
| 1167 | DH *dh; /* ...this, used for keys.... */ | ||
| 1168 | const unsigned int min; /* ...of length >= this. */ | ||
| 1169 | } dhparams[] = { | ||
| 1170 | { get_rfc3526_prime_8192, NULL, 6145 }, | ||
| 1171 | { get_rfc3526_prime_6144, NULL, 4097 }, | ||
| 1172 | { get_rfc3526_prime_4096, NULL, 3073 }, | ||
| 1173 | { get_rfc3526_prime_3072, NULL, 2049 }, | ||
| 1174 | { get_rfc3526_prime_2048, NULL, 1025 }, | ||
| 1175 | { get_rfc2409_prime_1024, NULL, 0 } | ||
| 1176 | }; | ||
| 1177 | |||
| 1178 | /* Hand out the same DH structure though once generated as we leak | ||
| 1179 | * memory otherwise and freeing the structure up after use would be | ||
| 1180 | * hard to track and in fact is not needed at all as it is safe to | ||
| 1181 | * use the same parameters over and over again security wise (in | ||
| 1182 | * contrast to the keys itself) and code safe as the returned structure | ||
| 1183 | * is duplicated by OpenSSL anyway. Hence no modification happens | ||
| 1184 | * to our copy. */ | ||
| 1158 | DH *tmp_dh_cb(SSL *ssl, int export, int keylen) | 1185 | DH *tmp_dh_cb(SSL *ssl, int export, int keylen) |
| 1159 | { | 1186 | { |
| 1160 | if (!export) keylen = 1024; | 1187 | EVP_PKEY *pkey = SSL_get_privatekey(ssl); |
| 1161 | if (keylen == 512) { | 1188 | int type = pkey ? EVP_PKEY_type(pkey->type) : EVP_PKEY_NONE; |
| 1162 | FILE *in = fopen("control/dh512.pem", "r"); | 1189 | unsigned n; |
| 1163 | if (in) { | 1190 | |
| 1164 | DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); | 1191 | /* |
| 1165 | fclose(in); | 1192 | * OpenSSL will call us with either keylen == 512 or keylen == 1024 |
| 1166 | if (dh) return dh; | 1193 | * (see the definition of SSL_EXPORT_PKEYLENGTH in ssl_locl.h). |
| 1194 | * Adjust the DH parameter length according to the size of the | ||
| 1195 | * RSA/DSA private key used for the current connection, and always | ||
| 1196 | * use at least 1024-bit parameters. | ||
| 1197 | * Note: This may cause interoperability issues with implementations | ||
| 1198 | * which limit their DH support to 1024 bit - e.g. Java 7 and earlier. | ||
| 1199 | * In this case, SSLCertificateFile can be used to specify fixed | ||
| 1200 | * 1024-bit DH parameters (with the effect that OpenSSL skips this | ||
| 1201 | * callback). | ||
| 1202 | */ | ||
| 1203 | if (type == EVP_PKEY_RSA || type == EVP_PKEY_DSA) | ||
| 1204 | keylen = EVP_PKEY_bits(pkey); | ||
| 1205 | |||
| 1206 | for (n = 0; n < sizeof(dhparams)/sizeof(dhparams[0]); n++) { | ||
| 1207 | if (keylen >= dhparams[n].min) { | ||
| 1208 | if (dhparams[n].dh == NULL) | ||
| 1209 | dhparams[n].dh = make_dh_params(dhparams[n].prime, "2"); | ||
| 1210 | return dhparams[n].dh; | ||
| 1167 | } | 1211 | } |
| 1168 | } | 1212 | } |
| 1169 | if (keylen == 1024) { | 1213 | |
| 1170 | FILE *in = fopen("control/dh1024.pem", "r"); | 1214 | return NULL; /* impossible to reach. */ |
| 1171 | if (in) { | 1215 | } |
| 1172 | DH *dh = PEM_read_DHparams(in, NULL, NULL, NULL); | ||
| 1173 | fclose(in); | ||
| 1174 | if (dh) return dh; | ||
| 1175 | } | ||
| 1176 | } | ||
| 1177 | return DH_generate_parameters(keylen, DH_GENERATOR_2, NULL, NULL); | ||
| 1178 | } | ||
| 1179 | 1216 | ||
| 1180 | /* don't want to fail handshake if cert isn't verifiable */ | 1217 | /* don't want to fail handshake if cert isn't verifiable */ |
| 1181 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } | 1218 | int verify_cb(int preverify_ok, X509_STORE_CTX *ctx) { return 1; } |
| @@ -1338,7 +1375,6 @@ void tls_init() | |||
| 1338 | SSL_set_cipher_list(myssl, ciphers); | 1375 | SSL_set_cipher_list(myssl, ciphers); |
| 1339 | alloc_free(saciphers.s); | 1376 | alloc_free(saciphers.s); |
| 1340 | 1377 | ||
| 1341 | SSL_set_tmp_rsa_callback(myssl, tmp_rsa_cb); | ||
| 1342 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); | 1378 | SSL_set_tmp_dh_callback(myssl, tmp_dh_cb); |
| 1343 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); | 1379 | SSL_set_rfd(myssl, ssl_rfd = substdio_fileno(&ssin)); |
| 1344 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); | 1380 | SSL_set_wfd(myssl, ssl_wfd = substdio_fileno(&ssout)); |
