Subject: [core] OSCORE: Questions about Section 5.2

From: Jaro Fietz <[email-masked]>
Date: Thu, 11 Oct 2018 11:14:16 +0200

(resending this mail as I didn't confirm my mail address for over a week 
which is apparently too long)

Hello authors,

I'm currently implementing parts of OSCORE in C for a minimal OSCORE 
server. While working through the specification I encountered two 
questions so far, both regarding section "5.2. AEAD Nonce".

The first question is about the statement "left-pad the Sender ID of the 
endpoint that generated the Partial IV (ID_PIV) in network byte order 
with zeroes to exactly nonce length minus 6 bytes" (Section 5.2)
Given that the Partial IV is the sender sequence number [1], the ID_PIV 
is the Sender ID of the respective Sender Context. The Sender ID itself 
is defined as "Sender ID. Byte string used to [...]" (Section 3.1). 
Combining this with the original statement of "left-pad the Sender ID 
[...] in network byte order" assumes that byte strings have a network 
byte order. From my understanding only primitives with a size larger 
than a single byte can have / are affected by endianess. But a byte 
string consists of bytes, which don't have a byte order. No matter the 
host byte order, a byte string will always be represented equal on all 
machines. Thus I'm not sure how to interpret the paraphrased statement 
"encode a byte string in network byte order". Both oscore_californium 
and aiocoap just write the byte array to the nonce, which is what I 
think is meant and what I did as well.

The second question is regarding the statement "concatenate the size of 
the ID_PIV (a single byte S) with the padded ID_PIV and the padded PIV" 
(Section 5.2), especially the "size of the ID_PIV".
As reasoned above, ID_PIV is a byte-string. The size of a byte-string to 
me would be its length in bytes. Given [2] and my interpretation, the 
Sender ID of all relevant nodes in a network would have the same length, 
only different contents. While the (size, id)-pairs (1, [1]) and (2, 
[0,1]) would technically be different sender IDs, I don't know if 
implementations would actually honour that behaviour and if it would 
make sense from a deployment point of view. Thus, the reason for 
including the length of the Sender ID isn't obvious to me (yet, it may 
become more obvious when I work further through the specification). Thus 
my initial question was what length exactly would be included in the 
nonce, leaving me with two interpretations: First, just have the same 
length of the Sender ID in all packets, which would be its byte-length 
(assuming all Sender ID byte strings are configured to have the same 
length). Second, interpret the Sender ID as network byte order integer, 
strip its leading zeroes and take the resulting number's byte-length.
When looking through existing implementations, I in fact encountered 
both interpretations. The oscore_californium project used the length of 
the sender id array [3, 4, 5], while aiocoap uses the zero-stripped 
length of its number representation [6].

Which of these interpretations is correct, so which one should I implement?

If the Sender ID was an integer instead of a byte string, both above 
statements would be logical and make sense, but in the context of byte 
arrays the wording feels a little to me.

BR,
Jaro

[1]: "The 'Partial IV' parameter. The value is set to the Sender 
Sequence Number." (Section 5)
[2]: "The maximum length of Sender ID in bytes equals the length of AEAD 
nonce minus 6, see Section 5.2." (Section 3.3)
[3]: 
https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/OSSerializer.java?at=basic_oscore2&fileviewer=file-view-default#OSSerializer.java-272 

[4]: 
https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/Encryptor.java?at=basic_oscore2&fileviewer=file-view-default#Encryptor.java-74 

[5]: 
https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/OSCoreCtx.java?at=basic_oscore2&fileviewer=file-view-default#OSCoreCtx.java-316 

[6]: 
https://github.com/chrysn/aiocoap/blob/1a7f8bbbe079714ed6ba4a979a70339688148bc6/aiocoap/oscore.py#L222-L229

---

From: Christian Amsüss <[email-masked]>
Date: Thu, 11 Oct 2018 13:09:44 +0200

Hello Jaro,

I can answer just a small part of this:

On Thu, Oct 11, 2018 at 11:14:16AM +0200, Jaro Fietz wrote:
> Given [2] and my interpretation, the Sender ID of all relevant nodes
> in a network would have the same length, only different contents.

