CCF
Loading...
Searching...
No Matches
cose_common.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3
4#pragma once
5
6#include "ccf/ds/hex.h"
7#include "ccf/receipt.h"
8
10#include <qcbor/qcbor.h>
11#include <qcbor/qcbor_spiffy_decode.h>
12#include <stdexcept>
13#include <string>
14#include <t_cose/t_cose_common.h>
15
16namespace ccf::cose
17{
18 namespace headers
19 {
20 static constexpr int64_t PARAM_ALG = 1;
21 static constexpr int64_t PARAM_CONTENT_TYPE = 3;
22 static constexpr int64_t PARAM_KID = 4;
23 static constexpr int64_t PARAM_X5CHAIN = 33;
24 static constexpr int64_t PARAM_VDP = 396;
25 static constexpr int64_t PARAM_INCLUSION_PROOFS = -1;
26
27 static constexpr auto CONTENT_TYPE_APPLICATION_JSON_VALUE =
28 "application/json";
29 }
30
31 using Signature = std::span<const uint8_t>;
32
33 static std::string qcbor_buf_to_string(const UsefulBufC& buf)
34 {
35 return {reinterpret_cast<const char*>(buf.ptr), buf.len};
36 }
37
38 static std::vector<uint8_t> qcbor_buf_to_byte_vector(const UsefulBufC& buf)
39 {
40 const auto* ptr = static_cast<const uint8_t*>(buf.ptr);
41 return {ptr, ptr + buf.len};
42 }
43
44 static bool is_ecdsa_alg(int64_t cose_alg)
45 {
46 return cose_alg == T_COSE_ALGORITHM_ES256 ||
47 cose_alg == T_COSE_ALGORITHM_ES384 || cose_alg == T_COSE_ALGORITHM_ES512;
48 }
49
50 static bool is_rsa_alg(int64_t cose_alg)
51 {
52 return cose_alg == T_COSE_ALGORITHM_PS256 ||
53 cose_alg == T_COSE_ALGORITHM_PS384 || cose_alg == T_COSE_ALGORITHM_PS512;
54 }
55
56 struct COSEDecodeError : public std::runtime_error
57 {
58 COSEDecodeError(const std::string& msg) : std::runtime_error(msg) {}
59 };
60
61 struct COSESignatureValidationError : public std::runtime_error
62 {
63 COSESignatureValidationError(const std::string& msg) :
64 std::runtime_error(msg)
65 {}
66 };
67
68 static std::string tstring_to_string(QCBORItem& item)
69 {
70 return {
71 static_cast<const char*>(item.val.string.ptr),
72 static_cast<const char*>(item.val.string.ptr) + item.val.string.len};
73 }
74
75 struct CwtClaims
76 {
77 int64_t iat{};
78 std::string iss;
79 std::string sub;
80 };
81
82 struct CcfClaims
83 {
84 std::string txid;
85 };
86
88 {
89 int alg{};
90 std::vector<uint8_t> kid;
93 int vds{};
94 };
95
96 struct Leaf
97 {
98 std::vector<uint8_t> write_set_digest;
99 std::string commit_evidence;
100 std::vector<uint8_t> claims_digest;
101 };
102
104 {
106 std::vector<std::pair<int64_t, std::vector<uint8_t>>> path;
107 };
108
110 {
112 std::vector<uint8_t> merkle_root;
113 };
114
115 static std::vector<uint8_t> recompute_merkle_root(const MerkleProof& proof)
116 {
117 auto ce_digest = ccf::crypto::Sha256Hash(proof.leaf.commit_evidence);
118
120 {
121 throw COSEDecodeError(fmt::format(
122 "Unsupported write set digest size in Merkle proof leaf: {}",
123 proof.leaf.write_set_digest.size()));
124 }
126 {
127 throw COSEDecodeError(fmt::format(
128 "Unsupported claims digest size in Merkle proof leaf: {}",
129 proof.leaf.claims_digest.size()));
130 }
131
132 std::span<const uint8_t, ccf::crypto::Sha256Hash::SIZE> wsd{
134 std::span<const uint8_t, ccf::crypto::Sha256Hash::SIZE> cd{
136 auto leaf_digest = ccf::crypto::Sha256Hash(
138 ce_digest,
140
141 for (const auto& element : proof.path)
142 {
143 if (element.first != 0)
144 {
145 std::span<const uint8_t, ccf::crypto::Sha256Hash::SIZE> sibling{
147 leaf_digest = ccf::crypto::Sha256Hash(
148 ccf::crypto::Sha256Hash::from_span(sibling), leaf_digest);
149 }
150 else
151 {
152 std::span<const uint8_t, ccf::crypto::Sha256Hash::SIZE> sibling{
154 leaf_digest = ccf::crypto::Sha256Hash(
155 leaf_digest, ccf::crypto::Sha256Hash::from_span(sibling));
156 }
157 }
158
159 return {leaf_digest.h.begin(), leaf_digest.h.end()};
160 }
161
162 static void decode_receipt_top_level_phdr(
163 QCBORDecodeContext& ctx, CcfCoseReceiptPhdr& phdr)
164 {
165 enum : std::uint8_t
166 {
167 ALG_INDEX,
168 KID_INDEX,
169 CWT_INDEX,
170 VDS_INDEX,
171 END_INDEX,
172 };
173
174 QCBORItem header_items[END_INDEX + 1];
175
176 header_items[ALG_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_ALG;
177 header_items[ALG_INDEX].uLabelType = QCBOR_TYPE_INT64;
178 header_items[ALG_INDEX].uDataType = QCBOR_TYPE_INT64;
179
180 header_items[KID_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_ID;
181 header_items[KID_INDEX].uLabelType = QCBOR_TYPE_INT64;
182 header_items[KID_INDEX].uDataType = QCBOR_TYPE_BYTE_STRING;
183
184 header_items[CWT_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_CWT;
185 header_items[CWT_INDEX].uLabelType = QCBOR_TYPE_INT64;
186 header_items[CWT_INDEX].uDataType = QCBOR_TYPE_MAP;
187
188 header_items[VDS_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_VDS;
189 header_items[VDS_INDEX].uLabelType = QCBOR_TYPE_INT64;
190 header_items[VDS_INDEX].uDataType = QCBOR_TYPE_INT64;
191
192 header_items[END_INDEX].uLabelType = QCBOR_TYPE_NONE;
193
194 QCBORDecode_GetItemsInMap(&ctx, header_items);
195
196 auto qcbor_result = QCBORDecode_GetError(&ctx);
197 if (qcbor_result != QCBOR_SUCCESS)
198 {
199 throw ccf::cose::COSEDecodeError(fmt::format(
200 "Failed to decode protected header: {}",
201 qcbor_err_to_str(qcbor_result)));
202 }
203
204 if (header_items[ALG_INDEX].uDataType == QCBOR_TYPE_NONE)
205 {
207 "COSE receipt missing 'alg' in protected header");
208 }
209 phdr.alg = header_items[ALG_INDEX].val.int64;
210
211 if (header_items[KID_INDEX].uDataType == QCBOR_TYPE_NONE)
212 {
214 "COSE receipt missing 'kid' in protected header");
215 }
216 phdr.kid =
217 ccf::cose::qcbor_buf_to_byte_vector(header_items[KID_INDEX].val.string);
218
219 if (header_items[VDS_INDEX].uDataType == QCBOR_TYPE_NONE)
220 {
222 "COSE receipt missing 'vds' in protected header");
223 }
224 phdr.vds = header_items[VDS_INDEX].val.int64;
225
226 if (phdr.vds != ccf::crypto::COSE_PHEADER_VDS_CCF_LEDGER_SHA256)
227 {
228 throw ccf::cose::COSEDecodeError(fmt::format(
229 "Expected VDS={} (CCF_LEDGER_SHA256), got {}",
230 ccf::crypto::COSE_PHEADER_VDS_CCF_LEDGER_SHA256,
231 phdr.vds));
232 }
233 }
234
235 static void decode_cwt_claims(QCBORDecodeContext& ctx, CwtClaims& cwt)
236 {
237 QCBORDecode_EnterMapFromMapN(&ctx, crypto::COSE_PHEADER_KEY_CWT);
238 auto decode_error = QCBORDecode_GetError(&ctx);
239 if (decode_error != QCBOR_SUCCESS)
240 {
241 throw COSEDecodeError(
242 fmt::format("Failed to decode CWT claims: {}", decode_error));
243 }
244
245 enum : std::uint8_t
246 {
247 IAT_INDEX,
248 ISS_INDEX,
249 SUB_INDEX,
250 END_CWT_INDEX,
251 };
252
253 QCBORItem cwt_items[END_CWT_INDEX + 1];
254
255 cwt_items[IAT_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_IAT;
256 cwt_items[IAT_INDEX].uLabelType = QCBOR_TYPE_INT64;
257 cwt_items[IAT_INDEX].uDataType = QCBOR_TYPE_INT64;
258
259 cwt_items[ISS_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_ISS;
260 cwt_items[ISS_INDEX].uLabelType = QCBOR_TYPE_INT64;
261 cwt_items[ISS_INDEX].uDataType = QCBOR_TYPE_TEXT_STRING;
262
263 cwt_items[SUB_INDEX].label.int64 = ccf::crypto::COSE_PHEADER_KEY_SUB;
264 cwt_items[SUB_INDEX].uLabelType = QCBOR_TYPE_INT64;
265 cwt_items[SUB_INDEX].uDataType = QCBOR_TYPE_TEXT_STRING;
266
267 cwt_items[END_CWT_INDEX].uLabelType = QCBOR_TYPE_NONE;
268
269 QCBORDecode_GetItemsInMap(&ctx, cwt_items);
270 decode_error = QCBORDecode_GetError(&ctx);
271 if (decode_error != QCBOR_SUCCESS)
272 {
273 throw COSEDecodeError(
274 fmt::format("Failed to decode CWT claims: {}", decode_error));
275 }
276
277 if (cwt_items[IAT_INDEX].uDataType == QCBOR_TYPE_NONE)
278 {
279 throw ccf::cose::COSEDecodeError("CWT claims missing 'iat' field");
280 }
281 cwt.iat = cwt_items[IAT_INDEX].val.int64;
282
283 if (cwt_items[ISS_INDEX].uDataType == QCBOR_TYPE_NONE)
284 {
285 throw ccf::cose::COSEDecodeError("CWT claims missing 'iss' field");
286 }
287 cwt.iss = tstring_to_string(cwt_items[ISS_INDEX]);
288
289 if (cwt_items[SUB_INDEX].uDataType == QCBOR_TYPE_NONE)
290 {
291 throw ccf::cose::COSEDecodeError("CWT claims missing 'sub' field");
292 }
293 cwt.sub = tstring_to_string(cwt_items[SUB_INDEX]);
294
295 QCBORDecode_ExitMap(&ctx);
296 }
297
298 static void decode_ccf_claims(QCBORDecodeContext& ctx, CcfClaims& ccf)
299 {
300 QCBORDecode_EnterMapFromMapSZ(
301 &ctx, ccf::crypto::COSE_PHEADER_KEY_CCF.c_str());
302 auto decode_error = QCBORDecode_GetError(&ctx);
303 if (decode_error != QCBOR_SUCCESS)
304 {
305 throw COSEDecodeError(
306 fmt::format("Failed to decode CCF claims: {}", decode_error));
307 }
308
309 enum : std::uint8_t
310 {
311 TXID_INDEX,
312 END_CCF_INDEX,
313 };
314
315 QCBORItem ccf_items[END_CCF_INDEX + 1];
316
317 ccf_items[TXID_INDEX].label.string = UsefulBufC{
318 ccf::crypto::COSE_PHEADER_KEY_TXID.data(),
319 ccf::crypto::COSE_PHEADER_KEY_TXID.size()};
320 ccf_items[TXID_INDEX].uLabelType = QCBOR_TYPE_TEXT_STRING;
321 ccf_items[TXID_INDEX].uDataType = QCBOR_TYPE_TEXT_STRING;
322
323 ccf_items[END_CCF_INDEX].uLabelType = QCBOR_TYPE_NONE;
324
325 QCBORDecode_GetItemsInMap(&ctx, ccf_items);
326 decode_error = QCBORDecode_GetError(&ctx);
327 if (decode_error != QCBOR_SUCCESS)
328 {
329 throw COSEDecodeError(
330 fmt::format("Failed to decode CCF claims: {}", decode_error));
331 }
332
333 if (ccf_items[TXID_INDEX].uDataType == QCBOR_TYPE_NONE)
334 {
335 throw ccf::cose::COSEDecodeError("CCF claims missing 'txid' field");
336 }
337 ccf.txid = tstring_to_string(ccf_items[TXID_INDEX]);
338
339 QCBORDecode_ExitMap(&ctx);
340 }
341
342 static CcfCoseReceiptPhdr decode_ccf_receipt_phdr(QCBORDecodeContext& ctx)
343 {
344 QCBORDecode_EnterBstrWrapped(
345 &ctx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, nullptr);
346 QCBORDecode_EnterMap(&ctx, nullptr);
347
348 CcfCoseReceiptPhdr phdr{};
349
350 decode_receipt_top_level_phdr(ctx, phdr);
351 decode_cwt_claims(ctx, phdr.cwt);
352 decode_ccf_claims(ctx, phdr.ccf);
353
354 QCBORDecode_ExitMap(&ctx);
355 QCBORDecode_ExitBstrWrapped(&ctx);
356
357 return phdr;
358 }
359
360 /* Expects QCBORDecodeContext to be at 'uhdr'. */
361 static std::vector<MerkleProof> decode_merkle_proofs(QCBORDecodeContext& ctx)
362 {
363 QCBORDecode_EnterMap(&ctx, nullptr);
364 auto err = QCBORDecode_GetError(&ctx);
365 if (err != QCBOR_SUCCESS)
366 {
367 throw COSEDecodeError(
368 fmt::format("Failed to enter unprotected header map: {}", err));
369 }
370
371 QCBORDecode_EnterMapFromMapN(&ctx, headers::PARAM_VDP);
372 err = QCBORDecode_GetError(&ctx);
373 if (err != QCBOR_SUCCESS)
374 {
375 throw COSEDecodeError(
376 fmt::format("Failed to enter Merkle proofs map: {}", err));
377 }
378
379 QCBORDecode_EnterArrayFromMapN(&ctx, headers::PARAM_INCLUSION_PROOFS);
380 err = QCBORDecode_GetError(&ctx);
381 if (err != QCBOR_SUCCESS)
382 {
383 throw COSEDecodeError(
384 fmt::format("Failed to enter Merkle proofs array: {}", err));
385 }
386
387 std::vector<uint8_t> root;
388 std::vector<MerkleProof> proofs;
389 for (;;)
390 {
391 QCBORDecode_EnterBstrWrapped(
392 &ctx, QCBOR_TAG_REQUIREMENT_NOT_A_TAG, nullptr);
393 err = QCBORDecode_GetError(&ctx);
394 if (err != QCBOR_SUCCESS)
395 {
396 err = QCBORDecode_GetAndResetError(&ctx);
397 if (err != QCBOR_ERR_NO_MORE_ITEMS)
398 {
399 throw COSEDecodeError(fmt::format(
400 "Expected NO_MORE_ITEMS after reading Merkle proofs, got {}", err));
401 }
402 break;
403 }
404
405 QCBORDecode_EnterMap(&ctx, nullptr);
406 err = QCBORDecode_GetError(&ctx);
407 if (err != QCBOR_SUCCESS)
408 {
409 throw COSEDecodeError(fmt::format("Failed to enter leaf map: {}", err));
410 }
411
412 QCBORDecode_EnterArrayFromMapN(
414
415 QCBORItem item;
416 MerkleProof proof;
417
418 QCBORDecode_GetNext(&ctx, &item);
419 if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
420 {
421 throw COSEDecodeError(fmt::format(
422 "Expected byte string for write_set_digest, got {}", item.uDataType));
423 }
424 proof.leaf.write_set_digest =
425 ccf::cose::qcbor_buf_to_byte_vector(item.val.string);
426
427 QCBORDecode_GetNext(&ctx, &item);
428 if (item.uDataType != QCBOR_TYPE_TEXT_STRING)
429 {
430 throw COSEDecodeError(fmt::format(
431 "Expected text string for commit_evidence, got {}", item.uDataType));
432 }
433
434 proof.leaf.commit_evidence =
435 ccf::cose::qcbor_buf_to_string(item.val.string);
436
437 QCBORDecode_GetNext(&ctx, &item);
438 if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
439 {
440 throw COSEDecodeError(fmt::format(
441 "Expected byte string for claims_digest, got {}", item.uDataType));
442 }
443
444 proof.leaf.claims_digest =
445 ccf::cose::qcbor_buf_to_byte_vector(item.val.string);
446
447 QCBORDecode_ExitArray(&ctx);
448
449 QCBORDecode_EnterArrayFromMapN(
451 err = QCBORDecode_GetError(&ctx);
452 if (err != QCBOR_SUCCESS)
453 {
454 throw COSEDecodeError(
455 fmt::format("Failed to enter path array: {}", err));
456 }
457
458 for (;;)
459 {
460 QCBORDecode_EnterArray(&ctx, &item);
461 if (QCBORDecode_GetError(&ctx) != QCBOR_SUCCESS)
462 {
463 err = QCBORDecode_GetAndResetError(&ctx);
464 if (err != QCBOR_ERR_NO_MORE_ITEMS)
465 {
466 throw COSEDecodeError(fmt::format(
467 "Expected NO_MORE_ITEMS after reading path, got {}", err));
468 }
469 break;
470 }
471
472 std::pair<int64_t, std::vector<uint8_t>> path_item;
473
474 err = QCBORDecode_GetNext(&ctx, &item);
475 if (err != QCBOR_SUCCESS)
476 {
477 throw COSEDecodeError(
478 fmt::format("Failed to get path direction item: {}", err));
479 }
480
481 if (item.uDataType == CBOR_SIMPLEV_TRUE)
482 {
483 path_item.first = 1;
484 }
485 else if (item.uDataType == CBOR_SIMPLEV_FALSE)
486 {
487 path_item.first = 0;
488 }
489 else
490 {
491 // Not a valid CBOR boolean
492 throw COSEDecodeError(fmt::format(
493 "Invalid path direction in Merkle proof: {}", item.uDataType));
494 }
495
496 err = QCBORDecode_GetNext(&ctx, &item);
497 if (err != QCBOR_SUCCESS)
498 {
499 throw COSEDecodeError(
500 fmt::format("Failed to get path hash item: {}", err));
501 }
502 if (item.uDataType != QCBOR_TYPE_BYTE_STRING)
503 {
504 throw COSEDecodeError(fmt::format(
505 "Expected byte string for path hash, got {}", item.uDataType));
506 }
507
508 path_item.second = ccf::cose::qcbor_buf_to_byte_vector(item.val.string);
509 proof.path.push_back(path_item);
510
511 QCBORDecode_ExitArray(&ctx);
512 err = QCBORDecode_GetError(&ctx);
513 if (err != QCBOR_SUCCESS)
514 {
515 throw COSEDecodeError(
516 fmt::format("Failed to exit path item array: {}", err));
517 }
518 }
519
520 QCBORDecode_ExitArray(&ctx); // path
521 err = QCBORDecode_GetError(&ctx);
522 if (err != QCBOR_SUCCESS)
523 {
524 throw COSEDecodeError(
525 fmt::format("Failed to exit path array: {}", err));
526 }
527
528 QCBORDecode_ExitMap(&ctx); // proof
529 err = QCBORDecode_GetError(&ctx);
530 if (err != QCBOR_SUCCESS)
531 {
532 throw COSEDecodeError(fmt::format("Failed to exit proof map: {}", err));
533 }
534
535 QCBORDecode_ExitBstrWrapped(&ctx); // wrapped proof
536 err = QCBORDecode_GetError(&ctx);
537 if (err != QCBOR_SUCCESS)
538 {
539 throw COSEDecodeError(
540 fmt::format("Failed to exit wrapped proof: {}", err));
541 }
542
543 proofs.push_back(proof);
544 }
545
546 QCBORDecode_ExitArray(&ctx); // proofs array
547 err = QCBORDecode_GetError(&ctx);
548 if (err != QCBOR_SUCCESS)
549 {
550 throw COSEDecodeError(
551 fmt::format("Failed to exit proofs array: {}", err));
552 }
553
554 QCBORDecode_ExitMap(&ctx); // VDP
555 err = QCBORDecode_GetError(&ctx);
556 if (err != QCBOR_SUCCESS)
557 {
558 throw COSEDecodeError(fmt::format("Failed to exit VDP map: {}", err));
559 }
560
561 QCBORDecode_ExitMap(&ctx); // uhdr
562 err = QCBORDecode_GetError(&ctx);
563 if (err != QCBOR_SUCCESS)
564 {
565 throw COSEDecodeError(fmt::format("Failed to exit uhdr map: {}", err));
566 }
567
568 return proofs;
569 }
570
571 static CcfCoseReceipt decode_ccf_receipt(
572 const std::vector<uint8_t>& cose_sign1, bool recompute_root)
573 {
574 QCBORError qcbor_result = QCBOR_SUCCESS;
575 QCBORDecodeContext ctx;
576 UsefulBufC buf{cose_sign1.data(), cose_sign1.size()};
577 QCBORDecode_Init(&ctx, buf, QCBOR_DECODE_MODE_NORMAL);
578
579 QCBORDecode_EnterArray(&ctx, nullptr);
580 qcbor_result = QCBORDecode_GetError(&ctx);
581 if (qcbor_result != QCBOR_SUCCESS)
582 {
583 throw COSEDecodeError("Failed to parse COSE_Sign1 outer array");
584 }
585
586 uint64_t tag = QCBORDecode_GetNthTagOfLast(&ctx, 0);
587 if (tag != CBOR_TAG_COSE_SIGN1)
588 {
589 throw COSEDecodeError("COSE_Sign1 is not tagged");
590 }
591
592 CcfCoseReceipt receipt;
593
594 receipt.phdr = decode_ccf_receipt_phdr(ctx);
595
596 if (recompute_root)
597 {
598 auto proofs = decode_merkle_proofs(ctx);
599 if (proofs.empty())
600 {
601 throw COSEDecodeError("No Merkle proofs found in COSE receipt");
602 }
603
604 receipt.merkle_root = recompute_merkle_root(proofs[0]);
605 for (size_t i = 1; i < proofs.size(); ++i)
606 {
607 auto root = recompute_merkle_root(proofs[i]);
608 if (root != receipt.merkle_root)
609 {
610 throw COSEDecodeError(
611 "Inconsistent Merkle roots computed from COSE receipt proofs");
612 }
613 }
614 }
615
616 return receipt;
617 }
618}
Definition sha256_hash.h:16
static Sha256Hash from_span(const std::span< const uint8_t, SIZE > &sp)
Definition sha256_hash.cpp:69
static constexpr size_t SIZE
Definition sha256_hash.h:18
Definition cose_signatures_config_interface.h:12
std::span< const uint8_t > Signature
Definition cose_common.h:31
uint64_t element
Definition sharing.cpp:20
std::vector< uint8_t > cose_sign1(const ECKeyPair_OpenSSL &key, const std::vector< std::shared_ptr< COSEParametersFactory > > &protected_headers, std::span< const uint8_t > payload, bool detached_payload)
Definition cose_sign.cpp:231
Definition app_interface.h:14
@ MERKLE_PROOF_LEAF_LABEL
Definition receipt.h:142
@ MERKLE_PROOF_PATH_LABEL
Definition receipt.h:143
STL namespace.
Definition cose_common.h:57
COSEDecodeError(const std::string &msg)
Definition cose_common.h:58
Definition cose_common.h:62
COSESignatureValidationError(const std::string &msg)
Definition cose_common.h:63
Definition cose_common.h:83
std::string txid
Definition cose_common.h:84
Definition cose_common.h:88
CwtClaims cwt
Definition cose_common.h:91
std::vector< uint8_t > kid
Definition cose_common.h:90
int vds
Definition cose_common.h:93
int alg
Definition cose_common.h:89
Definition cose_common.h:110
std::vector< uint8_t > merkle_root
Definition cose_common.h:112
CcfCoseReceiptPhdr phdr
Definition cose_common.h:111
Definition cose_common.h:76
std::string sub
Definition cose_common.h:79
int64_t iat
Definition cose_common.h:77
std::string iss
Definition cose_common.h:78
Definition cose_common.h:97
std::vector< uint8_t > claims_digest
Definition cose_common.h:100
std::string commit_evidence
Definition cose_common.h:99
std::vector< uint8_t > write_set_digest
Definition cose_common.h:98
Definition cose_common.h:104
std::vector< std::pair< int64_t, std::vector< uint8_t > > > path
Definition cose_common.h:106
Leaf leaf
Definition cose_common.h:105