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

Allow access of protected header, payload, and signature as byte strings #91

Open
letmaik opened this issue Aug 2, 2022 · 5 comments
Open

Comments

@letmaik
Copy link
Contributor

letmaik commented Aug 2, 2022

Being able to access protected header, payload, and signature bytes is useful for implementing things like countersignature validation in external libraries.

For inspiration, this is how go-cose exposes headers both decoded and as bytes: https://pkg.go.dev/github.com/veraison/go-cose#Headers
And here the overall structure: https://pkg.go.dev/github.com/veraison/go-cose#Sign1Message

@laurencelundblade
Copy link
Owner

My ability to read go is limited, but I did look at it.

I think what is there in https://github.com/laurencelundblade/t_cose/blob/dev/inc/t_cose/t_cose_parameters.h is still fairly reasonable. I was thinking that counter signatures would be an important test too. While we eventually want that support built right into t_cose, I think what is there would allow them. There are the header read and write callbacks that allow headers to be arbitrarily complex.

Go is intrinsically object-oriented and garbage collected, so t_cose can't ever be the same as an implementation in go without using a lot more memory for both code and data.

Is there anything in particular you want to suggest?

@letmaik
Copy link
Contributor Author

letmaik commented Aug 3, 2022

There is no issue accessing a countersignature (or other int-labelled parameters). The issue rather is that currently the protected header cannot be accessed as a buffer, but only decoded. The signature cannot be accessed at all:

t_cose_sign1_verify(struct t_cose_sign1_verify_ctx *context,
struct q_useful_buf_c sign1,
struct q_useful_buf_c *payload,
struct t_cose_parameters *parameters);

Validating COSE countersignatures for example requires constructing this:

         Countersign_structure = [
           context : "CounterSignature" / "CounterSignature0" /
                     "CounterSignatureV2" / "CounterSignature0V2" /,
           body_protected : empty_or_serialized_map,
           ? sign_protected : empty_or_serialized_map,
           external_aad : bstr,
           payload : bstr,
           ? other_fields : [ + bstr ]
         ]

other_fields would contain the signature. So the inputs here are the protected header bytes, the payload bytes, and the signature bytes of the original message, plus inputs from the countersignature itself (like its own protected header).

I think t_cose should allow this kind of validation to be implemented in a third-party library.

@laurencelundblade
Copy link
Owner

I see. Thanks for point that out.

Part of a solution might be this change that is in-the-works for QCBOR: laurencelundblade/QCBOR#117, but that still wouldn't make the payload and signature available to header processors.

But rather than complicate the custom header processor API, I think it's better if implementors of counter signatures implemented a signer/verifier as in a struct t_cose_signature_sign with its callbacks. That does pass all the right stuff. It is run-time linkable to the rest of t_cose.

The one weakness of it is that the crypto adaptor layer is not public, so the implementor of counter signatures would have to replicate it or do something different.

It would also be good to just add counter signatures to t_cose 2.0. Maybe sooner rather than later to validate the 2.0 design better.

@letmaik
Copy link
Contributor Author

letmaik commented Aug 4, 2022

laurencelundblade/QCBOR#117 wouldn't be needed for this since COSE bstr-wraps all relevant parts.

I had a look at the struct t_cose_signature_sign in the dev branch. Some observations:

Since countersignatures sign an existing signature, the current interface wouldn't quite work. The signature bytes aren't available, and in the case of COSE_Sign there would have to be a way to select which COSE_Signature to countersign (I don't think countersigning a signature within a COSE_Sign is a common usecase, but COSE_Sign1 may be a use case). The I-D says "The countersignature needs to be treated as a separate operation from the initial operation even if it is applied by the same user".

Countersignatures are either stored in the unprotected header or somewhere externally. I think the current API is mostly to support multiple signatures for COSE_Sign.

There will be new types of countersignatures apart from https://datatracker.ietf.org/doc/html/draft-ietf-cose-countersign-06. For example, there is https://datatracker.ietf.org/doc/draft-birkholz-scitt-receipts/ which defines a COSE countersignature based on Merkle trees, using a different data type and stored in a different header parameter, but relying on the same components as regular countersignatures: protected header bytes, payload bytes, signature bytes.

For reference, see how the .NET preview COSE library is extended to expose those bits: dotnet/runtime#72611

@laurencelundblade
Copy link
Owner

Yeah, that the counter signature is inserted far earlier in the message than the thing its counter signing kind of up ends things for the current t_cose. I think the current API can work for a counter signature in a COSE_Sign, but probably nothing else.

The problem is how to design this without losing the code size, simplicity and low stack-only memory use. Dunno yet....

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

No branches or pull requests

2 participants