-
Notifications
You must be signed in to change notification settings - Fork 56
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
Fix input wiping on decryption failure #337
Conversation
Closing and re-opening to poke the checks. |
Nice catch! I don't mind the additional I/O here. I do worry about the precedent set by taking this stance of considering what happens to the output buffer (and what impact that has if it also happens to be the input) on failure cases. This can get into really murky territory. The OpenSSL docs state that the contents of the output are "corrupt" and don't consider any of these factors. That flexibility is pretty useful in these circumstances. |
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.
LGTM
d0fc26f
to
f4f91ce
Compare
@@ -738,12 +738,9 @@ private int engineDecryptFinal( | |||
} | |||
} | |||
// Decryption completed successfully. | |||
// Copy from working buffer into actual output | |||
System.arraycopy(workingInputArray, workingInputOffset, output, outputOffset, outLen); |
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.
Maybe we can avoid this copy in case the output buffer doesn't overlap input. Still in the case of failure the output buffer would potentially be modified, but it's output buffer after all.
32182ef
to
20ff369
Compare
@@ -697,8 +697,8 @@ private int engineDecryptFinal( | |||
workingInputArray, | |||
workingInputOffset, | |||
workingInputLength, | |||
output, | |||
outputOffset, | |||
workingInputArray, // Output |
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.
In cases where the output buffer is distinct from the input, like here the copying back can be avoided by directly using the output buffer.
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.
I am willing to change this, however:
- The current design never leaks unauthenticated plaintext outside the ACCP boundary.
- The proposed change is more complicated and we're already seeing bugs creep in which suggest that we're nearing maximum complexity to safely work here.
So, if left to me, I would leave this as written, but I am willing to change it. (Or, to read it another way. I have one approval and one request for changes. Mind reaching consensus?)
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.
We spoke offline and I'm more hesitant now. My interpretation of the contract is that if the caller gives us an output buffer and a length we have no obligation to preserve the contents of that buffer even if the tag check fails. If we can preserve it for free, awesome, but if it adds O(n) memory I/O to all AES-GCM operations I'm less inclined. Even if we add the risky logic for overlap detection, what we'll find is that the perfect overlap case is the common case and it won't buy us much.
The remaining point of clarity for us is to look at how other libraries handle this case to determine if this is considered a bug as that's still a bit subjective to me. AFAICT, OpenSSL/AWS-LC will scribble over the output buffer and simply return an error code if the tag fails. I'd be hesitant to add new semantics at the ACCP layer which don't line up with the native library.
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.
My concern is us overwriting the input buffer (which happens to be the same).
I have personally seen decryption logic which attempts repeated in-place decryption using multiple keys. Unfortunately, I no longer have access to said code. However, wiping the in-place buffer on failure would absolutely break that code.
More interesting than how OpenSSL/AWS-LC behave is how other JCA providers behave as that's what ACCP is replacing.
20ff369
to
3c38a4e
Compare
3c38a4e
to
598d2d2
Compare
Alright, after many months, we discussed this as a team and decided to close this PR. Absent any specification that mandates a certain behavior we decided to keep the implementation choice which improves performance. This change in behavior has been deployed for several months and based on the evidence so far we are willing to tolerate the amount of breakage this may invite. |
PR #298 appears to have introduced a bug wherein when there is decryption failure can cause the input buffer to be wiped. Specifically, this happens for AES-GCM in-place decryption. (Ideally, the output buffer would remain unchanged in all failure cases, but that change is more understandable.)
This change:
So, this new change does incur a new memory copy relative to the current situation (but the same as before PR # 298) but does not incur any new memory allocation (so we keep that win from # 298).
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.