Skip to content

Commit

Permalink
Add a new TLSECDHCurve directive, for specifying the curve to use for…
Browse files Browse the repository at this point in the history
… ECDHE

ciphers.
  • Loading branch information
tjsaunders committed Apr 26, 2015
1 parent 9f1078f commit 9e960a6
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 22 deletions.
7 changes: 7 additions & 0 deletions RELEASE_NOTES
Expand Up @@ -122,6 +122,13 @@ ChangeLog files.
via the new SQLPasswordSaltEncoding directive; see
doc/contrib/mod_sql_passwd.html#SQLPasswordSaltEncoding for details.

TLSECDHCurve
When an FTPS client uses an ECDHE cipher, mod_tls currently will use
the X9.62 <code>prime256v1</code> curve. Some sites may, however,
wish to use other curves for ECDHE ciphers. These sites may now use
the new TLSECDHCurve directive to configure the curve; see
doc/contrib/mod_tls.html#TLSECDHCurve for details.

TransferOptions
There are some broken (<i>e.g.</i> old/mainframe) FTP clients that
will upload files, containing CRLF sequences, as ASCII data, but
Expand Down
109 changes: 96 additions & 13 deletions contrib/mod_tls.c
Expand Up @@ -2439,6 +2439,7 @@ static int tls_ctrl_renegotiate_cb(CALLBACK_FRAME) {
static DH *tls_dh_cb(SSL *ssl, int is_export, int keylen) {
DH *dh = NULL;
EVP_PKEY *pkey;
int pkeylen = 0;

/* OpenSSL will only ever call us (currently) with a keylen of 512 or 1024;
* see the SSL_EXPORT_PKEYLENGTH macro in ssl_locl.h. Sigh.
Expand All @@ -2455,13 +2456,10 @@ static DH *tls_dh_cb(SSL *ssl, int is_export, int keylen) {
if (pkey != NULL) {
if (EVP_PKEY_type(pkey->type) == EVP_PKEY_RSA ||
EVP_PKEY_type(pkey->type) == EVP_PKEY_DSA) {
int pkeylen;

pkeylen = EVP_PKEY_bits(pkey);
if (pkeylen != keylen) {
pr_trace_msg(trace_channel, 13,
"adjusted DH parameter length from %d to %d bits", keylen, pkeylen);
keylen = pkeylen;
}
}
}
Expand All @@ -2472,19 +2470,44 @@ static DH *tls_dh_cb(SSL *ssl, int is_export, int keylen) {
DH **dhs;

dhs = tls_tmp_dhs->elts;

/* Search the configured list of DH parameters twice: once for any sizes
* matching the actual requested size (usually 1024), and once for any
* matching the certificate private key size (pkeylen).
*
* This behavior allows site admins to configure a TLSDHParamFile that
* contains 1024-bit parameters, for e.g. Java 7 (and earlier) clients.
*/

/* Note: the keylen argument is in BITS, but DH_size() returns the number
* of BYTES.
*/
for (i = 0; i < tls_tmp_dhs->nelts; i++) {
int dhlen;

/* Note: the keylen argument is in BITS, but DH_size() returns
* the number of BYTES.
*/
dhlen = DH_size(dhs[i]) * 8;
if (dhlen == keylen) {
pr_trace_msg(trace_channel, 11,
"found matching DH parameter for key length %d", keylen);
return dhs[i];
}
}

for (i = 0; i < tls_tmp_dhs->nelts; i++) {
int dhlen;

dhlen = DH_size(dhs[i]) * 8;
if (dhlen == pkeylen) {
pr_trace_msg(trace_channel, 11,
"found matching DH parameter for certificate private key length %d",
pkeylen);
return dhs[i];
}
}
}

/* Still no DH parameters found? Use the built-in ones. */

switch (keylen) {
case 512:
dh = get_dh512();
Expand Down Expand Up @@ -2805,7 +2828,16 @@ static int tls_init_ctx(void) {
# if defined(SSL_CTX_set_ecdh_auto)
SSL_CTX_set_ecdh_auto(ssl_ctx, 1);
# else
SSL_CTX_set_tmp_ecdh_callback(ssl_ctx, tls_ecdh_cb);
c = find_config(main_server->conf, CONF_PARAM, "TLSECDHCurve", FALSE);
if (c != NULL) {
const EC_GROUP *group;

group = c->argv[0];
SSL_CTX_set_tmp_ecdh(ssl_ctx, group);

} else {
SSL_CTX_set_tmp_ecdh_callback(ssl_ctx, tls_ecdh_cb);
}
# endif
#endif /* PR_USE_OPENSSL_ECC */

Expand Down Expand Up @@ -8507,7 +8539,7 @@ MODRET set_tlseccertfile(cmd_rec *cmd) {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "The ", cmd->argv[0],
" directive cannot be used on this system, as your OpenSSL version "
"does have EC support", NULL));
#endif /* PR_USE_OPENSSL_ ECC */
#endif /* PR_USE_OPENSSL_ECC */
}

/* usage: TLSECCertificateKeyFile file */
Expand Down Expand Up @@ -8537,24 +8569,74 @@ MODRET set_tlseckeyfile(cmd_rec *cmd) {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "The ", cmd->argv[0],
" directive cannot be used on this system, as your OpenSSL version "
"does have EC support", NULL));
#endif /* PR_USE_OPENSSL_ ECC */
#endif /* PR_USE_OPENSSL_ECC */
}

