|
|
8ab518 |
diff --git a/doc/api/tls.md b/doc/api/tls.md
|
|
|
8ab518 |
index d42e062..e7186bd 100644
|
|
|
8ab518 |
--- a/doc/api/tls.md
|
|
|
8ab518 |
+++ b/doc/api/tls.md
|
|
|
8ab518 |
@@ -130,7 +130,11 @@ handshake extensions allowing you:
|
|
|
498a18 |
* NPN - to use one TLS server for multiple protocols (HTTP, SPDY)
|
|
|
498a18 |
* SNI - to use one TLS server for multiple hostnames with different SSL
|
|
|
498a18 |
certificates.
|
|
|
8ab518 |
-
|
|
|
498a18 |
+ **NOTE**: dueto a design flaw in node **SNI cannot be
|
|
|
498a18 |
+ used on the server side**, even so all parameters in related functions are
|
|
|
498a18 |
+ accepted for compatibility reasons. And thus the related events will not
|
|
|
498a18 |
+ fire unless one aranges this explicitly. This may change, when the OS
|
|
|
498a18 |
+ provides OpenSSL v1.0.2 or better and node gets linked to this version.
|
|
|
498a18 |
|
|
|
498a18 |
## Perfect Forward Secrecy
|
|
|
8ab518 |
|
|
|
498a18 |
diff --git a/src/node_constants.cc b/src/node_constants.cc
|
|
|
8ab518 |
index 51c2ee8..694d976 100644
|
|
|
498a18 |
--- a/src/node_constants.cc
|
|
|
498a18 |
+++ b/src/node_constants.cc
|
|
|
498a18 |
@@ -12,8 +12,13 @@
|
|
|
498a18 |
#include <sys/stat.h>
|
|
|
498a18 |
|
|
|
498a18 |
#if HAVE_OPENSSL
|
|
|
498a18 |
+# include <openssl/opensslconf.h>
|
|
|
498a18 |
+# include <openssl/opensslv.h>
|
|
|
498a18 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
# include <openssl/ec.h>
|
|
|
8ab518 |
+# endif
|
|
|
498a18 |
# include <openssl/ssl.h>
|
|
|
498a18 |
+
|
|
|
498a18 |
# ifndef OPENSSL_NO_ENGINE
|
|
|
498a18 |
# include <openssl/engine.h>
|
|
|
498a18 |
# endif // !OPENSSL_NO_ENGINE
|
|
|
498a18 |
@@ -961,12 +966,14 @@ void DefineOpenSSLConstants(Local<Object> target) {
|
|
|
498a18 |
|
|
|
498a18 |
#if HAVE_OPENSSL
|
|
|
498a18 |
// NOTE: These are not defines
|
|
|
8ab518 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
NODE_DEFINE_CONSTANT(target, POINT_CONVERSION_COMPRESSED);
|
|
|
498a18 |
|
|
|
498a18 |
NODE_DEFINE_CONSTANT(target, POINT_CONVERSION_UNCOMPRESSED);
|
|
|
498a18 |
|
|
|
498a18 |
NODE_DEFINE_CONSTANT(target, POINT_CONVERSION_HYBRID);
|
|
|
498a18 |
#endif
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
void DefineSystemConstants(Local<Object> target) {
|
|
|
498a18 |
diff --git a/src/node_crypto.cc b/src/node_crypto.cc
|
|
|
8ab518 |
index b3169ca..958c4e8 100644
|
|
|
498a18 |
--- a/src/node_crypto.cc
|
|
|
498a18 |
+++ b/src/node_crypto.cc
|
|
|
8ab518 |
@@ -30,6 +30,83 @@
|
|
|
498a18 |
#define OPENSSL_CONST
|
|
|
498a18 |
#endif
|
|
|
498a18 |
|
|
|
498a18 |
+#ifndef SSL_get_server_tmp_key
|
|
|
498a18 |
+/*
|
|
|
8ab518 |
+ * 1.0.2 SSL_get_server_tmp_key(s, pk) "backport". BAD HACK!!!
|
|
|
8ab518 |
+ * NOTE: This imports "foreign" knowledge and thus will break, when SESS_CERT
|
|
|
8ab518 |
+ * or CERT_PKEY change, which is definitely the case for the later for
|
|
|
8ab518 |
+ * all OpenSSL lib vers != 1.0.1. So don't try to bind to something else!
|
|
|
498a18 |
+ */
|
|
|
498a18 |
+# define SSL_PKEY_NUM 8
|
|
|
498a18 |
+typedef struct cert_pkey_st {
|
|
|
498a18 |
+ X509 *x509;
|
|
|
498a18 |
+ EVP_PKEY *privatekey;
|
|
|
498a18 |
+ /* Digest to use when signing */
|
|
|
498a18 |
+ const EVP_MD *digest;
|
|
|
498a18 |
+} CERT_PKEY;
|
|
|
498a18 |
+
|
|
|
498a18 |
+typedef struct sess_cert_st {
|
|
|
498a18 |
+ STACK_OF(X509) *cert_chain; /* as received from peer (not for SSL2) */
|
|
|
498a18 |
+ /* The 'peer_...' members are used only by clients. */
|
|
|
498a18 |
+ int peer_cert_type;
|
|
|
498a18 |
+ CERT_PKEY *peer_key; /* points to an element of peer_pkeys (never
|
|
|
498a18 |
+ * NULL!) */
|
|
|
498a18 |
+ CERT_PKEY peer_pkeys[SSL_PKEY_NUM];
|
|
|
498a18 |
+ /*
|
|
|
498a18 |
+ * Obviously we don't have the private keys of these, so maybe we
|
|
|
498a18 |
+ * shouldn't even use the CERT_PKEY type here.
|
|
|
498a18 |
+ */
|
|
|
498a18 |
+# ifndef OPENSSL_NO_RSA
|
|
|
498a18 |
+ RSA *peer_rsa_tmp; /* not used for SSL 2 */
|
|
|
498a18 |
+# endif
|
|
|
498a18 |
+# ifndef OPENSSL_NO_DH
|
|
|
498a18 |
+ DH *peer_dh_tmp; /* not used for SSL 2 */
|
|
|
498a18 |
+# endif
|
|
|
498a18 |
+# ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
+ EC_KEY *peer_ecdh_tmp;
|
|
|
498a18 |
+# endif
|
|
|
498a18 |
+ int references; /* actually always 1 at the moment */
|
|
|
498a18 |
+} SESS_CERT;
|
|
|
498a18 |
+
|
|
|
498a18 |
+static long SSL_get_server_tmp_key(SSL *s, void *parg) {
|
|
|
8ab518 |
+ if (s->server || !s->session || !s->session->sess_cert)
|
|
|
8ab518 |
+ return 0;
|
|
|
8ab518 |
+ else {
|
|
|
8ab518 |
+ SESS_CERT *sc;
|
|
|
8ab518 |
+ EVP_PKEY *ptmp;
|
|
|
8ab518 |
+ int rv = 0;
|
|
|
8ab518 |
+ sc = s->session->sess_cert;
|
|
|
498a18 |
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDH)
|
|
|
8ab518 |
+ if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp && !sc->peer_ecdh_tmp)
|
|
|
8ab518 |
+ return 0;
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
+ ptmp = EVP_PKEY_new();
|
|
|
8ab518 |
+ if (!ptmp)
|
|
|
8ab518 |
+ return 0;
|
|
|
8ab518 |
+ if (0) ;
|
|
|
498a18 |
+#ifndef OPENSSL_NO_RSA
|
|
|
8ab518 |
+ else if (sc->peer_rsa_tmp)
|
|
|
8ab518 |
+ rv = EVP_PKEY_set1_RSA(ptmp, sc->peer_rsa_tmp);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
+#ifndef OPENSSL_NO_DH
|
|
|
8ab518 |
+ else if (sc->peer_dh_tmp)
|
|
|
8ab518 |
+ rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
8ab518 |
+ else if (sc->peer_ecdh_tmp)
|
|
|
8ab518 |
+ rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp);
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
+ if (rv) {
|
|
|
8ab518 |
+ *(EVP_PKEY **)parg = ptmp;
|
|
|
8ab518 |
+ return 1;
|
|
|
8ab518 |
+ }
|
|
|
8ab518 |
+ EVP_PKEY_free(ptmp);
|
|
|
8ab518 |
+ return 0;
|
|
|
8ab518 |
+ }
|
|
|
498a18 |
+}
|
|
|
498a18 |
+#endif /* SSL_get_server_tmp_key */
|
|
|
498a18 |
+
|
|
|
498a18 |
+
|
|
|
498a18 |
#define THROW_AND_RETURN_IF_NOT_STRING_OR_BUFFER(val) \
|
|
|
498a18 |
do { \
|
|
|
498a18 |
if (!Buffer::HasInstance(val) && !val->IsString()) { \
|
|
|
8ab518 |
@@ -160,7 +237,11 @@ template int SSLWrap<TLSWrap>::TLSExtStatusCallback(SSL* s, void* arg);
|
|
|
498a18 |
#endif
|
|
|
498a18 |
|
|
|
498a18 |
template void SSLWrap<TLSWrap>::DestroySSL();
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
template int SSLWrap<TLSWrap>::SSLCertCallback(SSL* s, void* arg);
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+template int SSLWrap<TLSWrap>::SSLCertCallback(SSL* s, X509 **x509, EVP_PKEY **pkey);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
template void SSLWrap<TLSWrap>::WaitForCertCb(CertCb cb, void* arg);
|
|
|
498a18 |
|
|
|
498a18 |
|
|
|
8ab518 |
@@ -248,8 +329,23 @@ inline void CheckEntropy() {
|
|
|
498a18 |
}
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
+#ifndef NODE_FIPS_MODE
|
|
|
498a18 |
+#define NODE_FIPS_MODE 0
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
bool EntropySource(unsigned char* buffer, size_t length) {
|
|
|
498a18 |
+#ifdef OPENSSL_FIPS
|
|
|
498a18 |
+ // This call is important for FIPS Capable OpenSSL lib, otherwise
|
|
|
498a18 |
+ // RAND_status() will hang. Works for non-FIPS capable libs, too.
|
|
|
498a18 |
+ int err = FIPS_mode();
|
|
|
498a18 |
+ // Shouldn't this be a CLI switch?
|
|
|
498a18 |
+ if (err != NODE_FIPS_MODE && !FIPS_mode_set(NODE_FIPS_MODE)) {
|
|
|
498a18 |
+ err = ERR_get_error();
|
|
|
498a18 |
+ fprintf(stderr, "openssl fips failed: %s\n", ERR_error_string(err, NULL));
|
|
|
498a18 |
+ UNREACHABLE();
|
|
|
498a18 |
+ }
|
|
|
498a18 |
+#endif // OPENSSL_FIPS
|
|
|
498a18 |
+
|
|
|
498a18 |
// Ensure that OpenSSL's PRNG is properly seeded.
|
|
|
498a18 |
CheckEntropy();
|
|
|
498a18 |
// RAND_bytes() can return 0 to indicate that the entropy data is not truly
|
|
|
8ab518 |
@@ -271,8 +367,12 @@ void SecureContext::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
env->SetProtoMethod(t, "addCRL", SecureContext::AddCRL);
|
|
|
498a18 |
env->SetProtoMethod(t, "addRootCerts", SecureContext::AddRootCerts);
|
|
|
498a18 |
env->SetProtoMethod(t, "setCiphers", SecureContext::SetCiphers);
|
|
|
498a18 |
+ #ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
env->SetProtoMethod(t, "setECDHCurve", SecureContext::SetECDHCurve);
|
|
|
498a18 |
+ #endif
|
|
|
498a18 |
+ #ifndef OPENSSL_NO_DH
|
|
|
498a18 |
env->SetProtoMethod(t, "setDHParam", SecureContext::SetDHParam);
|
|
|
498a18 |
+ #endif
|
|
|
498a18 |
env->SetProtoMethod(t, "setOptions", SecureContext::SetOptions);
|
|
|
498a18 |
env->SetProtoMethod(t, "setSessionIdContext",
|
|
|
498a18 |
SecureContext::SetSessionIdContext);
|
|
|
8ab518 |
@@ -521,9 +621,20 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
|
|
|
498a18 |
for (int i = 0; i < sk_X509_num(extra_certs); i++) {
|
|
|
498a18 |
X509* ca = sk_X509_value(extra_certs, i);
|
|
|
8ab518 |
|
|
|
498a18 |
- // NOTE: Increments reference count on `ca`
|
|
|
498a18 |
- r = SSL_CTX_add1_chain_cert(ctx, ca);
|
|
|
498a18 |
-
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
8ab518 |
+ // If ctx->cert->key != NULL create ctx->cert->key->chain if not
|
|
|
8ab518 |
+ // already there, push 'ca' to this chain and finally increment the ca
|
|
|
8ab518 |
+ // reference count by 1 (this is the diff between *_add1_* and *_add0_*
|
|
|
8ab518 |
+ // - the later increments by 0 ;-)) and return 1. Otherwise or if
|
|
|
8ab518 |
+ // something fails in between, return 0.
|
|
|
8ab518 |
+ r = SSL_CTX_add1_chain_cert(ctx, ca);
|
|
|
498a18 |
+#else
|
|
|
8ab518 |
+ // Create ctx->extra_certs if not already there, just push 'ca' to this
|
|
|
8ab518 |
+ // chain and return 1. If something fails, return 0.
|
|
|
8ab518 |
+ // NOTE: 1.0.1- does not support multiple certs having its own chain in
|
|
|
8ab518 |
+ // a single context. There is just one: extra_chain!
|
|
|
32b10d |
+ r = SSL_CTX_add_extra_chain_cert(ctx, X509_dup(ca));
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
if (!r) {
|
|
|
498a18 |
ret = 0;
|
|
|
498a18 |
*issuer = nullptr;
|
|
|
8ab518 |
@@ -794,7 +905,7 @@ void SecureContext::SetCiphers(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
SSL_CTX_set_cipher_list(sc->ctx_, *ciphers);
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
-
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) {
|
|
|
8ab518 |
SecureContext* sc;
|
|
|
8ab518 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.Holder());
|
|
|
8ab518 |
@@ -820,8 +931,9 @@ void SecureContext::SetECDHCurve(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
|
|
|
498a18 |
EC_KEY_free(ecdh);
|
|
|
498a18 |
}
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
-
|
|
|
498a18 |
+#ifndef OPENSSL_NO_DH
|
|
|
498a18 |
void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
|
|
|
8ab518 |
SecureContext* sc;
|
|
|
8ab518 |
ASSIGN_OR_RETURN_UNWRAP(&sc, args.This());
|
|
|
8ab518 |
@@ -860,7 +972,7 @@ void SecureContext::SetDHParam(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
if (!r)
|
|
|
498a18 |
return env->ThrowTypeError("Error setting temp DH parameter");
|
|
|
498a18 |
}
|
|
|
498a18 |
-
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
void SecureContext::SetOptions(const FunctionCallbackInfo<Value>& args) {
|
|
|
8ab518 |
SecureContext* sc;
|
|
|
8ab518 |
@@ -2112,7 +2224,12 @@ void SSLWrap<Base>::WaitForCertCb(CertCb cb, void* arg) {
|
|
|
498a18 |
|
|
|
498a18 |
|
|
|
498a18 |
template <class Base>
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
int SSLWrap<Base>::SSLCertCallback(SSL* s, void* arg) {
|
|
|
498a18 |
+#else
|
|
|
8ab518 |
+ /* NOTE: For now this callback gets usually never called due to design flaws */
|
|
|
498a18 |
+int SSLWrap<Base>::SSLCertCallback(SSL* s, X509 **x509, EVP_PKEY **pkey) {
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
Base* w = static_cast<Base*>(SSL_get_app_data(s));
|
|
|
498a18 |
|
|
|
498a18 |
if (!w->is_server())
|
|
|
8ab518 |
@@ -2186,19 +2303,53 @@ void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
w->sni_context_.Reset(env->isolate(), ctx);
|
|
|
498a18 |
|
|
|
498a18 |
int rv;
|
|
|
498a18 |
+ X509* x509;
|
|
|
498a18 |
+ EVP_PKEY* pkey;
|
|
|
498a18 |
+ STACK_OF(X509)* chain;
|
|
|
498a18 |
|
|
|
498a18 |
// NOTE: reference count is not increased by this API methods
|
|
|
498a18 |
- X509* x509 = SSL_CTX_get0_certificate(sc->ctx_);
|
|
|
498a18 |
- EVP_PKEY* pkey = SSL_CTX_get0_privatekey(sc->ctx_);
|
|
|
498a18 |
- STACK_OF(X509)* chain;
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
8ab518 |
+ x509 = SSL_CTX_get0_certificate(sc->ctx_);
|
|
|
8ab518 |
+ pkey = SSL_CTX_get0_privatekey(sc->ctx_);
|
|
|
8ab518 |
+ rv = SSL_CTX_get0_chain_certs(sc->ctx_, &chain);
|
|
|
498a18 |
+#else
|
|
|
8ab518 |
+ SSL *ssl = SSL_new(sc->ctx_);
|
|
|
8ab518 |
+ rv = SSL_CTX_get_extra_chain_certs(sc->ctx_, &chain);
|
|
|
8ab518 |
+ if (ssl) {
|
|
|
8ab518 |
+ SSL_set_connect_state(ssl); /* just cleanup/reset state - cheap */
|
|
|
8ab518 |
+ x509 = SSL_get_certificate(ssl);
|
|
|
8ab518 |
+ SSL_free(ssl);
|
|
|
8ab518 |
+ } else {
|
|
|
8ab518 |
+ x509 = NULL;
|
|
|
8ab518 |
+ pkey = NULL;
|
|
|
8ab518 |
+ }
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
- rv = SSL_CTX_get0_chain_certs(sc->ctx_, &chain);
|
|
|
8ab518 |
- if (rv)
|
|
|
498a18 |
- rv = SSL_use_certificate(w->ssl_, x509);
|
|
|
8ab518 |
- if (rv)
|
|
|
498a18 |
- rv = SSL_use_PrivateKey(w->ssl_, pkey);
|
|
|
498a18 |
- if (rv && chain != nullptr)
|
|
|
498a18 |
- rv = SSL_set1_chain(w->ssl_, chain);
|
|
|
8ab518 |
+ if (rv)
|
|
|
8ab518 |
+ rv = SSL_use_certificate(w->ssl_, x509);
|
|
|
8ab518 |
+ if (rv)
|
|
|
8ab518 |
+ rv = SSL_use_PrivateKey(w->ssl_, pkey);
|
|
|
8ab518 |
+ if (rv && chain != nullptr) {
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
8ab518 |
+ // replaces w->ssl_->cert->key->chain with a copy of the given chain,
|
|
|
8ab518 |
+ // which is allowed to be NULL
|
|
|
8ab518 |
+ rv = SSL_set1_chain(w->ssl_, chain);
|
|
|
498a18 |
+#else
|
|
|
8ab518 |
+ // just replace the extra chain with the given chain - 1.0.1- does not
|
|
|
8ab518 |
+ // support chain per cert
|
|
|
8ab518 |
+ SSL_CTX_clear_extra_chain_certs(w->ssl_->ctx);
|
|
|
8ab518 |
+ if (chain != NULL) {
|
|
|
8ab518 |
+ int i;
|
|
|
8ab518 |
+ SSL_CTX* ctx = w->ssl_->ctx;
|
|
|
8ab518 |
+ for (i = 0; i < sk_X509_num(chain); i++) {
|
|
|
8ab518 |
+ // can't do anything: however others might be ok and still
|
|
|
8ab518 |
+ // satisfy requirements
|
|
|
8ab518 |
+ SSL_CTX_add_extra_chain_cert(ctx, sk_X509_value(chain,i));
|
|
|
8ab518 |
+ }
|
|
|
8ab518 |
+ }
|
|
|
8ab518 |
+ rv = 1;
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
+ }
|
|
|
498a18 |
if (rv)
|
|
|
498a18 |
rv = w->SetCACerts(sc);
|
|
|
498a18 |
if (!rv) {
|
|
|
8ab518 |
@@ -2262,9 +2413,14 @@ void SSLWrap<Base>::SetSNIContext(SecureContext* sc) {
|
|
|
498a18 |
|
|
|
498a18 |
template <class Base>
|
|
|
498a18 |
int SSLWrap<Base>::SetCACerts(SecureContext* sc) {
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
int err = SSL_set1_verify_cert_store(ssl_, SSL_CTX_get_cert_store(sc->ctx_));
|
|
|
498a18 |
if (err != 1)
|
|
|
498a18 |
return err;
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+ // there is no ssl_->cert->verify_store in <= 1.0.1. So no need to: free the
|
|
|
498a18 |
+ // old store, set the new one to it and increment its ref count.
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
|
|
|
498a18 |
STACK_OF(X509_NAME)* list = SSL_dup_CA_list(
|
|
|
498a18 |
SSL_CTX_get_client_CA_list(sc->ctx_));
|
|
|
8ab518 |
@@ -2543,7 +2699,11 @@ inline int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
|
|
|
498a18 |
SSL* ssl = static_cast<SSL*>(
|
|
|
498a18 |
X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
|
|
|
8ab518 |
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
if (SSL_is_server(ssl))
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+ if (ssl->server)
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
return 1;
|
|
|
498a18 |
|
|
|
498a18 |
// Client needs to check if the server cert is listed in the
|
|
|
8ab518 |
@@ -2625,8 +2785,21 @@ void Connection::New(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
SSL_set_info_callback(conn->ssl_, SSLInfoCallback);
|
|
|
498a18 |
|
|
|
498a18 |
InitNPN(sc);
|
|
|
498a18 |
-
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
SSL_set_cert_cb(conn->ssl_, SSLWrap<Connection>::SSLCertCallback, conn);
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+ /* 1.0.1 and less have no general cert callback. The closest for a client is
|
|
|
498a18 |
+ SSL_CTX_set_client_cert_cb(conn->ssl_->ctx, SSLWrap<Connection>::SSLCertCallback);
|
|
|
498a18 |
+ but on the client it is not needed/used by this implementation. Since this
|
|
|
498a18 |
+ the SSLCertCallback actually calls lib/_tls_wrap.js:oncertcb(), which in
|
|
|
498a18 |
+ turn loadSNI() and this the actual SNICallback of the JSON object, sets
|
|
|
498a18 |
+ the context and finally requestOCSP() and certCbDone(). Not sure, why
|
|
|
498a18 |
+ the SNICallback of the JSON object, doesn't get invoked via
|
|
|
498a18 |
+ SelectSNIContextCallback_() - design flaw because lets do 2 things at once
|
|
|
498a18 |
+ (i.e. do SNICallback and attach the certs ca chain), however, this means
|
|
|
498a18 |
+ no server side support for the SNI TLS/OCSP_state extension anymore.
|
|
|
498a18 |
+ */
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
|
|
|
498a18 |
if (is_server) {
|
|
|
8ab518 |
@@ -3754,7 +3927,8 @@ SignBase::Error Sign::SignFinal(const char* key_pem,
|
|
|
498a18 |
if (pkey == nullptr || 0 != ERR_peek_error())
|
|
|
498a18 |
goto exit;
|
|
|
498a18 |
|
|
|
498a18 |
-#ifdef NODE_FIPS_MODE
|
|
|
498a18 |
+#ifdef OPENSSL_FIPS
|
|
|
498a18 |
+ if (FIPS_mode()) {
|
|
|
498a18 |
/* Validate DSA2 parameters from FIPS 186-4 */
|
|
|
498a18 |
if (EVP_PKEY_DSA == pkey->type) {
|
|
|
498a18 |
size_t L = BN_num_bits(pkey->pkey.dsa->p);
|
|
|
8ab518 |
@@ -3775,7 +3949,8 @@ SignBase::Error Sign::SignFinal(const char* key_pem,
|
|
|
498a18 |
goto exit;
|
|
|
498a18 |
}
|
|
|
498a18 |
}
|
|
|
498a18 |
-#endif // NODE_FIPS_MODE
|
|
|
8ab518 |
+ }
|
|
|
498a18 |
+#endif // OPENSSL_FIPS
|
|
|
498a18 |
|
|
|
498a18 |
if (EVP_SignFinal(&mdctx_, *sig, sig_len, pkey))
|
|
|
498a18 |
fatal = false;
|
|
|
8ab518 |
@@ -4194,7 +4369,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
delete[] out_value;
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
-
|
|
|
498a18 |
+#ifndef OPENSSL_NO_DH
|
|
|
498a18 |
void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
|
|
|
498a18 |
|
|
|
8ab518 |
@@ -4246,7 +4421,7 @@ void DiffieHellman::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "DiffieHellmanGroup"),
|
|
|
498a18 |
t2->GetFunction());
|
|
|
498a18 |
}
|
|
|
498a18 |
-
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
bool DiffieHellman::Init(int primeLength, int g) {
|
|
|
498a18 |
dh = DH_new();
|
|
|
8ab518 |
@@ -4595,7 +4770,7 @@ bool DiffieHellman::VerifyContext() {
|
|
|
498a18 |
return true;
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
-
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
void ECDH::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
HandleScope scope(env->isolate());
|
|
|
498a18 |
|
|
|
8ab518 |
@@ -4613,7 +4788,7 @@ void ECDH::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH"),
|
|
|
498a18 |
t->GetFunction());
|
|
|
498a18 |
}
|
|
|
498a18 |
-
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
void ECDH::New(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
Environment* env = Environment::GetCurrent(args);
|
|
|
8ab518 |
@@ -5326,7 +5501,7 @@ void GetHashes(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
args.GetReturnValue().Set(ctx.arr);
|
|
|
498a18 |
}
|
|
|
498a18 |
|
|
|
498a18 |
-
|
|
|
498a18 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
void GetCurves(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
Environment* env = Environment::GetCurrent(args);
|
|
|
498a18 |
const size_t num_curves = EC_get_builtin_curves(nullptr, 0);
|
|
|
8ab518 |
@@ -5351,7 +5526,7 @@ void GetCurves(const FunctionCallbackInfo<Value>& args) {
|
|
|
498a18 |
|
|
|
498a18 |
args.GetReturnValue().Set(arr);
|
|
|
498a18 |
}
|
|
|
498a18 |
-
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
void Certificate::Initialize(Environment* env, Local<Object> target) {
|
|
|
498a18 |
HandleScope scope(env->isolate());
|
|
|
8ab518 |
@@ -5548,13 +5723,15 @@ void InitCryptoOnce() {
|
|
|
498a18 |
CRYPTO_set_locking_callback(crypto_lock_cb);
|
|
|
498a18 |
CRYPTO_THREADID_set_callback(crypto_threadid_cb);
|
|
|
498a18 |
|
|
|
498a18 |
-#ifdef NODE_FIPS_MODE
|
|
|
498a18 |
- if (!FIPS_mode_set(1)) {
|
|
|
498a18 |
- int err = ERR_get_error();
|
|
|
498a18 |
+#ifdef OPENSSL_FIPS
|
|
|
498a18 |
+ int err = FIPS_mode();
|
|
|
498a18 |
+ // Shouldn't this be a CLI switch?
|
|
|
498a18 |
+ if (err != NODE_FIPS_MODE && !FIPS_mode_set(NODE_FIPS_MODE)) {
|
|
|
8ab518 |
+ err = ERR_get_error();
|
|
|
498a18 |
fprintf(stderr, "openssl fips failed: %s\n", ERR_error_string(err, NULL));
|
|
|
498a18 |
UNREACHABLE();
|
|
|
498a18 |
}
|
|
|
498a18 |
-#endif // NODE_FIPS_MODE
|
|
|
498a18 |
+#endif // OPENSSL_FIPS
|
|
|
498a18 |
|
|
|
498a18 |
|
|
|
498a18 |
// Turn off compression. Saves memory and protects against CRIME attacks.
|
|
|
8ab518 |
@@ -5630,8 +5807,12 @@ void InitCrypto(Local<Object> target,
|
|
|
498a18 |
SecureContext::Initialize(env, target);
|
|
|
498a18 |
Connection::Initialize(env, target);
|
|
|
498a18 |
CipherBase::Initialize(env, target);
|
|
|
498a18 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
DiffieHellman::Initialize(env, target);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
ECDH::Initialize(env, target);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
Hmac::Initialize(env, target);
|
|
|
498a18 |
Hash::Initialize(env, target);
|
|
|
498a18 |
Sign::Initialize(env, target);
|
|
|
8ab518 |
@@ -5646,7 +5827,9 @@ void InitCrypto(Local<Object> target,
|
|
|
498a18 |
env->SetMethod(target, "getSSLCiphers", GetSSLCiphers);
|
|
|
498a18 |
env->SetMethod(target, "getCiphers", GetCiphers);
|
|
|
498a18 |
env->SetMethod(target, "getHashes", GetHashes);
|
|
|
498a18 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
env->SetMethod(target, "getCurves", GetCurves);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
env->SetMethod(target, "publicEncrypt",
|
|
|
498a18 |
PublicKeyCipher::Cipher
|
|
|
498a18 |
EVP_PKEY_encrypt_init,
|
|
|
498a18 |
diff --git a/src/node_crypto.h b/src/node_crypto.h
|
|
|
8ab518 |
index bf0c9f6..bb8e0e2 100644
|
|
|
498a18 |
--- a/src/node_crypto.h
|
|
|
498a18 |
+++ b/src/node_crypto.h
|
|
|
498a18 |
@@ -18,8 +18,12 @@
|
|
|
498a18 |
#include "v8.h"
|
|
|
498a18 |
|
|
|
498a18 |
#include <openssl/ssl.h>
|
|
|
498a18 |
+#ifndef OPENSSL_NO_EC
|
|
|
498a18 |
#include <openssl/ec.h>
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
#include <openssl/ecdh.h>
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
#ifndef OPENSSL_NO_ENGINE
|
|
|
498a18 |
# include <openssl/engine.h>
|
|
|
498a18 |
#endif // !OPENSSL_NO_ENGINE
|
|
|
498a18 |
@@ -101,8 +105,12 @@ class SecureContext : public BaseObject {
|
|
|
498a18 |
static void AddCRL(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
static void AddRootCerts(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
static void SetCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
static void SetECDHCurve(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
+#ifndef OPENSSL_NO_DH
|
|
|
498a18 |
static void SetDHParam(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
static void SetOptions(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
static void SetSessionIdContext(
|
|
|
498a18 |
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
@@ -273,7 +281,11 @@ class SSLWrap {
|
|
|
498a18 |
void* arg);
|
|
|
498a18 |
#endif // OPENSSL_NPN_NEGOTIATED
|
|
|
498a18 |
static int TLSExtStatusCallback(SSL* s, void* arg);
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
static int SSLCertCallback(SSL* s, void* arg);
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+ static int SSLCertCallback(SSL* s, X509 **x509, EVP_PKEY **pkey);
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
static void SSLGetter(v8::Local<v8::String> property,
|
|
|
498a18 |
const v8::PropertyCallbackInfo<v8::Value>& info);
|
|
|
498a18 |
|
|
|
8ab518 |
@@ -639,6 +651,7 @@ class PublicKeyCipher {
|
|
|
498a18 |
static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
498a18 |
};
|
|
|
8ab518 |
|
|
|
498a18 |
+#ifndef OPENSSL_NO_DH
|
|
|
498a18 |
class DiffieHellman : public BaseObject {
|
|
|
498a18 |
public:
|
|
|
498a18 |
~DiffieHellman() override {
|
|
|
8ab518 |
@@ -684,7 +697,9 @@ class DiffieHellman : public BaseObject {
|
|
|
498a18 |
int verifyError_;
|
|
|
498a18 |
DH* dh;
|
|
|
498a18 |
};
|
|
|
498a18 |
+#endif
|
|
|
498a18 |
|
|
|
498a18 |
+#ifndef OPENSSL_NO_ECDH
|
|
|
498a18 |
class ECDH : public BaseObject {
|
|
|
498a18 |
public:
|
|
|
498a18 |
~ECDH() override {
|
|
|
8ab518 |
@@ -720,6 +735,7 @@ class ECDH : public BaseObject {
|
|
|
498a18 |
EC_KEY* key_;
|
|
|
498a18 |
const EC_GROUP* group_;
|
|
|
498a18 |
};
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
|
|
|
498a18 |
class Certificate : public AsyncWrap {
|
|
|
498a18 |
public:
|
|
|
498a18 |
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
|
|
|
8ab518 |
index 116a379..ad44ed6 100644
|
|
|
498a18 |
--- a/src/tls_wrap.cc
|
|
|
498a18 |
+++ b/src/tls_wrap.cc
|
|
|
8ab518 |
@@ -144,7 +144,15 @@ void TLSWrap::InitSSL() {
|
|
|
498a18 |
|
|
|
498a18 |
InitNPN(sc_);
|
|
|
8ab518 |
|
|
|
498a18 |
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
|
|
498a18 |
SSL_set_cert_cb(ssl_, SSLWrap<TLSWrap>::SSLCertCallback, this);
|
|
|
498a18 |
+#else
|
|
|
498a18 |
+ /* 1.0.1 and less have at most for the client side the function
|
|
|
498a18 |
+ SSL_CTX_set_client_cert_cb(ssl_->ctx, SSLWrap<TLSWrap>::SSLCertCallback);
|
|
|
498a18 |
+ but on the client it is not needed/used by this implementation.
|
|
|
498a18 |
+ For more info see comments in src/node_crypto.cc Connection::New().
|
|
|
498a18 |
+ */
|
|
|
498a18 |
+#endif
|
|
|
8ab518 |
|
|
|
498a18 |
if (is_server()) {
|
|
|
498a18 |
SSL_set_accept_state(ssl_);
|