Skip to content

Commit dc8669c

Browse files
committed
src: simplify handling of kNoAuthTagLength
Since #61084, the `kNoAuthTagLength` constant is only used - during the entire lifetime of non-authenticating cipher/decipher objects and - during the initialization of authenticating cipher/decipher objects. In particular, it is never used during the lifetime of an authenticating cipher/decipher object once that object has been initialized. (Before said change, the constant was also used for ciphers in GCM mode to indicate that the user had not specified the length of the authentication tag in advance, but the authentication tag length must now always be specified or defaults to the block size in the case of GCM mode.) This commit simplifies the handling of `kNoAuthTagLength` based on the knowledge that it is not a valid value for AEAD ciphers beyond initialization.
1 parent 05d6b9b commit dc8669c

File tree

1 file changed

+37
-73
lines changed

1 file changed

+37
-73
lines changed

src/crypto/crypto_cipher.cc

Lines changed: 37 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -427,61 +427,44 @@ bool CipherBase::InitAuthenticated(const char* cipher_type,
427427
return false;
428428
}
429429

430-
if (ctx_.isGcmMode()) {
431-
if (auth_tag_len != kNoAuthTagLength) {
432-
if (!Cipher::IsValidGCMTagLength(auth_tag_len)) {
433-
THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
434-
env(),
435-
"Invalid authentication tag length: %u",
436-
auth_tag_len);
437-
return false;
438-
}
439-
440-
// Remember the given authentication tag length for later.
441-
auth_tag_len_ = auth_tag_len;
442-
}
443-
} else {
444-
if (auth_tag_len == kNoAuthTagLength) {
445-
// We treat ChaCha20-Poly1305 specially. Like GCM, the authentication tag
446-
// length defaults to 16 bytes when encrypting. Unlike GCM, the
447-
// authentication tag length also defaults to 16 bytes when decrypting,
448-
// whereas GCM would accept any valid authentication tag length.
449-
if (ctx_.isChaCha20Poly1305()) {
450-
auth_tag_len = EVP_CHACHAPOLY_TLS_TAG_LEN;
451-
} else {
452-
THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
453-
env(), "authTagLength required for %s", cipher_type);
454-
return false;
455-
}
456-
}
457-
430+
if (ctx_.isCcmMode()) {
458431
// TODO(tniessen) Support CCM decryption in FIPS mode
459-
460-
if (ctx_.isCcmMode() && kind_ == kDecipher && ncrypto::isFipsEnabled()) {
461-
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(env(),
462-
"CCM encryption not supported in FIPS mode");
432+
if (kind_ == kDecipher && ncrypto::isFipsEnabled()) {
433+
THROW_ERR_CRYPTO_UNSUPPORTED_OPERATION(
434+
env(), "CCM encryption not supported in FIPS mode");
463435
return false;
464436
}
465437

466-
// Tell OpenSSL about the desired length.
467-
if (!ctx_.setAeadTagLength(auth_tag_len)) {
438+
// Restrict the message length to min(INT_MAX, 2^(8*(15-iv_len))-1) bytes.
439+
CHECK(iv_len >= 7 && iv_len <= 13);
440+
max_message_size_ = INT_MAX;
441+
if (iv_len == 12) max_message_size_ = 16777215;
442+
if (iv_len == 13) max_message_size_ = 65535;
443+
}
444+
445+
if (auth_tag_len == kNoAuthTagLength) {
446+
// Both GCM and ChaCha20-Poly1305 have a default tag length of 16 bytes.
447+
// Other modes (CCM, OCB) require an explicit tag length.
448+
if (ctx_.isGcmMode()) {
449+
auth_tag_len = EVP_GCM_TLS_TAG_LEN;
450+
} else if (ctx_.isChaCha20Poly1305()) {
451+
auth_tag_len = EVP_CHACHAPOLY_TLS_TAG_LEN;
452+
} else {
468453
THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
469-
env(), "Invalid authentication tag length: %u", auth_tag_len);
454+
env(), "authTagLength required for %s", cipher_type);
470455
return false;
471456
}
472-
473-
// Remember the given authentication tag length for later.
474-
auth_tag_len_ = auth_tag_len;
475-
476-
if (ctx_.isCcmMode()) {
477-
// Restrict the message length to min(INT_MAX, 2^(8*(15-iv_len))-1) bytes.
478-
CHECK(iv_len >= 7 && iv_len <= 13);
479-
max_message_size_ = INT_MAX;
480-
if (iv_len == 12) max_message_size_ = 16777215;
481-
if (iv_len == 13) max_message_size_ = 65535;
482-
}
457+
} else if ((ctx_.isGcmMode() && !Cipher::IsValidGCMTagLength(auth_tag_len)) ||
458+
(!ctx_.isGcmMode() && !ctx_.setAeadTagLength(auth_tag_len))) {
459+
// GCM authentication tag lengths are restricted according to NIST 800-38d,
460+
// page 9. For other modes, we rely on OpenSSL to validate the length.
461+
THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
462+
env(), "Invalid authentication tag length: %u", auth_tag_len);
463+
return false;
483464
}
484465

