1 /*
2 * t_cose_test.c
3 *
4 * Copyright 2019-2020, Laurence Lundblade
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 * See BSD-3-Clause license in README.md
9 */
10
11 #include "t_cose_test.h"
12 #include "t_cose_sign1_sign.h"
13 #include "t_cose_sign1_verify.h"
14 #include "t_cose_make_test_messages.h"
15 #include "q_useful_buf.h"
16 #include "t_cose_crypto.h" /* For signature size constant */
17 #include "t_cose_util.h" /* for get_short_circuit_kid */
18
19
20 /*
21 * Public function, see t_cose_test.h
22 */
short_circuit_self_test()23 int_fast32_t short_circuit_self_test()
24 {
25 struct t_cose_sign1_sign_ctx sign_ctx;
26 struct t_cose_sign1_verify_ctx verify_ctx;
27 enum t_cose_err_t return_value;
28 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
29 struct q_useful_buf_c signed_cose;
30 struct q_useful_buf_c payload;
31
32
33 /* --- Make COSE Sign1 object --- */
34 t_cose_sign1_sign_init(&sign_ctx,
35 T_COSE_OPT_SHORT_CIRCUIT_SIG,
36 T_COSE_ALGORITHM_ES256);
37
38 /* No key necessary because short-circuit test mode is used */
39
40 return_value = t_cose_sign1_sign(&sign_ctx,
41 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
42 signed_cose_buffer,
43 &signed_cose);
44 if(return_value) {
45 return 1000 + return_value;
46 }
47 /* --- Done making COSE Sign1 object --- */
48
49
50 /* --- Start verifying the COSE Sign1 object --- */
51 /* Select short circuit signing */
52 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
53
54 /* No key necessary with short circuit */
55
56 /* Run the signature verification */
57 return_value = t_cose_sign1_verify(&verify_ctx,
58 /* COSE to verify */
59 signed_cose,
60 /* The returned payload */
61 &payload,
62 /* Don't return parameters */
63 NULL);
64 if(return_value) {
65 return 2000 + return_value;
66 }
67
68 /* compare payload output to the one expected */
69 if(q_useful_buf_compare(payload, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"))) {
70 return 3000;
71 }
72 /* --- Done verifying the COSE Sign1 object --- */
73
74 return 0;
75 }
76
77
78 /*
79 * Public function, see t_cose_test.h
80 */
short_circuit_verify_fail_test()81 int_fast32_t short_circuit_verify_fail_test()
82 {
83 struct t_cose_sign1_sign_ctx sign_ctx;
84 struct t_cose_sign1_verify_ctx verify_ctx;
85 enum t_cose_err_t return_value;
86 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
87 struct q_useful_buf_c signed_cose;
88 struct q_useful_buf_c payload;
89 size_t payload_offset;
90
91 /* --- Start making COSE Sign1 object --- */
92 t_cose_sign1_sign_init(&sign_ctx,
93 T_COSE_OPT_SHORT_CIRCUIT_SIG,
94 T_COSE_ALGORITHM_ES256);
95
96 /* No key necessary because short-circuit test mode is used */
97
98 return_value = t_cose_sign1_sign(&sign_ctx,
99 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
100 signed_cose_buffer,
101 &signed_cose);
102 if(return_value) {
103 return 1000 + return_value;
104 }
105 /* --- Done making COSE Sign1 object --- */
106
107
108 /* --- Start Tamper with payload --- */
109 /* Find the offset of the payload in COSE_Sign1 */
110 payload_offset = q_useful_buf_find_bytes(signed_cose, Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"));
111 if(payload_offset == SIZE_MAX) {
112 return 6000;
113 }
114 /* Change "payload" to "hayload" */
115 ((char *)signed_cose.ptr)[payload_offset] = 'h';
116 /* --- Tamper with payload Done --- */
117
118
119 /* --- Start verifying the COSE Sign1 object --- */
120
121 /* Select short circuit signing */
122 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
123
124 /* No key necessary with short circuit */
125
126 /* Run the signature verification */
127 return_value = t_cose_sign1_verify(&verify_ctx,
128 /* COSE to verify */
129 signed_cose,
130 /* The returned payload */
131 &payload,
132 /* Don't return parameters */
133 NULL);
134 if(return_value != T_COSE_ERR_SIG_VERIFY) {
135 return 4000 + return_value;
136 }
137 /* --- Done verifying the COSE Sign1 object --- */
138
139 return 0;
140 }
141
142
143 /*
144 * Public function, see t_cose_test.h
145 */
short_circuit_signing_error_conditions_test()146 int_fast32_t short_circuit_signing_error_conditions_test()
147 {
148 struct t_cose_sign1_sign_ctx sign_ctx;
149 QCBOREncodeContext cbor_encode;
150 enum t_cose_err_t return_value;
151 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300);
152 Q_USEFUL_BUF_MAKE_STACK_UB( small_signed_cose_buffer, 15);
153 struct q_useful_buf_c signed_cose;
154
155
156 /* -- Test bad algorithm ID 0 -- */
157 /* Use reserved alg ID 0 to cause error. */
158 t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, 0);
159
160 return_value = t_cose_sign1_sign(&sign_ctx,
161 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
162 signed_cose_buffer,
163 &signed_cose);
164 if(return_value != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) {
165 return -1;
166 }
167
168
169 /* -- Test bad algorithm ID -4444444 -- */
170 /* Use unassigned alg ID -4444444 to cause error. */
171 t_cose_sign1_sign_init(&sign_ctx, T_COSE_OPT_SHORT_CIRCUIT_SIG, -4444444);
172
173 return_value = t_cose_sign1_sign(&sign_ctx,
174 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
175 signed_cose_buffer,
176 &signed_cose);
177 if(return_value != T_COSE_ERR_UNSUPPORTED_SIGNING_ALG) {
178 return -2;
179 }
180
181
182
183 /* -- Tests detection of CBOR encoding error in the payload -- */
184 QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
185
186 t_cose_sign1_sign_init(&sign_ctx,
187 T_COSE_OPT_SHORT_CIRCUIT_SIG,
188 T_COSE_ALGORITHM_ES256);
189 return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
190
191
192 QCBOREncode_AddSZString(&cbor_encode, "payload");
193 /* Force a CBOR encoding error by closing a map that is not open */
194 QCBOREncode_CloseMap(&cbor_encode);
195
196 return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
197
198 if(return_value != T_COSE_ERR_CBOR_FORMATTING) {
199 return -3;
200 }
201
202
203 /* -- Tests the output buffer being too small -- */
204 t_cose_sign1_sign_init(&sign_ctx,
205 T_COSE_OPT_SHORT_CIRCUIT_SIG,
206 T_COSE_ALGORITHM_ES256);
207
208 return_value = t_cose_sign1_sign(&sign_ctx,
209 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
210 small_signed_cose_buffer,
211 &signed_cose);
212
213 if(return_value != T_COSE_ERR_TOO_SMALL) {
214 return -4;
215 }
216
217 return 0;
218 }
219
220
221 /*
222 * Public function, see t_cose_test.h
223 */
short_circuit_make_cwt_test()224 int_fast32_t short_circuit_make_cwt_test()
225 {
226 struct t_cose_sign1_sign_ctx sign_ctx;
227 struct t_cose_sign1_verify_ctx verify_ctx;
228 QCBOREncodeContext cbor_encode;
229 enum t_cose_err_t return_value;
230 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
231 struct q_useful_buf_c signed_cose;
232 struct q_useful_buf_c payload;
233 QCBORError cbor_error;
234
235 /* --- Start making COSE Sign1 object --- */
236
237 /* The CBOR encoder instance that the COSE_Sign1 is output into */
238 QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
239
240 t_cose_sign1_sign_init(&sign_ctx,
241 T_COSE_OPT_SHORT_CIRCUIT_SIG,
242 T_COSE_ALGORITHM_ES256);
243
244 /* Do the first part of the the COSE_Sign1, the parameters */
245 return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
246 if(return_value) {
247 return 1000 + return_value;
248 }
249
250 QCBOREncode_OpenMap(&cbor_encode);
251 QCBOREncode_AddSZStringToMapN(&cbor_encode, 1, "coap://as.example.com");
252 QCBOREncode_AddSZStringToMapN(&cbor_encode, 2, "erikw");
253 QCBOREncode_AddSZStringToMapN(&cbor_encode, 3, "coap://light.example.com");
254 QCBOREncode_AddInt64ToMapN(&cbor_encode, 4, 1444064944);
255 QCBOREncode_AddInt64ToMapN(&cbor_encode, 5, 1443944944);
256 QCBOREncode_AddInt64ToMapN(&cbor_encode, 6, 1443944944);
257 const uint8_t xx[] = {0x0b, 0x71};
258 QCBOREncode_AddBytesToMapN(&cbor_encode, 7, Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(xx));
259 QCBOREncode_CloseMap(&cbor_encode);
260
261 /* Finish up the COSE_Sign1. This is where the signing happens */
262 return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
263 if(return_value) {
264 return 2000 + return_value;
265 }
266
267 /* Finally close off the CBOR formatting and get the pointer and length
268 * of the resulting COSE_Sign1
269 */
270 cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
271 if(cbor_error) {
272 return 3000 + cbor_error;
273 }
274 /* --- Done making COSE Sign1 object --- */
275
276
277 /* --- Compare to expected from CWT RFC --- */
278 /* The first part, the intro and protected pararameters must be the same */
279 const uint8_t cwt_first_part_bytes[] = {0xd2, 0x84, 0x43, 0xa1, 0x01, 0x26};
280 struct q_useful_buf_c fp = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(cwt_first_part_bytes);
281 struct q_useful_buf_c head = q_useful_buf_head(signed_cose, sizeof(cwt_first_part_bytes));
282 if(q_useful_buf_compare(head, fp)) {
283 return -1;
284 }
285
286 /* Skip the key id, because this has the short-circuit key id */
287 const size_t kid_encoded_len =
288 1 +
289 1 +
290 2 +
291 32; // length of short-circuit key id
292
293 /* Compare the payload */
294 const uint8_t rfc8392_payload_bytes[] = {
295 0x58, 0x50, 0xa7, 0x01, 0x75, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f,
296 0x2f, 0x61, 0x73, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65,
297 0x2e, 0x63, 0x6f, 0x6d, 0x02, 0x65, 0x65, 0x72, 0x69, 0x6b, 0x77,
298 0x03, 0x78, 0x18, 0x63, 0x6f, 0x61, 0x70, 0x3a, 0x2f, 0x2f, 0x6c,
299 0x69, 0x67, 0x68, 0x74, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c,
300 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x04, 0x1a, 0x56, 0x12, 0xae, 0xb0,
301 0x05, 0x1a, 0x56, 0x10, 0xd9, 0xf0, 0x06, 0x1a, 0x56, 0x10, 0xd9,
302 0xf0, 0x07, 0x42, 0x0b, 0x71};
303
304 struct q_useful_buf_c fp2 = Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8392_payload_bytes);
305
306 struct q_useful_buf_c payload2 = q_useful_buf_tail(signed_cose,
307 sizeof(cwt_first_part_bytes)+kid_encoded_len);
308 struct q_useful_buf_c pl3 = q_useful_buf_head(payload2,
309 sizeof(rfc8392_payload_bytes));
310 if(q_useful_buf_compare(pl3, fp2)) {
311 return -2;
312 }
313
314 /* Skip the signature because ECDSA signatures usually have a random
315 component */
316
317
318 /* --- Start verifying the COSE Sign1 object --- */
319 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
320
321 /* No key necessary with short circuit */
322
323 /* Run the signature verification */
324 return_value = t_cose_sign1_verify(&verify_ctx,
325 /* COSE to verify */
326 signed_cose,
327 /* The returned payload */
328 &payload,
329 /* Don't return parameters */
330 NULL);
331 if(return_value) {
332 return 4000 + return_value;
333 }
334
335 /* Format the expected payload CBOR fragment */
336
337 /* compare payload output to the one expected */
338 if(q_useful_buf_compare(payload, q_useful_buf_tail(fp2, 2))) {
339 return 5000;
340 }
341 /* --- Done verifying the COSE Sign1 object --- */
342
343 return 0;
344 }
345
346
347 /*
348 * Public function, see t_cose_test.h
349 */
short_circuit_decode_only_test()350 int_fast32_t short_circuit_decode_only_test()
351 {
352 struct t_cose_sign1_sign_ctx sign_ctx;
353 struct t_cose_sign1_verify_ctx verify_ctx;
354 QCBOREncodeContext cbor_encode;
355 enum t_cose_err_t return_value;
356 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
357 struct q_useful_buf_c signed_cose;
358 struct q_useful_buf_c payload;
359 Q_USEFUL_BUF_MAKE_STACK_UB( expected_payload_buffer, 10);
360 struct q_useful_buf_c expected_payload;
361 QCBORError cbor_error;
362
363 /* --- Start making COSE Sign1 object --- */
364
365 /* The CBOR encoder instance that the COSE_Sign1 is output into */
366 QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
367
368 t_cose_sign1_sign_init(&sign_ctx,
369 T_COSE_OPT_SHORT_CIRCUIT_SIG,
370 T_COSE_ALGORITHM_ES256);
371
372 /* Do the first part of the the COSE_Sign1, the parameters */
373 return_value = t_cose_sign1_encode_parameters(&sign_ctx, &cbor_encode);
374 if(return_value) {
375 return 1000 + return_value;
376 }
377
378
379 QCBOREncode_AddSZString(&cbor_encode, "payload");
380
381 /* Finish up the COSE_Sign1. This is where the signing happens */
382 return_value = t_cose_sign1_encode_signature(&sign_ctx, &cbor_encode);
383 if(return_value) {
384 return 2000 + return_value;
385 }
386
387 /* Finally close of the CBOR formatting and get the pointer and length
388 * of the resulting COSE_Sign1
389 */
390 cbor_error = QCBOREncode_Finish(&cbor_encode, &signed_cose);
391 if(cbor_error) {
392 return 3000 + cbor_error;
393 }
394 /* --- Done making COSE Sign1 object --- */
395
396 /* -- Tweak signature bytes -- */
397 /* The signature is the last thing so reach back that many bytes and tweak
398 so if signature verification were attempted, it would fail */
399 const size_t last_byte_offset = signed_cose.len - T_COSE_EC_P256_SIG_SIZE;
400 ((uint8_t *)signed_cose.ptr)[last_byte_offset] += 1;
401
402
403 /* --- Start verifying the COSE Sign1 object --- */
404 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY);
405
406 /* No key necessary with short circuit */
407
408 /* Run the signature verification */
409 return_value = t_cose_sign1_verify(&verify_ctx,
410 /* COSE to verify */
411 signed_cose,
412 /* The returned payload */
413 &payload,
414 /* Don't return parameters */
415 NULL);
416
417
418 if(return_value) {
419 return 4000 + return_value;
420 }
421
422 /* Format the expected payload CBOR fragment */
423 QCBOREncode_Init(&cbor_encode, expected_payload_buffer);
424 QCBOREncode_AddSZString(&cbor_encode, "payload");
425 QCBOREncode_Finish(&cbor_encode, &expected_payload);
426
427 /* compare payload output to the one expected */
428 if(q_useful_buf_compare(payload, expected_payload)) {
429 return 5000;
430 }
431 /* --- Done verifying the COSE Sign1 object --- */
432
433 return 0;
434 }
435
436
437 /*
438 18( [
439 / protected / h’a10126’ / {
440 \ alg \ 1:-7 \ ECDSA 256 \
441 }/ ,
442 / unprotected / {
443 / kid / 4:’11’
444 },
445 / payload / ’This is the content.’,
446
447 / signature / h’8eb33e4ca31d1c465ab05aac34cc6b23d58fef5c083106c4
448 d25a91aef0b0117e2af9a291aa32e14ab834dc56ed2a223444547e01f11d3b0916e5
449 a4c345cacb36’
450 ] )
451
452 */
453
454 /* This comes from Appendix_C_2_1.json from COSE_C by Jim Schaad */
455 static const uint8_t rfc8152_example_2_1[] = {
456 0xD2, 0x84, 0x43, 0xA1, 0x01, 0x26, 0xA1, 0x04,
457 0x42, 0x31, 0x31, 0x54, 0x54, 0x68, 0x69, 0x73,
458 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20,
459 0x63, 0x6F, 0x6E, 0x74, 0x65, 0x6E, 0x74, 0x2E, /* end of hdrs and payload*/
460 0x58, 0x40, 0x8E, 0xB3, 0x3E, 0x4C, 0xA3, 0x1D, /* Sig starts with 0x58 */
461 0x1C, 0x46, 0x5A, 0xB0, 0x5A, 0xAC, 0x34, 0xCC,
462 0x6B, 0x23, 0xD5, 0x8F, 0xEF, 0x5C, 0x08, 0x31,
463 0x06, 0xC4, 0xD2, 0x5A, 0x91, 0xAE, 0xF0, 0xB0,
464 0x11, 0x7E, 0x2A, 0xF9, 0xA2, 0x91, 0xAA, 0x32,
465 0xE1, 0x4A, 0xB8, 0x34, 0xDC, 0x56, 0xED, 0x2A,
466 0x22, 0x34, 0x44, 0x54, 0x7E, 0x01, 0xF1, 0x1D,
467 0x3B, 0x09, 0x16, 0xE5, 0xA4, 0xC3, 0x45, 0xCA,
468 0xCB, 0x36};
469
470
471 /*
472 * Public function, see t_cose_test.h
473 */
cose_example_test()474 int_fast32_t cose_example_test()
475 {
476 enum t_cose_err_t return_value;
477 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
478 struct q_useful_buf_c output;
479 struct t_cose_sign1_sign_ctx sign_ctx;
480 struct q_useful_buf_c head_actual;
481 struct q_useful_buf_c head_exp;
482
483 t_cose_sign1_sign_init(&sign_ctx,
484 T_COSE_OPT_SHORT_CIRCUIT_SIG,
485 T_COSE_ALGORITHM_ES256);
486
487 t_cose_sign1_set_signing_key(&sign_ctx,
488 T_COSE_NULL_KEY,
489 Q_USEFUL_BUF_FROM_SZ_LITERAL("11"));
490
491 /* Make example C.2.1 from RFC 8152 */
492
493 return_value = t_cose_sign1_sign(&sign_ctx,
494 Q_USEFUL_BUF_FROM_SZ_LITERAL("This is the content."),
495 signed_cose_buffer,
496 &output);
497
498 if(return_value != T_COSE_SUCCESS) {
499 return return_value;
500 }
501
502 /* Compare only the headers and payload as this was not signed
503 * with the same key as the example. The first 32 bytes contain
504 * the header parameters and payload. */
505 head_actual = q_useful_buf_head(output, 32);
506 head_exp = q_useful_buf_head(Q_USEFUL_BUF_FROM_BYTE_ARRAY_LITERAL(rfc8152_example_2_1), 32);
507
508 if(q_useful_buf_compare(head_actual, head_exp)) {
509 return -1000;
510 }
511
512 return return_value;
513 }
514
515
run_test_sign_and_verify(uint32_t test_mess_options)516 static enum t_cose_err_t run_test_sign_and_verify(uint32_t test_mess_options)
517 {
518 struct t_cose_sign1_sign_ctx sign_ctx;
519 struct t_cose_sign1_verify_ctx verify_ctx;
520 QCBOREncodeContext cbor_encode;
521 enum t_cose_err_t return_value;
522 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
523 struct q_useful_buf_c signed_cose;
524 struct q_useful_buf_c payload;
525
526 /* --- Start making COSE Sign1 object --- */
527
528 /* The CBOR encoder instance that the COSE_Sign1 is output into */
529 QCBOREncode_Init(&cbor_encode, signed_cose_buffer);
530
531 t_cose_sign1_sign_init(&sign_ctx,
532 T_COSE_OPT_SHORT_CIRCUIT_SIG,
533 T_COSE_ALGORITHM_ES256);
534
535 return_value =
536 t_cose_test_message_sign1_sign(&sign_ctx,
537 test_mess_options,
538 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
539 signed_cose_buffer,
540 &signed_cose);
541 if(return_value) {
542 return ((enum t_cose_err_t) (2000 + return_value));
543 }
544 /* --- Done making COSE Sign1 object --- */
545
546
547 /* --- Start verifying the COSE Sign1 object --- */
548 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
549
550 /* No key necessary with short circuit */
551
552
553 /* Run the signature verification */
554 return_value = t_cose_sign1_verify(&verify_ctx,
555 /* COSE to verify */
556 signed_cose,
557 /* The returned payload */
558 &payload,
559 /* Don't return parameters */
560 NULL);
561
562 return return_value;
563 }
564
565
566
567 #ifdef T_COSE_DISABLE_SHORT_CIRCUIT_SIGN
568 /* copied from t_cose_util.c so these tests that depend on
569 * short circuit signatures can run even when it is
570 * is disabled. TODO: is this dependency real?*/
571
572 /* This is a random hard coded key ID that is used to indicate
573 * short-circuit signing. It is OK to hard code this as the
574 * probability of collision with this ID is very low and the same
575 * as for collision between any two key IDs of any sort.
576 */
577
578 static const uint8_t defined_short_circuit_kid[] = {
579 0xef, 0x95, 0x4b, 0x4b, 0xd9, 0xbd, 0xf6, 0x70,
580 0xd0, 0x33, 0x60, 0x82, 0xf5, 0xef, 0x15, 0x2a,
581 0xf8, 0xf3, 0x5b, 0x6a, 0x6c, 0x00, 0xef, 0xa6,
582 0xa9, 0xa7, 0x1f, 0x49, 0x51, 0x7e, 0x18, 0xc6};
583
584 static struct q_useful_buf_c ss_kid;
585
586
587 /*
588 * Public function. See t_cose_util.h
589 */
get_short_circuit_kid(void)590 static struct q_useful_buf_c get_short_circuit_kid(void)
591 {
592 ss_kid.len = sizeof(defined_short_circuit_kid);
593 ss_kid.ptr = defined_short_circuit_kid;
594
595 return ss_kid;
596 }
597 #endif /* T_COSE_DISABLE_SHORT_CIRCUIT_SIGN */
598
all_header_parameters_test()599 int_fast32_t all_header_parameters_test()
600 {
601 enum t_cose_err_t return_value;
602 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 300);
603 struct q_useful_buf_c output;
604 struct q_useful_buf_c payload;
605 struct t_cose_parameters parameters;
606 struct t_cose_sign1_sign_ctx sign_ctx;
607 struct t_cose_sign1_verify_ctx verify_ctx;
608
609
610 t_cose_sign1_sign_init(&sign_ctx,
611 T_COSE_OPT_SHORT_CIRCUIT_SIG,
612 T_COSE_ALGORITHM_ES256);
613
614 t_cose_sign1_set_signing_key(&sign_ctx,
615 T_COSE_NULL_KEY,
616 Q_USEFUL_BUF_FROM_SZ_LITERAL("11"));
617
618 return_value =
619 t_cose_test_message_sign1_sign(&sign_ctx,
620 T_COSE_TEST_ALL_PARAMETERS,
621 Q_USEFUL_BUF_FROM_SZ_LITERAL("This is the content."),
622 signed_cose_buffer,
623 &output);
624 if(return_value) {
625 return 1;
626 }
627
628 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
629
630 /* No key necessary with short circuit */
631
632
633 return_value = t_cose_sign1_verify(&verify_ctx,
634 /* COSE to verify */
635 output,
636 /* The returned payload */
637 &payload,
638 /* Get parameters for checking */
639 ¶meters);
640
641 // Need to compare to short circuit kid
642 if(q_useful_buf_compare(parameters.kid, get_short_circuit_kid())) {
643 return 2;
644 }
645
646 if(parameters.cose_algorithm_id != T_COSE_ALGORITHM_ES256) {
647 return 3;
648 }
649
650 #ifndef T_COSE_DISABLE_CONTENT_TYPE
651 if(parameters.content_type_uint != 1) {
652 return 4;
653 }
654 #endif /* T_COSE_DISABLE_CONTENT_TYPE */
655
656 if(q_useful_buf_compare(parameters.iv, Q_USEFUL_BUF_FROM_SZ_LITERAL("iv"))) {
657 return 5;
658 }
659
660 if(q_useful_buf_compare(parameters.partial_iv, Q_USEFUL_BUF_FROM_SZ_LITERAL("partial_iv"))) {
661 return 6;
662 }
663
664 return 0;
665 }
666
667 struct test_case {
668 uint32_t test_option;
669 enum t_cose_err_t result;
670 };
671
672 static struct test_case bad_parameters_tests_table[] = {
673 /* Test existance of the critical header. Also makes sure that
674 * it works with the max number of labels allowed in it.
675 */
676 {T_COSE_TEST_EMPTY_PROTECTED_PARAMETERS, T_COSE_ERR_UNSUPPORTED_HASH},
677
678 {T_COSE_TEST_DUP_CONTENT_ID, T_COSE_ERR_DUPLICATE_PARAMETER},
679
680 {T_COSE_TEST_UNCLOSED_PROTECTED, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
681
682 {T_COSE_TEST_TOO_LARGE_CONTENT_TYPE, T_COSE_ERR_BAD_CONTENT_TYPE},
683
684 /* This makes consume_item() error out */
685 {T_COSE_TEST_NOT_WELL_FORMED_2, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
686
687 {T_COSE_TEST_KID_IN_PROTECTED, T_COSE_ERR_DUPLICATE_PARAMETER},
688
689 {T_COSE_TEST_TOO_MANY_UNKNOWN, T_COSE_ERR_TOO_MANY_PARAMETERS},
690
691 {T_COSE_TEST_UNPROTECTED_NOT_MAP, T_COSE_ERR_PARAMETER_CBOR},
692
693 {T_COSE_TEST_BAD_CRIT_PARAMETER, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
694
695 {T_COSE_TEST_BAD_CRIT_PARAMETER, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
696
697 {T_COSE_TEST_NOT_WELL_FORMED_1, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
698
699 {T_COSE_TEST_NO_UNPROTECTED_PARAMETERS, T_COSE_ERR_PARAMETER_CBOR},
700
701 {T_COSE_TEST_NO_PROTECTED_PARAMETERS, T_COSE_ERR_SIGN1_FORMAT},
702
703 {T_COSE_TEST_EXTRA_PARAMETER, T_COSE_SUCCESS},
704
705 {T_COSE_TEST_PARAMETER_LABEL, T_COSE_ERR_PARAMETER_CBOR},
706
707 {T_COSE_TEST_BAD_PROTECTED, T_COSE_ERR_PARAMETER_CBOR},
708
709 {0, T_COSE_SUCCESS}
710 };
711
712
713 /*
714 * Public function, see t_cose_test.h
715 */
bad_parameters_test()716 int_fast32_t bad_parameters_test()
717 {
718 struct test_case *test;
719
720 for(test = bad_parameters_tests_table; test->test_option; test++) {
721 if(run_test_sign_and_verify(test->test_option) != test->result) {
722 return (int_fast32_t)(test - bad_parameters_tests_table);
723 }
724 }
725
726 return 0;
727 }
728
729
730
731
732 static struct test_case crit_tests_table[] = {
733 /* Test existance of the critical header. Also makes sure that
734 * it works with the max number of labels allowed in it.
735 */
736 {T_COSE_TEST_CRIT_PARAMETER_EXIST, T_COSE_SUCCESS},
737
738 /* Exceed the max number of labels by one and get an error */
739 {T_COSE_TEST_TOO_MANY_CRIT_PARAMETER_EXIST, T_COSE_ERR_CRIT_PARAMETER},
740
741 /* A critical parameter exists in the protected section, but the
742 * format of the internals of this parameter is not the expected CBOR
743 */
744 {T_COSE_TEST_BAD_CRIT_LABEL, T_COSE_ERR_CRIT_PARAMETER},
745
746 /* A critical label is listed in the protected section, but
747 * the label doesn't exist. This works for integer-labeled header params.
748 */
749 {T_COSE_TEST_UNKNOWN_CRIT_UINT_PARAMETER, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER},
750
751 /* A critical label is listed in the protected section, but
752 * the label doesn't exist. This works for string-labeled header params.
753 */
754 {T_COSE_TEST_UNKNOWN_CRIT_TSTR_PARAMETER, T_COSE_ERR_UNKNOWN_CRITICAL_PARAMETER},
755
756 /* The critical labels list is not protected */
757 {T_COSE_TEST_CRIT_NOT_PROTECTED, T_COSE_ERR_PARAMETER_NOT_PROTECTED},
758
759 {T_COSE_TEST_EMPTY_CRIT_PARAMETER, T_COSE_ERR_CRIT_PARAMETER},
760
761 {T_COSE_TEST_TOO_MANY_TSTR_CRIT_LABLELS, T_COSE_ERR_CRIT_PARAMETER},
762
763 {0, T_COSE_SUCCESS}
764 };
765
766
767 /*
768 * Public function, see t_cose_test.h
769 */
crit_parameters_test()770 int_fast32_t crit_parameters_test()
771 {
772 struct test_case *test;
773
774 for(test = crit_tests_table; test->test_option; test++) {
775 if(run_test_sign_and_verify(test->test_option) != test->result) {
776 return (int_fast32_t)(test - crit_tests_table);
777 }
778 }
779
780 return 0;
781 }
782
783
784 /*
785 * Public function, see t_cose_test.h
786 */
content_type_test()787 int_fast32_t content_type_test()
788 {
789 #ifndef T_COSE_DISABLE_CONTENT_TYPE
790
791 struct t_cose_parameters parameters;
792 struct t_cose_sign1_sign_ctx sign_ctx;
793 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
794 struct q_useful_buf_c output;
795 struct q_useful_buf_c payload;
796 enum t_cose_err_t return_value;
797 struct t_cose_sign1_verify_ctx verify_ctx;
798
799
800 /* -- integer content type -- */
801 t_cose_sign1_sign_init(&sign_ctx,
802 T_COSE_OPT_SHORT_CIRCUIT_SIG,
803 T_COSE_ALGORITHM_ES256);
804
805 t_cose_sign1_set_content_type_uint(&sign_ctx, 42);
806
807 return_value = t_cose_sign1_sign(&sign_ctx,
808 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
809 signed_cose_buffer,
810 &output);
811 if(return_value) {
812 return 1;
813 }
814
815 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
816
817 return_value = t_cose_sign1_verify(&verify_ctx,
818 output,
819 &payload,
820 ¶meters);
821 if(return_value) {
822 return 2;
823 }
824
825 if(parameters.content_type_uint != 42) {
826 return 5;
827 }
828
829
830 /* -- string content type -- */
831 t_cose_sign1_sign_init(&sign_ctx,
832 T_COSE_OPT_SHORT_CIRCUIT_SIG,
833 T_COSE_ALGORITHM_ES256);
834
835 t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain");
836
837 return_value = t_cose_sign1_sign(&sign_ctx,
838 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
839 signed_cose_buffer,
840 &output);
841 if(return_value) {
842 return 1;
843 }
844
845 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_ALLOW_SHORT_CIRCUIT);
846
847 return_value = t_cose_sign1_verify(&verify_ctx,
848 output,
849 &payload,
850 ¶meters);
851 if(return_value) {
852 return 2;
853 }
854
855 if(q_useful_buf_compare(parameters.content_type_tstr, Q_USEFUL_BUF_FROM_SZ_LITERAL("text/plain"))) {
856 return 6;
857 }
858
859
860 /* -- content type in error -- */
861 t_cose_sign1_sign_init(&sign_ctx,
862 T_COSE_OPT_SHORT_CIRCUIT_SIG,
863 T_COSE_ALGORITHM_ES256);
864
865 t_cose_sign1_set_content_type_tstr(&sign_ctx, "text/plain");
866 t_cose_sign1_set_content_type_uint(&sign_ctx, 42);
867
868
869 return_value = t_cose_sign1_sign(&sign_ctx,
870 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
871 signed_cose_buffer,
872 &output);
873 if(return_value != T_COSE_ERR_DUPLICATE_PARAMETER) {
874 return 1;
875 }
876 #endif
877 return 0;
878
879 }
880
881
882 struct sign1_sample {
883 struct q_useful_buf_c CBOR;
884 enum t_cose_err_t expected_error;
885 };
886
887 static struct sign1_sample sign1_sample_inputs[] = {
888 /* With an indefinite length string payload */
889 { {(uint8_t[]){0x84, 0x40, 0xa0, 0x5f, 0x00, 0xff, 0x40}, 7}, T_COSE_ERR_SIGN1_FORMAT},
890 /* Too few items in unprotected header parameters bucket */
891 { {(uint8_t[]){0x84, 0x40, 0xa3, 0x40, 0x40}, 5}, T_COSE_ERR_PARAMETER_CBOR},
892 /* Too few items in definite array */
893 { {(uint8_t[]){0x83, 0x40, 0xa0, 0x40}, 4}, T_COSE_ERR_SIGN1_FORMAT},
894 /* Too-long signature */
895 { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x4f}, 5}, T_COSE_ERR_SIGN1_FORMAT},
896 /* Too-long payload */
897 { {(uint8_t[]){0x84, 0x40, 0xa0, 0x4f, 0x40}, 5}, T_COSE_ERR_SIGN1_FORMAT},
898 /* Too-long protected parameters bucket */
899 { {(uint8_t[]){0x84, 0x4f, 0xa0, 0x40, 0x40}, 5}, T_COSE_ERR_SIGN1_FORMAT},
900 /* Unterminated indefinite length */
901 { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40}, 6}, T_COSE_ERR_CBOR_NOT_WELL_FORMED},
902 /* The smallest legal COSE_Sign1 using indefinite lengths */
903 { {(uint8_t[]){0x9f, 0x40, 0xbf, 0xff, 0x40, 0x40, 0xff}, 7}, T_COSE_SUCCESS},
904 /* The smallest legal COSE_Sign1 using definite lengths */
905 { {(uint8_t[]){0x84, 0x40, 0xa0, 0x40, 0x40}, 5}, T_COSE_SUCCESS},
906 /* Just one not-well-formed byte -- a reserved value */
907 { {(uint8_t[]){0x3c}, 1}, T_COSE_ERR_SIGN1_FORMAT },
908 /* terminate the list */
909 { {NULL, 0}, T_COSE_SUCCESS },
910 };
911
912
913 /*
914 * Public function, see t_cose_test.h
915 */
sign1_structure_decode_test(void)916 int_fast32_t sign1_structure_decode_test(void)
917 {
918 const struct sign1_sample *sample;
919 struct q_useful_buf_c payload;
920 enum t_cose_err_t result;
921 struct t_cose_sign1_verify_ctx verify_ctx;
922
923
924 for(sample = sign1_sample_inputs; !q_useful_buf_c_is_null(sample->CBOR); sample++) {
925 t_cose_sign1_verify_init(&verify_ctx, T_COSE_OPT_DECODE_ONLY);
926
927
928 result = t_cose_sign1_verify(&verify_ctx,
929 sample->CBOR,
930 &payload,
931 NULL);
932 if(result != sample->expected_error) {
933 /* Returns 100 * index of the input + the unexpected error code */
934 const size_t sample_index = (size_t)(sample - sign1_sample_inputs) / sizeof(struct sign1_sample);
935 return (int32_t)((sample_index+1)*100 + result);
936 }
937 }
938
939 return 0;
940 }
941
942
943 #ifdef T_COSE_ENABLE_HASH_FAIL_TEST
944
945 /* Linkage to global variable in t_cose_test_crypto.c. This is only
946 * used for an occasional test in a non-threaded environment so a global
947 * variable is safe. This test and the hacks in the crypto code are
948 * never enabled for commercial deployments.
949 */
950 extern int hash_test_mode;
951
952
953 /*
954 * Public function, see t_cose_test.h
955 */
short_circuit_hash_fail_test()956 int_fast32_t short_circuit_hash_fail_test()
957 {
958 struct t_cose_sign1_sign_ctx sign_ctx;
959 enum t_cose_err_t return_value;
960 struct q_useful_buf_c wrapped_payload;
961 Q_USEFUL_BUF_MAKE_STACK_UB( signed_cose_buffer, 200);
962
963 /* See test description in t_cose_test.h for a full description of
964 * what this does and what it needs to run.
965 */
966
967
968 /* Set the global variable to cause the hash implementation to
969 * error out so this test can see what happens
970 */
971 hash_test_mode = 1;
972
973 t_cose_sign1_sign_init(&sign_ctx,
974 T_COSE_OPT_SHORT_CIRCUIT_SIG,
975 T_COSE_ALGORITHM_ES256);
976
977 return_value = t_cose_sign1_sign(&sign_ctx,
978 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
979 signed_cose_buffer,
980 &wrapped_payload);
981
982 hash_test_mode = 0;
983
984 if(return_value != T_COSE_ERR_HASH_GENERAL_FAIL) {
985 return 2000 + return_value;
986 }
987
988
989 /* Set the global variable to cause the hash implementation to
990 * error out so this test can see what happens
991 */
992 hash_test_mode = 2;
993
994 t_cose_sign1_sign_init(&sign_ctx,
995 T_COSE_OPT_SHORT_CIRCUIT_SIG,
996 T_COSE_ALGORITHM_ES256);
997
998 return_value = t_cose_sign1_sign(&sign_ctx,
999 Q_USEFUL_BUF_FROM_SZ_LITERAL("payload"),
1000 signed_cose_buffer,
1001 &wrapped_payload);
1002
1003 hash_test_mode = 0;
1004
1005 if(return_value != T_COSE_ERR_HASH_GENERAL_FAIL) {
1006 return 2000 + return_value;
1007 }
1008
1009 return 0;
1010 }
1011
1012 #endif /* T_COSE_ENABLE_HASH_FAIL_TEST */
1013