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
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
/** @file */
/** @ingroup oscore_api
*
* @addtogroup oscore_protection OSCORE protection API
*
* @brief API for creating OSCORE messages from CoAP messages
*
* These functions create OSCORE messages (that can be used with the @ref
* oscore_msg) from native messages (that were used with the @ref
* oscore_native_msg). On reception, they decrypt the message and make it
* viewable as a @ref oscore_msg_protected_t; on transmission, the outgoing
* message buffer is wrapped in a @ref oscore_msg_protected_t so that options
* can be written to it in the right places, and eventually encrypted before
* transmission.
*
* @anchor oscore_protection_finish
*
* @note
* Several functions that finish off a OSCORE message return the native message
* that was originally passed in.
*
* @note
* Those are returned for the benefit of applications that would not otherwise
* hold a reference to the encapsulated message. Applications may rely on those
* to to be the same (but, usually, internally modified) message that was
* passed in when the @ref oscore_msg_protected_t was created, and can thus
* ignore those return values.
*
* @{
*/
/** @brief Pre-parsed OSCORE header information
*
* This type contains the information extracted from the OSCORE header.
* Instances may only live as long as the message they belong to does and is
* not moved in memory.
*
* When such a type was created, it was already verified that it is well-formed
* and contains no unknown extension bits.
*
* Currently, it is a simple fat pointer, but that is subject to change as an
* implementation detail.
*
*/
typedef struct oscore_oscoreoption_t;
/** @brief Parse an OSCORE option
*
* This reads a CoAP OSCORE option and creates an @ref oscore_oscoreoption_t
* from it if it is well-formed and has no unknown or invalid fields.
*
* Typically this is used at initial processing of a message when its options
* are first iterated over, and an OSCORE option is encountered.
*
* The @p input provided needs to be valid for as long as the resulting @p out
* is used. In the typical case, this is provided by the @ref
* oscore_specific_native_requirements.
*
* @param[out] out Uninitialized memory to parse the option into
* @param[in] input OSCORE option encoded according to OSCORE Header Compression
* @param[in] input_len Length of the encoded OSCORE option
* @return true if the option could be parsed entirely.
*/
bool ;
/** @brief Clone a request @ref oscore_requestid_t
*
* @param[out] dest Previously uninitialized memory location of the destination
* @param[in] src Memory location of a source
*
* This copies message correlation data, but sets the new copy's "may reuse the
* partial IV" flag to false, thus ensuring that at most one response is sent
* using the client-provided nonce.
*/
void ;
/** @brief Results of unprotect request operations
*
* Users of the library should never check for identity to unsuccessful values,
* as those may be extended in future to provide better debugging.
* */
;
/** @brief Request message decryption
*
* Unprotect a request message with a given security context.
*
* @param[in] protected A received request message
* @param[out] unprotected A pre-allocated, uninitialized @ref oscore_msg_protected_t that will be made available on success
* @param[in] header An @ref oscore_oscoreoption_t extracted from `message`
* @param[inout] secctx The security context with which to decrypt (and by which to validate) the message
* @param[out] request_id An uninitialized request ID that can later be used to protect the response
*
* @return OSCORE_UNPROTECT_REQUEST_OK if decryption and authentication
* succeeded and the request could be verified and replay protection succeeded,
* OSCORE_UNPROTECT_REQUEST_DUPLICATE if decryption and authentication
* succeeded byt the replay protection indicates it could be a replay (or
* replay protection is not set up correctly yet), and any other if
* decryption/authentication failed.
*
* The OK and DUPLICATE results both count as successful in terms of
* initialization: A message will be available in `unprotected`, but in the
* duplicate case must only be processed further if it is safe (in the
* CoAP/REST sense, ie. side effect free; currently that's GET and FETCH
* requests).
*
* @note The result enum is used to reduce the risk of API users inadvertedly
* processing replays. The information about whether a request was (possibly) a
* duplicate or not is also encoded in request_id's "is first use" property,
* but having a dedicated return value forces users to take a conscious
* decision.
*
* When this function is followed up by a @ref oscore_prepare_response (as it
* usually is), the same @ref design_thread "unmodified security context" and
* @p request_id must be used in that subsequent call.
*/
enum oscore_unprotect_request_result ;
/** @brief Results of unprotect response operations
*
* This is different from @ref oscore_unprotect_request_result in that no
* replay protection is active in response processing, so there is no
* "_DUPLICATE" outcome.
*
* Users of the library should never check for identity to unsuccessful values,
* as those may be extended in future to provide better debugging.
* */
;
/** @brief Response message decryption
*
* Unprotect a message with a given security context.
*
* @param[in] protected A received message
* @param[out] unprotected A pre-allocated, uninitialized @ref oscore_msg_protected_t that will be made available on success
* @param[in] header An @ref oscore_oscoreoption_t extracted from `message`
* @param[inout] secctx The security context with which to decrypt (and by which to validate) the message
* @param[in] request_id Matching information from the protect step of the request message.
*
* @return OSCORE_UNPROTECT_OK if decryption and authentication succeeded,
* or any other if decryption/authentication failed.
*
*/
enum oscore_unprotect_response_result ;
/** @brief Free a native message from a protected message's control
*
* This relinquishes an @ref oscore_msg_protected_t's hold on a native message
* after it has been used in an unprotect operation.
*
* The message can not be expected to have meaningful content any more (in
* practice, it will contain its outer options as well as a payload consisting
* of the OSCORE plaintext).
*
* This function's counterpart in protect operations is @ref oscore_encrypt_message.
*
* The result @ref oscore_protection_finish "may be discarded".
*
*/
oscore_msg_native_t ;
/** @brief Results of message encryption preparation
*
* Users of the library should never check for identity to unsuccessful values,
* as those may be extended in future to provide better debugging.
* */
;
/** @brief Response message preparation
*
* Start building a message for encryption with a given security context.
*
* @param[in] protected An allocated message into which the operations on @p unprotected can write
* @param[in] unprotected A pre-allocated, uninititialized @ref oscore_msg_protected_t that the message can be written to
* @param[inout] secctx A security context used to protect the message, which a sequence number will be taken from on demand
* @param[inout] request_id The request ID of the incoming message. This is marked for input and output because creating the response re-using the request ID's sequence number will clear its "first use" property.
*
* @return OSCORE_PREPARE_OK if all information is available to continue, or
* any other if not.
*
* @attention The @p secctx passed in here must be the same as in the preceding
* @ref oscore_unprotect_request call, and may only be used to protect and
* unprotect other messages (and not altered in any other way) until the
* subsequent @ref oscore_encrypt_message function has been called. See
* @ref design_thread for more details.
*/
enum oscore_prepare_result ;
/** @brief Request message preparation
*
* Start building a message for encryption with a given security context.
*
* @param[in] protected An allocated message into which the operations on @p unprotected can write
* @param[in] unprotected A pre-allocated, uninititialized @ref oscore_msg_protected_t that the message can be written to
* @param[inout] secctx A security context used to protect the message, which a sequence number will be taken from on demand
* @param[out] request_id The request ID created in the process for this exchange, and is later used to unprotect the response.
*
* @return OSCORE_PREPARE_OK if all information is available to continue, or
* any other if not.
*
* @attention The @p secctx passed in here may only be used to protect and
* unprotect other messages (and not altered in any other way) until the
* subsequent @ref oscore_encrypt_message function has been called.
* See @ref design_thread for more details.
*/
enum oscore_prepare_result ;
/** @brief Results of message encryption
*
* Users of the library should never check for identity to unsuccessful values,
* as those may be extended in future to provide better debugging.
* */
;
/** @brief Encrypt a previously prepared and populated message
*
* This encrypts a that has been initiallized by @ref oscore_prepare_request or
* @ref oscore_prepare_response. The @ref oscore_msg_protected_trim_payload
* function must be called on the message before it is encrypted (which needs
* to happen anyway because the allocated message size in practically all cases
* exceeds the required number of bytes on the wire, eg. because the length of
* the OSCORE option depends on the sequence number).
*
* @param[inout] unprotected The message that has been built. This is described as "inout" because while the struct is coming in initialized, it should be considered uninitialized after this function. It is a usage error (that is caught unless assertions are disabled) to use the same struct for anything else that assumes that it is initialized.
* @param[out] protected The native message that was passed in in the protection step, which now contains the ciphertext.
* @return OSCORE_FINISH_OK if all steps succeeded, any other value otherwise.
*
* @attention Be sure to check the success value of this before sending @p
* protected. That message may be easily in a state in which the CoAP backend
* would accept it for sending, but contains unencrypted data. Not setting that
* field was considered as an API alternative (that would be slightly safer to
* use as the user has chances of getting NULL pointers back that the sending
* CoAP library would hopefully refuse loudly), but eventually discarded
* because of the risks of whole-program optimizing compilers reinstating
* turning that undefined behavior into the present behavior (without the
* benefit of this warning to the user).
*
* Even when this function returns unsuccessfully, the underlying native
* message is returned in @p protected and can be freed. Likewise, either way,
* the @p unprotected can not be used after this call any more.
*
* The value returned in @p protected
* @ref oscore_protection_finish "may be discarded"
* as it's the same originally passed in (but still needs to be a valid
* pointer).
*/
enum oscore_finish_result ;
/** @} */