Skip to content
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

Ensure critical header contains valid labels #78

Merged
merged 3 commits into from
Jun 21, 2022

Conversation

qmuntal
Copy link
Contributor

@qmuntal qmuntal commented Jun 20, 2022

Issue found by Trail of Bits during security review.

A protected header parameter containing a non-comparable element type, such a slice or a map, will produce a runtime panic while being encoded and decoded.

This is because the element is being used as map key to validate there are no missing critical headers, but non-comparable types can't be used as map keys, as per the Go spec.

Investigating this issue, I found we are missing to validate that the critical header array only contains valid labels (RFC 8152 Section 3.1), which are restricted to integers and strings (RFC 8152 Section 1.2).

This PR adds a new validation step which ensures that the elements of the critical header are valid labels when encoding and decoding a protected header.

By doing that we also fix the original issue, as integers and strings are always comparable.

@yogeshbdeshpande @shizhMSFT @thomas-fossati

Signed-off-by: qmuntal [email protected]

@qmuntal qmuntal changed the title Enusre critical header contains valid labels Ensure critical header contains valid labels Jun 20, 2022
Copy link
Contributor

@shizhMSFT shizhMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@thomas-fossati thomas-fossati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Question: this seems scoped to the decoding of protected headers. Should there be a similar check for the unprotected blob?

@qmuntal
Copy link
Contributor Author

qmuntal commented Jun 20, 2022

Thanks! Question: this seems scoped to the decoding of protected headers. Should there be a similar check for the unprotected blob?

The critical parameters must be placed in the protected header, so the check does not apply to the unprotected header.

@thomas-fossati
Copy link
Contributor

thomas-fossati commented Jun 20, 2022

Thanks! Question: this seems scoped to the decoding of protected headers. Should there be a similar check for the unprotected blob?

The critical parameters must be placed in the protected header, so the check does not apply to the unprotected header.

Right, so if we want to be compliant with the COSE spec, shouldn't we also enforce the check on the unprotected headers map? ( Apologies in advance if this is a stupid question, I'm context-switching from something completely different and I may be slightly confused :-) )

@qmuntal
Copy link
Contributor Author

qmuntal commented Jun 20, 2022

Right, so if we want to be compliant with the COSE spec, shouldn't we also enforce the check on the unprotected headers map? ( Apologies in advance if this is a stupid question, I'm context-switching from something completely different and I may be slightly confused :-) )

Not stupid at all. I'll let @shizhMSFT and @yogeshbdeshpande decide, as I might also be missing some context.

The spec says:

crit: ... When present, this parameter MUST be placed in the protected header bucket.

This seems to imply that the unprotected header can't contain the crit parameter, so we have to error out when it happens.

@yogeshbdeshpande
Copy link
Contributor

Reviewing now: let me check and comment!

@thomas-fossati
Copy link
Contributor

Right, so if we want to be compliant with the COSE spec, shouldn't we also enforce the check on the unprotected headers map? ( Apologies in advance if this is a stupid question, I'm context-switching from something completely different and I may be slightly confused :-) )

Not stupid at all. I'll let @shizhMSFT and @yogeshbdeshpande decide, as I might also be missing some context.

The spec says:

crit: ... When present, this parameter MUST be placed in the protected header bucket.

This seems to imply that the unprotected header can't contain the crit parameter, so we have to error out when it happens.

True dat. What I was referencing is the other bit of the spec that says that it's an error to have labels that aren't int / tstr -- for which we seem to be missing the corresponding check. Again, unless I'm utterly confused.

@qmuntal
Copy link
Contributor Author

qmuntal commented Jun 20, 2022

True dat. What I was referencing is the other bit of the spec that says that it's an error to have labels that aren't int / tstr -- for which we seem to be missing the corresponding check. Again, unless I'm utterly confused.

The only other use of labels are header map keys, and we are already checking those are either integers or strings in validateHeaderLabel, so we are not missing any more checks, at least that I'm aware of.

@yogeshbdeshpande
Copy link
Contributor

Understanding the thread and checking: There are two points of checking here, if I understand correctly.

  1. Verify that the Value part of Protected Header, Critical Header Map(crit) is all Labels, which in turn could be int/tstr. This check ensures that.

  2. Should we check whether all the Map Keys in all Headers (Protected and Unprotected) are all valid Labels.

I think, 2 does seem to be a valid check and we should address it. However ValidateHeaderLable used in both Marshal and UnMarshal so it is fine. My take.

headers.go Outdated Show resolved Hide resolved
@thomas-fossati
Copy link
Contributor

thomas-fossati commented Jun 20, 2022

True dat. What I was referencing is the other bit of the spec that says that it's an error to have labels that aren't int / tstr -- for which we seem to be missing the corresponding check. Again, unless I'm utterly confused.

The only other use of labels are header map keys, and we are already checking those are either integers or strings in validateHeaderLabel, so we are not missing any more checks, at least that I'm aware of.

Isn't that scoped to the decoding side only? If not, ignore me :-) , otherwise this bit of the spec may apply:

   The presence of a label in a COSE map that is not a string or an
   integer is an error.  Applications can either fail processing or
   process messages with incorrect labels; however, they MUST NOT create
   messages with incorrect labels.

in paricular, the however, they MUST NOT create [...] which refers to the Marshalling ops

Copy link
Contributor

@yogeshbdeshpande yogeshbdeshpande left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor

@shizhMSFT shizhMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines +448 to +449
case uint64:
label = int64(v)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we intercept the potential overflow here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll rather do it in another PR. This is clearly an issue but requires its own discussion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. #79 for tracking this.

@thomas-fossati
Copy link
Contributor

True dat. What I was referencing is the other bit of the spec that says that it's an error to have labels that aren't int / tstr -- for which we seem to be missing the corresponding check. Again, unless I'm utterly confused.

The only other use of labels are header map keys, and we are already checking those are either integers or strings in validateHeaderLabel, so we are not missing any more checks, at least that I'm aware of.

Isn't that scoped to the decoding side only? If not, ignore me :-) , otherwise this bit of the spec may apply:

   The presence of a label in a COSE map that is not a string or an
   integer is an error.  Applications can either fail processing or
   process messages with incorrect labels; however, they MUST NOT create
   messages with incorrect labels.

in paricular, the however, they MUST NOT create [...] which refers to the Marshalling ops

Scratch that, I was talking rubbish.

Copy link
Contributor

@thomas-fossati thomas-fossati left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢 it!

@thomas-fossati thomas-fossati merged commit b870a00 into veraison:main Jun 21, 2022
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.

4 participants