Skip to content

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

Closed
wants to merge 1 commit into from

Conversation

catenacyber
Copy link
Contributor

Copy link
Collaborator

@gilles-peskine-arm gilles-peskine-arm left a 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;
Copy link
Collaborator

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?

Copy link
Contributor

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:

  1. an empty byte string is not a valid ASN1 integer.
  2. the value zero can be represented as any number (>=1) of 00 bytes.
  3. the bytes 00 00 00 00 00 00 00 00 00 00 12 34 56 78 are a valid ASN1 integer, with the value 0x12345678
  4. the byte 87 is not a valid integer in ASN1, presumably 0x87 has to rendered as 00 87?
  5. the bytes 87 65 43 21 are not a valid integer in ASN1
  6. the bytes 00 87 65 43 21 are a valid ASN1 integer in ASN1, with 'value' 0x87654321. Which is negative.
  7. 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).

Copy link
Contributor

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):

  1. is too relaxed about leading zeros (each value has exactly one valid representation)
  2. errors on correctly represented negative values
  3. 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.

Copy link
Collaborator

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.

Copy link
Collaborator

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.

@gilles-peskine-arm
Copy link
Collaborator

I'm closing in favor of a tested fix in #297

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants