1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
/** @file */
/** @ingroup oscore_contextpair
*
* @addtogroup oscore_context_b1 Security context with Appendix B.1 recovery
*
* @brief A pre-derived context implementation that occasionally needs to be persisted
*
* This security context contains a @ref oscore_context_primitive, along with
* additional indicators for the mechanisms described in [Appendix B.1 of
* RFC8613](https://tools.ietf.org/html/rfc8613#appendix-B.1).
*
* Such a security context is superior to a primitive context as it can be used
* across reboots without the need to persist its state after any operation;
* it can recover lost state by skipping sequence numbers or asking for
* resubmission of the first request. A notable downside is that until the
* replay window is recovered, replays of old messages can be used to slowly
* exhaust own sequence numbers.
*
* There are aspects to its use:
*
* * Peristence: Two aspects of the context can be persisted, the sequence
* number and the replay window. Persisting the sequence number is mandatory,
* the replay window optional. (Persisting spares a round trip during the
* first request to the server from that given security context).
*
* * Sequence number persistence
*
* * When a context is created, the application needs to provide the last
* persisted sequence number in a @ref oscore_context_b1_initialize call.
*
* * After that, and repeatedly later on, the application should query the
* next sequence number to persist using the
* @ref oscore_context_b1_get_wanted call. When it has persisted that
* number, it uses @ref oscore_context_b1_allow_high call to inform the
* context
* that that sequence number has been persisted.
*
* Failure to do this often or fast enough results in temporary errors
* when sending messages, but does not endanger security. (In particular,
* no own messages can be sent until @ref oscore_context_b1_allow_high
* has been called).
*
* Once @ref oscore_context_b1_allow_high has been called, @ref
* oscore_context_b1_initialize must not be called in subsequent
* startups with any value of @ref oscore_context_b1_allow_high from
* earlier calls. This is crucial for security; failure to do this
* correctly typically results in nonce reuse and subsequent breach of
* the key.
*
* A method to extract and persist the current sequence number at
* shutdown (in analogy to the below) would be possible (mostly the
* documentation would become more verbose), but is currently not
* implemented as the ill-effect of not recovering a precise sequence
* number is just the loss of some sequence number space, and not an
* additional round-trip.
*
* * Replay window persistence (optional)
*
* An application can use the @ref oscore_context_b1_replay_extract
* function to extract the 9 byte necessary to express the replay window
* state. After that call, it must not use the security context any more --
* this is typically done at a controlled device shutdown, or when entering
* a deep sleep state in which the security context's data is lost.
*
* It can then use that persisted replay window state once (!) at the next
* startup using @ref oscore_context_b1_initialize. The data must be
* removed (or marked as deleted) in the persistent storage before that
* function is called. Failure to do so affects security with the same
* results as above.
*
* On startups that were not immediately preceded by an extraction, no
* replay window is reinjected. That is fine, and only results in an
* additional roundtrip for the first exchange message.
*
* * Application integration: libOSCORE can not manage the additional exchanges
* for replay window recovery on its own, as that would include sending
* messages on its own. It does, however, assist the application author in
* sending the right messages:
*
* * A server whose replay window was not initialized will see the first
* received message as @ref OSCORE_UNPROTECT_REQUEST_DUPLICATE. Rather than
* erring out with an unprotected 4.01 Unauthorized message, the server can
* use @ref oscore_context_b1_build_401echo to create a suitable response
* (which is a protected 4.01 with Echo option) if indicated by
* @ref oscore_context_b1_process_request.
*
* Alternatively, it may build its own response (which may be a 4.01, or
* even an actual result in case of safe requests) and include the echo
* value reported by @ref oscore_context_b1_get_echo in it.
*
* The call to @ref oscore_context_b1_process_request also serves to
* recognize any incoming Echo options and thus initialize the replay
* state.
*
* * A client that receives a 4.01 response with an Echo option needs to
* resubmit the request, and use any Echo value found in the response in
* its next request.
*
* Providing additional helpers here is [being considered](https://gitlab.com/oscore/liboscore/issues/47),
* and would profit from user feedback.
*
* @{
*/
/** @brief Data for a security context that can perform B.1 recovery
*
* This must always be initialized using @ref oscore_context_b1_initialize.
* (It will stay practically unusable until @ref oscore_context_b1_allow_high
* has been called as well, but until then the context is technically
* initialized, it's just that most operations will fail).
* */
;
/** @brief Persistable replay data of a B.1 context
*
* Such a datum can be extracted at shutdown using @ref
* oscore_context_b1_replay_extract and used in @ref
* oscore_context_b1_initialize once. Between those, it can be persisted in
* arbitrary form.
* */
;
/** @brief Initialize a B.1 context
*
* This is the way to initialize a @ref oscore_context_b1 struct.
*
* @param[inout] secctx B.1 security context to initialize; must not be NULL,
* and must be partially initialized.
* @param[in] immutables Primitive security context key material that will be
* used throughout the life time of the security context.
* @param[in] seqno The last (and highest) value that was ever passed to a @ref
* oscore_context_b1_allow_high call to this context, or 0 for brand-new
* contexts.
* @param[in] replaydata A struct previously obtained using
* @ref oscore_context_b1_replay_extract. Before this function is called,
* it must be ensuered that the same replaydata will not be passed in here
* again. Alternatively (ie. if replay extraction is not used, or if the
* extracted data has been removed before new one was extracted and
* persisted), NULL may be passed to start the Appendix B.1.2 recovery
* process.
*
*/
void ;
/** @brief State to a B.1 context that sequence numbers up to excluding @p
* seqno may be used freely
*
* This must be called before using the security context, and may be called at
* any later time with any value equal to or larger than the previous value
* passed with the same function. A convenient way to come up with such values
* that do not change too frequently is using
* @ref oscore_context_b1_get_wanted.
*
* This must only be called when it can be guaranteed that later calls to @ref
* oscore_context_b1_initialize will not give any value persisted earlier than
* @p seqno.
*
* @param[inout] secctx B.1 security context to update
* @param[in] seqno The persistent sequence number limit
*
*/
void ;
/** @brief The next sequence number a B.1 context wants to be allowed to use
*
* @param[in] secctx B.1 security context to query
*
* @return the sequence number that should be used on the next @ref
* oscore_context_b1_allow_high call
*
* Note that this is a plain convenience function that implements static
* increments of a default size, which are stepped whenever the previous
* allocation is half used up. Applications are free to come up with their own
* numbers based on predicted traffic, as long as the constraints of @ref
* oscore_context_b1_allow_high are met.
*
*/
uint64_t ;
/** @brief Take the replay data of a security context for persistence
*
* @param[inout] secctx B.1 security context to shut down. This is marked inout
* as the security context is uninitialized after this.
* @param[out] replaydata Location into which to move the replay window data.
*
* This function can be used during shutdown to take the security context's
* replay window and make it available for the next startup.
*
* After calling this function, the security context must not be used any more;
* instead, the same context can later be initialized using the extracted
* replaydata in @ref oscore_context_b1_initialize.
*
*/
void ;
/** @brief Find the Echo value used by a B.1 context for recovery
*
* This function provides access to the Echo value that is used (sent in
* responses, and recognized in requests) when a server is trying to run B.1.2
* replay window recovery.
*
* The obtained Echo value is valid until secctx is used again, and stable as
* long as the context is only used (but not changed).
*
* It should only be called when the replay window is uninitialized, and
* sequence numbers are available (as it takes one of its own to make the
* implenetation easier); calling it under other circumstances has no lasting
* side effects, but may result in the indication of a zero-length slice (which
* does no harm security-wise as that value is not recognized later, worst case
* it makes the first request fail) - but those preconditions are typically
* satisfied when used.
*
* This must only be called on a B.1 backed security context.
*
*/
void ;
/** @brief Helper function for processing incoming requests in B.1 contexts
*
* This function performs two tasks:
*
* * It checks whether it'd make sense to send an Echo value with the response
* to recover the replay window, returning the result.
*
* * It tries to recover the replay window using data from the incoming
* request. When it does, the request can be considered fresh in the sense of
* certainly not being a replay, and the request's unprotection status is
* upgraded from OSCORE_UNPROTECT_REQUEST_DUPLICATE to
* OSCORE_UNPROTECT_REQUEST_OK.
*
* At the same time, the request ID's is-first-use flag is set.
*
* It is best run after unprotecting a request and before any further
* processing. It is usually very cheap as it returns early on seeing the
* security context's initialized state. If it returns true, a good next step
* is building a response using @ref oscore_context_b1_build_401echo.
*
* @param[in] secctx The B.1 security context used with this request
* @param[in] request A received request message
* @param[inout] unprotectresult The result of the message's unprotect operation
* @param[inout] requestid The request ID of he unprotected message
* @return true if responding with an Echo option would help recover the replay window
*
*/
bool ;
/** @brief Build a 4.01 Unauthorized with Echo response
*
* This convenience function builds a protected 4.01 Unauthorized response with
* a suitable Echo option into a native message that is sent in response to a
* request that is rejected by the duplicate detection.
*
* It must only be used on security contexts backed by a B.1 context (or will
* crash), and only if @ref oscore_context_b1_replay_is_uninitialized returned
* true (or might send client and server into an endless exchange without
* results).
*
* @param[inout] message Native message into which the response is written
* @param[inout] secctx Security context to be used
* @param[inout] requestid ID of the request that is responded to. This is
* formally inout as the protection process reserves the right to update
* the request ID, but is practically in only because the function is only
* called in situations when the request ID's first use flag is clear
* anyway.
* @return true on success; the native message must be cleared by the
* application if it is to be sent, or must not be sent at all.
*/
bool ;
/** @} */