mirror of
https://github.com/nodejs/node.git
synced 2024-12-01 16:10:02 +01:00
53bef423f3
Exposes SSL_CTX_set_keylog_callback in the form of a `keylog` event that is emitted on clients and servers. This enables easy debugging of TLS connections with i.e. Wireshark, which is a long-requested feature. PR-URL: https://github.com/nodejs/node/pull/27654 Refs: https://github.com/nodejs/node/issues/2363 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Sam Roberts <vieuxtech@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
835 lines
28 KiB
C++
835 lines
28 KiB
C++
// Copyright Joyent, Inc. and other Node contributors.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
|
// copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to permit
|
|
// persons to whom the Software is furnished to do so, subject to the
|
|
// following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be included
|
|
// in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
// USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
#ifndef SRC_NODE_CRYPTO_H_
|
|
#define SRC_NODE_CRYPTO_H_
|
|
|
|
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
// ClientHelloParser
|
|
#include "node_crypto_clienthello.h"
|
|
|
|
#include "env.h"
|
|
#include "base_object.h"
|
|
#include "util.h"
|
|
|
|
#include "v8.h"
|
|
|
|
#include <openssl/err.h>
|
|
#include <openssl/ssl.h>
|
|
|
|
namespace node {
|
|
namespace crypto {
|
|
|
|
// Forcibly clear OpenSSL's error stack on return. This stops stale errors
|
|
// from popping up later in the lifecycle of crypto operations where they
|
|
// would cause spurious failures. It's a rather blunt method, though.
|
|
// ERR_clear_error() isn't necessarily cheap either.
|
|
struct ClearErrorOnReturn {
|
|
~ClearErrorOnReturn() { ERR_clear_error(); }
|
|
};
|
|
|
|
// Pop errors from OpenSSL's error stack that were added
|
|
// between when this was constructed and destructed.
|
|
struct MarkPopErrorOnReturn {
|
|
MarkPopErrorOnReturn() { ERR_set_mark(); }
|
|
~MarkPopErrorOnReturn() { ERR_pop_to_mark(); }
|
|
};
|
|
|
|
// Define smart pointers for the most commonly used OpenSSL types:
|
|
using X509Pointer = DeleteFnPtr<X509, X509_free>;
|
|
using BIOPointer = DeleteFnPtr<BIO, BIO_free_all>;
|
|
using SSLCtxPointer = DeleteFnPtr<SSL_CTX, SSL_CTX_free>;
|
|
using SSLSessionPointer = DeleteFnPtr<SSL_SESSION, SSL_SESSION_free>;
|
|
using SSLPointer = DeleteFnPtr<SSL, SSL_free>;
|
|
using PKCS8Pointer = DeleteFnPtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
|
|
using EVPKeyPointer = DeleteFnPtr<EVP_PKEY, EVP_PKEY_free>;
|
|
using EVPKeyCtxPointer = DeleteFnPtr<EVP_PKEY_CTX, EVP_PKEY_CTX_free>;
|
|
using EVPMDPointer = DeleteFnPtr<EVP_MD_CTX, EVP_MD_CTX_free>;
|
|
using RSAPointer = DeleteFnPtr<RSA, RSA_free>;
|
|
using ECPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
|
using BignumPointer = DeleteFnPtr<BIGNUM, BN_free>;
|
|
using NetscapeSPKIPointer = DeleteFnPtr<NETSCAPE_SPKI, NETSCAPE_SPKI_free>;
|
|
using ECGroupPointer = DeleteFnPtr<EC_GROUP, EC_GROUP_free>;
|
|
using ECPointPointer = DeleteFnPtr<EC_POINT, EC_POINT_free>;
|
|
using ECKeyPointer = DeleteFnPtr<EC_KEY, EC_KEY_free>;
|
|
using DHPointer = DeleteFnPtr<DH, DH_free>;
|
|
|
|
extern int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx);
|
|
|
|
extern void UseExtraCaCerts(const std::string& file);
|
|
|
|
void InitCryptoOnce();
|
|
|
|
class SecureContext : public BaseObject {
|
|
public:
|
|
~SecureContext() override {
|
|
Reset();
|
|
}
|
|
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(SecureContext)
|
|
SET_SELF_SIZE(SecureContext)
|
|
|
|
SSLCtxPointer ctx_;
|
|
X509Pointer cert_;
|
|
X509Pointer issuer_;
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
bool client_cert_engine_provided_ = false;
|
|
#endif // !OPENSSL_NO_ENGINE
|
|
|
|
static const int kMaxSessionSize = 10 * 1024;
|
|
|
|
// See TicketKeyCallback
|
|
static const int kTicketKeyReturnIndex = 0;
|
|
static const int kTicketKeyHMACIndex = 1;
|
|
static const int kTicketKeyAESIndex = 2;
|
|
static const int kTicketKeyNameIndex = 3;
|
|
static const int kTicketKeyIVIndex = 4;
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
unsigned char ticket_key_name_[16];
|
|
unsigned char ticket_key_aes_[16];
|
|
unsigned char ticket_key_hmac_[16];
|
|
#endif
|
|
|
|
protected:
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
static const int64_t kExternalSize = sizeof(SSL_CTX);
|
|
#else
|
|
// OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size
|
|
// as of OpenSSL 1.1.0f.
|
|
static const int64_t kExternalSize = 872;
|
|
#endif
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetCert(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void AddCACert(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void AddCRL(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void AddRootCerts(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetCipherSuites(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetCiphers(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetECDHCurve(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetDHParam(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetOptions(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetSessionIdContext(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetSessionTimeout(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetMinProto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetMaxProto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetMinProto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetMaxProto(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void LoadPKCS12(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
static void SetClientCertEngine(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
#endif // !OPENSSL_NO_ENGINE
|
|
static void GetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetTicketKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetFreeListLength(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void EnableTicketKeyCallback(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void CtxGetter(const v8::FunctionCallbackInfo<v8::Value>& info);
|
|
|
|
template <bool primary>
|
|
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static int TicketKeyCallback(SSL* ssl,
|
|
unsigned char* name,
|
|
unsigned char* iv,
|
|
EVP_CIPHER_CTX* ectx,
|
|
HMAC_CTX* hctx,
|
|
int enc);
|
|
|
|
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
|
|
static int TicketCompatibilityCallback(SSL* ssl,
|
|
unsigned char* name,
|
|
unsigned char* iv,
|
|
EVP_CIPHER_CTX* ectx,
|
|
HMAC_CTX* hctx,
|
|
int enc);
|
|
#endif
|
|
|
|
SecureContext(Environment* env, v8::Local<v8::Object> wrap)
|
|
: BaseObject(env, wrap) {
|
|
MakeWeak();
|
|
env->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize);
|
|
}
|
|
|
|
inline void Reset() {
|
|
if (ctx_ != nullptr) {
|
|
env()->isolate()->AdjustAmountOfExternalAllocatedMemory(-kExternalSize);
|
|
}
|
|
ctx_.reset();
|
|
cert_.reset();
|
|
issuer_.reset();
|
|
}
|
|
};
|
|
|
|
// SSLWrap implicitly depends on the inheriting class' handle having an
|
|
// internal pointer to the Base class.
|
|
template <class Base>
|
|
class SSLWrap {
|
|
public:
|
|
enum Kind {
|
|
kClient,
|
|
kServer
|
|
};
|
|
|
|
SSLWrap(Environment* env, SecureContext* sc, Kind kind)
|
|
: env_(env),
|
|
kind_(kind),
|
|
next_sess_(nullptr),
|
|
session_callbacks_(false),
|
|
awaiting_new_session_(false),
|
|
cert_cb_(nullptr),
|
|
cert_cb_arg_(nullptr),
|
|
cert_cb_running_(false) {
|
|
ssl_.reset(SSL_new(sc->ctx_.get()));
|
|
CHECK(ssl_);
|
|
env_->isolate()->AdjustAmountOfExternalAllocatedMemory(kExternalSize);
|
|
}
|
|
|
|
virtual ~SSLWrap() {
|
|
DestroySSL();
|
|
}
|
|
|
|
inline void enable_session_callbacks() { session_callbacks_ = true; }
|
|
inline bool is_server() const { return kind_ == kServer; }
|
|
inline bool is_client() const { return kind_ == kClient; }
|
|
inline bool is_awaiting_new_session() const { return awaiting_new_session_; }
|
|
inline bool is_waiting_cert_cb() const { return cert_cb_ != nullptr; }
|
|
|
|
protected:
|
|
typedef void (*CertCb)(void* arg);
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
// Size allocated by OpenSSL: one for SSL structure, one for SSL3_STATE and
|
|
// some for buffers.
|
|
// NOTE: Actually it is much more than this
|
|
static const int64_t kExternalSize =
|
|
sizeof(SSL) + sizeof(SSL3_STATE) + 42 * 1024;
|
|
#else
|
|
// OpenSSL 1.1.0 has opaque structures. This is an estimate based on the size
|
|
// as of OpenSSL 1.1.0f.
|
|
static const int64_t kExternalSize = 4448 + 1024 + 42 * 1024;
|
|
#endif
|
|
|
|
static void ConfigureSecureContext(SecureContext* sc);
|
|
static void AddMethods(Environment* env, v8::Local<v8::FunctionTemplate> t);
|
|
|
|
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
static SSL_SESSION* GetSessionCallback(SSL* s,
|
|
unsigned char* key,
|
|
int len,
|
|
int* copy);
|
|
#else
|
|
static SSL_SESSION* GetSessionCallback(SSL* s,
|
|
const unsigned char* key,
|
|
int len,
|
|
int* copy);
|
|
#endif
|
|
static int NewSessionCallback(SSL* s, SSL_SESSION* sess);
|
|
static void KeylogCallback(const SSL* s, const char* line);
|
|
static void OnClientHello(void* arg,
|
|
const ClientHelloParser::ClientHello& hello);
|
|
|
|
static void GetPeerCertificate(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetCertificate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetFinished(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPeerFinished(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void LoadSession(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void IsSessionReused(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void VerifyError(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetCipher(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 GetTLSTicket(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void NewSessionDone(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetOCSPResponse(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void RequestOCSP(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetEphemeralKeyInfo(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetProtocol(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
#ifdef SSL_set_max_send_fragment
|
|
static void SetMaxSendFragment(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
#endif // SSL_set_max_send_fragment
|
|
|
|
static void GetALPNNegotiatedProto(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetALPNProtocols(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static int SelectALPNCallback(SSL* s,
|
|
const unsigned char** out,
|
|
unsigned char* outlen,
|
|
const unsigned char* in,
|
|
unsigned int inlen,
|
|
void* arg);
|
|
static int TLSExtStatusCallback(SSL* s, void* arg);
|
|
static int SSLCertCallback(SSL* s, void* arg);
|
|
|
|
void DestroySSL();
|
|
void WaitForCertCb(CertCb cb, void* arg);
|
|
void SetSNIContext(SecureContext* sc);
|
|
int SetCACerts(SecureContext* sc);
|
|
|
|
inline Environment* ssl_env() const {
|
|
return env_;
|
|
}
|
|
|
|
Environment* const env_;
|
|
Kind kind_;
|
|
SSLSessionPointer next_sess_;
|
|
SSLPointer ssl_;
|
|
bool session_callbacks_;
|
|
bool awaiting_new_session_;
|
|
|
|
// SSL_set_cert_cb
|
|
CertCb cert_cb_;
|
|
void* cert_cb_arg_;
|
|
bool cert_cb_running_;
|
|
|
|
ClientHelloParser hello_parser_;
|
|
|
|
v8::Global<v8::ArrayBufferView> ocsp_response_;
|
|
v8::Global<v8::Value> sni_context_;
|
|
|
|
friend class SecureContext;
|
|
};
|
|
|
|
// A helper class representing a read-only byte array. When deallocated, its
|
|
// contents are zeroed.
|
|
class ByteSource {
|
|
public:
|
|
ByteSource() = default;
|
|
ByteSource(ByteSource&& other);
|
|
~ByteSource();
|
|
|
|
ByteSource& operator=(ByteSource&& other);
|
|
|
|
const char* get() const;
|
|
size_t size() const;
|
|
|
|
static ByteSource FromStringOrBuffer(Environment* env,
|
|
v8::Local<v8::Value> value);
|
|
|
|
static ByteSource FromString(Environment* env,
|
|
v8::Local<v8::String> str,
|
|
bool ntc = false);
|
|
|
|
static ByteSource FromBuffer(v8::Local<v8::Value> buffer,
|
|
bool ntc = false);
|
|
|
|
static ByteSource NullTerminatedCopy(Environment* env,
|
|
v8::Local<v8::Value> value);
|
|
|
|
static ByteSource FromSymmetricKeyObject(v8::Local<v8::Value> handle);
|
|
|
|
ByteSource(const ByteSource&) = delete;
|
|
ByteSource& operator=(const ByteSource&) = delete;
|
|
|
|
private:
|
|
const char* data_ = nullptr;
|
|
char* allocated_data_ = nullptr;
|
|
size_t size_ = 0;
|
|
|
|
ByteSource(const char* data, char* allocated_data, size_t size);
|
|
|
|
static ByteSource Allocated(char* data, size_t size);
|
|
static ByteSource Foreign(const char* data, size_t size);
|
|
};
|
|
|
|
enum PKEncodingType {
|
|
// RSAPublicKey / RSAPrivateKey according to PKCS#1.
|
|
kKeyEncodingPKCS1,
|
|
// PrivateKeyInfo or EncryptedPrivateKeyInfo according to PKCS#8.
|
|
kKeyEncodingPKCS8,
|
|
// SubjectPublicKeyInfo according to X.509.
|
|
kKeyEncodingSPKI,
|
|
// ECPrivateKey according to SEC1.
|
|
kKeyEncodingSEC1
|
|
};
|
|
|
|
enum PKFormatType {
|
|
kKeyFormatDER,
|
|
kKeyFormatPEM
|
|
};
|
|
|
|
struct AsymmetricKeyEncodingConfig {
|
|
bool output_key_object_;
|
|
PKFormatType format_;
|
|
v8::Maybe<PKEncodingType> type_ = v8::Nothing<PKEncodingType>();
|
|
};
|
|
|
|
typedef AsymmetricKeyEncodingConfig PublicKeyEncodingConfig;
|
|
|
|
struct PrivateKeyEncodingConfig : public AsymmetricKeyEncodingConfig {
|
|
const EVP_CIPHER* cipher_;
|
|
ByteSource passphrase_;
|
|
};
|
|
|
|
enum KeyType {
|
|
kKeyTypeSecret,
|
|
kKeyTypePublic,
|
|
kKeyTypePrivate
|
|
};
|
|
|
|
// This uses the built-in reference counter of OpenSSL to manage an EVP_PKEY
|
|
// which is slightly more efficient than using a shared pointer and easier to
|
|
// use.
|
|
class ManagedEVPPKey {
|
|
public:
|
|
ManagedEVPPKey() = default;
|
|
explicit ManagedEVPPKey(EVPKeyPointer&& pkey);
|
|
ManagedEVPPKey(const ManagedEVPPKey& that);
|
|
ManagedEVPPKey& operator=(const ManagedEVPPKey& that);
|
|
|
|
operator bool() const;
|
|
EVP_PKEY* get() const;
|
|
|
|
private:
|
|
EVPKeyPointer pkey_;
|
|
};
|
|
|
|
class KeyObject : public BaseObject {
|
|
public:
|
|
static v8::Local<v8::Function> Initialize(Environment* env,
|
|
v8::Local<v8::Object> target);
|
|
|
|
static v8::MaybeLocal<v8::Object> Create(Environment* env,
|
|
KeyType type,
|
|
const ManagedEVPPKey& pkey);
|
|
|
|
// TODO(tniessen): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(KeyObject)
|
|
SET_SELF_SIZE(KeyObject)
|
|
|
|
KeyType GetKeyType() const;
|
|
|
|
// These functions allow unprotected access to the raw key material and should
|
|
// only be used to implement cryptograohic operations requiring the key.
|
|
ManagedEVPPKey GetAsymmetricKey() const;
|
|
const char* GetSymmetricKey() const;
|
|
size_t GetSymmetricKeySize() const;
|
|
|
|
protected:
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
void InitSecret(v8::Local<v8::ArrayBufferView> abv);
|
|
void InitPublic(const ManagedEVPPKey& pkey);
|
|
void InitPrivate(const ManagedEVPPKey& pkey);
|
|
|
|
static void GetAsymmetricKeyType(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
v8::Local<v8::Value> GetAsymmetricKeyType() const;
|
|
|
|
static void GetSymmetricKeySize(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void Export(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
v8::Local<v8::Value> ExportSecretKey() const;
|
|
v8::MaybeLocal<v8::Value> ExportPublicKey(
|
|
const PublicKeyEncodingConfig& config) const;
|
|
v8::MaybeLocal<v8::Value> ExportPrivateKey(
|
|
const PrivateKeyEncodingConfig& config) const;
|
|
|
|
KeyObject(Environment* env,
|
|
v8::Local<v8::Object> wrap,
|
|
KeyType key_type)
|
|
: BaseObject(env, wrap),
|
|
key_type_(key_type),
|
|
symmetric_key_(nullptr, nullptr) {
|
|
MakeWeak();
|
|
}
|
|
|
|
private:
|
|
const KeyType key_type_;
|
|
std::unique_ptr<char, std::function<void(char*)>> symmetric_key_;
|
|
unsigned int symmetric_key_len_;
|
|
ManagedEVPPKey asymmetric_key_;
|
|
};
|
|
|
|
class CipherBase : public BaseObject {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(CipherBase)
|
|
SET_SELF_SIZE(CipherBase)
|
|
|
|
protected:
|
|
enum CipherKind {
|
|
kCipher,
|
|
kDecipher
|
|
};
|
|
enum UpdateResult {
|
|
kSuccess,
|
|
kErrorMessageSize,
|
|
kErrorState
|
|
};
|
|
enum AuthTagState {
|
|
kAuthTagUnknown,
|
|
kAuthTagKnown,
|
|
kAuthTagPassedToOpenSSL
|
|
};
|
|
static const unsigned kNoAuthTagLength = static_cast<unsigned>(-1);
|
|
|
|
void CommonInit(const char* cipher_type,
|
|
const EVP_CIPHER* cipher,
|
|
const unsigned char* key,
|
|
int key_len,
|
|
const unsigned char* iv,
|
|
int iv_len,
|
|
unsigned int auth_tag_len);
|
|
void Init(const char* cipher_type,
|
|
const char* key_buf,
|
|
int key_buf_len,
|
|
unsigned int auth_tag_len);
|
|
void InitIv(const char* cipher_type,
|
|
const unsigned char* key,
|
|
int key_len,
|
|
const unsigned char* iv,
|
|
int iv_len,
|
|
unsigned int auth_tag_len);
|
|
bool InitAuthenticated(const char* cipher_type, int iv_len,
|
|
unsigned int auth_tag_len);
|
|
bool CheckCCMMessageLength(int message_len);
|
|
UpdateResult Update(const char* data, int len, AllocatedBuffer* out);
|
|
bool Final(AllocatedBuffer* out);
|
|
bool SetAutoPadding(bool auto_padding);
|
|
|
|
bool IsAuthenticatedMode() const;
|
|
bool SetAAD(const char* data, unsigned int len, int plaintext_len);
|
|
bool MaybePassAuthTagToOpenSSL();
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Init(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void InitIv(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Update(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void Final(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAutoPadding(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
static void GetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAuthTag(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetAAD(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
CipherBase(Environment* env,
|
|
v8::Local<v8::Object> wrap,
|
|
CipherKind kind)
|
|
: BaseObject(env, wrap),
|
|
ctx_(nullptr),
|
|
kind_(kind),
|
|
auth_tag_state_(kAuthTagUnknown),
|
|
auth_tag_len_(kNoAuthTagLength),
|
|
pending_auth_failed_(false) {
|
|
MakeWeak();
|
|
}
|
|
|
|
private:
|
|
DeleteFnPtr<EVP_CIPHER_CTX, EVP_CIPHER_CTX_free> ctx_;
|
|
const CipherKind kind_;
|
|
AuthTagState auth_tag_state_;
|
|
unsigned int auth_tag_len_;
|
|
char auth_tag_[EVP_GCM_TLS_TAG_LEN];
|
|
bool pending_auth_failed_;
|
|
int max_message_size_;
|
|
};
|
|
|
|
class Hmac : public BaseObject {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(Hmac)
|
|
SET_SELF_SIZE(Hmac)
|
|
|
|
protected:
|
|
void HmacInit(const char* hash_type, const char* key, int key_len);
|
|
bool HmacUpdate(const char* data, int len);
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void HmacInit(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void HmacUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void HmacDigest(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
Hmac(Environment* env, v8::Local<v8::Object> wrap)
|
|
: BaseObject(env, wrap),
|
|
ctx_(nullptr) {
|
|
MakeWeak();
|
|
}
|
|
|
|
private:
|
|
DeleteFnPtr<HMAC_CTX, HMAC_CTX_free> ctx_;
|
|
};
|
|
|
|
class Hash : public BaseObject {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(Hash)
|
|
SET_SELF_SIZE(Hash)
|
|
|
|
bool HashInit(const char* hash_type);
|
|
bool HashUpdate(const char* data, int len);
|
|
|
|
protected:
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void HashUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void HashDigest(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
Hash(Environment* env, v8::Local<v8::Object> wrap)
|
|
: BaseObject(env, wrap),
|
|
mdctx_(nullptr) {
|
|
MakeWeak();
|
|
}
|
|
|
|
private:
|
|
EVPMDPointer mdctx_;
|
|
};
|
|
|
|
class SignBase : public BaseObject {
|
|
public:
|
|
typedef enum {
|
|
kSignOk,
|
|
kSignUnknownDigest,
|
|
kSignInit,
|
|
kSignNotInitialised,
|
|
kSignUpdate,
|
|
kSignPrivateKey,
|
|
kSignPublicKey
|
|
} Error;
|
|
|
|
SignBase(Environment* env, v8::Local<v8::Object> wrap)
|
|
: BaseObject(env, wrap) {
|
|
}
|
|
|
|
Error Init(const char* sign_type);
|
|
Error Update(const char* data, int len);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(SignBase)
|
|
SET_SELF_SIZE(SignBase)
|
|
|
|
protected:
|
|
void CheckThrow(Error error);
|
|
|
|
EVPMDPointer mdctx_;
|
|
};
|
|
|
|
class Sign : public SignBase {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
struct SignResult {
|
|
Error error;
|
|
AllocatedBuffer signature;
|
|
|
|
explicit SignResult(
|
|
Error err,
|
|
AllocatedBuffer&& sig = AllocatedBuffer())
|
|
: error(err), signature(std::move(sig)) {}
|
|
};
|
|
|
|
SignResult SignFinal(
|
|
const ManagedEVPPKey& pkey,
|
|
int padding,
|
|
const v8::Maybe<int>& saltlen);
|
|
|
|
protected:
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SignInit(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SignUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SignFinal(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
Sign(Environment* env, v8::Local<v8::Object> wrap) : SignBase(env, wrap) {
|
|
MakeWeak();
|
|
}
|
|
};
|
|
|
|
class Verify : public SignBase {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
Error VerifyFinal(const ManagedEVPPKey& key,
|
|
const char* sig,
|
|
int siglen,
|
|
int padding,
|
|
const v8::Maybe<int>& saltlen,
|
|
bool* verify_result);
|
|
|
|
protected:
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void VerifyInit(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void VerifyUpdate(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void VerifyFinal(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
Verify(Environment* env, v8::Local<v8::Object> wrap) : SignBase(env, wrap) {
|
|
MakeWeak();
|
|
}
|
|
};
|
|
|
|
class PublicKeyCipher {
|
|
public:
|
|
typedef int (*EVP_PKEY_cipher_init_t)(EVP_PKEY_CTX* ctx);
|
|
typedef int (*EVP_PKEY_cipher_t)(EVP_PKEY_CTX* ctx,
|
|
unsigned char* out, size_t* outlen,
|
|
const unsigned char* in, size_t inlen);
|
|
|
|
enum Operation {
|
|
kPublic,
|
|
kPrivate
|
|
};
|
|
|
|
template <Operation operation,
|
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
static bool Cipher(Environment* env,
|
|
const ManagedEVPPKey& pkey,
|
|
int padding,
|
|
const unsigned char* data,
|
|
int len,
|
|
AllocatedBuffer* out);
|
|
|
|
template <Operation operation,
|
|
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
|
|
EVP_PKEY_cipher_t EVP_PKEY_cipher>
|
|
static void Cipher(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
};
|
|
|
|
class DiffieHellman : public BaseObject {
|
|
public:
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
|
|
bool Init(int primeLength, int g);
|
|
bool Init(const char* p, int p_len, int g);
|
|
bool Init(const char* p, int p_len, const char* g, int g_len);
|
|
|
|
protected:
|
|
static void DiffieHellmanGroup(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GenerateKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPrime(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetGenerator(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void ComputeSecret(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void VerifyErrorGetter(
|
|
const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
DiffieHellman(Environment* env, v8::Local<v8::Object> wrap)
|
|
: BaseObject(env, wrap),
|
|
verifyError_(0) {
|
|
MakeWeak();
|
|
}
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(DiffieHellman)
|
|
SET_SELF_SIZE(DiffieHellman)
|
|
|
|
private:
|
|
static void GetField(const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
const BIGNUM* (*get_field)(const DH*),
|
|
const char* err_if_null);
|
|
static void SetKey(const v8::FunctionCallbackInfo<v8::Value>& args,
|
|
int (*set_field)(DH*, BIGNUM*), const char* what);
|
|
bool VerifyContext();
|
|
|
|
int verifyError_;
|
|
DHPointer dh_;
|
|
};
|
|
|
|
class ECDH : public BaseObject {
|
|
public:
|
|
~ECDH() override {
|
|
group_ = nullptr;
|
|
}
|
|
|
|
static void Initialize(Environment* env, v8::Local<v8::Object> target);
|
|
static ECPointPointer BufferToPoint(Environment* env,
|
|
const EC_GROUP* group,
|
|
v8::Local<v8::Value> buf);
|
|
|
|
// TODO(joyeecheung): track the memory used by OpenSSL types
|
|
SET_NO_MEMORY_INFO()
|
|
SET_MEMORY_INFO_NAME(ECDH)
|
|
SET_SELF_SIZE(ECDH)
|
|
|
|
protected:
|
|
ECDH(Environment* env, v8::Local<v8::Object> wrap, ECKeyPointer&& key)
|
|
: BaseObject(env, wrap),
|
|
key_(std::move(key)),
|
|
group_(EC_KEY_get0_group(key_.get())) {
|
|
MakeWeak();
|
|
CHECK_NOT_NULL(group_);
|
|
}
|
|
|
|
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GenerateKeys(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void ComputeSecret(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetPrivateKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void GetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
static void SetPublicKey(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
|
|
bool IsKeyPairValid();
|
|
bool IsKeyValidForCurve(const BignumPointer& private_key);
|
|
|
|
ECKeyPointer key_;
|
|
const EC_GROUP* group_;
|
|
};
|
|
|
|
bool EntropySource(unsigned char* buffer, size_t length);
|
|
#ifndef OPENSSL_NO_ENGINE
|
|
void SetEngine(const v8::FunctionCallbackInfo<v8::Value>& args);
|
|
#endif // !OPENSSL_NO_ENGINE
|
|
void InitCrypto(v8::Local<v8::Object> target);
|
|
|
|
} // namespace crypto
|
|
} // namespace node
|
|
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
|
|
|
|
#endif // SRC_NODE_CRYPTO_H_
|