Blame SOURCES/nodejs-disable-openssl-1.0.2-features.patch

498a18
From f32cc672fd1bf3012427f0a2f4188e47ca45f4aa Mon Sep 17 00:00:00 2001
498a18
From: Tomas Hrcka <thrcka@redhat.com>
498a18
Date: Tue, 5 Apr 2016 17:02:03 +0200
498a18
Subject: [PATCH] pllm
498a18
498a18
---
498a18
 doc/api/tls.markdown  |   5 ++
498a18
 src/node_constants.cc |   7 ++
498a18
 src/node_crypto.cc    | 241 +++++++++++++++++++++++++++++++++++++++++++-------
498a18
 src/node_crypto.h     |  18 +++-
498a18
 src/tls_wrap.cc       |  10 ++-
498a18
 5 files changed, 247 insertions(+), 34 deletions(-)
498a18
498a18
diff --git a/doc/api/tls.markdown b/doc/api/tls.markdown
498a18
index 2d23e3f..f2f0c57 100644
498a18
--- a/doc/api/tls.markdown
498a18
+++ b/doc/api/tls.markdown
498a18
@@ -130,6 +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.
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
 
498a18
 ## Perfect Forward Secrecy
498a18
diff --git a/src/node_constants.cc b/src/node_constants.cc
498a18
index 51c2ee8..ca8dae4 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>
498a18
+#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
498a18
+# 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
498a18
index 382a42f..a9570fe 100644
498a18
--- a/src/node_crypto.cc
498a18
+++ b/src/node_crypto.cc
498a18
@@ -34,6 +34,83 @@
498a18
 #define OPENSSL_CONST
498a18
 #endif
498a18
 