466+
// Remember the given authentication tag length for later.
467+
auth_tag_len_ = auth_tag_len;
485468
return true;
486469
}
487470

@@ -510,11 +493,11 @@ void CipherBase::GetAuthTag(const FunctionCallbackInfo<Value>& args) {
510493

511494
// Only callable after Final and if encrypting.
512495
if (cipher->ctx_ || cipher->kind_ != kCipher ||
513-
cipher->auth_tag_len_ == kNoAuthTagLength ||
514496
cipher->auth_tag_state_ != kAuthTagComputed) {
515497
return;
516498
}
517499

500+
CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength);
518501
Local<Value> ret;
519502
if (Buffer::Copy(env, cipher->auth_tag_, cipher->auth_tag_len_)
520503
.ToLocal(&ret)) {
@@ -540,30 +523,17 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) {
540523
}
541524
unsigned int tag_len = auth_tag.size();
542525

543-
bool is_valid;
544-
if (cipher->ctx_.isGcmMode()) {
545-
// Restrict GCM tag lengths according to NIST 800-38d, page 9.
546-
is_valid = (cipher->auth_tag_len_ == kNoAuthTagLength ||
547-
cipher->auth_tag_len_ == tag_len) &&
548-
Cipher::IsValidGCMTagLength(tag_len);
549-
} else {
550-
// At this point, the tag length is already known and must match the
551-
// length of the given authentication tag.
552-
CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength);
553-
is_valid = cipher->auth_tag_len_ == tag_len;
554-
}
555-
556-
// TODO(tniessen): refactor this check.
557-
if (!is_valid ||
558-
(cipher->ctx_.isGcmMode() && cipher->auth_tag_len_ == kNoAuthTagLength &&
559-
tag_len != EVP_GCM_TLS_TAG_LEN)) {
526+
// Older versions of Node.js did allow setting the auth tag length implicitly
527+
// for GCM mode (see DEP0182). We now require knowledge of the expected tag
528+
// length up front, so it must have been set during initialization.
529+
// The configured tag length must match the length of the given auth tag.
530+
CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength);
531+
if (cipher->auth_tag_len_ != tag_len) {
560532
return THROW_ERR_CRYPTO_INVALID_AUTH_TAG(
561533
env, "Invalid authentication tag length: %u", tag_len);
562534
}
563535

564-
cipher->auth_tag_len_ = tag_len;
565536
CHECK_LE(cipher->auth_tag_len_, ncrypto::Cipher::MAX_AUTH_TAG_LENGTH);
566-
567537
if (!cipher->ctx_.setAeadTag({auth_tag.data(), cipher->auth_tag_len_})) {
568538
return args.GetReturnValue().Set(false);
569539
}
@@ -772,13 +742,7 @@ bool CipherBase::Final(std::unique_ptr<BackingStore>* out) {
772742
}
773743

774744
if (ok && kind_ == kCipher && IsAuthenticatedMode()) {
775-
// In GCM mode, the authentication tag length can be specified in advance,
776-
// but defaults to 16 bytes when encrypting. In CCM and OCB mode, it must
777-
// always be given by the user.
778-
if (auth_tag_len_ == kNoAuthTagLength) {
779-
CHECK(ctx_.isGcmMode());
780-
auth_tag_len_ = EVP_GCM_TLS_TAG_LEN;
781-
}
745+
CHECK_NE(auth_tag_len_, kNoAuthTagLength);
782746
ok = ctx_.getAeadTag(auth_tag_len_,
783747
reinterpret_cast<unsigned char*>(auth_tag_));
784748
if (ok) {

0 commit comments

Comments
 (0)