Subject: [core] OSCOAP -02: sequence number reuse?

From: Christian Amsüss <[email-masked]>
Date: Tue, 21 Mar 2017 20:56:24 +0100

Hello OSCOAP authors,

implementing OSCOAP -02, I'm worried about possible reuse of sequence
numbers. To make sure I understand things right, I'd like to outline
first my understanding of IVs currently specified:

* Assume the server has sender ID 01, and the client has sender ID 02.
* The server's Sender IV is derived from 01, let's say it is
  00010000000000; in analogy, the client's Sender IV is then
  00020000000000.
* The server's Recipient IV is then 00020000000000, the clients'
  Recipient IV is 00010000000000.

(If I'm completely off by here, please let me know and skip the rest).

When the client sends a request with seqno 1, the partial IV it sends is
01, and it uses IV 00020000000001. In the response, the server uses the
same sequence number but as a response, and according to 7.3 #3, it uses
the IV 80020000000001 (its recipient IV, first bit flipped and request
seqno applied). In that process, the server never touches its sequence
number counter.

When then, much later, the client starts an observation, it might send a
request with seqno 257 and IV 00020000000101. The server would, in its
response, fall into the second case of 7.3 #3, have its sequence number
at 1 and produce 80020000000001 (its recipient IV, first bit flipped,
and its own sequence number), which is the very IV we've had before.

(Again, if I'm completely off by here, ...).

I suppose the whole idea behind using the top-most bit on responses is
to partition the available IVs into a half that is self-determined and
one that is peer-determined. The idea is valid IMO, provided we stick
with "only one sender and one recipient" scenarios. Its execution would
need modification, though, unless I got the above wrong. I'd suggest:

* The first bit is flipped iff the sequence number of the request gets
  used (in which case neither server nor client do any checking of the
  sequence number, as it is as unique as the request's).

  Whenever a message is sent that carries its own sequence number
  (either because it is a request or because it is an observe response),
  its sender uses up a sequence number, its recipient checks the number,
  and the first bit stays as it is.

Furthermore, the use of one's Recipient IV for sending a message worries
me: This means that two different base IVs are used with the same key
(as long as the server acts as a server, it uses x002000000nnnn, but
when it asks back, it uses 0001000000nnnn). That means that the
10000000001(hex)st message the server uses in its role as a client
IV-collides with the 1st it uses in an observation.

IMO, everyone should still use their Sender IV for sending, and let the
first-bit flipping do the partitioning.

Hoping you didn't have to skip here from the first "If"
Christian

-- 
Christian Amsüss                      | Energy Harvesting Solutions GmbH
founder, system architect             | headquarter:
mailto:[email-masked]  | Arbeitergasse 15, A-4400 Steyr
tel:+43-664-97-90-6-39                | http://www.energyharvesting.at/
                                      | ATU68476614

---

From: Göran Selander <[email-masked]>
Date: Wed, 22 Mar 2017 10:17:02 +0000

Hi Christian,

Excellent, thanks for reading carefully! There are indeed two errors in
the text:

- Clearly Sender IV should be used with Sender key in 7.3 #3
- The point with flipping the bit is to enforce disjoint sequence number
ranges when using the same IV. The intended construction was that the
sequence number used by the sender would not have the flipped bit.

Judging by your proposal you got the point despite these errors. I’ve
updated the draft, please check if I got it right:

https://github.com/core-wg/oscoap/commit/f375f4c62cbc8737f4ab9163a815912d7a
364cb3

As an exercise, verify that this construction works even if client and
server change roles. And also with Observe in that case.

Göran

---

From: Christian Amsüss <[email-masked]>
Date: Wed, 22 Mar 2017 16:49:26 +0100

> server change roles. And also with Observe in that case.

As I read it now, it should work. (Without observe and role reversal, it
works in my implementation, the rest is pending but requires some more
streamlining in the API).

Where I do see trouble coming up is when the multicast proposals get
warmed up again. For then, I can envision at least two solutions[1], so
I suppose we're good.

Best regards
Christian

[1]: (Diverting this into a footnote so it's on record, even though it's
not relevant for this thread itself, but might spin off a new one for
multicast:)

* Approach A: Unless only one node that is allowed to do requests, all
  responses must bear a sequence number of their own instead of
  mirroring.

  This adds back the sequence numbers to the message length. (As the
  multicast responses probably need the KID as well, this just means
  that the compressed responses take the [partIV, kid, ciphertext] form.

* Approach B: Allocate not 1 but n "mirror spaces". This would take
  ceil(log2(n_participants)) bits off the sequence number range, but the
  responders would then only need to send their KID (sender ID) and the
  ciphertext.

  (Basically they'd encode the peer number in reverse bit sequence in
  the partial IV, where 0 is used for sequence numbers the device has
  dealt itself, 1 is for sequence numbers out of the list of the first
  partner (or the unicast partner), and 2 etc is for sequence numbers of
  other people's pools.