-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
crypto: add support for AES-CCM #18138
Conversation
991a94c
to
6d0a3e0
Compare
Rebased due to a conflict with #18017. @nodejs/crypto and @nodejs/tsc, is there anything I can do to aid in discussing and reviewing this change? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generally LGTM but needs docs.
@jasnell Thanks! Yes, documentation is still pending, I just want to discuss the general API before documenting its details :) |
ping @nodejs/tsc |
be707a9
to
78d0441
Compare
@bnoordhuis Thank you for your thorough review! I tried to address all suggestions (except #18138 (comment)), PTAL if you can. |
e2f87d4
to
4c4dad0
Compare
✔️ Light CI: https://ci.nodejs.org/job/node-test-commit-light/179/ |
Seems like I found the cause of the FIPS failure thanks to gdb. openssl/openssl@9cca7be introduced a slight change to the CCM API back in 2015, and this change never made it into the FIPS release. Without this commit, the authentication tag must be specified along with its length when decrypting, and I believe this makes it incompatible with our current design. The only option I can think of right now is to make CCM unsupported when in FIPS mode and to throw an error in This is the conflicting line: (gdb) f
#0 aes_ccm_ctrl (c=0x3d1b490, type=17, arg=8, ptr=0x0) at e_aes.c:1284
1284 if ((c->encrypt && ptr) || (!c->encrypt && !ptr))
(gdb) next
1285 return 0; There is one other thing I came across, OpenSSL 1.1.0 seems to have fixed the problem with |
I'm okay with that. |
I'm good with not supporting CCM in FIPS also. |
For now, I only disabled CCM decryption in FIPS mode, PTAL. |
great work guys , I was waiting for this |
@bluetiger30 This change will most likely be included in all releases beginning with node 10.0.0, but not in previous releases. |
@addaleax I suggested to make it semver-minor in #18138 (comment) without response, I am okay with that. The only reason I marked this semver-major is that it can break code which incorrectly used CCM before, because we did not account for that in previous releases, e.g., if you pass invalid CCM options to |
Yes, I'm fine with this addition and the API and being conservative on semver-major is probably a good idea although I wouldn't say it's essential. However #19794 is more important than getting this landed for Node 10 and that PR is going to heavily impact this one. AES-CCM is going to have fairly minimal use due to the necessarily awkward API so this is pretty low priority (sorry @tniessen but I suspect you already understand this). Getting #19794 safely landed without holding it up even further is critical so I'd rather see this PR have to change to fit that PR rather than the other way around. @tniessen could you do a quick investigation to see what changes might be required to sit on top of the 1.1.0 support @shigeki is adding? I wouldn't discard the exact code in this PR btw, we could possibly relax the semver-major and land this on 8.x as it is now so it's not entirely useless as it is now. I think I'd prefer to wait until after 10.x goes live to make a call on 8.x support for CCM. |
Side note: On a par with OpenSSL.
It indeed seems to be, the lack of TSC attention was noticeable long before 1.1.0h was even released. There haven't been any changes to this PR in weeks.
It lands cleanly and lite CI passes: https://ci.nodejs.org/job/node-test-commit-lite/589/ |
R=@danbev perhaps? |
beautiful, if this lands cleanly with 1.1.0 then I see no other holdup, lgtm |
Only CI that didn't finish last time was Linux, so here's a re-run of just that: https://ci.nodejs.org/job/node-test-commit-linux/17674/ |
Commit 8fb4ea9 ("test: add deprecation code to expectWarning") did not take into account that the same warning could be expected multiple times. This bug was discovered in nodejs#18138 and this commit adds a fix for this issue. Refs: nodejs#18138
I created tniessen@a191f6b by "landing" #19766, #18138 (this PR) and #19794 (in this order) on top of the current master. Again, there were no conflicts. Additional CI for that commit: https://ci.nodejs.org/job/node-test-commit/17477/ Unless someone objects, I intend to land this along with #19766 today. |
Commit 8fb4ea9 ("test: add deprecation code to expectWarning") did not take into account that the same warning could be expected multiple times. This bug was discovered in #18138 and this commit adds a fix for this issue. PR-URL: #19766 Refs: #18138 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: James M Snell <jasnell@gmail.com>
CI is a mess, but not because of these changes. lgtm, let's get it merged, thanks for the hard work on this @tniessen. |
This commit adds support for another AEAD algorithm and introduces required API changes and extensions. Due to the design of CCM itself and the way OpenSSL implements it, there are some restrictions when using this mode as outlined in the updated documentation. PR-URL: #18138 Fixes: #2383 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Shigeki Ohtsu <ohtsu@ohtsu.org> Reviewed-By: Rod Vagg <rod@vagg.org> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
@Trott I marked this PR as semver-major again given that multiple TSC members approved after nodejs/TSC#516 and that it landed in time for node 10. At the very least, this is semver-minor. |
This change replaces some constants with better alternatives which were unavailable in OpenSSL 1.0.2. Refs: nodejs#19794 Refs: nodejs#18138
This change replaces some constants with better alternatives which were unavailable in OpenSSL 1.0.2. PR-URL: #20339 Refs: #19794 Refs: #18138 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This change replaces some constants with better alternatives which were unavailable in OpenSSL 1.0.2. PR-URL: #20339 Refs: #19794 Refs: #18138 Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
openssl/openssl@67c81ec just landed and slightly relaxes one of the difficulties in using CCM, thus reducing the API differences between CCM and other modes slightly. I am not sure if it is worth cherry-picking since I assume we usually only cherry-pick security stuff. |
CCM ("Counter with Cipher Block Chaining-Message Authentication Code")
OpenSSL currently supports two AEAD algorithms, GCM and CCM. While node has supported GCM for years, CCM is a bit more difficult to implement and use.
Currently, this PR implements an API similar to what was proposed by @brycekahle in #2383:
createCipher
,createDecipher
,createCipheriv
andcreateDecipheriv
accept an optionauthTagLength
. While the tag length is not relevant for GCM, it is for CCM. (And yes, using CCM withcreateCipher
/createDecipher
is inherently insecure.)setAAD
accepts additionaloptions
as an optional second argument. The only currently recognized option isplaintextLength
, which specifies the length of the plaintext / ciphertext in bytes.There are some critical aspects:
authTagLength
option when using CCM. Not providing this option causes an error to be thrown bycreate(De|C)ipher(iv)?
.plaintextLength
option when using CCM if and only if AAD is provided. The explanation is simple, the length of the plaintext is encoded into the first block of the cipher, and thus must be available before performing an update (and before encoding the AAD).update()
can only be called once. Again, the reason is very simple, CCM operates in what is sometimes called a "packet" or "offline mode", meaning that all data is processed at once.Some of these points can be relaxed:
authTagLength
option, we could simplify the migration to this "new" AEAD. We could stick with the default value used within OpenSSL (12 bytes) or upgrade to 16 bytes (as e.g. pycryptodome does).setAAD
untilupdate
is called, we take away the need to specify theplaintextLength
. All data still needs to be passed toupdate
in a single call.We should discuss both, but it should be possible to add these features later on if they turn out to be good ideas (as long as they don't break anything). Aside from that, I am always happy about feedback and suggestions!
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passesAffected core subsystem(s)
crypto