The expectation is that the shortest (zero-length) ID would be used in
cases wherever that's beneficial, eg. when a constrained device
primarily utilizes one context in which it is addressed as a server. For
the communication partner (which might be an unconstrained device in
such scenarios, and/or rarely addressed as a server), one would pick an
ID that's long enough to tell all that device's incoming messages apart.

> While the (size, id)-pairs (1, [1]) and (2, [0,1]) would
> technically be different sender IDs, I don't know if implementations would
> actually honour that behaviour

They certainly should. Left-trimming zeros off an ID will lead to
surprising results in every 256th situation.

> while aiocoap uses the zero-stripped length of its number
> representation [6].

You briefly had me worried I got it wrong myself -- but the
left-trimming that's happenign is on the sequence numbers, not on the
sender IDs. Sequence numbers need to be represented by the shortest big
endian (but non-zero-length) representation; representing them any
different would break the AAD agreement.

> I'm currently implementing parts of OSCORE in C for a minimal OSCORE server.

Slightly off topic: Would that happen to be a freely licensed
implementation? If so, I know of an embedded operating system project
that would love to hear about this.

Best regards
Christian

-- 
A beginning is the time for taking the most delicate care that the
balances are correct.
  -- Princess Irulan, Manual of Muad'Dib

---

From: Jaro Fietz <[email-masked]>
Date: Thu, 11 Oct 2018 14:41:30 +0200

Hello Christian,

thanks for your quick answer, it clarified the second of my questions.

On 10/11/18 1:09 PM, Christian Amsüss wrote:
> primarily utilizes one context in which it is addressed as a server.
This is an interesting optimization. I'm not too sure about the actual 
benefits though. To me this would only result in the constrained nodes 
being able to shave off a few bytes of allocation when constructing the 
response and saving their sender_id to persistent storage.
> sender IDs.
Sorry, I must have skipped incorrectly over the tuple construction. 
Reading through it again, your code is, of course, correct :)
> that would love to hear about this.
I'm implementing OSCORE on top of zephyr (not integrated into it) for an 
embedded board. Currently it isn't open source, but I asked my advisor, 
who'll forward the request to the supervisor.
Judging from your github history I expect you ask for RIOT-OS? :)

BR,
Jaro

---

From: Christian Amsüss <[email-masked]>
Date: Thu, 11 Oct 2018 15:31:21 +0200

Hello Jaro,

> benefits though. To me this would only result in the constrained nodes being
> able to shave off a few bytes of allocation when constructing the response
> and saving their sender_id to persistent storage.

It's much more about message size. There are applications that need to
get an OSCORE message through w/o fragmentation over single link layer
messages (6TiSCH joining), and this helps fitting things in there.

> Judging from your github history I expect you ask for RIOT-OS? :)

Indeed, RIOT is what I have in mind. There have been successful cases of
code shared between Zephyr and RIOT, and I think that collaboration
could be fruitful here, if licensing permits.

At any rates, I'm looking forward to interoperate with a constrained
application in future plug tests.

Best regards
Christian

-- 
To use raw power is to make yourself infinitely vulnerable to greater powers.
  -- Bene Gesserit axiom

---

From: Francesca Palombini <[email-masked]>
Date: Wed, 24 Oct 2018 12:38:30 +0000

Hi Jaro,

Thank you for your mail and sorry for the delayed reply.

Regarding the first question, you are right, “network byte order” was not the correct term in this instance (it might have been leftover from a previous version of OSCORE where Sender ID was of type integer, and used to clarify “left padding”). Your comment also applies to the 1st bullet, regarding Partial IV which is also a byte string. Yes, your (and other implementers) interpretation is correct. We have now removed “network byte order” in Section 5.2: https://core-wg.github.io/oscoap/draft-ietf-core-object-security.html#rfc.section.5.2

For the second question, thanks Christian for coming to the rescue, but yes, we did mean for different ID sizes to mean different IDs. So, 0x01 is different than 0x0001.  Also, the empty byte string is a valid ID. The reason for this was to be able to save bytes, as well as increase the IDs space. We sure hope implementations comply with this. So the length to use in the nonce is its byte length which does not have to be the same in all senders, which is the reason why we include it in the nonce computation as well.

Thanks for your email, and we would be interested to hear more about your implementation if you can share with us,
Francesca

From: core <[email-masked]> on behalf of Jaro Fietz <[email-masked]>
Date: Thursday, 11 October 2018 at 12:24
To: "[email-masked]" <[email-masked]>
Cc: "[email-masked]" <[email-masked]>, "[email-masked]" <[email-masked]>, "[email-masked]" <[email-masked]>
Subject: [core] OSCORE: Questions about Section 5.2

(resending this mail as I didn't confirm my mail address for over a week which is apparently too long)

Hello authors,

I'm currently implementing parts of OSCORE in C for a minimal OSCORE server. While working through the specification I encountered two questions so far, both regarding section "5.2. AEAD Nonce".

The first question is about the statement "left-pad the Sender ID of the endpoint that generated the Partial IV (ID_PIV) in network byte order with zeroes to exactly nonce length minus 6 bytes" (Section 5.2)
Given that the Partial IV is the sender sequence number [1], the ID_PIV is the Sender ID of the respective Sender Context. The Sender ID itself is defined as "Sender ID. Byte string used to [...]" (Section 3.1). Combining this with the original statement of "left-pad the Sender ID [...] in network byte order" assumes that byte strings have a network byte order. From my understanding only primitives with a size larger than a single byte can have / are affected by endianess. But a byte string consists of bytes, which don't have a byte order. No matter the host byte order, a byte string will always be represented equal on all machines. Thus I'm not sure how to interpret the paraphrased statement "encode a byte string in network byte order". Both oscore_californium and aiocoap just write the byte array to the nonce, which is what I think is meant and what I did as well.

The second question is regarding the statement "concatenate the size of the ID_PIV (a single byte S) with the padded ID_PIV and the padded PIV" (Section 5.2), especially the "size of the ID_PIV".
As reasoned above, ID_PIV is a byte-string. The size of a byte-string to me would be its length in bytes. Given [2] and my interpretation, the Sender ID of all relevant nodes in a network would have the same length, only different contents. While the (size, id)-pairs (1, [1]) and (2, [0,1]) would technically be different sender IDs, I don't know if implementations would actually honour that behaviour and if it would make sense from a deployment point of view. Thus, the reason for including the length of the Sender ID isn't obvious to me (yet, it may become more obvious when I work further through the specification). Thus my initial question was what length exactly would be included in the nonce, leaving me with two interpretations: First, just have the same length of the Sender ID in all packets, which would be its byte-length (assuming all Sender ID byte strings are configured to have the same length). Second, interpret the Sender ID as network byte order integer, strip its leading zeroes and take the resulting number's byte-length.
When looking through existing implementations, I in fact encountered both interpretations. The oscore_californium project used the length of the sender id array [3, 4, 5], while aiocoap uses the zero-stripped length of its number representation [6].

If the Sender ID was an integer instead of a byte string, both above statements would be logical and make sense, but in the context of byte arrays the wording feels a little to me.

BR,
Jaro

[1]: "The 'Partial IV' parameter. The value is set to the Sender Sequence Number." (Section 5)
[2]: "The maximum length of Sender ID in bytes equals the length of AEAD nonce minus 6, see Section 5.2." (Section 3.3)
[3]: https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/OSSerializer.java?at=basic_oscore2&fileviewer=file-view-default#OSSerializer.java-272
[4]: https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/Encryptor.java?at=basic_oscore2&fileviewer=file-view-default#Encryptor.java-74
[5]: https://bitbucket.org/lseitz/oscore/src/67680eaddcbc84967b5529868ce86db4abd54e72/oscore-cf/src/main/java/org/eclipse/californium/oscore/OSCoreCtx.java?at=basic_oscore2&fileviewer=file-view-default#OSCoreCtx.java-316
[6]: https://github.com/chrysn/aiocoap/blob/1a7f8bbbe079714ed6ba4a979a70339688148bc6/aiocoap/oscore.py#L222-L229