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
Security issue (DoS) in Crypto++ ASN1 decoder #346
Comments
This is a necessary fix. Thank you to Gergely for the submission. Note that, in the proposed patch to BERDecodeTextString, there is not only a fix for this issue, but also a new optimization where bt.Get() is called directly on memory managed by std::string, instead of retrieving data first into SecByteBlock, and then moving it to the string. This optimization opens a door to another possible issue. bt.Get() may fail halfway, which would result in data being partly written into memory managed by std::string before throwing a decode exception. In this occurrence, the partly written data might not get cleared, which it would have been if it was written to SecByteBlock instead. I suggest avoiding the optimization implemented by this patch in this particular function, but otherwise adopting the fix. |
In addition, I believe the proposed fix to BERDecodeBitString can be improved. If bc == 0, BERDecodeBitString will call str.resize(bc-1), which will be str.resize(SIZE_MAX). This seems unlikely to succeed on any platform, but if the allocation request is passed to the OS, it could result in the program being aborted. I suggest also adding an explicit check here to prevent bc == 0. |
Hi! I am Gergely Nagy who reported this bug. BERDecodeTextString is called when it is requested explicitly to put the decoded data in a std::string, This is my new revised suggested patch based on the comments above:
|
I have created a pull request #347 with the revised patch. |
I've got some of the |
This simple code reproduces the issue, the maximum failing length really depends on the platform.
|
Thanks @ngg, @denisbider. I think I am seeing better results with the patch below. It rejects malformed The throw is a tad bit worrisome because some of this can be valid ASN.1 BER when streaming and using indefinite length encoding. But the best I can tell, streaming is not fully supported in Crypto++'s implementation, so I think its mostly an academic concern. Ironically, I think we reject some inputs we should accept. I need to look into it in more detail, but we don't seem to be handling constructed values properly in all cases. Here's what the cut-in for
|
@noloader: Note that the proposed fix, to check MaxRetrievable() in BERLengthDecode itself, changes the interface in a way that's potentially breaking. Currently, this is legal:
After the change to BERDecodeLength, the above will no longer work. In fact, there will be no way for the user to check what number of bytes they might need to pump, without implementing their own version of BERDecodeLength. Gergely's proposal fixes this in a way that does not change the contract in this corner case. However, it has the slight disadvantage that the check has to be performed when decoding each structure type. In my opinion, the time of decoding the structure is the more appropriate place to check this. |
Thanks @denisbider.
I think this is what I am struggling with. There's a not-so-readily-apparent intersection with streaming ASN.1 objects. Stepping back, when do we support the filter interface with |
I don't think that BERDecodeLength should check the remaining length. It can break currently working totally valid codes like the one @denisbider mentioned. |
@noloader - what is the problem with BERGeneralDecoder? It means that places that use it have to check the length. If you would like to avoid this, so as to reduce the number of places where this check needs to occur and can go wrong, I think it would make sense to add the length check into However, I would not put this check into BERDecodeLength, simply because the act of decoding a length does not imply intent to decode everything that follows it. |
... However,
Then in
That's an assert, but that will be omitted in production, which means an unchecked allocation will occur in Release modes:
So yeah, I think it may definitely be worth it to add this check to |
Sorry about falling of the radar. I was a bit under the weather for about a week. Sorry about that. We have had more time to think about things, and I think we have two different problems. The first problem is @ngg's initial finding, and I think the analysis and revised patch is correct. I'm going to get it checked in with some test cases shortly. I think the The I need to write some test code to see what feels right or works best for |
The library was a tad bit fast and loose with respect to parsing some of the ASN.1 presented to it. It was kind of like we used Alternate Encoding Rules (AER), which was more relaxed than BER, CER or DER. This commit closes most of the gaps. The changes are distantly related to Issue 346. Issue 346 caught a CVE bcause of the transient DoS. These fixes did not surface with negative effcts. Rather, the library was a bit too accomodating to the point it was not conforming
Here's a small test program that streams data into the decoder. Its a bit contrived because of the
And:
|
Fixes security issue (DoS) in Crypto++ ASN1 decoder: weidai11/cryptopp#346 Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
Fixes security issue (DoS) in Crypto++ ASN1 decoder: weidai11/cryptopp#346 Signed-off-by: Peter Korsgaard <peter@korsgaard.com> (cherry picked from commit 222808a)
By default the member, named m_mark, is set to the maximum number of elements. If SetMark() is called, then m_mark is adjusted. Upon deallocation and zeroization, STDMIN(m_size, m_mark) elements are zeroized. We wanted to use a high water mark, but we could not track the writes to the allocation. operator[] would have been OK, but ::memcpy would have been problematic
Cleared at Crypto++ 6.0 release. |
We sent a copy to the mailing list at Security issue (DoS) in Crypto++ ASN1 decoder.
We asked for a CVE to be assigned on oss-security.CVE-2016-9939 was assigned to the issue.On Mon, Dec 12, 2016 at 8:45 AM, Gergely Nagy ngg@tresorit.com wrote:
Here is the patch that was attached to the email.
The text was updated successfully, but these errors were encountered: