Uh oh!
There was an error while loading. Please reload this page.
crypto: allocate more memory for cipher.update() - #20370
Conversation
yhwang
commented
Apr 27, 2018
one question: should we put an assertion to check the |
addaleax
commented
Apr 27, 2018
@yhwang I think that makes sense, yes. 👍 /cc @nodejs/crypto |
ryzokuken
commented
Apr 27, 2018
Is there no 3DES support in Node 9? I tried the test in Node 9 and it threw |
yhwang
commented
Apr 27, 2018
@addaleax Let me do it. thanks @ryzokuken does it means that I should label this with |
06718c4 to
4c995d4CompareMarking this as security as I wrote a report for the Node.js security team a couple of days ago. An attacker can - hypothetically - write eight bytes into (un)allocated heap and at least partially control their contents. |
ryzokuken
commented
Apr 28, 2018
@yhwang I think @tniessen and @addaleax would know better. AFAIK, ~/Code/temp/node
❯ node crypto.jsnode(79558,0x7fffa1d72380) malloc: *** error for object 0x10250fd60: incorrect checksum for freed object - object was probably modified after being freed.*** set a breakpoint in malloc_error_break to debug[1] 79558 abort node crypto.jsbut yeah, label it so that it doesn't land on Node.js 6, 8 and 9 (if I hope this clarifies everything. |
addaleax
commented
Apr 28, 2018
I mean, the dont-land labels depend on a couple factors – as in, what is the negative impact if we do merge this to an LTS line? Does it make backporting there easier? The only downside I can think of is slightly higher memory consumption, but as I understand it these chunks are not all that large to begin with. Plus, we could reduce that problem by doing a shrinking |
bnoordhuis
left a comment
There was a problem hiding this comment.
The bug is that key wrap algorithms overflow because of the envelope that's added?
Allocating double the block size doesn't look Obviously Correct to me as the envelope size has no direct relationship to the block size.
The reason this PR fixes the immediate issue is because openssl currently only supports AES and 3DES key wrap modes, where envelope size == block size by happenstance.
I think a better solution is to check first if EVP_CIPHER_mode(cipher) == EVP_CIPH_WRAP_MODE and then check the NID against a whitelist with EVP_CIPHER_nid(cipher) and throw an exception when we don't recognize it.
You can look up the NIDs with grep wrap deps/openssl/openssl/crypto/objects/obj_dat.h | grep NID but note that some ciphers are disabled in our builds so you probably want to intersect with node -p 'crypto.getCiphers().filter(s => s.toLowerCase().includes("wrap"))'.
Ideally, each whitelisted cipher should have a test case to make sure it's working as expected.
There was a problem hiding this comment.
I'd use fixed strings to keep the test deterministic.
tniessen
commented
Apr 28, 2018
@bnoordhuis I was thinking the same thing, but a better solution can still be implemented later on. This patch at least makes sure that we don't overwrite unallocated heap memory. (And yes, the connection between envelope size and blocksize is debatable.) |
bnoordhuis
commented
Apr 28, 2018
I can live with that but I'd suggest the following:
That way there can be no hidden footguns or time bombs. @yhwang Ping me if you have questions or want help. |
yhwang
commented
Apr 29, 2018
I want to say: I love your comments and I will update my change according to your comments. @bnoordhuis I will ping you if I need help. I have a family event this weekend and will be back to this next Tuesday. I will do the change then. |
yhwang
commented
May 1, 2018
I am not sure if it's the envelope. Based on the spec it's the sha1 of the key: https://tools.ietf.org/html/rfc3217#section-2 For the key wrap algorithms, seems you can call
It shouldn't be specific to key wrap algorithms. We should do the check for the algorithms that we supports, right? |
tniessen
commented
May 1, 2018
If that works, that would be great, but I couldn't find a conclusive solution in the documentation. |
yhwang
commented
May 1, 2018
@tniessen I can't find documentation either. I read the logic in |
yhwang
commented
May 1, 2018
@tniessen I updated the change to get output length before memory allocation. @bnoordhuis please let me know should I add CHECK for key wrapping? (my question is should we do the CHECK for all supported algorithms but not only for key wrapping? If that's the case, should I do it separately?) For |
tniessen
left a comment
There was a problem hiding this comment.
LGTM assuming you checked the returned value manually and CI passes. I'd still prefer to see this behavior of EVP_CipherUpdate documented just so we don't rely on undefined behavior, but that's probably beyond our power.
There was a problem hiding this comment.
Nit: Period at the end of the sentence.
bnoordhuis
commented
May 2, 2018
That's 3DES. AES is different: https://tools.ietf.org/html/rfc3394#page-4. I use 'envelope' as a catch-all for the key wrap data that's added.
I think they're the only ones that add extra data. But if there's a reliable generic way of detecting that upfront, so much the better. |
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com>
yhwang
commented
May 2, 2018
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com> PR-URL: #20370Fixes: #19655 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
tniessen
commented
May 4, 2018
Landed in f7cdeba. |
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com> PR-URL: #20370Fixes: #19655 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
bnoordhuis
commented
May 8, 2018
Back-porters, this should land along with #20587. |
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com> PR-URL: #20370Fixes: #19655 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com> PR-URL: nodejs#20370Fixes: nodejs#19655 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
For key wrapping algorithms, calling EVP_CipherUpdate() with null output could obtain the size for the ciphertext. Then use the returned size to allocate output buffer. Also add a test case to verify des3-wrap. Signed-off-by: Yihong Wang <yh.wang@ibm.com> Backport-PR-URL: #20706 PR-URL: #20370Fixes: #19655 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
For some algorithms, they need extra 2x blocksize to store the ciphertext in
order to avoid invalid write. Also add a test case to verify it.
refs: #19655
Signed-off-by: Yihong Wang yh.wang@ibm.com
Checklist
make -j4 test(UNIX), orvcbuild test(Windows) passes