Skip to content

Commit 627a15f

Browse files
davidbenevanlucas
authored andcommitted
crypto: emulate OpenSSL 1.0 ticket scheme in 1.1
OpenSSL 1.0.x used a 48-byte ticket key, but OpenSSL 1.1.x made it larger by using a larger HMAC-SHA256 key and using AES-256-CBC to encrypt. However, Node's public API exposes the 48-byte key. Implement the ticket key callback to restore the OpenSSL 1.0.x behavior. PR-URL: #16130 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Rod Vagg <[email protected]>
1 parent 85ffc2f commit 627a15f

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

src/node_crypto.cc

+61
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,19 @@ void SecureContext::Init(const FunctionCallbackInfo<Value>& args) {
615615
SSL_SESS_CACHE_NO_AUTO_CLEAR);
616616
SSL_CTX_sess_set_get_cb(sc->ctx_, SSLWrap<Connection>::GetSessionCallback);
617617
SSL_CTX_sess_set_new_cb(sc->ctx_, SSLWrap<Connection>::NewSessionCallback);
618+
619+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
620+
// OpenSSL 1.1.0 changed the ticket key size, but the OpenSSL 1.0.x size was
621+
// exposed in the public API. To retain compatibility, install a callback
622+
// which restores the old algorithm.
623+
if (RAND_bytes(sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) <= 0 ||
624+
RAND_bytes(sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_)) <= 0 ||
625+
RAND_bytes(sc->ticket_key_aes_, sizeof(sc->ticket_key_aes_)) <= 0) {
626+
return env->ThrowError("Error generating ticket keys");
627+
}
628+
SSL_CTX_set_tlsext_ticket_key_cb(sc->ctx_,
629+
SecureContext::TicketCompatibilityCallback);
630+
#endif
618631
}
619632

620633

@@ -1292,11 +1305,17 @@ void SecureContext::GetTicketKeys(const FunctionCallbackInfo<Value>& args) {
12921305
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
12931306

12941307
Local<Object> buff = Buffer::New(wrap->env(), 48).ToLocalChecked();
1308+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
1309+
memcpy(Buffer::Data(buff), wrap->ticket_key_name_, 16);
1310+
memcpy(Buffer::Data(buff) + 16, wrap->ticket_key_hmac_, 16);
1311+
memcpy(Buffer::Data(buff) + 32, wrap->ticket_key_aes_, 16);
1312+
#else
12951313
if (SSL_CTX_get_tlsext_ticket_keys(wrap->ctx_,
12961314
Buffer::Data(buff),
12971315
Buffer::Length(buff)) != 1) {
12981316
return wrap->env()->ThrowError("Failed to fetch tls ticket keys");
12991317
}
1318+
#endif
13001319

13011320
args.GetReturnValue().Set(buff);
13021321
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys)
@@ -1319,11 +1338,17 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) {
13191338
return env->ThrowTypeError("Ticket keys length must be 48 bytes");
13201339
}
13211340

1341+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
1342+
memcpy(wrap->ticket_key_name_, Buffer::Data(args[0]), 16);
1343+
memcpy(wrap->ticket_key_hmac_, Buffer::Data(args[0]) + 16, 16);
1344+
memcpy(wrap->ticket_key_aes_, Buffer::Data(args[0]) + 32, 16);
1345+
#else
13221346
if (SSL_CTX_set_tlsext_ticket_keys(wrap->ctx_,
13231347
Buffer::Data(args[0]),
13241348
Buffer::Length(args[0])) != 1) {
13251349
return env->ThrowError("Failed to fetch tls ticket keys");
13261350
}
1351+
#endif
13271352

13281353
args.GetReturnValue().Set(true);
13291354
#endif // !def(OPENSSL_NO_TLSEXT) && def(SSL_CTX_get_tlsext_ticket_keys)
@@ -1434,6 +1459,42 @@ int SecureContext::TicketKeyCallback(SSL* ssl,
14341459
}
14351460

14361461

1462+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
1463+
int SecureContext::TicketCompatibilityCallback(SSL* ssl,
1464+
unsigned char* name,
1465+
unsigned char* iv,
1466+
EVP_CIPHER_CTX* ectx,
1467+
HMAC_CTX* hctx,
1468+
int enc) {
1469+
SecureContext* sc = static_cast<SecureContext*>(
1470+
SSL_CTX_get_app_data(SSL_get_SSL_CTX(ssl)));
1471+
1472+
if (enc) {
1473+
memcpy(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_));
1474+
if (RAND_bytes(iv, 16) <= 0 ||
1475+
EVP_EncryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr,
1476+
sc->ticket_key_aes_, iv) <= 0 ||
1477+
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_),
1478+
EVP_sha256(), nullptr) <= 0) {
1479+
return -1;
1480+
}
1481+
return 1;
1482+
}
1483+
1484+
if (memcmp(name, sc->ticket_key_name_, sizeof(sc->ticket_key_name_)) != 0) {
1485+
// The ticket key name does not match. Discard the ticket.
1486+
return 0;
1487+
}
1488+
1489+
if (EVP_DecryptInit_ex(ectx, EVP_aes_128_cbc(), nullptr, sc->ticket_key_aes_,
1490+
iv) <= 0 ||
1491+
HMAC_Init_ex(hctx, sc->ticket_key_hmac_, sizeof(sc->ticket_key_hmac_),
1492+
EVP_sha256(), nullptr) <= 0) {
1493+
return -1;
1494+
}
1495+
return 1;
1496+
}
1497+
#endif
14371498

14381499

14391500
void SecureContext::CtxGetter(Local<String> property,

src/node_crypto.h

+15
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,12 @@ class SecureContext : public BaseObject {
103103
static const int kTicketKeyNameIndex = 3;
104104
static const int kTicketKeyIVIndex = 4;
105105

106+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
107+
unsigned char ticket_key_name_[16];
108+
unsigned char ticket_key_aes_[16];
109+
unsigned char ticket_key_hmac_[16];
110+
#endif
111+
106112
protected:
107113
#if OPENSSL_VERSION_NUMBER < 0x10100000L
108114
static const int64_t kExternalSize = sizeof(SSL_CTX);
@@ -148,6 +154,15 @@ class SecureContext : public BaseObject {
148154
HMAC_CTX* hctx,
149155
int enc);
150156

157+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
158+
static int TicketCompatibilityCallback(SSL* ssl,
159+
unsigned char* name,
160+
unsigned char* iv,
161+
EVP_CIPHER_CTX* ectx,
162+
HMAC_CTX* hctx,
163+
int enc);
164+
#endif
165+
151166
SecureContext(Environment* env, v8::Local<v8::Object> wrap)
152167
: BaseObject(env, wrap),
153168
ctx_(nullptr),

0 commit comments

Comments
 (0)