498a18
+#ifndef SSL_get_server_tmp_key
498a18
+/*
498a18
+      1.0.2 SSL_get_server_tmp_key(s, pk) "backport". BAD HACK!!!
498a18
+      NOTE: This imports "foreign" knowledge and thus will break, when SESS_CERT
498a18
+      or CERT_PKEY change, which is definitely the case for the later for
498a18
+      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) {
498a18
+	if (s->server || !s->session || !s->session->sess_cert)
498a18
+		return 0;
498a18
+	else {
498a18
+		SESS_CERT *sc;
498a18
+		EVP_PKEY *ptmp;
498a18
+		int rv = 0;
498a18
+		sc = s->session->sess_cert;
498a18
+#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DH) && !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDH)
498a18
+		if (!sc->peer_rsa_tmp && !sc->peer_dh_tmp && !sc->peer_ecdh_tmp)
498a18
+			return 0;
498a18
+#endif
498a18
+		ptmp = EVP_PKEY_new();
498a18
+		if (!ptmp)
498a18
+			return 0;
498a18
+		if (0) ;
498a18
+#ifndef OPENSSL_NO_RSA
498a18
+		else if (sc->peer_rsa_tmp)
498a18
+			rv = EVP_PKEY_set1_RSA(ptmp, sc->peer_rsa_tmp);
498a18
+#endif
498a18
+#ifndef OPENSSL_NO_DH
498a18
+		else if (sc->peer_dh_tmp)
498a18
+			rv = EVP_PKEY_set1_DH(ptmp, sc->peer_dh_tmp);
498a18
+#endif
498a18
+#ifndef OPENSSL_NO_ECDH
498a18
+		else if (sc->peer_ecdh_tmp)
498a18
+			rv = EVP_PKEY_set1_EC_KEY(ptmp, sc->peer_ecdh_tmp);
498a18
+#endif
498a18
+		if (rv) {
498a18
+			*(EVP_PKEY **)parg = ptmp;
498a18
+			return 1;
498a18
+		}
498a18
+		EVP_PKEY_free(ptmp);
498a18
+		return 0;
498a18
+	}
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()) {      \
498a18
@@ -164,7 +241,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
 
498a18
@@ -258,8 +339,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
498a18
@@ -281,8 +377,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);
498a18
@@ -528,10 +628,20 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
498a18
 
498a18
     for (int i = 0; i < sk_X509_num(extra_certs); i++) {
498a18
       X509* ca = sk_X509_value(extra_certs, i);
498a18
-
498a18
-      // NOTE: Increments reference count on `ca`
498a18
-      r = SSL_CTX_add1_chain_cert(ctx, ca);
498a18
-
498a18
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
498a18
+		// If ctx->cert->key != NULL create ctx->cert->key->chain if not
498a18
+		// already there, push 'ca' to this chain and finally increment the ca
498a18
+		// reference count by 1 (this is the diff between *_add1_* and *_add0_*
498a18
+		// - the later increments by 0 ;-)) and return 1. Otherwise or if
498a18
+		// something fails in between, return 0.
498a18
+		r = SSL_CTX_add1_chain_cert(ctx, ca);
498a18
+#else
498a18
+		// Create ctx->extra_certs if not already there, just push 'ca' to this
498a18
+		// chain and return 1. If something fails, return 0.
498a18
+		// NOTE: 1.0.1- does not support multiple certs having its own chain in
498a18
+		//       a single context. There is just one: extra_chain!
498a18
+		r = SSL_CTX_add_extra_chain_cert(ctx, ca);
498a18
+#endif
498a18
       if (!r) {
498a18
         ret = 0;
498a18
         *issuer = nullptr;
498a18
@@ -797,7 +907,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) {
498a18
   SecureContext* sc = Unwrap<SecureContext>(args.Holder());
498a18
   Environment* env = sc->env();
498a18
@@ -822,8 +932,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) {
498a18
   SecureContext* sc = Unwrap<SecureContext>(args.This());
498a18
   Environment* env = sc->env();
498a18
@@ -861,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) {
498a18
   SecureContext* sc = Unwrap<SecureContext>(args.Holder());
498a18
@@ -2087,7 +2198,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
498a18
+/* NOTE: For now this callback gets usually never called dueto 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())
498a18
@@ -2159,19 +2275,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
498a18
+	x509 = SSL_CTX_get0_certificate(sc->ctx_);
498a18
+	pkey = SSL_CTX_get0_privatekey(sc->ctx_);
498a18
+	rv = SSL_CTX_get0_chain_certs(sc->ctx_, &chain);
498a18
+#else
498a18
+	SSL *ssl = SSL_new(sc->ctx_);
498a18
+	rv = SSL_CTX_get_extra_chain_certs(sc->ctx_, &chain);
498a18
+	if (ssl) {
498a18
+		SSL_set_connect_state(ssl);	/* just cleanup/reset state - cheap */
498a18
+		x509 = SSL_get_certificate(ssl);
498a18
+		SSL_free(ssl);
498a18
+	} else {
498a18
+		x509 = NULL;
498a18
+		pkey = NULL;
498a18
+	}
498a18
+#endif
498a18
 
498a18
-    rv = SSL_CTX_get0_chain_certs(sc->ctx_, &chain);
498a18
     if (rv)
498a18
-      rv = SSL_use_certificate(w->ssl_, x509);
498a18
+	rv = SSL_use_certificate(w->ssl_, x509);
498a18
     if (rv)
498a18
-      rv = SSL_use_PrivateKey(w->ssl_, pkey);
498a18
-    if (rv && chain != nullptr)
498a18
-      rv = SSL_set1_chain(w->ssl_, chain);
498a18
+        rv = SSL_use_PrivateKey(w->ssl_, pkey);
498a18
+    if (rv && chain != nullptr) {
498a18
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
498a18
+	// replaces w->ssl_->cert->key->chain with a copy of the given chain,
498a18
+	// which is allowed to be NULL
498a18
+	rv = SSL_set1_chain(w->ssl_, chain);
498a18
+#else
498a18
+	// just replace the extra chain with the given chain - 1.0.1- does not
498a18
+	// support chain per cert
498a18
+	SSL_CTX_clear_extra_chain_certs(w->ssl_->ctx);
498a18
+	if (chain != NULL) {
498a18
+		int i;
498a18
+		SSL_CTX* ctx = w->ssl_->ctx;
498a18
+		for (i = 0; i < sk_X509_num(chain); i++) {
498a18
+			// can't do anything: however others might be ok and still
498a18
+			// satisfy requirements
498a18
+			SSL_CTX_add_extra_chain_cert(ctx, sk_X509_value(chain,i));
498a18
+		}
498a18
+	}
498a18
+	rv = 1;
498a18
+#endif
498a18
+	}
498a18
     if (rv)