/* usage: TLSECDHCurve name */
MODRET set_tlsecdhcurve(cmd_rec *cmd) {
#ifdef PR_USE_OPENSSL_ECC
char *curve_name = NULL;
int curve_nid = -1;
EC_GROUP *group = NULL;

CHECK_ARGS(cmd, 1);
CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

curve_name = cmd->argv[1];

/* The special-case handling of these curve names is copied from OpenSSL's
* apps/ecparam.c code.
*/

if (strcmp(curve_name, "secp192r1") == 0) {
curve_nid = NID_X9_62_prime192v1;

} else if (strcmp(curve_name, "secp256r1") == 0) {
curve_nid = NID_X9_62_prime256v1;

} else {
curve_nid = OBJ_sn2nid(curve_name);
if (curve_nid == 0) {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to create '", curve_name,
"' EC curve: ", tls_get_errors(), NULL));
}
}

group = EC_GROUP_new_by_curve_name(curve_nid);
if (group == NULL) {
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "unable to create '", curve_name,
"' EC curve: ", tls_get_errors(), NULL));
}

EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE);
EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED);

(void) add_config_param(cmd->argv[1], 1, group);
return PR_HANDLED(cmd);

#else
CONF_ERROR(cmd, pstrcat(cmd->tmp_pool, "The ", cmd->argv[0],
" directive cannot be used on this system, as your OpenSSL version "
"does have EC support", NULL));
#endif /* PR_USE_OPENSSL_ECC */
}

