Browse Source

tls: use `SSL_set_cert_cb` for async SNI/OCSP

Do not enable ClientHello parser for async SNI/OCSP. Use new
OpenSSL-1.0.2's API `SSL_set_cert_cb` to pause the handshake process and
load the cert/OCSP response asynchronously. Hopefuly this will make
whole async SNI/OCSP process much faster and will eventually let us
remove the ClientHello parser itself (which is currently used only for
async session, see #1462 for the discussion of removing it).

NOTE: Ported our code to `SSL_CTX_add1_chain_cert` to use
`SSL_CTX_get0_chain_certs` in `CertCbDone`. Test provided for this
feature.

Fix: https://github.com/iojs/io.js/issues/1423
PR-URL: https://github.com/iojs/io.js/pull/1464
Reviewed-By: Shigeki Ohtsu <ohtsu@iij.ad.jp>
v2.0.2
Fedor Indutny 10 years ago
parent
commit
550c2638c0
  1. 41
      lib/_tls_wrap.js
  2. 1
      src/env.h
  3. 132
      src/node_crypto.cc
  4. 26
      src/node_crypto.h
  5. 17
      src/tls_wrap.cc
  6. 6
      src/tls_wrap.h
  7. 47
      test/fixtures/keys/Makefile
  8. 18
      test/fixtures/keys/agent1-cert.pem
  9. 31
      test/fixtures/keys/agent6-cert.pem
  10. 12
      test/fixtures/keys/agent6-csr.pem
  11. 15
      test/fixtures/keys/agent6-key.pem
  12. 18
      test/fixtures/keys/agent6.cnf
  13. 27
      test/fixtures/keys/ca1-cert.pem
  14. 2
      test/fixtures/keys/ca1-cert.srl
  15. 30
      test/fixtures/keys/ca1-key.pem
  16. 3
      test/fixtures/keys/ca1.cnf
  17. 16
      test/fixtures/keys/ca3-cert.pem
  18. 1
      test/fixtures/keys/ca3-cert.srl
  19. 13
      test/fixtures/keys/ca3-csr.pem
  20. 15
      test/fixtures/keys/ca3-key.pem
  21. 23
      test/fixtures/keys/ca3.cnf
  22. 4
      test/parallel/test-tls-peer-certificate.js
  23. 27
      test/parallel/test-tls-sni-server-client.js

41
lib/_tls_wrap.js

@ -141,29 +141,23 @@ function onclienthello(hello) {
if (err) if (err)
return self.destroy(err); return self.destroy(err);
// Servername came from SSL session self._handle.endParser();
// NOTE: TLS Session ticket doesn't include servername information });
// }
// Another note, From RFC3546:
//
// If, on the other hand, the older function oncertcb(info) {
// session is resumed, then the server MUST ignore extensions appearing var self = this;
// in the client hello, and send a server hello containing no var servername = info.servername;
// extensions; in this case the extension functionality negotiated
// during the original session initiation is applied to the resumed
// session.
//
// Therefore we should account session loading when dealing with servername
var servername = session && session.servername || hello.servername;
loadSNI(self, servername, function(err, ctx) { loadSNI(self, servername, function(err, ctx) {
if (err) if (err)
return self.destroy(err); return self.destroy(err);
requestOCSP(self, hello, ctx, function(err) { requestOCSP(self, info, ctx, function(err) {
if (err) if (err)
return self.destroy(err); return self.destroy(err);
self._handle.endParser(); self._handle.certCbDone();
});
}); });
}); });
} }
@ -333,16 +327,19 @@ TLSSocket.prototype._init = function(socket, wrap) {
ssl.onhandshakestart = onhandshakestart.bind(this); ssl.onhandshakestart = onhandshakestart.bind(this);
ssl.onhandshakedone = onhandshakedone.bind(this); ssl.onhandshakedone = onhandshakedone.bind(this);
ssl.onclienthello = onclienthello.bind(this); ssl.onclienthello = onclienthello.bind(this);
ssl.oncertcb = oncertcb.bind(this);
ssl.onnewsession = onnewsession.bind(this); ssl.onnewsession = onnewsession.bind(this);
ssl.lastHandshakeTime = 0; ssl.lastHandshakeTime = 0;
ssl.handshakes = 0; ssl.handshakes = 0;
if (this.server && if (this.server) {
(listenerCount(this.server, 'resumeSession') > 0 || if (listenerCount(this.server, 'resumeSession') > 0 ||
listenerCount(this.server, 'newSession') > 0 || listenerCount(this.server, 'newSession') > 0) {
listenerCount(this.server, 'OCSPRequest') > 0)) {
ssl.enableSessionCallbacks(); ssl.enableSessionCallbacks();
} }
if (listenerCount(this.server, 'OCSPRequest') > 0)
ssl.enableCertCb();
}
} else { } else {
ssl.onhandshakestart = function() {}; ssl.onhandshakestart = function() {};
ssl.onhandshakedone = this._finishInit.bind(this); ssl.onhandshakedone = this._finishInit.bind(this);
@ -382,7 +379,7 @@ TLSSocket.prototype._init = function(socket, wrap) {
options.server._contexts.length)) { options.server._contexts.length)) {
assert(typeof options.SNICallback === 'function'); assert(typeof options.SNICallback === 'function');
this._SNICallback = options.SNICallback; this._SNICallback = options.SNICallback;
ssl.enableHelloParser(); ssl.enableCertCb();
} }
if (process.features.tls_npn && options.NPNProtocols) if (process.features.tls_npn && options.NPNProtocols)

1
src/env.h

