Skip to content
This repository was archived by the owner on Jan 21, 2019. It is now read-only.
This repository was archived by the owner on Jan 21, 2019. It is now read-only.

Allow specification of ECC named curve used in ECDH key exchange #14

@BenBE

Description

@BenBE

In recent versions ejabberd allows for the DH parameters to be set in its configuration. But a similar setting for the ECDH parameters is missing. In a quick shot, of which the results are included below, I tried to add this feature in p1_tls, so it can be used in ejabberd.

The intention is to allow the used named curve for ECC to be specified in the ejabberd config by providing its name in a setting like "ecdh_curvename" or "s2s_ecdh_curvename" (for s2s).

diff --git a/c_src/p1_tls_drv.c b/c_src/p1_tls_drv.c
index 30c5e62..010e830 100644
--- a/c_src/p1_tls_drv.c
+++ b/c_src/p1_tls_drv.c
@@ -55,6 +55,7 @@ typedef unsigned __int32 uint32_t;
 #endif

 #define CIPHERS "DEFAULT:!EXPORT:!LOW:!RC4:!SSLv2"
+#define NID_ECDH_DEFAULTCURVE NID_X9_62_prime256v1

 /**
  * Prepare the SSL options flag.
@@ -326,15 +327,23 @@ static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
  * for details.
  */
 #ifndef OPENSSL_NO_ECDH
-static void setup_ecdh(SSL_CTX *ctx)
+static void setup_ecdh(SSL_CTX *ctx, char* ecdh_curvename)
 {
+   int nidCurve;
    EC_KEY *ecdh;

    if (SSLeay() < 0x1000005fL) {
       return;
    }

-   ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+   if (ecdh_curvename && (( nidCurve = OBJ_sn2nid(ecdh_curvename) ))) {
+      ecdh = EC_KEY_new_by_curve_name(nidCurve);
+   }
+
+   if (ecdh == NULL) {
+      ecdh = EC_KEY_new_by_curve_name(NID_ECDH_DEFAULTCURVE);
+   }
+
    SSL_CTX_set_options(ctx, SSL_OP_SINGLE_ECDH_USE);
    SSL_CTX_set_tmp_ecdh(ctx, ecdh);

@@ -537,10 +546,13 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle,
     size_t protocol_options_len = strlen(protocol_options);
     char *dh_file = protocol_options + protocol_options_len + 1;
     size_t dh_file_len = strlen(dh_file);
+    char *ecdh_curvename = dh_file + dh_file_len + 1;
+    size_t ecdh_curvename_len = strlen(ecdh_curvename);
     char *hash_key = (char *)driver_alloc(key_file_len +
                           ciphers_len +
                           protocol_options_len +
-                          dh_file_len + 1);
+                          dh_file_len +
+                          ecdh_curvename + 1);
     long options = 0L;

     if (protocol_options_len != 0) {
@@ -556,13 +568,16 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle,
        free(popts);
     }

-    sprintf(hash_key, "%s%s%s%s", key_file, ciphers, protocol_options,
-        dh_file);
+    sprintf(hash_key, "%s%s%s%s%s", key_file, ciphers, protocol_options,
+        dh_file, ecdh_curvename);
     SSL_CTX *ssl_ctx = hash_table_lookup(hash_key, &key_mtime, &dh_mtime);

     if (dh_file_len == 0)
        dh_file = NULL;

+    if (ecdh_curvename_len == 0)
+       ecdh_curvename = NULL;
+
     if (is_modified(key_file, &key_mtime) ||
         is_modified(dh_file, &dh_mtime) ||
         ssl_ctx == NULL)
@@ -588,7 +603,7 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle,
        SSL_CTX_set_cipher_list(ctx, ciphers);

 #ifndef OPENSSL_NO_ECDH
-       setup_ecdh(ctx);
+       setup_ecdh(ctx, ecdh_curvename);
 #endif
 #ifndef OPENSSL_NO_DH
        res = setup_dh(ctx, dh_file);
diff --git a/src/p1_tls.erl b/src/p1_tls.erl
index 74158cc..73eb1aa 100644
--- a/src/p1_tls.erl
+++ b/src/p1_tls.erl
@@ -145,11 +145,19 @@ tcp_to_tls(TCPSocket, Options) ->
                        false ->
                            <<>>
                    end,
+          ECCurveName = case lists:keysearch(eccurvename, 1, Options) of
+                       {value, {eccurvename, E}} ->
+                           iolist_to_binary(E);
+                       false ->
+                           <<>>
+                   end,
           CertFile1 = iolist_to_binary(CertFile),
      case catch port_control(Port, Command bor Flags,
-                 <<CertFile1/binary, 0, Ciphers/binary,
-                   0, ProtocolOpts/binary, 0, DHFile/binary,
-                   0>>)
+                 <<CertFile1/binary, 0,
+                   Ciphers/binary, 0,
+                   ProtocolOpts/binary, 0,
+                   DHFile/binary, 0,
+                   ECCurveName/binary, 0>>)
          of
        {'EXIT', {badarg, _}} -> {error, einval};
        <<0>> ->

I know this is by far not perfect, but should provide a good starting point for further developments.

Thanks to emias (IRC) for reviewing of and commenting on this initial PoC.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions