Subject: [Cbor] Combining CBOR protocol libraries

From: Laurence Lundblade <[email-masked]>
Date: Thu, 20 May 2021 12:37:43 -0700

This is in the context of defining how CoSWID should be integrated into EAT <https://github.com/ietf-rats-wg/eat/pull/102>, but seems like a general CBOR protocol library implementation issue.

Let’s say you have a CoSWID library that uses tinyCBOR for CBOR decoding. Further let’s say all you have is a header and lib, no source. You have a .h file and a .a file.

Same for an EAT implementation, but it uses QCBOR for CBOR decoding.

I assume the input to the CoSWID decoding library is a binary byte string with the encoded CBOR. Can’t really be anything else, can it?

How to you take the binary encoded CoSWID out of the EAT and feed it to the CoSWID library?

If the EAT claim to hold a CoSWID is defined like this

eat_coswid_claim = (
    coswid => concise-swid-tag
)

it is truly not possible to feed the CoSWID from the EAT to the CoSWID library. QCBOR, and as far as I know, most CBOR decoders do not provide access to a still-encoded sub-chunk of the CBOR they are decoding. There’s no way to get the binary CBOR encoded byte string out of the EAT.

It seems the only possibility here is byte string wrapping like this:

eat_coswid_claim = (
    coswid => bstr .cbor concise-swid-tag
)

I think this generalizes to just about every CBOR protocol that includes another CBOR protocol. Every time you put a CBOR protocol message inside another different CBOR protocol message is MUST be byte string wrapped!

OK, well maybe there can be some exceptions, but I don’t think they are universal enough that they can be assumed in CBOR protocol design.

If the two libraries use the same CBOR decoder, then EAT’s decoder instance can be handed to the CoSWID decoder for temporary use to decode the CoSWID. Or similarly, if the two protocols’s being combined always go hand-in-hand and thus will rarely be implemented by separate libraries, then implementations will usually use the same CBOR decoder.

Note that this doesn’t really arise for COSE payloads because they are always byte-string wrapped.

Seems like the CBOR-based X.509 certificates going into COSE headers partially have this problem. In a lot of cases the COSE library and the CBOR-based X.509 cert library will go hand-in-hand and use the same decoder. But note that without byte-string wrapping of CBOR-based cert, they will always have to go hand-in-hand. You will not be able to integrate a CBOR-Cert library that uses one CBOR decoder in with a COSE library that uses a different decoder.

So the up shot for me here is that best practice for a CBOR protocol that is embedded in another CBOR protocol is byte-string wrapping.

LL

---

From: Thomas Fossati <[email-masked]>
Date: Thu, 20 May 2021 20:14:19 +0000

Hi Laurence,

On 20/05/2021, 20:38, "Laurence Lundblade" <[email-masked]> wrote:
> This is in the context of defining how CoSWID should be integrated
> into EAT <https://github.com/ietf-rats-wg/eat/pull/102>, but seems
> like a general CBOR protocol library implementation issue.  Let’s say
> you have a CoSWID library that uses tinyCBOR for CBOR decoding.
> Further let’s say all you have is a header and lib, no source. You
> have a .h file and a .a file.
>
> I assume the input to the CoSWID decoding library is a binary byte
> string with the encoded CBOR. Can’t really be anything else, can it?
>

The CBOR library we use follows the glorious Golang institution of
providing the RawMessage type [1].

It goes both ways: you can use it to delay decoding or to pre-encode.

Maybe the C libraries could be extended to do something similar?

Cheers!

[1] https://github.com/fxamacker/cbor

IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.

---

From: Laurence Lundblade <[email-masked]>
Date: Thu, 20 May 2021 14:10:37 -0700

> On May 20, 2021, at 1:14 PM, Thomas Fossati <[email-masked]> wrote:
> 

Yes, I could do that in QCBOR and probably others could too. It would require traversal of the CoSWID twice, once to find the end of it in the EAT decode and then once to actually decode it. Generally, CPUs are so fast these days, even little ones, that CPU consumption doesn’t seem like a problem to me. It would definitely be more code to do this than byte-string wrapping, but not a huge amount.

This has to be for all flavors of CBOR decoder, C, Rust, Python… 

This would be come a requirement on all your better CBOR decoders as I expect embedding some CBOR in other will be common as we build-up the CBOR-based protocol infrastructure.

