Branch data Line data Source code
1 : : /*
2 : : Copyright (c) 2021 Fraunhofer AISEC. See the COPYRIGHT
3 : : file at the top-level directory of this distribution.
4 : :
5 : : Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 : : http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 : : <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 : : option. This file may not be copied, modified, or distributed
9 : : except according to those terms.
10 : : */
11 : :
12 : : #include <stdbool.h>
13 : : #include <stdint.h>
14 : :
15 : : #include "edhoc/buffer_sizes.h"
16 : :
17 : : #include "edhoc/cert.h"
18 : :
19 : : #include "common/memcpy_s.h"
20 : : #include "common/oscore_edhoc_error.h"
21 : : #include "common/crypto_wrapper.h"
22 : : #include "common/print_util.h"
23 : :
24 : : #include "cbor/edhoc_decode_cert.h"
25 : :
26 : : #ifdef MBEDTLS
27 : : #define MBEDTLS_ALLOW_PRIVATE_ACCESS
28 : :
29 : : #include <psa/crypto.h>
30 : : #include <mbedtls/asn1.h>
31 : : #include <mbedtls/error.h>
32 : : #include <mbedtls/md.h>
33 : : #include <mbedtls/oid.h>
34 : : #include <mbedtls/x509.h>
35 : : #include <mbedtls/x509_crt.h>
36 : :
37 : : struct deser_sign_ctx_s {
38 : : uint8_t *seek;
39 : : uint8_t *end;
40 : : int unit_size;
41 : : };
42 : :
43 : 2 : static void deser_sign_ctx_init(struct deser_sign_ctx_s *ctx, uint8_t *seek,
44 : : uint8_t *end, int unit_size)
45 : : {
46 : 2 : ctx->seek = seek;
47 : 2 : ctx->end = end;
48 : 2 : ctx->unit_size = unit_size;
49 : 2 : }
50 : :
51 : 4 : static int deser_sign_cb(void *void_ctx, int tag, unsigned char *start,
52 : : size_t len)
53 : : {
54 [ + - ]: 4 : if (tag == MBEDTLS_ASN1_INTEGER) {
55 : 4 : struct deser_sign_ctx_s *ctx = void_ctx;
56 : 4 : uint8_t *unit_end = ctx->seek + ctx->unit_size;
57 [ + - ]: 4 : if (unit_end <= ctx->end) {
58 : 4 : memcpy(ctx->seek, start + len - ctx->unit_size,
59 : 4 : (uint32_t)ctx->unit_size);
60 : 4 : ctx->seek = unit_end;
61 : : }
62 : : }
63 : 4 : return 0;
64 : : }
65 : :
66 : 4 : static int find_pk_cb(void *void_ppk, int tag, unsigned char *start, size_t len)
67 : : {
68 : : (void)len;
69 : :
70 [ + + ]: 4 : if (tag == MBEDTLS_ASN1_BIT_STRING) {
71 : 2 : uint8_t **pk = void_ppk;
72 : 2 : *pk = start;
73 : : }
74 : 4 : return 0;
75 : : }
76 : :
77 : : #define PSA_KEY_ALL_USAGES \
78 : : (PSA_KEY_USAGE_EXPORT | PSA_KEY_USAGE_COPY | PSA_KEY_USAGE_ENCRYPT | \
79 : : PSA_KEY_USAGE_DECRYPT | PSA_KEY_USAGE_SIGN_MESSAGE | \
80 : : PSA_KEY_USAGE_VERIFY_MESSAGE | PSA_KEY_USAGE_SIGN_HASH | \
81 : : PSA_KEY_USAGE_VERIFY_HASH | PSA_KEY_USAGE_DERIVE)
82 : :
83 : : #else /* MBEDTLS */
84 : :
85 : : #define ISSUER_CN_OID "\x55\x04\x03"
86 : :
87 : : #define EXPECTO_TAG(tag, cursor, len) \
88 : : if (*cursor != tag) { \
89 : : rv = wrong_parameter; \
90 : : PRINTF(RED \
91 : : "Runtime error: expected %s tag at %s:%d\n\n" RESET, \
92 : : #tag, __FILE__, __LINE__); \
93 : : break; \
94 : : } else { \
95 : : cursor++; \
96 : : mbedtls_asn1_get_len(&cursor, end, &len); \
97 : : if (0 == *cursor) { \
98 : : cursor++; \
99 : : len--; \
100 : : } \
101 : : }
102 : :
103 : : enum tag_map_enum {
104 : : ASN1_INTEGER = 0x02,
105 : : ASN1_BIT_STRING = 0x03,
106 : : ASN1_SEQUENCE = 0x30
107 : : };
108 : :
109 : : /* Extracted from mbedtls library; asn1_parse.c */
110 : : /* License for file: Apache-2.0 */
111 : : /* ASN.1 DER encoding is described in ITU-T X.690 standard. */
112 : : /* First bit of length byte contains information, if length
113 : : value shall be concatenated with following byte length. */
114 : : static int mbedtls_asn1_get_len(const unsigned char **p,
115 : : const unsigned char *end, uint32_t *len)
116 : : {
117 : : if ((end - *p) < 1)
118 : : return (buffer_to_small);
119 : :
120 : : if ((**p & 0x80) == 0)
121 : : *len = *(*p)++;
122 : : else {
123 : : switch (**p & 0x7F) {
124 : : case 1:
125 : : if ((end - *p) < 2)
126 : : return (buffer_to_small);
127 : :
128 : : *len = (*p)[1];
129 : : (*p) += 2;
130 : : break;
131 : :
132 : : case 2:
133 : : if ((end - *p) < 3)
134 : : return (buffer_to_small);
135 : :
136 : : *len = ((uint32_t)(*p)[1] << 8) | (*p)[2];
137 : : (*p) += 3;
138 : : break;
139 : :
140 : : case 3:
141 : : if ((end - *p) < 4)
142 : : return (buffer_to_small);
143 : :
144 : : *len = ((uint32_t)(*p)[1] << 16) |
145 : : ((uint32_t)(*p)[2] << 8) | (*p)[3];
146 : : (*p) += 4;
147 : : break;
148 : :
149 : : case 4:
150 : : if ((end - *p) < 5)
151 : : return (buffer_to_small);
152 : :
153 : : *len = ((uint32_t)(*p)[1] << 24) |
154 : : ((uint32_t)(*p)[2] << 16) |
155 : : ((uint32_t)(*p)[3] << 8) | (*p)[4];
156 : : (*p) += 5;
157 : : break;
158 : :
159 : : default:
160 : : return (buffer_to_small);
161 : : }
162 : : }
163 : :
164 : : if (*len > (uint32_t)(end - *p))
165 : : return (buffer_to_small);
166 : :
167 : : return (0);
168 : : }
169 : :
170 : : #endif /* MBEDTLS */
171 : :
172 : : /**
173 : : * @brief retrieves the public key of the CA from CRED_ARRAY.
174 : : *
175 : : *
176 : : * @param[in] cred_array contains the public key of the root CA
177 : : * @param[in] issuer the issuer name, i.e. the name of the CA
178 : : * @param[out] root_pk the root public key
179 : : * @return error code
180 : : */
181 : 2 : static enum err ca_pk_get(const struct cred_array *cred_array,
182 : : const uint8_t *issuer, struct byte_array *root_pk)
183 : : {
184 : : /* when single credential without certificate is stored, return stored ca_pk if available */
185 [ + - ]: 2 : if (1 == cred_array->len
186 : : #ifdef MBEDTLS
187 : : /* In case no MBEDTLS is enabled, issuer identification is not extracted from certificate */
188 [ + - ]: 2 : && (0 == cred_array->ptr[0].ca.len ||
189 [ - + ]: 2 : NULL == cred_array->ptr[0].ca.ptr)
190 : : #endif
191 : : ) {
192 [ # # ]: 0 : if (NULL == cred_array->ptr[0].ca_pk.ptr ||
193 [ # # ]: 0 : 0 == cred_array->ptr[0].ca_pk.len) {
194 : 0 : return no_such_ca;
195 : : }
196 : :
197 : 0 : root_pk->ptr = cred_array->ptr[0].ca_pk.ptr;
198 : 0 : root_pk->len = cred_array->ptr[0].ca_pk.len;
199 : 0 : return ok;
200 : : }
201 : :
202 : : #ifdef MBEDTLS
203 : : /* Accept only certificate based search if multiple credentials available*/
204 [ + - ]: 2 : for (uint16_t i = 0; i < cred_array->len; i++) {
205 [ + - ]: 2 : if (NULL == cred_array->ptr[i].ca.ptr ||
206 [ - + ]: 2 : 0 == cred_array->ptr[i].ca.len) {
207 : 0 : continue;
208 : : }
209 : :
210 : 2 : PRINT_ARRAY("cred_array[i].ca.ptr", cred_array->ptr[i].ca.ptr,
211 : : cred_array->ptr[i].ca.len);
212 : :
213 : : mbedtls_x509_crt m_cert;
214 : 2 : mbedtls_x509_crt_init(&m_cert);
215 : :
216 : : /* parse the certificate */
217 [ - + ]: 4 : TRY_EXPECT(mbedtls_x509_crt_parse_der_nocopy(
218 : : &m_cert, cred_array->ptr[i].ca.ptr,
219 : : cred_array->ptr[i].ca.len),
220 : : 0);
221 : :
222 : 2 : const mbedtls_x509_name *p = &m_cert.subject;
223 : 2 : const mbedtls_asn1_buf *subject_id = NULL;
224 [ + + ]: 4 : while (p) {
225 [ + - - + : 2 : if (0 == MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &p->oid)) {
+ - ]
226 : 2 : subject_id = &p->val;
227 : : }
228 : 2 : p = p->next;
229 : : };
230 : :
231 [ + - ]: 2 : if (0 == memcmp(subject_id->p, issuer, subject_id->len)) {
232 : 2 : root_pk->ptr = cred_array->ptr[i].ca_pk.ptr;
233 : 2 : root_pk->len = cred_array->ptr[i].ca_pk.len;
234 : 2 : PRINT_ARRAY("Root PK of the CA", root_pk->ptr,
235 : : root_pk->len);
236 : 2 : mbedtls_x509_crt_free(&m_cert);
237 : 2 : return ok;
238 : : } else {
239 : 0 : mbedtls_x509_crt_free(&m_cert);
240 : : }
241 : : }
242 : : #endif /* MBEDTLS */
243 : :
244 : 0 : return no_such_ca;
245 : : }
246 : :
247 : 0 : enum err cert_c509_verify(struct const_byte_array *cert,
248 : : const struct cred_array *cred_array,
249 : : struct byte_array *pk, bool *verified)
250 : : {
251 : 0 : size_t decode_len = 0;
252 : : struct cert c;
253 : :
254 [ # # ]: 0 : TRY_EXPECT(cbor_decode_cert(cert->ptr, cert->len, &c, &decode_len), 0);
255 : :
256 : 0 : PRINT_MSG("CBOR certificate parsed.\n");
257 : 0 : PRINTF("Certificate type: %d\n", c.cert_type);
258 : 0 : PRINT_ARRAY("issuer", c.cert_issuer.value, (uint32_t)c.cert_issuer.len);
259 : 0 : PRINTF("validity_not_before: %d\n", c.cert_validity_not_before);
260 : 0 : PRINTF("validity_not_after: %d\n", c.cert_validity_not_after);
261 : 0 : PRINT_ARRAY("subject", c.cert_subject.value,
262 : : (uint32_t)c.cert_subject.len);
263 : 0 : PRINT_ARRAY("PK", c.cert_pk.value, (uint32_t)c.cert_pk.len);
264 : 0 : PRINTF("extensions: %d\n", c.cert_extensions);
265 : 0 : PRINTF("issuer_signature_algorithm: %d\n",
266 : : c.cert_issuer_signature_algorithm);
267 : 0 : PRINT_ARRAY("Signature", c.cert_signature.value,
268 : : (uint32_t)c.cert_signature.len);
269 : :
270 : : /*get the CA's public key*/
271 : : struct byte_array root_pk;
272 [ # # ]: 0 : TRY(ca_pk_get(cred_array, c.cert_issuer.value, &root_pk));
273 : :
274 : : /*verify the certificates signature*/
275 : 0 : struct const_byte_array m = BYTE_ARRAY_INIT(
276 : : cert->ptr, cert->len - 2 - (uint32_t)c.cert_signature.len);
277 : 0 : struct const_byte_array sgn = BYTE_ARRAY_INIT(
278 : : c.cert_signature.value, (uint32_t)c.cert_signature.len);
279 : :
280 [ # # ]: 0 : TRY(verify((enum sign_alg)c.cert_issuer_signature_algorithm, &root_pk,
281 : : &m, &sgn, verified));
282 : :
283 [ # # ]: 0 : TRY(_memcpy_s(pk->ptr, pk->len, c.cert_pk.value,
284 : : (uint32_t)c.cert_pk.len));
285 : 0 : pk->len = (uint32_t)c.cert_pk.len;
286 : :
287 : 0 : return ok;
288 : : }
289 : :
290 : 2 : enum err cert_x509_verify(struct const_byte_array *cert,
291 : : const struct cred_array *cred_array,
292 : : struct byte_array *pk, bool *verified)
293 : : {
294 : : #ifdef MBEDTLS
295 : :
296 : 2 : PRINT_MSG("Start parsing an ASN.1 certificate\n");
297 : :
298 : : mbedtls_x509_crt m_cert;
299 : 2 : mbedtls_x509_crt_init(&m_cert);
300 : :
301 : : /* parse the certificate */
302 [ - + ]: 2 : TRY_EXPECT(mbedtls_x509_crt_parse_der_nocopy(&m_cert, cert->ptr,
303 : : cert->len),
304 : : 0);
305 : :
306 : : /* some raw data from certificate */
307 : 2 : PRINT_ARRAY("cert.serial", m_cert.serial.p,
308 : : (uint32_t)m_cert.serial.len);
309 : 2 : PRINT_ARRAY("cert.issuer_raw", m_cert.issuer_raw.p,
310 : : (uint32_t)m_cert.issuer_raw.len);
311 : :
312 : : /* write details about the issuer */
313 : : /* and find CN (Common Name), further referred to as "issuer_id" */
314 : 2 : const mbedtls_x509_name *p = &m_cert.issuer;
315 : :
316 : : #ifdef DEBUG_PRINT
317 : : const char *short_name;
318 : : #endif
319 : 2 : const mbedtls_asn1_buf *issuer_id = NULL;
320 [ + + ]: 4 : while (p) {
321 : : #ifdef DEBUG_PRINT
322 : 2 : mbedtls_oid_get_attr_short_name(&p->oid, &short_name);
323 : 2 : PRINTF(" %s: %.*s\n", short_name, (int)p->val.len,
324 : : p->val.p);
325 : : #endif
326 [ + - - + : 2 : if (0 == MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &p->oid)) {
+ - ]
327 : 2 : issuer_id = &p->val;
328 : : }
329 : 2 : p = p->next;
330 : : };
331 : :
332 : 2 : PRINT_ARRAY("cert issuer_id", issuer_id->p, (uint32_t)issuer_id->len);
333 : :
334 : : enum sign_alg sign_alg;
335 : :
336 : : /* make sure it is ECDSA */
337 [ + - ]: 2 : if (MBEDTLS_PK_ECDSA == m_cert.sig_pk) {
338 : 2 : sign_alg = ES256;
339 : : } else {
340 : 0 : mbedtls_x509_crt_free(&m_cert);
341 : 0 : return unsupported_signature_algorithm;
342 : : }
343 : :
344 : : /* check hash algorithm and init signature buffer */
345 : : const mbedtls_md_info_t *md_info =
346 : 2 : mbedtls_md_info_from_type(m_cert.sig_md);
347 [ - + ]: 2 : if (NULL == md_info) {
348 : 0 : PRINTF("mbedtls_md_info_from_type(%d) : not found\n",
349 : : m_cert.sig_md);
350 : 0 : mbedtls_x509_crt_free(&m_cert);
351 : 0 : return unsupported_signature_algorithm;
352 : : }
353 : 2 : int hash_len = mbedtls_md_get_size(md_info);
354 : :
355 [ - + - + ]: 2 : BYTE_ARRAY_NEW(sig, SIGNATURE_SIZE, get_signature_len(sign_alg));
356 : :
357 : : /* get the public key of the CA */
358 : : struct byte_array root_pk;
359 [ - + ]: 2 : TRY(ca_pk_get(cred_array, issuer_id->p, &root_pk));
360 : :
361 : : /* deserialize signature from ASN.1 to raw concatenation of (R, S) */
362 : : {
363 : 2 : uint8_t *pp = m_cert.sig.p;
364 : : struct deser_sign_ctx_s deser_sign_ctx;
365 : 2 : deser_sign_ctx_init(&deser_sign_ctx, sig.ptr, sig.ptr + sig.len,
366 : : hash_len);
367 : 2 : mbedtls_asn1_traverse_sequence_of(&pp, pp + m_cert.sig.len, 0,
368 : : 0, 0, 0, deser_sign_cb,
369 : : &deser_sign_ctx);
370 : 2 : PRINT_ARRAY("Certificate signature", sig.ptr, sig.len);
371 : : }
372 : :
373 : : /*verify the certificates signature*/
374 : 2 : struct const_byte_array m =
375 : 2 : BYTE_ARRAY_INIT(m_cert.tbs.p, (uint32_t)m_cert.tbs.len);
376 [ - + ]: 2 : TRY(verify(sign_alg, &root_pk, &m, (struct const_byte_array *)&sig,
377 : : verified));
378 : :
379 : : /* export the public key from certificate */
380 : : {
381 : 2 : uint8_t *cpk = NULL;
382 : 2 : uint32_t cpk_len = 0;
383 : 2 : uint8_t *pp = m_cert.pk_raw.p;
384 : 2 : mbedtls_asn1_traverse_sequence_of(&pp, pp + m_cert.pk_raw.len,
385 : : 0, 0, 0, 0, find_pk_cb, &cpk);
386 [ + - ]: 2 : if (cpk) {
387 [ + - ]: 2 : if (*cpk == 0) {
388 : 2 : ++cpk;
389 : : }
390 : 2 : cpk_len = (uint32_t)m_cert.pk_raw.len -
391 : 2 : (uint32_t)(cpk - m_cert.pk_raw.p);
392 : : }
393 [ - + ]: 2 : TRY(_memcpy_s(pk->ptr, pk->len, cpk, (uint32_t)cpk_len));
394 : 2 : pk->len = (uint32_t)cpk_len;
395 : 2 : PRINT_ARRAY("pk from cert", pk->ptr, pk->len);
396 : : }
397 : :
398 : : /* cleanup */
399 : 2 : mbedtls_x509_crt_free(&m_cert);
400 : :
401 : 2 : return ok;
402 : :
403 : : #else /* MBEDTLS */
404 : :
405 : : const uint8_t *tbs_start = cert->ptr;
406 : : const uint8_t *tbs_end = &cert->ptr[cert->len];
407 : : BYTE_ARRAY_NEW(sig, SIGNATURE_SIZE, get_signature_len(ES256));
408 : :
409 : : enum err rv = certificate_authentication_failed;
410 : :
411 : : /* Crude way to get TBSCertificate address, public key and signature */
412 : : do {
413 : : const uint8_t *cursor = cert->ptr;
414 : : const uint8_t *end = &cert->ptr[cert->len];
415 : : uint32_t len;
416 : :
417 : : /* Get first tag, which should be first sequence */
418 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
419 : :
420 : : /* Get second, inner tag, which should be TBSCertificate */
421 : : tbs_start = cursor;
422 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
423 : : tbs_end = cursor + len;
424 : :
425 : : /* Iterate over 6 elements to get to public key according to X.509 schema */
426 : : for (uint32_t iter = 0; iter < 6; iter++) {
427 : : /* TAG shall not be parsed as it is not used */
428 : : cursor++;
429 : : /* Get section length */
430 : : mbedtls_asn1_get_len(&cursor, end, &len);
431 : : cursor += len;
432 : : }
433 : :
434 : : /* Here should be 7th element with information about key */
435 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
436 : :
437 : : /* Here should be element with information about type of key */
438 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
439 : : /* This section is being skippped */
440 : : cursor += len;
441 : :
442 : : /* Expected BIT STRING containing public key */
443 : : EXPECTO_TAG(ASN1_BIT_STRING, cursor, len);
444 : :
445 : : /* Now cursor points to public key */
446 : : _memcpy_s(pk->ptr, pk->len, cursor, (uint32_t)len);
447 : : pk->len = (uint32_t)len;
448 : : PRINT_ARRAY("pk from cert", pk->ptr, pk->len);
449 : :
450 : : /* We can skip whole TBSCertificate */
451 : : cursor = tbs_end;
452 : :
453 : : /* Here should be information about signature algorithm */
454 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
455 : : /* We can skip algorithm info length */
456 : : cursor += len;
457 : :
458 : : /* Expected BIT STRING containing signature */
459 : : EXPECTO_TAG(ASN1_BIT_STRING, cursor, len);
460 : : // cursor++;
461 : :
462 : : EXPECTO_TAG(ASN1_SEQUENCE, cursor, len);
463 : :
464 : : EXPECTO_TAG(ASN1_INTEGER, cursor, len);
465 : :
466 : : TRY_EXPECT((cursor + len) <= end, 1);
467 : : _memcpy_s(sig.ptr, SIGNATURE_SIZE, cursor, (uint32_t)len);
468 : : sig.len = len;
469 : : cursor += len;
470 : : PRINT_ARRAY("Certificate signature - part1", sig.ptr,
471 : : (uint32_t)sig.len);
472 : :
473 : : EXPECTO_TAG(ASN1_INTEGER, cursor, len);
474 : : TRY_EXPECT((cursor + len) <= end, 1);
475 : : _memcpy_s(sig.ptr + sig.len,
476 : : (uint32_t)(SIGNATURE_SIZE - sig.len), cursor,
477 : : (uint32_t)len);
478 : : sig.len += len;
479 : : rv = ok;
480 : : PRINT_ARRAY("Certificate signature", sig.ptr,
481 : : (uint32_t)sig.len);
482 : :
483 : : } while (0);
484 : :
485 : : struct byte_array root_pk;
486 : : struct const_byte_array m =
487 : : BYTE_ARRAY_INIT(tbs_start, (uint32_t)(tbs_end - tbs_start));
488 : :
489 : : if (ok == rv) {
490 : : for (uint32_t iter = 0; iter < cred_array->len; iter++) {
491 : : /* Issuer will not be read from certificate, so no identification is possible within public keys array. */
492 : : TRY(ca_pk_get(&cred_array[iter], NULL, &root_pk));
493 : : PRINT_ARRAY("pk from cred_list", root_pk.ptr,
494 : : root_pk.len);
495 : : struct const_byte_array s = { .ptr = sig.ptr,
496 : : .len = sig.len };
497 : : rv = verify(ES256, &root_pk, &m, &s, verified);
498 : : }
499 : : }
500 : : return rv;
501 : :
502 : : #endif /* MBEDTLS */
503 : : }
|