@ -55,6 +55,7 @@ namespace node {
V(bytes_parsed_string, "bytesParsed") \ V(bytes_parsed_string, "bytesParsed") \
V(callback_string, "callback") \ V(callback_string, "callback") \
V(change_string, "change") \ V(change_string, "change") \
V(oncertcb_string, "oncertcb") \
V(onclose_string, "_onclose") \ V(onclose_string, "_onclose") \
V(code_string, "code") \ V(code_string, "code") \
V(compare_string, "compare") \ V(compare_string, "compare") \

132
src/node_crypto.cc

@ -132,6 +132,8 @@ template int SSLWrap<TLSWrap>::SelectNextProtoCallback(
#endif #endif
template int SSLWrap<TLSWrap>::TLSExtStatusCallback(SSL* s, void* arg); template int SSLWrap<TLSWrap>::TLSExtStatusCallback(SSL* s, void* arg);
template void SSLWrap<TLSWrap>::DestroySSL(); template void SSLWrap<TLSWrap>::DestroySSL();
template int SSLWrap<TLSWrap>::SSLCertCallback(SSL* s, void* arg);
template void SSLWrap<TLSWrap>::WaitForCertCb(CertCb cb, void* arg);
static void crypto_threadid_cb(CRYPTO_THREADID* tid) { static void crypto_threadid_cb(CRYPTO_THREADID* tid) {
@ -511,7 +513,8 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
} }
while ((ca = PEM_read_bio_X509(in, nullptr, CryptoPemCallback, nullptr))) { while ((ca = PEM_read_bio_X509(in, nullptr, CryptoPemCallback, nullptr))) {
r = SSL_CTX_add_extra_chain_cert(ctx, ca); // NOTE: Increments reference count on `ca`
r = SSL_CTX_add1_chain_cert(ctx, ca);
if (!r) { if (!r) {
X509_free(ca); X509_free(ca);
@ -987,6 +990,7 @@ void SSLWrap<Base>::AddMethods(Environment* env, Handle<FunctionTemplate> t) {
env->SetProtoMethod(t, "verifyError", VerifyError); env->SetProtoMethod(t, "verifyError", VerifyError);
env->SetProtoMethod(t, "getCurrentCipher", GetCurrentCipher); env->SetProtoMethod(t, "getCurrentCipher", GetCurrentCipher);
env->SetProtoMethod(t, "endParser", EndParser); env->SetProtoMethod(t, "endParser", EndParser);
env->SetProtoMethod(t, "certCbDone", CertCbDone);
env->SetProtoMethod(t, "renegotiate", Renegotiate); env->SetProtoMethod(t, "renegotiate", Renegotiate);
env->SetProtoMethod(t, "shutdownSSL", Shutdown); env->SetProtoMethod(t, "shutdownSSL", Shutdown);
env->SetProtoMethod(t, "getTLSTicket", GetTLSTicket); env->SetProtoMethod(t, "getTLSTicket", GetTLSTicket);
@ -1869,6 +1873,122 @@ int SSLWrap<Base>::TLSExtStatusCallback(SSL* s, void* arg) {
#endif // NODE__HAVE_TLSEXT_STATUS_CB #endif // NODE__HAVE_TLSEXT_STATUS_CB
template <class Base>
void SSLWrap<Base>::WaitForCertCb(CertCb cb, void* arg) {
cert_cb_ = cb;
cert_cb_arg_ = arg;
}
template <class Base>
int SSLWrap<Base>::SSLCertCallback(SSL* s, void* arg) {
Base* w = static_cast<Base*>(SSL_get_app_data(s));
if (!w->is_server())
return 1;
if (!w->is_waiting_cert_cb())
return 1;
if (w->cert_cb_running_)
return -1;
Environment* env = w->env();
HandleScope handle_scope(env->isolate());
Context::Scope context_scope(env->context());
w->cert_cb_running_ = true;
Local<Object> info = Object::New(env->isolate());
SSL_SESSION* sess = SSL_get_session(s);
if (sess != nullptr) {
if (sess->tlsext_hostname == nullptr) {
info->Set(env->servername_string(), String::Empty(env->isolate()));
} else {
Local<String> servername = OneByteString(env->isolate(),
sess->tlsext_hostname,
strlen(sess->tlsext_hostname));
info->Set(env->servername_string(), servername);
}
info->Set(env->tls_ticket_string(),
Boolean::New(env->isolate(), sess->tlsext_ticklen != 0));
}
bool ocsp = s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp;
info->Set(env->ocsp_request_string(), Boolean::New(env->isolate(), ocsp));
Local<Value> argv[] = { info };
w->MakeCallback(env->oncertcb_string(), ARRAY_SIZE(argv), argv);
if (!w->cert_cb_running_)
return 1;
// Performing async action, wait...
return -1;
}
template <class Base>
void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) {
Base* w = Unwrap<Base>(args.Holder());
Environment* env = w->env();
CHECK(w->is_waiting_cert_cb() && w->cert_cb_running_);
Local<Object> object = w->object();
Local<Value> ctx = object->Get(env->sni_context_string());
Local<FunctionTemplate> cons = env->secure_context_constructor_template();
// Not an object, probably undefined or null
if (!ctx->IsObject())
goto fire_cb;
if (cons->HasInstance(ctx)) {
SecureContext* sc = Unwrap<SecureContext>(ctx.As<Object>());
w->sni_context_.Reset();
w->sni_context_.Reset(env->isolate(), ctx);
int rv;
// NOTE: reference count is not increased by this API methods
X509* x509 = SSL_CTX_get0_certificate(sc->ctx_);
EVP_PKEY* pkey = SSL_CTX_get0_privatekey(sc->ctx_);
STACK_OF(X509)* chain;
rv = SSL_CTX_get0_chain_certs(sc->ctx_, &chain);
if (rv)
rv = SSL_use_certificate(w->ssl_, x509);
if (rv)
rv = SSL_use_PrivateKey(w->ssl_, pkey);
if (rv && chain != nullptr)
rv = SSL_set1_chain(w->ssl_, chain);
if (!rv) {
unsigned long err = ERR_get_error();
if (!err)
return env->ThrowError("CertCbDone");
return ThrowCryptoError(env, err);
}
} else {
// Failure: incorrect SNI context object
Local<Value> err = Exception::TypeError(env->sni_context_err_string());
w->MakeCallback(env->onerror_string(), 1, &err);
return;
}
fire_cb:
CertCb cb;
void* arg;
cb = w->cert_cb_;
arg = w->cert_cb_arg_;
w->cert_cb_running_ = false;
w->cert_cb_ = nullptr;
w->cert_cb_arg_ = nullptr;
cb(arg);
}
template <class Base> template <class Base>
void SSLWrap<Base>::SSLGetter(Local<String> property, void SSLWrap<Base>::SSLGetter(Local<String> property,
const PropertyCallbackInfo<Value>& info) { const PropertyCallbackInfo<Value>& info) {
@ -1975,6 +2095,10 @@ int Connection::HandleSSLError(const char* func,
DEBUG_PRINT("[%p] SSL: %s want read\n", ssl_, func); DEBUG_PRINT("[%p] SSL: %s want read\n", ssl_, func);
return 0; return 0;
} else if (err == SSL_ERROR_WANT_X509_LOOKUP) {
DEBUG_PRINT("[%p] SSL: %s want x509 lookup\n", ssl_, func);
return 0;
} else if (err == SSL_ERROR_ZERO_RETURN) { } else if (err == SSL_ERROR_ZERO_RETURN) {
HandleScope scope(ssl_env()->isolate()); HandleScope scope(ssl_env()->isolate());
@ -2140,7 +2264,7 @@ int Connection::SelectSNIContextCallback_(SSL *s, int *ad, void* arg) {
// Call the SNI callback and use its return value as context // Call the SNI callback and use its return value as context
if (!conn->sniObject_.IsEmpty()) { if (!conn->sniObject_.IsEmpty()) {
conn->sniContext_.Reset(); conn->sni_context_.Reset();
Local<Value> arg = PersistentToLocal(env->isolate(), conn->servername_); Local<Value> arg = PersistentToLocal(env->isolate(), conn->servername_);
Local<Value> ret = conn->MakeCallback(env->onselect_string(), 1, &arg); Local<Value> ret = conn->MakeCallback(env->onselect_string(), 1, &arg);
@ -2149,7 +2273,7 @@ int Connection::SelectSNIContextCallback_(SSL *s, int *ad, void* arg) {
Local<FunctionTemplate> secure_context_constructor_template = Local<FunctionTemplate> secure_context_constructor_template =
env->secure_context_constructor_template(); env->secure_context_constructor_template();
if (secure_context_constructor_template->HasInstance(ret)) { if (secure_context_constructor_template->HasInstance(ret)) {
conn->sniContext_.Reset(env->isolate(), ret); conn->sni_context_.Reset(env->isolate(), ret);
SecureContext* sc = Unwrap<SecureContext>(ret.As<Object>()); SecureContext* sc = Unwrap<SecureContext>(ret.As<Object>());
InitNPN(sc); InitNPN(sc);
SSL_set_SSL_CTX(s, sc->ctx_); SSL_set_SSL_CTX(s, sc->ctx_);
@ -2188,6 +2312,8 @@ void Connection::New(const FunctionCallbackInfo<Value>& args) {
InitNPN(sc); InitNPN(sc);
SSL_set_cert_cb(conn->ssl_, SSLWrap<Connection>::SSLCertCallback, conn);
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
if (is_server) { if (is_server) {
SSL_CTX_set_tlsext_servername_callback(sc->ctx_, SelectSNIContextCallback_); SSL_CTX_set_tlsext_servername_callback(sc->ctx_, SelectSNIContextCallback_);

26
src/node_crypto.h

@ -143,7 +143,10 @@ class SSLWrap {
kind_(kind), kind_(kind),
next_sess_(nullptr), next_sess_(nullptr),
session_callbacks_(false), session_callbacks_(false),
new_session_wait_(false) { new_session_wait_(false),
cert_cb_(nullptr),
cert_cb_arg_(nullptr),
cert_cb_running_(false) {
ssl_ = SSL_new(sc->ctx_); ssl_ = SSL_new(sc->ctx_);
env_->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize); env_->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize);
CHECK_NE(ssl_, nullptr); CHECK_NE(ssl_, nullptr);
@ -160,6 +163,9 @@ class SSLWrap {
npn_protos_.Reset(); npn_protos_.Reset();
selected_npn_proto_.Reset(); selected_npn_proto_.Reset();
#endif #endif
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
sni_context_.Reset();
#endif
#ifdef NODE__HAVE_TLSEXT_STATUS_CB #ifdef NODE__HAVE_TLSEXT_STATUS_CB
ocsp_response_.Reset(); ocsp_response_.Reset();
#endif // NODE__HAVE_TLSEXT_STATUS_CB #endif // NODE__HAVE_TLSEXT_STATUS_CB
@ -170,8 +176,11 @@ class SSLWrap {
inline bool is_server() const { return kind_ == kServer; } inline bool is_server() const { return kind_ == kServer; }
inline bool is_client() const { return kind_ == kClient; } inline bool is_client() const { return kind_ == kClient; }
inline bool is_waiting_new_session() const { return new_session_wait_; } inline bool is_waiting_new_session() const { return new_session_wait_; }
inline bool is_waiting_cert_cb() const { return cert_cb_ != nullptr; }
protected: protected:
typedef void (*CertCb)(void* arg);
// Size allocated by OpenSSL: one for SSL structure, one for SSL3_STATE and // Size allocated by OpenSSL: one for SSL structure, one for SSL3_STATE and
// some for buffers. // some for buffers.
// NOTE: Actually it is much more than this // NOTE: Actually it is much more than this
@ -199,6 +208,7 @@ class SSLWrap {
static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args); static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetCurrentCipher(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetCurrentCipher(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EndParser(const v8::FunctionCallbackInfo<v8::Value>& args); static void EndParser(const v8::FunctionCallbackInfo<v8::Value>& args);
static void CertCbDone(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args); static void Renegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args); static void Shutdown(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetTLSTicket(const v8::FunctionCallbackInfo<v8::Value>& args); static void GetTLSTicket(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -227,10 +237,12 @@ class SSLWrap {
void* arg); void* arg);
#endif // OPENSSL_NPN_NEGOTIATED #endif // OPENSSL_NPN_NEGOTIATED
static int TLSExtStatusCallback(SSL* s, void* arg); static int TLSExtStatusCallback(SSL* s, void* arg);
static int SSLCertCallback(SSL* s, void* arg);
static void SSLGetter(v8::Local<v8::String> property, static void SSLGetter(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info); const v8::PropertyCallbackInfo<v8::Value>& info);
void DestroySSL(); void DestroySSL();
void WaitForCertCb(CertCb cb, void* arg);
inline Environment* ssl_env() const { inline Environment* ssl_env() const {
return env_; return env_;
@ -242,6 +254,12 @@ class SSLWrap {
SSL* ssl_; SSL* ssl_;
bool session_callbacks_; bool session_callbacks_;
bool new_session_wait_; bool new_session_wait_;
// SSL_set_cert_cb
CertCb cert_cb_;
void* cert_cb_arg_;
bool cert_cb_running_;
ClientHelloParser hello_parser_; ClientHelloParser hello_parser_;
#ifdef NODE__HAVE_TLSEXT_STATUS_CB #ifdef NODE__HAVE_TLSEXT_STATUS_CB
@ -253,6 +271,10 @@ class SSLWrap {
v8::Persistent<v8::Value> selected_npn_proto_; v8::Persistent<v8::Value> selected_npn_proto_;
#endif // OPENSSL_NPN_NEGOTIATED #endif // OPENSSL_NPN_NEGOTIATED
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
v8::Persistent<v8::Value> sni_context_;
#endif
friend class SecureContext; friend class SecureContext;
}; };
@ -264,7 +286,6 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
~Connection() override { ~Connection() override {
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
sniObject_.Reset(); sniObject_.Reset();
sniContext_.Reset();
servername_.Reset(); servername_.Reset();
#endif #endif
} }
@ -279,7 +300,6 @@ class Connection : public SSLWrap<Connection>, public AsyncWrap {
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB #ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
v8::Persistent<v8::Object> sniObject_; v8::Persistent<v8::Object> sniObject_;
v8::Persistent<v8::Value> sniContext_;
v8::Persistent<v8::String> servername_; v8::Persistent<v8::String> servername_;
#endif #endif

17
src/tls_wrap.cc

@ -150,6 +150,8 @@ void TLSWrap::InitSSL() {
InitNPN(sc_); InitNPN(sc_);
SSL_set_cert_cb(ssl_, SSLWrap<TLSWrap>::SSLCertCallback, this);
if (is_server()) { if (is_server()) {
SSL_set_accept_state(ssl_); SSL_set_accept_state(ssl_);
} else if (is_client()) { } else if (is_client()) {
@ -355,6 +357,7 @@ Local<Value> TLSWrap::GetSSLError(int status, int* err, const char** msg) {
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
case SSL_ERROR_WANT_X509_LOOKUP:
break; break;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
return scope.Escape(env()->zero_return_string()); return scope.Escape(env()->zero_return_string());
@ -738,12 +741,6 @@ void TLSWrap::EnableSessionCallbacks(
const FunctionCallbackInfo<Value>& args) { const FunctionCallbackInfo<Value>& args) {
TLSWrap* wrap = Unwrap<TLSWrap>(args.Holder()); TLSWrap* wrap = Unwrap<TLSWrap>(args.Holder());
wrap->enable_session_callbacks(); wrap->enable_session_callbacks();
EnableHelloParser(args);
}
void TLSWrap::EnableHelloParser(const FunctionCallbackInfo<Value>& args) {
TLSWrap* wrap = Unwrap<TLSWrap>(args.Holder());
NodeBIO::FromBIO(wrap->enc_in_)->set_initial(kMaxHelloLength); NodeBIO::FromBIO(wrap->enc_in_)->set_initial(kMaxHelloLength);
wrap->hello_parser_.Start(SSLWrap<TLSWrap>::OnClientHello, wrap->hello_parser_.Start(SSLWrap<TLSWrap>::OnClientHello,
OnClientHelloParseEnd, OnClientHelloParseEnd,
@ -759,6 +756,12 @@ void TLSWrap::DestroySSL(const FunctionCallbackInfo<Value>& args) {
} }
void TLSWrap::EnableCertCb(const FunctionCallbackInfo<Value>& args) {
TLSWrap* wrap = Unwrap<TLSWrap>(args.Holder());
wrap->WaitForCertCb(OnClientHelloParseEnd, wrap);
}
void TLSWrap::OnClientHelloParseEnd(void* arg) { void TLSWrap::OnClientHelloParseEnd(void* arg) {
TLSWrap* c = static_cast<TLSWrap*>(arg); TLSWrap* c = static_cast<TLSWrap*>(arg);
c->Cycle(); c->Cycle();
@ -857,8 +860,8 @@ void TLSWrap::Initialize(Handle<Object> target,
env->SetProtoMethod(t, "start", Start); env->SetProtoMethod(t, "start", Start);
env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode); env->SetProtoMethod(t, "setVerifyMode", SetVerifyMode);
env->SetProtoMethod(t, "enableSessionCallbacks", EnableSessionCallbacks); env->SetProtoMethod(t, "enableSessionCallbacks", EnableSessionCallbacks);
env->SetProtoMethod(t, "enableHelloParser", EnableHelloParser);
env->SetProtoMethod(t, "destroySSL", DestroySSL); env->SetProtoMethod(t, "destroySSL", DestroySSL);
env->SetProtoMethod(t, "enableCertCb", EnableCertCb);
StreamBase::AddMethods<TLSWrap>(env, t, StreamBase::kFlagHasWritev); StreamBase::AddMethods<TLSWrap>(env, t, StreamBase::kFlagHasWritev);
SSLWrap<TLSWrap>::AddMethods(env, t); SSLWrap<TLSWrap>::AddMethods(env, t);

6
src/tls_wrap.h

@ -130,7 +130,7 @@ class TLSWrap : public crypto::SSLWrap<TLSWrap>,
static void SetVerifyMode(const v8::FunctionCallbackInfo<v8::Value>& args); static void SetVerifyMode(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EnableSessionCallbacks( static void EnableSessionCallbacks(
const v8::FunctionCallbackInfo<v8::Value>& args); const v8::FunctionCallbackInfo<v8::Value>& args);
static void EnableHelloParser( static void EnableCertCb(
const v8::FunctionCallbackInfo<v8::Value>& args); const v8::FunctionCallbackInfo<v8::Value>& args);
static void DestroySSL(const v8::FunctionCallbackInfo<v8::Value>& args); static void DestroySSL(const v8::FunctionCallbackInfo<v8::Value>& args);
@ -159,10 +159,6 @@ class TLSWrap : public crypto::SSLWrap<TLSWrap>,
// If true - delivered EOF to the js-land, either after `close_notify`, or // If true - delivered EOF to the js-land, either after `close_notify`, or
// after the `UV_EOF` on socket. // after the `UV_EOF` on socket.
bool eof_; bool eof_;
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
v8::Persistent<v8::Value> sni_context_;
#endif // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
}; };
} // namespace node } // namespace node

47
test/fixtures/keys/Makefile

@ -17,6 +17,28 @@ ca2-cert.pem: ca2.cnf
echo '01' > ca2-serial echo '01' > ca2-serial
touch ca2-database.txt touch ca2-database.txt
#
# Create Subordinate Certificate Authority: ca3
# ('password' is used for the CA password.)
#
ca3-key.pem:
openssl genrsa -out ca3-key.pem 1024
ca3-csr.pem: ca3.cnf ca3-key.pem
openssl req -new \
-extensions v3_ca -config ca3.cnf -key ca3-key.pem -out ca3-csr.pem
ca3-cert.pem: ca3-csr.pem ca3-key.pem ca3.cnf ca1-cert.pem ca1-key.pem
openssl x509 -req \
-extfile ca3.cnf \
-extensions v3_ca \
-days 9999 \
-passin "pass:password" \
-in ca3-csr.pem \
-CA ca1-cert.pem \
-CAkey ca1-key.pem \
-CAcreateserial \
-out ca3-cert.pem
# #
# agent1 is signed by ca1. # agent1 is signed by ca1.
@ -157,6 +179,31 @@ agent5-cert.pem: agent5-csr.pem ca2-cert.pem ca2-key.pem
agent5-verify: agent5-cert.pem ca2-cert.pem agent5-verify: agent5-cert.pem ca2-cert.pem
openssl verify -CAfile ca2-cert.pem agent5-cert.pem openssl verify -CAfile ca2-cert.pem agent5-cert.pem
#
# agent6 is signed by ca3
#
agent6-key.pem:
openssl genrsa -out agent6-key.pem 1024
agent6-csr.pem: agent6.cnf agent6-key.pem
openssl req -new -config agent6.cnf -key agent6-key.pem -out agent6-csr.pem
agent6-cert.pem: agent6-csr.pem ca3-cert.pem ca3-key.pem
openssl x509 -req \
-days 9999 \
-passin "pass:password" \
-in agent6-csr.pem \
-CA ca3-cert.pem \
-CAkey ca3-key.pem \
-CAcreateserial \
-extfile agent6.cnf \
-out agent6-cert.pem
cat ca3-cert.pem >> agent6-cert.pem
agent6-verify: agent6-cert.pem ca3-cert.pem
openssl verify -CAfile ca3-cert.pem agent6-cert.pem
ec-key.pem: ec-key.pem:
openssl ecparam -genkey -out ec-key.pem -name prime256v1 openssl ecparam -genkey -out ec-key.pem -name prime256v1

18
test/fixtures/keys/agent1-cert.pem

@ -1,9 +1,9 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIC1jCCAj+gAwIBAgIJAJqEq8+4pyq+MA0GCSqGSIb3DQEBBQUAMHoxCzAJBgNV MIIC1jCCAj+gAwIBAgIJAJqEq8+4pyrAMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
BAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCU0YxDzANBgNVBAoTBkpveWVu BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu
dDEQMA4GA1UECxMHTm9kZS5qczEMMAoGA1UEAxMDY2ExMSAwHgYJKoZIhvcNAQkB dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZIhvcNAQkB
FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNDA0MTUyMTMxMzFaFw00MTA4MzAyMTMx FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNTA0MTgxMzI5MDhaFw00MjA5MDIxMzI5
MzFaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCU0YxDzAN MDhaMH0xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTELMAkGA1UEBxMCU0YxDzAN
BgNVBAoTBkpveWVudDEQMA4GA1UECxMHTm9kZS5qczEPMA0GA1UEAxMGYWdlbnQx BgNVBAoTBkpveWVudDEQMA4GA1UECxMHTm9kZS5qczEPMA0GA1UEAxMGYWdlbnQx
MSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG9w0B MSAwHgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG9w0B
AQEFAAOBjQAwgYkCgYEAuOs3hW8rF+7xx5iB9wjmIgd+HTqRFUeKxG+mWV35Hl6A AQEFAAOBjQAwgYkCgYEAuOs3hW8rF+7xx5iB9wjmIgd+HTqRFUeKxG+mWV35Hl6A
@ -11,8 +11,8 @@ AQEFAAOBjQAwgYkCgYEAuOs3hW8rF+7xx5iB9wjmIgd+HTqRFUeKxG+mWV35Hl6A
lRxqJGXTjx+vG/0nDCXLBhoDKO00zEccdjGS8xEjjieQQr+KeASmIm0kQmuN5YcC lRxqJGXTjx+vG/0nDCXLBhoDKO00zEccdjGS8xEjjieQQr+KeASmIm0kQmuN5YcC
AwEAAaNhMF8wXQYIKwYBBQUHAQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz AwEAAaNhMF8wXQYIKwYBBQUHAQEEUTBPMCMGCCsGAQUFBzABhhdodHRwOi8vb2Nz
cC5ub2RlanMub3JnLzAoBggrBgEFBQcwAoYcaHR0cDovL2NhLm5vZGVqcy5vcmcv cC5ub2RlanMub3JnLzAoBggrBgEFBQcwAoYcaHR0cDovL2NhLm5vZGVqcy5vcmcv
Y2EuY2VydDANBgkqhkiG9w0BAQUFAAOBgQAx6rhnYbPygJwIm6nidyx+ydJQC4Gk Y2EuY2VydDANBgkqhkiG9w0BAQsFAAOBgQA45MmH28Gns+1yu9w9MR/oR8hKDMnG
JD+pzbdJkTS+01r+xjVY/Wckn4JAsIlo/MMn055rs2cfdjoQtlj6yjEU6AP/7bfr E4yDZ+9SofWdqRsGe5MNeMbp9c+FxIxODcNmdhV5Ao6+ZCRX4N9GjLqUL1jQoFAs
Mju4lBxDLACJ2y5/rfj3wO4q4Knd4Q4mPWjlS2SwmkHZ21QOqJ6Ig9ps6HPM7syw pT/U80ZU+4bz2EwGMBQt7CJZb/u+j8/vXheyGFZkCWEQj6AgZQFTniRRQJLwbiy5
ZYQ3WQ1LOPAxMg== uDktGqnhvamyrg==
-----END CERTIFICATE----- -----END CERTIFICATE-----

31
test/fixtures/keys/agent6-cert.pem

@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIICajCCAdOgAwIBAgIJAMTNiT75p13MMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu
dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2EzMSAwHgYJKoZIhvcNAQkB
FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNTA0MTgxMzI4NDFaFw00MjA5MDIxMzI4
NDFaMHQxCzAJBgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDERMA8GA1UECgwI
VHJlc29yaXQxFjAUBgNVBAMMDcOBZMOhbSBMaXBwYWkxJzAlBgkqhkiG9w0BCQEW
GGFkYW0ubGlwcGFpQHRyZXNvcml0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
gYkCgYEA3Iwmwd6gdWH1AlSFeuVsEY/2MQm3XluOyHR9HNtXkWqwcQqVL8FX3NHt
//1jaSTMJjkR4FhC9R0hX6wyUuBp11J4GzoDqd02JUkCeUISq/3/2G+ynaZCx5Eo
GNHhcN0gALTCET/1QMD9h4aBjRbij3iHUghcbgverfkasp59WWcCAwEAATANBgkq
hkiG9w0BAQsFAAOBgQAmfrCJY+FPeOraPTUQTYf9rXqfVRQEVc/yyVygPbtg3gtA
yST0wI/g6sBjQ6Mm39yMf4rkWmwOKGtrKcqs9o9NdM5g5QQSWeg925Ex6aB+REgz
qjaAsLM88BJ0QU76VPi6K0hDSpeuQ6Zrcp93VkdGdVZzna3FSCMTNRnSq/GuMQ==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIICgjCCAeugAwIBAgIJAJqEq8+4pyq/MA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu
dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZIhvcNAQkB
FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNTA0MTgxMzI4NDFaFw00MjA5MDIxMzI4
NDFaMHoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzAN
BgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2EzMSAw
HgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAqs4MKn9saUIu/9EfHQPouC3kL9Mo5sd1WR6RBeSd8cqeFxXW
EWEq/P0hUeAH1sY0u8RFOccJmSJg8KTyRGc+VZzWimopz17mTuQY4hPW4bFzqmQm
7STfJz5eHzynBTU8jk5omi8hjbnRA38jOm4D7rN/vqtB+RG+vEhxONnq4DMCAwEA
AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQBo8rX1uZWHvKHG
gWw+LXrY24Pkg8NdDRmfqEVyuaR4GoGGOXCqlVaFa6x+4/eqOUzHoC9uGfPtjrvW
BYQ1o/l0JZWW4KZYuXoVuMUSj+sel82mf9zLDeq5WYTPECgJDMfgVpXOmhHfyezn
SkUTX7XJUohjET+X5BqTFlqRT/RfIw==
-----END CERTIFICATE-----

12
test/fixtures/keys/agent6-csr.pem

@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIB2TCCAUICAQAwdDELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MREw
DwYDVQQKDAhUcmVzb3JpdDEWMBQGA1UEAwwNw4Fkw6FtIExpcHBhaTEnMCUGCSqG
SIb3DQEJARYYYWRhbS5saXBwYWlAdHJlc29yaXQuY29tMIGfMA0GCSqGSIb3DQEB
AQUAA4GNADCBiQKBgQDcjCbB3qB1YfUCVIV65WwRj/YxCbdeW47IdH0c21eRarBx
CpUvwVfc0e3//WNpJMwmORHgWEL1HSFfrDJS4GnXUngbOgOp3TYlSQJ5QhKr/f/Y
b7KdpkLHkSgY0eFw3SAAtMIRP/VAwP2HhoGNFuKPeIdSCFxuC96t+Rqynn1ZZwID
AQABoCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3JkMA0GCSqG
SIb3DQEBCwUAA4GBAEU4gmRyeeh5TMYG3bI0biXr+9CvkYBaHwZD5o4TUo8AenIR
NTrJdy9Pg9B23eOnEnCDB+KMfl08UuaPxbKRXRtYm1rTC8v5wmJEpZdWxum4c3hL
3o7J8/LmjRGQImr5vnS5zmsVrBLtjW+jVpSg5xnXFKQmpXPfgRwhvbu0lXf7
-----END CERTIFICATE REQUEST-----

15
test/fixtures/keys/agent6-key.pem

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXgIBAAKBgQDcjCbB3qB1YfUCVIV65WwRj/YxCbdeW47IdH0c21eRarBxCpUv
wVfc0e3//WNpJMwmORHgWEL1HSFfrDJS4GnXUngbOgOp3TYlSQJ5QhKr/f/Yb7Kd
pkLHkSgY0eFw3SAAtMIRP/VAwP2HhoGNFuKPeIdSCFxuC96t+Rqynn1ZZwIDAQAB
AoGBAIL3AsjbL8OksL56fG0XMY5YQ6SpFWeFzQsCCY2KPrzOcwodc6vRDyDE1KTP
zimQvV3xQ8lKADDX5IqQka2fL5mgF+LighVvGHDm6M4ILJb46SDbuINwnqqvVuye
+OwjHBGEmKu18K+eL/YoCh3+sFTKP/18F7c7DGskCyzyub5RAkEA+Fs1ROx5w8AH
cbIH4fMU/QBGQVnuKgNXGSPcT6NHqFLbrhvNn5HwoF1SiJKkML1h3gVpj3T8kquw
Y1FcTVB9eQJBAONV1qXFo7i5gl2FyPuXvpgdzIXxzzr6q3seDkCR7q/vfBo+kKAx
zyG2xjJrCc9+ox4Vh257qK9b57W6R6sWNd8CQQCeAHjNVpzI2nxh6t908k8h/nCz
1uDcPa/FwLjCuaA3CC/Wfr28jP5HJ9gAJzrp/zIqK8tShxzAuxXGudY9Ib4RAkEA
v+3elIIx4WktOQwUTOUmEoNGAufOD3tGf2E2oykRnRPRcM7Vh4nF2C7ZUgOweq/t
wx5mAs7/8VzkWTb1/ul3fQJACLBXTChgyA77i5C/035tLwQbeLOjexLblEI0dgkW
HIa8q4ZL0M7L+/oziQ8zIT0bTAqEG1Q00PgFLl3m8gDuNg==
-----END RSA PRIVATE KEY-----

18
test/fixtures/keys/agent6.cnf

@ -0,0 +1,18 @@
[ req ]
string_mask = utf8only
utf8 = yes
default_bits = 1024
days = 999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
[ req_distinguished_name ]
C = HU
L = Budapest
O = Tresorit
CN = Ádám Lippai
emailAddress = adam.lippai@tresorit.com
[ req_attributes ]
challengePassword = A challenge password

27
test/fixtures/keys/ca1-cert.pem

@ -1,15 +1,16 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICazCCAdQCCQC1CQyJn8L/kzANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJV MIICgjCCAeugAwIBAgIJAI3yHAFGivOTMA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
UzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQKEwZKb3llbnQxEDAO BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu
BgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqGSIb3DQEJARYRcnlA dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZIhvcNAQkB
dGlueWNsb3Vkcy5vcmcwHhcNMTQwNDE1MjEzMTMxWhcNNDEwODMwMjEzMTMxWjB6 FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNTA0MTgxMzI4NDFaFw00MjA5MDIxMzI4
MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExCzAJBgNVBAcTAlNGMQ8wDQYDVQQK NDFaMHoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzAN
EwZKb3llbnQxEDAOBgNVBAsTB05vZGUuanMxDDAKBgNVBAMTA2NhMTEgMB4GCSqG BgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAw
SIb3DQEJARYRcnlAdGlueWNsb3Vkcy5vcmcwgZ8wDQYJKoZIhvcNAQEBBQADgY0A HgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG9w0BAQEF
MIGJAoGBALBXMk/xFR2GN2v/wKreZKyIitGphxYGoJ2d//s/wM6qqyIW94aiq3sm AAOBjQAwgYkCgYEAwbF7gKfk7nGLcH0lbok1UJEBpMiQ49YxUqT/oIfXBaRjMODX
1zpmOTPTorT9Pk32A7uKKHfrafB+yA07QXgCYXgzcn17nfFInncDyGdggNFGAO13 RknQxpARWw4R8qj+Zeu9zZZ8Hzv3dAxtcpnMTgeoPUL3HCStk0bK8QrFdkFrBxQD
5JuC3JC8pRJpEokkMszpHJxPdR6gKXIT05blUnpwGT/AmYJ8S59lAgMBAAEwDQYJ mF92r9Mgr/fz+x7rSZuCIKhATwB5iJOz63fRctTL5tBmzG15JUG1GN5HPZECAwEA
KoZIhvcNAQEFBQADgYEAAb+Pye0I+k927Qi2+cUowLS5MtmrEosUbTYwI4rqYSR2 AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQAnAHtchz5FGqod
aiibqmC3Z55N72ktQ2pJKP8I1t3Rk+j8/yIKWzSn5Jd2GT4ZzqbANrdLKeAsfVDK 8twiFF3yQdGN3WE3VC3A6VrcmjKUp+M7f0uRDYw4uKUhadyZdYhMn39fe9DVN6rC
pnsUR1IV/sdIvuELm+P4kyK5wafJytUjD+A4SH2oWN4EozDR1OidAhJrraXQksw= 6wUUoe4hSs+0SWi6Ora7DFpCbm6fNpooSr0K0OUMZ2opwDmAEPdVOSPRhzQJ/cNp
s3mxIrkAQ5kgJSSGlPETMEumQmXDfA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

2
test/fixtures/keys/ca1-cert.srl

@ -1 +1 @@
9A84ABCFB8A72ABE 9A84ABCFB8A72AC0

30
test/fixtures/keys/ca1-key.pem

@ -1,17 +1,17 @@
-----BEGIN ENCRYPTED PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY-----
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIJ36Z9tFiv2oCAggA MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI4tZeEUDNwLoCAggA
MBQGCCqGSIb3DQMHBAjCAyUwdFh+7gSCAoD9Sv9009MmLb8+wHhYhxmrPrpeYZOt MBQGCCqGSIb3DQMHBAglCttpxF+UrASCAoCOiXoMG1+CJFtRnovzp0wSCeEtieI3
W8xfELfal/2XWFe41WV41Qsa2HyN03VeyQjb+cnKvZX6HUCe5zVMUsf+B91yQBqR jntJkCBF+NNUZrbWaQqWO+Id8KjXNFQdUo7lYT0d0w5lf52OHTyswjN0ILCOp/WN
jOZgsgoflEC3tFrhW5ogmRnjuok3CbTYLx0f8GMucSRNa9ZPhpfUjrVcCUrKKRJ+ eVMDfgmaJXtaah2l++hDFhcbGsOdRcwM0+yComF02Qxr13ftYnIPzUH4+Ix1i1Tr
owk0VxWQkRqMF/8WJJgHxnm8/jLbNKuHbwY8SSQO/pStyKxqx5rBXAA/YCrAx7EZ 6eBGDBJv0eXDZj/dLrploA7/pepKlytRw2stIL99TSICR54UQ7fyZ/oS6NvoQU7U
aDvc2q9EwRHX+hWIhpIkYna7PwnNAX03Ghv4iiwUlwHoomvgxExdUc9T8HBQu/xP iBCVsrkjyE6jHJZ6vNe/ZjM8ZdLM9K2inoldpFaavDTh6GwHC6e3e9FJuJk6X30e
2pmUqwTglAdRb0tNiYrF+yIesAlqBc1qoi7tv2SM3gTowdw2PeHq5MA/ShV21oC8 s2lhrVLOmxLuFS168iApyA8XvVTg/RG08DvkzUUFv8+HNETH0Qkb5kpJM+pPzwyu
51bc0OxRkEFsHGLIs1v5qzs21JhX0IKvb5LDHAaze2RwODfnCTcQb8jYaFZNmwpt c5et2fX8YuQRc8SdIdd+Z0lZJga1IciEXlsfzGeUtcZKUjBZ5yPTx+1InfcNFDKR
ZrHgBQBwOHSvZ9CCqInDDtGBhYRlQIQRGgj9Ju5fruRYycn8vE58OcIfF52dwLKB wCU2p0Haj9OCcvSBzU53I57RYXkENMEHQ46/FytGULXHimIoIR/SEbrqbKX0xDmT
7sjTFX0O0b58wpiQSJzbHGbjNlQNRXxdk9v1qfP8vx8rFHLoFSScaZomavp4uijU rc/4c4vI5+tQPYMjo0rqydLAb5YjWCivrXDVXVHrG0YFsAoJkvTBLXlPiqTcnkea
yLKVwquzEOVOMP8cC+yRk+zkcb9EE2pE1CqG0Mj6MHH1Lha98kakTIAS/VG59/Mp KACuq7B+ymdVmpjV891OLuN3Yah+HgrvTkMlNexsFWvGpis03UYwpI6bppe4dHtt
EqZoRtJ6n/DzscrRpHIm+170ufLGmivmTeOXcMyHv1pGp35c5VbmUTZCxcE7A/0f rLBlgtyxFLJ9hu/YnkR6HcrjKaW5kGFDX06elAZBdPD/6foghzTb4jw3OK6a4ue0
WPLVB3lBPgsvR/4NVx9A6mvXbkp2yngdfbvQgzRDG6pfrE1xeiUAyRCts7dR3Q9/ PE/zF6d7QWW+w5xKtNO62WWKABi9OtLhdUNVAFyBlaA43zYbnXkyfmv0l7LXPZ9t
dNHIM2wsiO3A/8Up1vrY6d/dcJt7cwjHRkx2eQFbpeE+a4CCNZ7gXFcwHLigBH8G Ps+BmG4r/gxO6GmZZ40sRXFjpkj230bTjbN6sUrU3WgOszMy0uFAph+zBUIMZWSP
uTTVZf4HJavjXiYlkY3OFnPuz4KzanJzuqluKeIdJwSEkp9Kra/Id0eO wqZWmQi8MHQ4+Qm8N5GdXUTXw32eZ60bj82QGPso/NNxzDQsk5wd+bR3
-----END ENCRYPTED PRIVATE KEY----- -----END ENCRYPTED PRIVATE KEY-----

3
test/fixtures/keys/ca1.cnf

@ -5,6 +5,7 @@ distinguished_name = req_distinguished_name
attributes = req_attributes attributes = req_attributes
prompt = no prompt = no
output_password = password output_password = password
x509_extensions = v3_ca
[ req_distinguished_name ] [ req_distinguished_name ]
C = US C = US
@ -18,3 +19,5 @@ emailAddress = ry@tinyclouds.org
[ req_attributes ] [ req_attributes ]
challengePassword = A challenge password challengePassword = A challenge password
[ v3_ca ]
basicConstraints = CA:TRUE

16
test/fixtures/keys/ca3-cert.pem

@ -0,0 +1,16 @@
-----BEGIN CERTIFICATE-----
MIICgjCCAeugAwIBAgIJAJqEq8+4pyq/MA0GCSqGSIb3DQEBCwUAMHoxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzANBgNVBAoMBkpveWVu
dDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2ExMSAwHgYJKoZIhvcNAQkB
FhFyeUB0aW55Y2xvdWRzLm9yZzAeFw0xNTA0MTgxMzI4NDFaFw00MjA5MDIxMzI4
NDFaMHoxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDzAN
BgNVBAoMBkpveWVudDEQMA4GA1UECwwHTm9kZS5qczEMMAoGA1UEAwwDY2EzMSAw
HgYJKoZIhvcNAQkBFhFyeUB0aW55Y2xvdWRzLm9yZzCBnzANBgkqhkiG9w0BAQEF
AAOBjQAwgYkCgYEAqs4MKn9saUIu/9EfHQPouC3kL9Mo5sd1WR6RBeSd8cqeFxXW
EWEq/P0hUeAH1sY0u8RFOccJmSJg8KTyRGc+VZzWimopz17mTuQY4hPW4bFzqmQm
7STfJz5eHzynBTU8jk5omi8hjbnRA38jOm4D7rN/vqtB+RG+vEhxONnq4DMCAwEA
AaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQBo8rX1uZWHvKHG
gWw+LXrY24Pkg8NdDRmfqEVyuaR4GoGGOXCqlVaFa6x+4/eqOUzHoC9uGfPtjrvW
BYQ1o/l0JZWW4KZYuXoVuMUSj+sel82mf9zLDeq5WYTPECgJDMfgVpXOmhHfyezn
SkUTX7XJUohjET+X5BqTFlqRT/RfIw==
-----END CERTIFICATE-----

1
test/fixtures/keys/ca3-cert.srl

@ -0,0 +1 @@
C4CD893EF9A75DCC

13
test/fixtures/keys/ca3-csr.pem

@ -0,0 +1,13 @@
-----BEGIN CERTIFICATE REQUEST-----
MIIB3zCCAUgCAQAwejELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMQswCQYDVQQH
DAJTRjEPMA0GA1UECgwGSm95ZW50MRAwDgYDVQQLDAdOb2RlLmpzMQwwCgYDVQQD
DANjYTMxIDAeBgkqhkiG9w0BCQEWEXJ5QHRpbnljbG91ZHMub3JnMIGfMA0GCSqG
SIb3DQEBAQUAA4GNADCBiQKBgQCqzgwqf2xpQi7/0R8dA+i4LeQv0yjmx3VZHpEF
5J3xyp4XFdYRYSr8/SFR4AfWxjS7xEU5xwmZImDwpPJEZz5VnNaKainPXuZO5Bji
E9bhsXOqZCbtJN8nPl4fPKcFNTyOTmiaLyGNudEDfyM6bgPus3++q0H5Eb68SHE4
2ergMwIDAQABoCUwIwYJKoZIhvcNAQkHMRYMFEEgY2hhbGxlbmdlIHBhc3N3b3Jk
MA0GCSqGSIb3DQEBCwUAA4GBABMaKC7NVVdfoQeKwIy5lYo17mOr4WcWHPNRcoIy
rAHLcAzFOp0RCSZ7ROVRR6O/QIBYapUmPmdYRhKfz1g35xCX3+T28cWXngALV5v0
XzMYJiew+97/LlNnBwoTRafAorviugdbFgJeMpYHRkG7/zXQsBz+hwgymKZnHW9D
Dl4h
-----END CERTIFICATE REQUEST-----

15
test/fixtures/keys/ca3-key.pem

@ -0,0 +1,15 @@
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqzgwqf2xpQi7/0R8dA+i4LeQv0yjmx3VZHpEF5J3xyp4XFdYR
YSr8/SFR4AfWxjS7xEU5xwmZImDwpPJEZz5VnNaKainPXuZO5BjiE9bhsXOqZCbt
JN8nPl4fPKcFNTyOTmiaLyGNudEDfyM6bgPus3++q0H5Eb68SHE42ergMwIDAQAB
AoGBAJkcc5N0/j2s8mynjXh5FJhlqvOkGjol+m+VEvNxaJRiySxwiqCxtdNrJf87
EEvbCVJ4MoYEgfof8z5E3lerJRgqrhY2RSfiQrSUA89Lw9uYzcx28zhWpwwmuLHY
5gjz+LCDDS5okLsXnl2awHXADEmcx29sZnRS6dGRFcf8F0FhAkEA1c7HrW8Vghu2
FlRaY6LOuoFNAHM++ugoWrC85/moYevLG8wAJCuSIp/RuWrx1FdJoa7rfhyS649v
cMGN0m1yHwJBAMyC1S1QoqXSdoqN8OrXyHJmaSbWG8IMLcT2FXA8Mk3Tk0zWSjiz
sk/O85NsmUQQnkRgbtSS+w0Kc0OMWXbfl20CQH+igFsNjEZuaoXr90WxhD2cQK57
HebEvopdJXhJ9nX2P/qpDpCJHiTjSVyp9hFvxjnp5RUU07QhnUIvmY073rsCQFMN
ovNHNvZutVNpd3h372B+NJ/f/d/dQE0nvucYmzk9/ikLMZM7buO4YPTy+n9I3G1a
WEgd9LSEFPFOsxpyjTUCQGn9XTyeSo1EoVuV21DE0Cnx30YsnPKMT1YRS7QgjDPK
RA3fSsvnhtTzT53kfJ/ZurBV+RKbePL1JVqDtGvJVeE=
-----END RSA PRIVATE KEY-----

23
test/fixtures/keys/ca3.cnf

@ -0,0 +1,23 @@
[ req ]
default_bits = 1024
days = 999
distinguished_name = req_distinguished_name
attributes = req_attributes
prompt = no
output_password = password
x509_extensions = v3_ca
[ req_distinguished_name ]
C = US
ST = CA
L = SF
O = Joyent
OU = Node.js
CN = ca3
emailAddress = ry@tinyclouds.org
[ req_attributes ]
challengePassword = A challenge password
[ v3_ca ]
basicConstraints = CA:TRUE

4
test/parallel/test-tls-peer-certificate.js

@ -36,13 +36,13 @@ server.listen(common.PORT, function() {
common.debug(util.inspect(peerCert)); common.debug(util.inspect(peerCert));
assert.equal(peerCert.subject.emailAddress, 'ry@tinyclouds.org'); assert.equal(peerCert.subject.emailAddress, 'ry@tinyclouds.org');
assert.equal(peerCert.serialNumber, '9A84ABCFB8A72ABE'); assert.equal(peerCert.serialNumber, '9A84ABCFB8A72AC0');
assert.deepEqual(peerCert.infoAccess['OCSP - URI'], assert.deepEqual(peerCert.infoAccess['OCSP - URI'],
[ 'http://ocsp.nodejs.org/' ]); [ 'http://ocsp.nodejs.org/' ]);
var issuer = peerCert.issuerCertificate; var issuer = peerCert.issuerCertificate;
assert.ok(issuer.issuerCertificate === issuer); assert.ok(issuer.issuerCertificate === issuer);
assert.equal(issuer.serialNumber, 'B5090C899FC2FF93'); assert.equal(issuer.serialNumber, '8DF21C01468AF393');
verified = true; verified = true;
server.close(); server.close();
}); });

27
test/parallel/test-tls-sni-server-client.js

@ -35,6 +35,11 @@ var SNIContexts = {
'asterisk.test.com': { 'asterisk.test.com': {
key: loadPEM('agent3-key'), key: loadPEM('agent3-key'),
cert: loadPEM('agent3-cert') cert: loadPEM('agent3-cert')
},
'chain.example.com': {
key: loadPEM('agent6-key'),
// NOTE: Contains ca3 chain cert
cert: loadPEM('agent6-cert')
} }
}; };
@ -42,32 +47,29 @@ var serverPort = common.PORT;
var clientsOptions = [{ var clientsOptions = [{
port: serverPort, port: serverPort,
key: loadPEM('agent1-key'),
cert: loadPEM('agent1-cert'),
ca: [loadPEM('ca1-cert')], ca: [loadPEM('ca1-cert')],
servername: 'a.example.com', servername: 'a.example.com',
rejectUnauthorized: false rejectUnauthorized: false
}, { }, {
port: serverPort, port: serverPort,
key: loadPEM('agent2-key'),
cert: loadPEM('agent2-cert'),
ca: [loadPEM('ca2-cert')], ca: [loadPEM('ca2-cert')],
servername: 'b.test.com', servername: 'b.test.com',
rejectUnauthorized: false rejectUnauthorized: false
}, { }, {
port: serverPort, port: serverPort,
key: loadPEM('agent2-key'),
cert: loadPEM('agent2-cert'),
ca: [loadPEM('ca2-cert')], ca: [loadPEM('ca2-cert')],
servername: 'a.b.test.com', servername: 'a.b.test.com',
rejectUnauthorized: false rejectUnauthorized: false
}, { }, {
port: serverPort, port: serverPort,
key: loadPEM('agent3-key'),
cert: loadPEM('agent3-cert'),
ca: [loadPEM('ca1-cert')], ca: [loadPEM('ca1-cert')],
servername: 'c.wrong.com', servername: 'c.wrong.com',
rejectUnauthorized: false rejectUnauthorized: false
}, {
port: serverPort,
ca: [loadPEM('ca1-cert')],
servername: 'chain.example.com',
rejectUnauthorized: false
}]; }];
var serverResults = [], var serverResults = [],
@ -79,6 +81,7 @@ var server = tls.createServer(serverOptions, function(c) {
server.addContext('a.example.com', SNIContexts['a.example.com']); server.addContext('a.example.com', SNIContexts['a.example.com']);
server.addContext('*.test.com', SNIContexts['asterisk.test.com']); server.addContext('*.test.com', SNIContexts['asterisk.test.com']);
server.addContext('chain.example.com', SNIContexts['chain.example.com']);
server.listen(serverPort, startTest); server.listen(serverPort, startTest);
@ -105,7 +108,9 @@ function startTest() {
} }
process.on('exit', function() { process.on('exit', function() {
assert.deepEqual(serverResults, ['a.example.com', 'b.test.com', assert.deepEqual(serverResults, [
'a.b.test.com', 'c.wrong.com']); 'a.example.com', 'b.test.com', 'a.b.test.com', 'c.wrong.com',
assert.deepEqual(clientResults, [true, true, false, false]); 'chain.example.com'
]);
assert.deepEqual(clientResults, [true, true, false, false, true]);
}); });

Loading…
Cancel
Save