diff --git a/lib/crypto.js b/lib/crypto.js index 67d9ab7cf7f..97d9f92cd7b 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -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); diff --git a/src/node_crypto.cc b/src/node_crypto.cc index da4cfb6dca3..112f3d32d27 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -126,13 +126,15 @@ void SecureContext::Initialize(Handle target) { Local t = FunctionTemplate::New(SecureContext::New); secure_context_constructor = Persistent::New(t); + Local 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); @@ -319,6 +321,14 @@ static X509* LoadX509 (Handle v) { return x509; } +Handle SecureContext::GetKey(Local property, + const AccessorInfo &info) { + SecureContext *sc = ObjectWrap::Unwrap(info.Holder()); + if (sc->pkey_) + return sc->pkey_->handle_; + return Null(); +} + Handle SecureContext::SetKey(const Arguments& args) { HandleScope scope; @@ -336,6 +346,10 @@ Handle 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, @@ -427,35 +441,45 @@ int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, BIO *in) { } -Handle SecureContext::SetCert(const Arguments& args) { +Handle SecureContext::GetCert(Local property, + const AccessorInfo &info) { + SecureContext *sc = ObjectWrap::Unwrap(info.Holder()); + if (sc->cert_) + return sc->cert_->handle_; + return Null(); +} + + +void SecureContext::SetCert(Local property, + Local value, + const AccessorInfo& info) { HandleScope scope; - SecureContext *sc = ObjectWrap::Unwrap(args.Holder()); + SecureContext *sc = ObjectWrap::Unwrap(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(); } @@ -688,6 +712,24 @@ Handle 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); diff --git a/src/node_crypto.h b/src/node_crypto.h index 91fbb2249b8..a76a22abafd 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -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 New(const v8::Arguments& args); static v8::Handle Init(const v8::Arguments& args); + static v8::Handle GetKey(v8::Local property, + const v8::AccessorInfo &info); static v8::Handle SetKey(const v8::Arguments& args); - static v8::Handle SetCert(const v8::Arguments& args); + static v8::Handle GetCert(v8::Local property, + const v8::AccessorInfo &info); + static void SetCert(v8::Local property, + v8::Local value, + const v8::AccessorInfo& info); static v8::Handle AddCACert(const v8::Arguments& args); static v8::Handle AddCRL(const v8::Arguments& args); static v8::Handle AddRootCerts(const v8::Arguments& args); @@ -85,6 +93,8 @@ class SecureContext : ObjectWrap { SecureContext() : ObjectWrap() { ctx_ = NULL; ca_store_ = NULL; + cert_ = NULL; + pkey_ = NULL; } void FreeCTXMem() { diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index b1517740e9a..92cdf92d591 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -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')