So which is the better practice, byte-string wrapping for protocols or a requirement on your better CBOR decoders?

LL

---

From: Brian E Carpenter <[email-masked]>
Date: Fri, 21 May 2021 09:45:29 +1200

On 21-May-21 07:37, Laurence Lundblade wrote:
...
> OK, well maybe there can be some exceptions, but I don’t think they are universal enough that they can be assumed in CBOR protocol design.

...

> So the up shot for me here is that best practice for a CBOR protocol that is embedded in another CBOR protocol is byte-string wrapping.

On 21-May-21 09:10, Laurence Lundblade wrote:
...
> So which is the better practice, byte-string wrapping for protocols or a requirement on your better CBOR decoders?

I don't see how having a class of "better" decoders works with interoperability. If we require that both ends have a "better" decoder, we've effectively forked CBOR, haven't we?

We wrote this problem into the GRASP API (whose RFC, I understand, is less than 24 hours away):

>> A requirement for all language mappings and all API implementations is 
that, regardless of what other options exist for a language-specific representation of the value, there is always an option to use a raw CBOR data 
item as the value. The API will then wrap this with CBOR Tag 24 as an encoded CBOR data item for transmission via GRASP, and unwrap it after reception. By this means, ASAs will be able to communicate regardless of programming language.

I have some "interesting" code for this in my Python GRASP implementation, which decides on the fly whether to build a Tag24 or not, and if necessary de-tags an incoming Tag24 item. In other words, I had to write a nano 
encoder/decoder into my own code.

    Brian

---

From: Laurence Lundblade <[email-masked]>
Date: Thu, 20 May 2021 15:25:58 -0700

> On May 20, 2021, at 2:45 PM, Brian E Carpenter <[email-masked]> wrote:
> 

There’s always half-way implementations of protocols kicking around in GitHub and some of them may be useful in limited contexts. A CBOR decoder might also not implement preferred serialization, indefinite length string decoding and such and that is usually OK.

> encoder/decoder into my own code.

So I take it you prefer byte-string wrapping as a best practice?

LL

---

From: Brian E Carpenter <[email-masked]>
Date: Fri, 21 May 2021 11:35:49 +1200

On 21-May-21 10:25, Laurence Lundblade wrote:
> There’s always half-way implementations of protocols kicking around in GitHub and some of them may be useful in limited contexts. A CBOR 
decoder might also not implement preferred serialization, indefinite length string decoding and such and that is usually OK.

> So I take it you prefer byte-string wrapping as a best practice?

I think so, for the reason in my quote from the GRASP API - it allows you 
to be reasonably certain of being language-independent.

    Brian

---

From: Thomas Fossati <[email-masked]>
Date: Fri, 21 May 2021 07:16:07 +0000

On 20/05/2021, 22:10, "Laurence Lundblade" <[email-masked]> wrote:
> So which is the better practice, byte-string wrapping for protocols or
> a requirement on your better CBOR decoders?

From an IETF perspective, what we can do to make protocol composition
easier is to do as you suggested.

---

From: Laurence Lundblade <[email-masked]>
Date: Fri, 21 May 2021 12:12:27 -0700

I’ve made an update to the manifests and swevidece EAT claims here <https://github.com/ietf-rats-wg/eat/pull/102> that requires byte string wrapping. It also puts tags to use for kind of a full solution for identifying and handing off sub-protocol in the CBOR context. It goes like this:

If the sub-protocol is CBOR based (e.g. a CoSWID), then wrap it in a byte string and rely on the sub-protocol tag for dispatch to the correct handler.

If the sub-protocol is NOT CBOR based (e.g. and XML SWID), then contain it in a tagged byte string and again use the tag for dispatch.

In the first the tag is the contents of the byte string wrapping and in the second the byte string is the contents of a tag.

Note that I’m using the word “tag” here to mean the tag number AND tag content. I believe the at is the correct use of the tag in the CBOR context, even though it is counter intuitive.

(I also plan to eventually allow QCBOR to return raw encoded CBOR for arrays and maps to be able to implement protocols that don’t add the byte string wrapping layer)

LL

> On May 21, 2021, at 12:16 AM, Thomas Fossati <[email-masked]> wrote:
> 
> _______________________________________________
> CBOR mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/cbor
>