Skip to content

Commit

Permalink
add ECDHE support
Browse files Browse the repository at this point in the history
  • Loading branch information
ksdlck committed Nov 28, 2012
1 parent d5ab2a7 commit 2b9a558
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 0 deletions.
3 changes: 3 additions & 0 deletions lib/crypto.js
Expand Up @@ -90,6 +90,9 @@ exports.createCredentials = function(options, context) {

if (context) return c;

if (options.ecdheCurves)
c.context.setECDHECurves.apply(c.context, options.ecdheCurves);

if (options.key) {
if (options.passphrase) {
c.context.setKey(options.key, options.passphrase);
Expand Down
2 changes: 2 additions & 0 deletions lib/tls.js
Expand Up @@ -1109,6 +1109,7 @@ function Server(/* [options], listener */) {
cert: self.cert,
ca: self.ca,
ciphers: self.ciphers || DEFAULT_CIPHERS,
ecdheCurves: self.ecdheCurves,
secureProtocol: self.secureProtocol,
secureOptions: self.secureOptions,
crl: self.crl,
Expand Down Expand Up @@ -1197,6 +1198,7 @@ Server.prototype.setOptions = function(options) {
if (options.secureProtocol) this.secureProtocol = options.secureProtocol;
if (options.crl) this.crl = options.crl;
if (options.ciphers) this.ciphers = options.ciphers;
if (options.ecdheCurves) this.ecdheCurves = options.ecdheCurves;
var secureOptions = options.secureOptions || 0;
if (options.honorCipherOrder) {
secureOptions |= constants.SSL_OP_CIPHER_SERVER_PREFERENCE;
Expand Down
100 changes: 100 additions & 0 deletions src/node_crypto.cc
Expand Up @@ -131,6 +131,10 @@ void SecureContext::Initialize(Handle<Object> target) {
t->SetClassName(String::NewSymbol("SecureContext"));

NODE_SET_PROTOTYPE_METHOD(t, "init", SecureContext::Init);
NODE_SET_PROTOTYPE_METHOD(t, "setECDHECurves",
SecureContext::SetECDHECurves);
NODE_SET_PROTOTYPE_METHOD(t, "clearECDHECurves",
SecureContext::ClearECDHECurves);
NODE_SET_PROTOTYPE_METHOD(t, "setKey", SecureContext::SetKey);
NODE_SET_PROTOTYPE_METHOD(t, "setCert", SecureContext::SetCert);
NODE_SET_PROTOTYPE_METHOD(t, "addCACert", SecureContext::AddCACert);
Expand Down Expand Up @@ -220,6 +224,8 @@ Handle<Value> SecureContext::Init(const Arguments& args) {

sc->ctx_ = SSL_CTX_new(method);

SSL_CTX_set_app_data(sc->ctx_, sc);

// SSL session cache configuration
SSL_CTX_set_session_cache_mode(sc->ctx_,
SSL_SESS_CACHE_SERVER |
Expand All @@ -232,6 +238,100 @@ Handle<Value> SecureContext::Init(const Arguments& args) {
return True();
}

static EC_KEY *SecureContext_ecdhe_key_cb(SSL *ssl, int is_ex, int bit_len) {
SecureContext *sc = (SecureContext *)SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl));

assert(NULL != sc->ecdhe_keys);

for (int i = 0; i < sc->ecdhe_keys_len; i++)
if (sc->ecdhe_keys[i].bit_len >= bit_len)
return sc->ecdhe_keys[i].key;

if (0 < sc->ecdhe_keys_len)
return sc->ecdhe_keys[sc->ecdhe_keys_len - 1].key;

return NULL;
}

Handle<Value> SecureContext::SetECDHECurves(const Arguments& args) {
HandleScope scope;

SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder());
sc->_ClearECDHECurves();

char err[80];
int i = 0;

sc->ecdhe_keys_len = args.Length();
sc->ecdhe_keys = new BitLenKey<EC_KEY>[sc->ecdhe_keys_len];

for (; i < args.Length(); i++) {
String::Utf8Value _curvesn(args[i]);
const char *curvesn = *_curvesn;

int curvenid = OBJ_sn2nid(curvesn);
if (NID_undef == curvenid) {
snprintf(err, 80, "Invalid curve: %s", curvesn);
goto err_obj_sn2nid;
}

EC_KEY *key = EC_KEY_new_by_curve_name(curvenid);
if (NULL == key) {
snprintf(err, 80, "Failed to generate key for curve: %s", curvesn);
goto err_ec_key_new;
}

const EC_GROUP *grp = EC_KEY_get0_group(key);
if (NULL == grp) {
snprintf(err, 80, "Failed to get group for curve: %s", curvesn);
goto err_ec_key_get_group;
}

sc->ecdhe_keys[i].bit_len = EC_GROUP_get_degree(grp);
sc->ecdhe_keys[i].key = key;
}

SSL_CTX_set_tmp_ecdh_callback(sc->ctx_, SecureContext_ecdhe_key_cb);

return True();

err_obj_sn2nid:
err_ec_key_new:
i--;

err_ec_key_get_group:
for (; i >= 0; i--)
EC_KEY_free(sc->ecdhe_keys[i].key);

delete sc->ecdhe_keys;
sc->ecdhe_keys = NULL;

return ThrowException(Exception::Error(String::New(err)));
}

Handle<Value> SecureContext::ClearECDHECurves(const Arguments& args) {
HandleScope scope;

SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(args.Holder());

sc->_ClearECDHECurves();

return True();
}

void SecureContext::_ClearECDHECurves(void) {
if (NULL == ecdhe_keys)
return;

for (int i = 0; i < ecdhe_keys_len; i++)
EC_KEY_free(ecdhe_keys[i].key);

delete ecdhe_keys;
ecdhe_keys = NULL;

SSL_CTX_set_tmp_ecdh_callback(ctx_, NULL);
}


SSL_SESSION* SecureContext::GetSessionCallback(SSL* s,
unsigned char* key,
Expand Down
15 changes: 15 additions & 0 deletions src/node_crypto.h
Expand Up @@ -27,6 +27,7 @@
#include "node_object_wrap.h"
#include "v8.h"

#include <openssl/objects.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/evp.h>
Expand All @@ -52,6 +53,11 @@ static X509_STORE* root_cert_store;
// Forward declaration
class Connection;

template <typename KeyType> struct BitLenKey {
int bit_len;
KeyType *key;
};

class SecureContext : ObjectWrap {
public:
static void Initialize(v8::Handle<v8::Object> target);
Expand All @@ -60,11 +66,16 @@ class SecureContext : ObjectWrap {
// TODO: ca_store_ should probably be removed, it's not used anywhere.
X509_STORE *ca_store_;

int ecdhe_keys_len;
BitLenKey<EC_KEY> *ecdhe_keys;

protected:
static const int kMaxSessionSize = 10 * 1024;

static v8::Handle<v8::Value> New(const v8::Arguments& args);
static v8::Handle<v8::Value> Init(const v8::Arguments& args);
static v8::Handle<v8::Value> SetECDHECurves(const v8::Arguments& args);
static v8::Handle<v8::Value> ClearECDHECurves(const v8::Arguments& args);
static v8::Handle<v8::Value> SetKey(const v8::Arguments& args);
static v8::Handle<v8::Value> SetCert(const v8::Arguments& args);
static v8::Handle<v8::Value> AddCACert(const v8::Arguments& args);
Expand All @@ -85,8 +96,11 @@ class SecureContext : ObjectWrap {
SecureContext() : ObjectWrap() {
ctx_ = NULL;
ca_store_ = NULL;
ecdhe_keys = NULL;
}

void _ClearECDHECurves(void);

void FreeCTXMem() {
if (ctx_) {
if (ctx_->cert_store == root_cert_store) {
Expand All @@ -106,6 +120,7 @@ class SecureContext : ObjectWrap {

~SecureContext() {
FreeCTXMem();
_ClearECDHECurves();
}

private:
Expand Down

0 comments on commit 2b9a558

Please sign in to comment.