/* usage: TLSEngine on|off */
MODRET set_tlsengine(cmd_rec *cmd) {
int bool = -1;
int engine = -1;
config_rec *c = NULL;

CHECK_ARGS(cmd, 1);
CHECK_CONF(cmd, CONF_ROOT|CONF_VIRTUAL|CONF_GLOBAL);

bool = get_boolean(cmd, 1);
if (bool == -1)
engine = get_boolean(cmd, 1);
if (engine == -1) {
CONF_ERROR(cmd, "expected Boolean parameter");
}

c = add_config_param(cmd->argv[0], 1, NULL);
c->argv[0] = pcalloc(c->pool, sizeof(unsigned char));
*((unsigned char *) c->argv[0]) = bool;
*((unsigned char *) c->argv[0]) = engine;

return PR_HANDLED(cmd);
}
Expand Down Expand Up @@ -10227,6 +10309,7 @@ static conftable tls_conftab[] = {
{ "TLSDSACertificateKeyFile", set_tlsdsakeyfile, NULL },
{ "TLSECCertificateFile", set_tlseccertfile, NULL },
{ "TLSECCertificateKeyFile", set_tlseckeyfile, NULL },
{ "TLSECDHCurve", set_tlsecdhcurve, NULL },
{ "TLSEngine", set_tlsengine, NULL },
{ "TLSLog", set_tlslog, NULL },
{ "TLSMasqueradeAddress", set_tlsmasqaddr, NULL },
Expand Down
75 changes: 66 additions & 9 deletions doc/contrib/mod_tls.html
@@ -1,6 +1,3 @@
<!-- $Id: mod_tls.html,v 1.43 2013-12-09 23:15:16 castaglia Exp $ -->
<!-- $Source: /home/proftpd-core/backup/proftp-cvsroot/proftpd/doc/contrib/mod_tls.html,v $ -->

<html>
<head>
<title>ProFTPD module mod_tls</title>
Expand Down Expand Up @@ -57,6 +54,7 @@ <h2>Directives</h2>
<li><a href="#TLSDSACertificateKeyFile">TLSDSACertificateKeyFile</a>
<li><a href="#TLSECCertificateFile">TLSECACertificateFile</a>
<li><a href="#TLSECCertificateKeyFile">TLSECCertificateKeyFile</a>
<li><a href="#TLSECDHCurve">TLSECDHCurve</a>
<li><a href="#TLSEngine">TLSEngine</a>
<li><a href="#TLSLog">TLSLog</a>
<li><a href="#TLSMasqueradeAddress">TLSMasqueradeAddress</a>
Expand Down Expand Up @@ -366,7 +364,7 @@ <h2><a name="TLSCipherSuite">TLSCipherSuite</a></h2>
<p>
The OpenSSL command
<pre>
openssl ciphers -v <em>&lt;list of ciphers&gt;</em>
$ openssl ciphers -v <em>&lt;list of ciphers&gt;</em>
</pre>
may be used to list all of the ciphers and the order described by a specific
<em>&lt;list of ciphers&gt;</em>.
Expand Down Expand Up @@ -438,7 +436,7 @@ <h2><a name="TLSCryptoDevice">TLSCryptoDevice</a></h2>
<p>
The OpenSSL command
<pre>
openssl engine
$ openssl engine
</pre>
may be used to list all of the engine drivers supported by OpenSSL.

Expand All @@ -465,15 +463,23 @@ <h2><a name="TLSDHParamFile">TLSDHParamFile</a></h2>
that comes with OpenSSL may be used to generate an appropriate file for this
directive:
<pre>
# openssl dhparam -outform PEM -2 <i>nbits</i> &gt;&gt; dhparams.pem
# openssl dhparam -outform PEM -5 <i>nbits</i> &gt;&gt; dhparams.pem
$ openssl dhparam -outform PEM -2 <i>nbits</i> &gt;&gt; dhparams.pem
$ openssl dhparam -outform PEM -5 <i>nbits</i> &gt;&gt; dhparams.pem
</pre>
Using either -2 or -5 as the generator is fine. The <em>nbits</em> value used
should vary between 512 and 4096, inclusive.

<p>
The <em>file</em> parameter must be an absolute path.

<p>
<b>Note<b> that as of <code>proftpd-1.3.6rc1</code> and later, for
Diffie-Hellman key exchanges, <code>mod_tls</code> will generate DH parameters
that match the size of the server certificate's RSA/DSA key. Some clients,
such as Java 7 (and earlier) code, cannot handle DH parameter lengths greater
than 1024 bits; see this <a href="#TLSJavaDH">FAQ</a> for a workaround for such
clients.

<p>
<hr>
<h2><a name="TLSDSACertficateFile">TLSDSACertficateFile</a></h2>
Expand Down Expand Up @@ -586,6 +592,19 @@ <h2><a name="TLSECCertificateKeyFile">TLSECCertificateKeyFile</a></h2>
TLSECCertificateKeyFile /etc/ftpd/server-ec-key.pem
</pre>

<p>
<hr>
<h2><a name="TLSECDHCurve">TLSECDHCurve</a></h2>
<strong>Syntax:</strong> TLSECDHCurve <em>curve</em><br>
<strong>Default:</strong> TLSECDHCurve prime256v1<br>
<strong>Context:</strong> server config, <code>&lt;VirtualHost&gt;</code>, <code>&lt;Global&gt;</code><br>
<strong>Module:</strong> mod_tls<br>
<strong>Compatibility:</strong> 1.3.6rc1 and later

<p>
The <code>TLSECDHCurve/code> directive specifies the EC curve to use for
ECDHE ciphers.

<p>
<hr>
<h2><a name="TLSEngine">TLSEngine</a></h2>
Expand Down Expand Up @@ -1792,7 +1811,7 @@ <h2><a name="Usage">Usage</a></h2>
Much of the documentation for Apache's <code>mod_ssl</code>, concerning
certificates, OpenSSL usage, <i>etc</i> applies to this module as well:
<pre>
<a href="http://www.modssl.org/docs/2.7/">http://www.modssl.org/docs/2.7/</a>
<a href="http://httpd.apache.org/docs/2.4/mod/mod_ssl.html">http://httpd.apache.org/docs/2.4/mod/mod_ssl.html</a>
</pre>
The OpenSSL documentation, and its
<a href="http://www.openssl.org/support/faq.cgi">FAQ</a>, are recommended as
Expand Down Expand Up @@ -1827,6 +1846,44 @@ <h2><a name="Usage">Usage</a></h2>
This trace logging can generate large files; it is intended for debugging use
only, and should be removed from any production configuration.

<p><a name="FAQ">
<b>Frequently Asked Questions</b><br>

<p><a name="TLSJavaDH">
<font color=red>Question</font>: When I use a Java client to connect to my
<code>proftpd</code> server using FTPS, it fails with exceptions such as:
<pre>
java.lang.RuntimeException: Could not generate DH keypair and java.security.InvalidAlgorithmParameterException: Prime size must be multiple of 64, and can only range from 512 to 1024 (inclusive)
</pre>
How can I fix this?<br>
<font color=blue>Answer</font>: This happens because <code>mod_tls</code> tries
to use longer DH parameter lengths when it can, but not all clients support
longer DH parameter lengths.

<p>
To address this, you need to configure a custom 1024-bit DH parameter via the
<a href="#TLSDHParamFile"><code>TLSDHParamFile</code></a> directive. You
can generate a custom DH parameter using <code>openssl dhparam</code>,
<i>e.g.</i>:
<pre>
$ openssl dhparam -outform PEM -5 1024 &gt; dh1024.pem
</pre>
Alternatively, you can append the following standard 1024-bit DH parameters
from <a href="http://www.faqs.org/rfcs/rfc2409">RFC 2409</a>, section 6.2,
into a <code>dh1024.pem</code> file:
<pre>
-----BEGIN DH PARAMETERS-----
MIGHAoGBAP//////////yQ/aoiFowjTExmKLgNwc0SkCTgiKZ8x0Agu+pjsTmyJR
Sgh5jjQE3e+VGbPNOkMbMCsKbfJfFDdP4TVtbVHCReSFtXZiXn7G9ExC6aY37WsL
/1y29Aa37e44a/taiZ+lrp8kEXxLH+ZJKGZR7OZTgf//////////AgEC
-----END DH PARAMETERS-----
</pre>
Then tell <code>mod_tls</code> to use that DH parameter:
<pre>
# Use 1024-bit DH parameters for the Java clients
TLSDHParamFile /path/to/dh1024.pem
</pre>

<p>
<hr>
<h2><a name="Installation">Installation</a></h2>
Expand Down Expand Up @@ -1863,7 +1920,7 @@ <h2><a name="Installation">Installation</a></h2>

<hr>
<font size=2><b><i>
&copy; Copyright 2002-2014 TJ Saunders<br>
&copy; Copyright 2002-2015 TJ Saunders<br>
All Rights Reserved<br>
</i></b></font>

Expand Down

0 comments on commit 9e960a6

Please sign in to comment.