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                                        &parameters);
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                                        &parameters);
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                                        &parameters);
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