-
Notifications
You must be signed in to change notification settings - Fork 96
Fix undefined shift in asn1 parsing #295
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
Conversation
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.
Thanks for the proposed fix, but I think it isn't right.
I've already started to look at the issue and expect to have a fix soon.
@@ -163,7 +163,7 @@ int mbedtls_asn1_get_int( unsigned char **p, | |||
*val = 0; | |||
while( len-- > 0 ) | |||
{ | |||
*val = ( *val << 8 ) | **p; | |||
*val = ( ((unsigned int) *val) << 8 ) | **p; |
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.
That results in the wrong value when the value fits in an unsigned int
but not in an int
, doesn't it?
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.
The undefined behaviour is one thing, but the entire function looks ... tricky.
If I was to reverse engineer the ASN1 INTEGER spec from this code I would have to deduce that:
- an empty byte string is not a valid ASN1 integer.
- the value zero can be represented as any number (>=1) of
00
bytes. - the bytes
00 00 00 00 00 00 00 00 00 00 12 34 56 78
are a valid ASN1 integer, with the value0x12345678
- the byte
87
is not a valid integer in ASN1, presumably 0x87 has to rendered as00 87
? - the bytes
87 65 43 21
are not a valid integer in ASN1 - the bytes
00 87 65 43 21
are a valid ASN1 integer in ASN1, with 'value' 0x87654321. Which is negative. - the bytes
12 34 56 78 00
are not a valid integer in ASN1.
The strangest artefact of the implementation is the (**p & 0x80) != 0
test which rejects values that have msb set (e.g. 4 above). But it doesn't reject values >=231 which in our systems are cast to negative signed integer values (see 6 above).
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.
.. and now I've read teh ASN.1 DER encoding rules... and this function implementation (after the UB fix):
- is too relaxed about leading zeros (each value has exactly one valid representation)
- errors on correctly represented negative values
- returns a negative result for correctly formatted postive integers in the range 231 <= v < 232
Item 1 does no substantial harm. Item 2 might make some scenarios fail that should succeed - but the scope of ASN.1 usage in this library might not require negative integer values. Item 3 is a real defect, with unclear consequences.
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.
now I've read teh ASN.1 DER encoding rules
Commiserations.
is too relaxed about leading zeros
We don't necessarily reject non-BER encodings. It's a matter of interoperability. I'd like to tighten things up, because being liberal in what you accept is not such a good idea, but we can only do that after a careful review to ensure we don't break somebody's workflow.
errors on correctly represented negative values
This is cryptography. We don't deal in negative values. The fact that the encoding supports them is an unfortunate historical relic.
returns a negative result for correctly formatted postive integers
Or rather, since this is a signed int, triggered undefined behavior, which in many environments would manifest itself by returning a negative result. The correct behavior is actually to return an error since the number is out of the representable range in this case.
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.
If I was to reverse engineer the ASN1 INTEGER spec
Note that we don't exactly implement the ASN.1 specification or even a subset of it. We implement something that is close to a subset of it, but that works in the real world which is a vicious circle of people not quite implementing the specification correctly and the rest having to follow through for interoperability and backward compatibility.
I'm closing in favor of a tested fix in #297 |
Found by oss-fuzz
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=18102
This is similar to a previous fix some time ago :
https://github.com/ARMmbed/mbedtls/pull/1625/files#diff-8d3acce410d251c6ead39efd401db23eR3316