blob: 077a57b13fbc2c62865ce0ccb9c68dcb64282a83 [file] [log] [blame]
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -08001/*
2 * attest_token.c
3 *
4 * Copyright (c) 2018-2019, Laurence Lundblade. All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 *
8 * See BSD-3-Clause license in README.md
9 */
10
11#include "attest_token.h"
12#include "qcbor.h"
13#include "t_cose_sign1_sign.h"
14
15
16/**
17 * \file attest_token.c
18 *
19 * \brief Attestation token creation implementation
20 *
21 * Outline of token creation. Much of this occurs inside
22 * t_cose_sign1_init() and t_cose_sign1_finish().
23 *
24 * - Create encoder context
25 * - Open the CBOR array that hold the \c COSE_Sign1
26 * - Write COSE Headers
27 * - Protected Header
28 * - Algorithm ID
29 * - Unprotected Headers
30 * - Key ID
31 * - Open payload bstr
32 * - Write payload data… lots of it…
33 * - Get bstr that is the encoded payload
34 * - Compute signature
35 * - Create a separate encoder context for \c Sig_structure
36 * - Encode CBOR context identifier
37 * - Encode protected headers
38 * - Encode two empty bstr
39 * - Add one more empty bstr that is a "fake payload"
40 * - Close off \c Sig_structure
41 * - Hash all but "fake payload" of \c Sig_structure
42 * - Get payload bstr ptr and length
43 * - Continue hash of the real encoded payload
44 * - Run ECDSA
45 * - Write signature into the CBOR output
46 * - Close CBOR array holding the \c COSE_Sign1
47 */
48
49/*
50 * \brief Map t_cose error to attestation token error.
51 *
52 * \param[in] err The t_cose error to map.
53 *
54 * \return the attestation token error.
55 *
56 */
57static enum attest_token_err_t t_cose_err_to_attest_err(enum t_cose_err_t err)
58{
59 switch(err) {
60
61 case T_COSE_SUCCESS:
62 return ATTEST_TOKEN_ERR_SUCCESS;
63
64 case T_COSE_ERR_UNSUPPORTED_HASH:
65 return ATTEST_TOKEN_ERR_HASH_UNAVAILABLE;
66
67 default:
68 /* A lot of the errors are not mapped because they are
69 * primarily internal errors that should never happen. They
70 * end up here.
71 */
72 return ATTEST_TOKEN_ERR_GENERAL;
73 }
74}
75
76
77/*
78 Public function. See attest_token.h
79 */
80enum attest_token_err_t attest_token_start(struct attest_token_ctx *me,
81 uint32_t opt_flags,
82 int32_t key_select,
83 int32_t cose_alg_id,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -080084 const struct q_useful_buf *out_buf)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -080085{
86 /* approximate stack usage on 32-bit machine: 4 bytes */
87 enum t_cose_err_t cose_return_value;
88 enum attest_token_err_t return_value;
89
90 /* Remember some of the configuration values */
91 me->opt_flags = opt_flags;
92 me->key_select = key_select;
93
94 /* Spin up the CBOR encoder */
95 QCBOREncode_Init(&(me->cbor_enc_ctx), *out_buf);
96
97
98 /* Initialize COSE signer. This will cause the cose headers to be
99 * encoded and written into out_buf using me->cbor_enc_ctx
100 */
101 cose_return_value = t_cose_sign1_init(&(me->signer_ctx),
102 opt_flags &
103 TOKEN_OPT_SHORT_CIRCUIT_SIGN,
104 cose_alg_id,
105 key_select,
106 &(me->cbor_enc_ctx));
107 if(cose_return_value) {
108 return_value = t_cose_err_to_attest_err(cose_return_value);
109 goto Done;
110 }
111
112 /* Open the payload-wrapping bstr */
113 QCBOREncode_BstrWrap(&(me->cbor_enc_ctx));
114
115 QCBOREncode_OpenMap(&(me->cbor_enc_ctx));
116
117 return_value = ATTEST_TOKEN_ERR_SUCCESS;
118
119Done:
120 return return_value;
121}
122
123
124/*
125 Public function. See attest_token.h
126 */
127QCBOREncodeContext *attest_token_borrow_cbor_cntxt(struct attest_token_ctx *me)
128{
129 return &(me->cbor_enc_ctx);
130}
131
132
133/*
134 Public function. See attest_token.h
135 */
136void attest_token_add_integer(struct attest_token_ctx *me,
137 int32_t label,
138 int64_t Value)
139{
140 QCBOREncode_AddInt64ToMapN(&(me->cbor_enc_ctx), label, Value);
141}
142
143
144/*
145 Public function. See attest_token.h
146 */
147void attest_token_add_bstr(struct attest_token_ctx *me,
148 int32_t label,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800149 const struct q_useful_buf_c *bstr)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800150{
151 QCBOREncode_AddBytesToMapN(&(me->cbor_enc_ctx),
152 label,
153 *bstr);
154}
155
156
157/*
158 Public function. See attest_token.h
159 */
160void attest_token_add_tstr(struct attest_token_ctx *me,
161 int32_t label,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800162 const struct q_useful_buf_c *tstr)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800163{
164 QCBOREncode_AddTextToMapN(&(me->cbor_enc_ctx), label, *tstr);
165}
166
167
168/*
169 See attest_token.h
170 */
171void attest_token_add_encoded(struct attest_token_ctx *me,
172 int32_t label,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800173 const struct q_useful_buf_c *encoded)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800174{
175 QCBOREncode_AddEncodedToMapN(&(me->cbor_enc_ctx), label, *encoded);
176}
177
178
179/*
180 Public function. See attest_token.h
181 */
182enum attest_token_err_t
183attest_token_finish(struct attest_token_ctx *me,
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800184 struct q_useful_buf_c *completed_token)
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800185{
186 /* approximate stack usage on 32-bit machine: 4 + 4 + 8 + 8 = 24 */
187 enum attest_token_err_t return_value = ATTEST_TOKEN_ERR_SUCCESS;
188 /* The payload with all the claims that is signed */
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800189 struct q_useful_buf_c token_payload_ub;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800190 /* The completed and signed encoded cose_sign1 */
Laurence Lundbladee1610ad2019-02-20 13:53:20 -0800191 struct q_useful_buf_c completed_token_ub;
Laurence Lundbladeaffd65a2018-12-18 10:50:48 -0800192 QCBORError qcbor_result;
193 enum t_cose_err_t cose_return_value;
194
195 QCBOREncode_CloseMap(&(me->cbor_enc_ctx));
196
197 /* Close off the payload-wrapping bstr. This gives us back the
198 * pointer and length of the payload that needs to be hashed as
199 * part of the signature
200 */
201 QCBOREncode_CloseBstrWrap(&(me->cbor_enc_ctx), &token_payload_ub);
202
203 /* Finish off the cose signature. This does all the interesting work of
204 hashing and signing */
205 cose_return_value =
206 t_cose_sign1_finish(&(me->signer_ctx), token_payload_ub);
207 if(cose_return_value) {
208 /* Main errors are invoking the hash or signature */
209 return_value = t_cose_err_to_attest_err(cose_return_value);
210 goto Done;
211 }
212
213 /* Close off the CBOR encoding and return the completed token */
214 qcbor_result = QCBOREncode_Finish(&(me->cbor_enc_ctx),
215 &completed_token_ub);
216 if(qcbor_result == QCBOR_ERR_BUFFER_TOO_SMALL) {
217 return_value = ATTEST_TOKEN_ERR_TOO_SMALL;
218 } else if (qcbor_result != QCBOR_SUCCESS) {
219 /* likely from array not closed, too many closes, ... */
220 return_value = ATTEST_TOKEN_ERR_CBOR_FORMATTING;
221 } else {
222 *completed_token = completed_token_ub;
223 }
224
225Done:
226 return return_value;
227}
228