Skip to content

Commit

Permalink
Exposing pkey, cert from crypto context to js land
Browse files Browse the repository at this point in the history
This will solve exposing pkey, cert from pkcs12/pfx to js
  • Loading branch information
ssuda committed Oct 10, 2012
1 parent 3053f4d commit e550dd0
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 17 deletions.
2 changes: 1 addition & 1 deletion lib/crypto.js
Expand Up @@ -85,7 +85,7 @@ exports.createCredentials = function(options, context) {
}
}

if (options.cert) c.context.setCert(options.cert);
if (options.cert) c.context.cert = options.cert;

if (options.ciphers) c.context.setCiphers(options.ciphers);

Expand Down
72 changes: 57 additions & 15 deletions src/node_crypto.cc
Expand Up @@ -126,13 +126,15 @@ void SecureContext::Initialize(Handle<Object> target) {

Local<FunctionTemplate> t = FunctionTemplate::New(SecureContext::New);
secure_context_constructor = Persistent<FunctionTemplate>::New(t);
Local<ObjectTemplate> o = t->InstanceTemplate();

t->InstanceTemplate()->SetInternalFieldCount(1);
o->SetInternalFieldCount(1);
o->SetAccessor(String::New("cert"), SecureContext::GetCert, SecureContext::SetCert);
o->SetAccessor(String::New("pkey"), SecureContext::GetKey, NULL);
t->SetClassName(String::NewSymbol("SecureContext"));

NODE_SET_PROTOTYPE_METHOD(t, "init", SecureContext::Init);
NODE_SET_PROTOTYPE_METHOD(t, "setKey", SecureContext::SetKey);
NODE_SET_PROTOTYPE_METHOD(t, "setCert", SecureContext::SetCert);
NODE_SET_PROTOTYPE_METHOD(t, "addCACert", SecureContext::AddCACert);
NODE_SET_PROTOTYPE_METHOD(t, "addCRL", SecureContext::AddCRL);
NODE_SET_PROTOTYPE_METHOD(t, "addRootCerts", SecureContext::AddRootCerts);
Expand Down Expand Up @@ -319,6 +321,14 @@ static X509* LoadX509 (Handle<Value> v) {
return x509;
}

Handle<Value> SecureContext::GetKey(Local<String> property,
const AccessorInfo &info) {
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(info.Holder());
if (sc->pkey_)
return sc->pkey_->handle_;
return Null();
}


Handle<Value> SecureContext::SetKey(const Arguments& args) {
HandleScope scope;
Expand All @@ -336,6 +346,10 @@ Handle<Value> SecureContext::SetKey(const Arguments& args) {
BIO *bio = LoadBIO(args[0]);
if (!bio) return False();

BUF_MEM *bio_buf;
BIO_get_mem_ptr(bio, &bio_buf);
sc->pkey_ = Buffer::New(bio_buf->data, bio_buf->length);

String::Utf8Value passphrase(args[1]);

EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, NULL,
Expand Down Expand Up @@ -427,35 +441,45 @@ int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, BIO *in) {
}


Handle<Value> SecureContext::SetCert(const Arguments& args) {
Handle<Value> SecureContext::GetCert(Local<String> property,
const AccessorInfo &info) {
SecureContext *sc = ObjectWrap::Unwrap<SecureContext>(info.Holder());
if (sc->cert_)
return sc->cert_->handle_;
return Null();
}


void SecureContext::SetCert(Local<String> property,
Local<Value> value,
const AccessorInfo& info) {
HandleScope scope;

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

if (args.Length() != 1) {
return ThrowException(Exception::TypeError(
String::New("Bad parameter")));
}

BIO* bio = LoadBIO(args[0]);
if (!bio) return False();
BIO* bio = LoadBIO(value);
if (!bio) return;

int rv = SSL_CTX_use_certificate_chain(sc->ctx_, bio);
BUF_MEM *bio_buf;
BIO_get_mem_ptr(bio, &bio_buf);

sc->cert_ = Buffer::New(bio_buf->data, bio_buf->length);

int rv = SSL_CTX_use_certificate_chain(sc->ctx_, bio);
BIO_free(bio);

if (!rv) {
unsigned long err = ERR_get_error();
if (!err) {
return ThrowException(Exception::Error(
ThrowException(Exception::Error(
String::New("SSL_CTX_use_certificate_chain")));
return;
}
char string[120];
ERR_error_string_n(err, string, sizeof string);
return ThrowException(Exception::Error(String::New(string)));
ThrowException(Exception::Error(String::New(string)));
}

return True();
}


Expand Down Expand Up @@ -688,6 +712,24 @@ Handle<Value> SecureContext::LoadPKCS12(const Arguments& args) {
SSL_CTX_add_client_CA(sc->ctx_, x509);
}

BIO *bio_out = BIO_new(BIO_s_mem());
if (PEM_write_bio_X509(bio_out, cert)) {
BUF_MEM *bio_buf;
BIO_get_mem_ptr(bio_out, &bio_buf);
sc->cert_ = Buffer::New(bio_buf->data, bio_buf->length);
}
BIO_free(bio_out);

bio_out = BIO_new(BIO_s_mem());
if (PEM_ASN1_write_bio((i2d_of_void*)i2d_PrivateKey,
((pkey->type == EVP_PKEY_DSA)? PEM_STRING_DSA:PEM_STRING_RSA), bio_out,
(void *)pkey, NULL, NULL, 0, NULL, NULL)) {
BUF_MEM *bio_buf;
BIO_get_mem_ptr(bio_out, &bio_buf);
sc->pkey_ = Buffer::New(bio_buf->data, bio_buf->length);
}
BIO_free(bio_out);

EVP_PKEY_free(pkey);
X509_free(cert);
sk_X509_free(extraCerts);
Expand Down
12 changes: 11 additions & 1 deletion src/node_crypto.h
Expand Up @@ -59,14 +59,22 @@ class SecureContext : ObjectWrap {
SSL_CTX *ctx_;
// TODO: ca_store_ should probably be removed, it's not used anywhere.
X509_STORE *ca_store_;

Buffer *cert_, *pkey_;

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> GetKey(v8::Local<v8::String> property,
const v8::AccessorInfo &info);
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> GetCert(v8::Local<v8::String> property,
const v8::AccessorInfo &info);
static void SetCert(v8::Local<v8::String> property,
v8::Local<v8::Value> value,
const v8::AccessorInfo& info);
static v8::Handle<v8::Value> AddCACert(const v8::Arguments& args);
static v8::Handle<v8::Value> AddCRL(const v8::Arguments& args);
static v8::Handle<v8::Value> AddRootCerts(const v8::Arguments& args);
Expand All @@ -85,6 +93,8 @@ class SecureContext : ObjectWrap {
SecureContext() : ObjectWrap() {
ctx_ = NULL;
ca_store_ = NULL;
cert_ = NULL;
pkey_ = NULL;
}

void FreeCTXMem() {
Expand Down
9 changes: 9 additions & 0 deletions test/simple/test-crypto.js
Expand Up @@ -72,6 +72,15 @@ assert.throws(function() {
crypto.createCredentials({pfx:'sample', passphrase:'test'});
}, 'not enough data');

//Cert, Key Read Tests
assert.equal(certPem, credentials.context.cert.toString('ascii'));
assert.equal(keyPem, credentials.context.pkey.toString('ascii'));
assert.doesNotThrow(function() {
var c = crypto.createCredentials({pfx:certPfx, passphrase:'sample'});
assert.equal(certPem, c.context.cert.toString('ascii'));
assert.equal(keyPem, c.context.pkey.toString('ascii'));
});

// Test HMAC
var h1 = crypto.createHmac('sha1', 'Node')
.update('some data')
Expand Down

0 comments on commit e550dd0

Please sign in to comment.