498a18
       rv = w->SetCACerts(sc);
498a18
     if (!rv) {
498a18
@@ -2233,10 +2383,15 @@ 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
-
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
498a18
+  
498a18
   STACK_OF(X509_NAME)* list = SSL_dup_CA_list(
498a18
       SSL_CTX_get_client_CA_list(sc->ctx_));
498a18
 
498a18
@@ -2513,8 +2668,11 @@ inline int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
498a18
   // Server does not need to check the whitelist.
498a18
   SSL* ssl = static_cast<SSL*>(
498a18
       X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
498a18
-
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
498a18
@@ -2594,8 +2752,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) {
498a18
@@ -3689,7 +3860,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);
498a18
@@ -3710,7 +3882,8 @@ SignBase::Error Sign::SignFinal(const char* key_pem,
498a18
       goto exit;
498a18
     }
498a18
   }
498a18
-#endif  // NODE_FIPS_MODE
498a18
+}
498a18
+#endif  // OPENSSL_FIPS
498a18
 
498a18
   if (EVP_SignFinal(&mdctx_, *sig, sig_len, pkey))
498a18
     fatal = false;
498a18
@@ -4125,7 +4298,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
 
498a18
@@ -4177,7 +4350,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();
498a18
@@ -4517,7 +4690,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
 
498a18
@@ -4535,7 +4708,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);
498a18
@@ -5240,7 +5413,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);
498a18
@@ -5265,7 +5438,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());
498a18
@@ -5462,13 +5635,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)) {
498a18
+    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.
498a18
@@ -5544,8 +5719,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);
498a18
@@ -5560,7 +5739,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
498a18
index cb94650..e1c0032 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
 
498a18
@@ -645,7 +657,7 @@ class PublicKeyCipher {
498a18
             EVP_PKEY_cipher_t EVP_PKEY_cipher>
498a18
   static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
498a18
 };
498a18
-
498a18
+#ifndef OPENSSL_NO_DH
498a18
 class DiffieHellman : public BaseObject {
498a18
  public:
498a18
   ~DiffieHellman() override {
498a18
@@ -691,7 +703,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 {
498a18
@@ -727,7 +741,7 @@ class ECDH : public BaseObject {
498a18
   EC_KEY* key_;
498a18
   const EC_GROUP* group_;
498a18
 };
498a18
-
498a18
+#endif
498a18
 class Certificate : public AsyncWrap {
498a18
  public:
498a18
   static void Initialize(Environment* env, v8::Local<v8::Object> target);
498a18
diff --git a/src/tls_wrap.cc b/src/tls_wrap.cc
498a18
index 85730b3..47441bd 100644
498a18
--- a/src/tls_wrap.cc
498a18
+++ b/src/tls_wrap.cc
498a18
@@ -140,9 +140,15 @@ void TLSWrap::InitSSL() {
498a18
 #endif  // SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
498a18
 
498a18
   InitNPN(sc_);
498a18
-
498a18
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
498a18
   SSL_set_cert_cb(ssl_, SSLWrap<TLSWrap>::SSLCertCallback, this);
498a18
-
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
498a18
   if (is_server()) {
498a18
     SSL_set_accept_state(ssl_);
498a18
   } else if (is_client()) {
498a18
-- 
498a18
2.5.5
498a18