diff options
author | Tobias Nießen <tniessen@tnie.de> | 2018-06-14 15:18:14 +0200 |
---|---|---|
committer | Tobias Nießen <tniessen@tnie.de> | 2018-07-18 13:10:10 +0200 |
commit | b3f459e6cf0076915cfd0e9ea130e3ceaa4448d1 (patch) | |
tree | 216f339af1939b6ca69928e2d577b6a9b36fbc69 /src | |
parent | b75bde3bc55efe263f65b7990177bd05be822a48 (diff) | |
download | android-node-v8-b3f459e6cf0076915cfd0e9ea130e3ceaa4448d1.tar.gz android-node-v8-b3f459e6cf0076915cfd0e9ea130e3ceaa4448d1.tar.bz2 android-node-v8-b3f459e6cf0076915cfd0e9ea130e3ceaa4448d1.zip |
crypto: add support for OCB mode for AEAD
PR-URL: https://github.com/nodejs/node/pull/21447
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: James M Snell <jasnell@gmail.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/node_crypto.cc | 50 |
1 files changed, 31 insertions, 19 deletions
diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 5bceae0ce0..00c1785f4c 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2683,6 +2683,11 @@ void CipherBase::Init(const FunctionCallbackInfo<Value>& args) { cipher->Init(*cipher_type, key_buf, key_buf_len, auth_tag_len); } +static bool IsSupportedAuthenticatedMode(int mode) { + return mode == EVP_CIPH_CCM_MODE || + mode == EVP_CIPH_GCM_MODE || + mode == EVP_CIPH_OCB_MODE; +} void CipherBase::InitIv(const char* cipher_type, const char* key, @@ -2700,8 +2705,7 @@ void CipherBase::InitIv(const char* cipher_type, const int expected_iv_len = EVP_CIPHER_iv_length(cipher); const int mode = EVP_CIPHER_mode(cipher); - const bool is_gcm_mode = (EVP_CIPH_GCM_MODE == mode); - const bool is_ccm_mode = (EVP_CIPH_CCM_MODE == mode); + const bool is_authenticated_mode = IsSupportedAuthenticatedMode(mode); const bool has_iv = iv_len >= 0; // Throw if no IV was passed and the cipher requires an IV @@ -2712,7 +2716,7 @@ void CipherBase::InitIv(const char* cipher_type, } // Throw if an IV was passed which does not match the cipher's fixed IV length - if (!is_gcm_mode && !is_ccm_mode && has_iv && iv_len != expected_iv_len) { + if (!is_authenticated_mode && has_iv && iv_len != expected_iv_len) { return env()->ThrowError("Invalid IV length"); } @@ -2728,7 +2732,7 @@ void CipherBase::InitIv(const char* cipher_type, "Failed to initialize cipher"); } - if (IsAuthenticatedMode()) { + if (is_authenticated_mode) { CHECK(has_iv); if (!InitAuthenticated(cipher_type, iv_len, auth_tag_len)) return; @@ -2803,7 +2807,7 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, int iv_len, } const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); - if (mode == EVP_CIPH_CCM_MODE) { + if (mode == EVP_CIPH_CCM_MODE || mode == EVP_CIPH_OCB_MODE) { if (auth_tag_len == kNoAuthTagLength) { char msg[128]; snprintf(msg, sizeof(msg), "authTagLength required for %s", cipher_type); @@ -2813,25 +2817,29 @@ bool CipherBase::InitAuthenticated(const char* cipher_type, int iv_len, #ifdef NODE_FIPS_MODE // TODO(tniessen) Support CCM decryption in FIPS mode - if (kind_ == kDecipher && FIPS_mode()) { + if (mode == EVP_CIPH_CCM_MODE && kind_ == kDecipher && FIPS_mode()) { env()->ThrowError("CCM decryption not supported in FIPS mode"); return false; } #endif - if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_CCM_SET_TAG, auth_tag_len, + // Tell OpenSSL about the desired length. + if (!EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_SET_TAG, auth_tag_len, nullptr)) { env()->ThrowError("Invalid authentication tag length"); return false; } + // Remember the given authentication tag length for later. auth_tag_len_ = auth_tag_len; - // Restrict the message length to min(INT_MAX, 2^(8*(15-iv_len))-1) bytes. - CHECK(iv_len >= 7 && iv_len <= 13); - max_message_size_ = INT_MAX; - if (iv_len == 12) max_message_size_ = 16777215; - if (iv_len == 13) max_message_size_ = 65535; + if (mode == EVP_CIPH_CCM_MODE) { + // Restrict the message length to min(INT_MAX, 2^(8*(15-iv_len))-1) bytes. + CHECK(iv_len >= 7 && iv_len <= 13); + max_message_size_ = INT_MAX; + if (iv_len == 12) max_message_size_ = 16777215; + if (iv_len == 13) max_message_size_ = 65535; + } } else { CHECK_EQ(mode, EVP_CIPH_GCM_MODE); @@ -2870,7 +2878,7 @@ bool CipherBase::IsAuthenticatedMode() const { // Check if this cipher operates in an AEAD mode that we support. CHECK(ctx_); const int mode = EVP_CIPHER_CTX_mode(ctx_.get()); - return mode == EVP_CIPH_GCM_MODE || mode == EVP_CIPH_CCM_MODE; + return IsSupportedAuthenticatedMode(mode); } @@ -2903,16 +2911,18 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo<Value>& args) { return args.GetReturnValue().Set(false); } - // Restrict GCM tag lengths according to NIST 800-38d, page 9. unsigned int tag_len = Buffer::Length(args[0]); const int mode = EVP_CIPHER_CTX_mode(cipher->ctx_.get()); bool is_valid; if (mode == EVP_CIPH_GCM_MODE) { + // Restrict GCM tag lengths according to NIST 800-38d, page 9. is_valid = (cipher->auth_tag_len_ == kNoAuthTagLength || cipher->auth_tag_len_ == tag_len) && IsValidGCMTagLength(tag_len); } else { - CHECK_EQ(mode, EVP_CIPH_CCM_MODE); + // At this point, the tag length is already known and must match the + // length of the given authentication tag. + CHECK(mode == EVP_CIPH_CCM_MODE || mode == EVP_CIPH_OCB_MODE); CHECK_NE(cipher->auth_tag_len_, kNoAuthTagLength); is_valid = cipher->auth_tag_len_ == tag_len; } @@ -3008,7 +3018,7 @@ CipherBase::UpdateResult CipherBase::Update(const char* data, if (kind_ == kDecipher && IsAuthenticatedMode() && auth_tag_len_ > 0 && auth_tag_len_ != kNoAuthTagLength && !auth_tag_set_) { CHECK(EVP_CIPHER_CTX_ctrl(ctx_.get(), - EVP_CTRL_GCM_SET_TAG, + EVP_CTRL_AEAD_SET_TAG, auth_tag_len_, reinterpret_cast<unsigned char*>(auth_tag_))); auth_tag_set_ = true; @@ -3121,10 +3131,12 @@ bool CipherBase::Final(unsigned char** out, int* out_len) { if (ok && kind_ == kCipher && IsAuthenticatedMode()) { // In GCM mode, the authentication tag length can be specified in advance, - // but defaults to 16 bytes when encrypting. In CCM mode, it must always - // be given by the user. - if (mode == EVP_CIPH_GCM_MODE && auth_tag_len_ == kNoAuthTagLength) + // but defaults to 16 bytes when encrypting. In CCM and OCB mode, it must + // always be given by the user. + if (auth_tag_len_ == kNoAuthTagLength) { + CHECK(mode == EVP_CIPH_GCM_MODE); auth_tag_len_ = sizeof(auth_tag_); + } CHECK_EQ(1, EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_AEAD_GET_TAG, auth_tag_len_, reinterpret_cast<unsigned char*>(auth_tag_))); |