1 /* 2 * attest_token.h 3 * 4 * Copyright (c) 2018-2019, Laurence Lundblade. 5 * Copyright (c) 2020-2023, Arm Limited. All rights reserved. 6 * 7 * SPDX-License-Identifier: BSD-3-Clause 8 * 9 * See BSD-3-Clause license in README.md 10 */ 11 12 #ifndef __ATTEST_TOKEN_H__ 13 #define __ATTEST_TOKEN_H__ 14 15 #include <stdint.h> 16 #include "qcbor/qcbor.h" 17 #ifdef SYMMETRIC_INITIAL_ATTESTATION 18 #include "t_cose_mac0_sign.h" 19 #else 20 #include "t_cose_sign1_sign.h" 21 #endif 22 23 #ifdef __cplusplus 24 extern "C" { 25 #endif 26 27 /** 28 * \file attest_token.h 29 * 30 * \brief Attestation Token Creation Interface 31 * 32 * The context and functions here are the way to create an attestation 33 * token. The steps are roughly: 34 * 35 * -# Create and initialize an attest_token_encode_ctx indicating the 36 * options, key and such using attest_token_encode_start(). 37 * 38 * -# Use various add methods to fill in the payload with claims. The 39 * encoding context can also be borrowed for more rich payloads. 40 * 41 * -# Call attest_token_encode_finish() to create the signature and finish 42 * formatting the COSE signed output. 43 */ 44 45 /** 46 Error codes returned from attestation token creation. 47 */ 48 enum attest_token_err_t { 49 /** Success */ 50 ATTEST_TOKEN_ERR_SUCCESS = 0, 51 /** The buffer passed in to receive the output is too small. */ 52 ATTEST_TOKEN_ERR_TOO_SMALL, 53 /** Something went wrong formatting the CBOR, most likely the 54 payload has maps or arrays that are not closed. */ 55 ATTEST_TOKEN_ERR_CBOR_FORMATTING, 56 /** A general, unspecific error when creating or decoding the 57 token. */ 58 ATTEST_TOKEN_ERR_GENERAL, 59 /** A hash function that is needed to make the token is not 60 available. */ 61 ATTEST_TOKEN_ERR_HASH_UNAVAILABLE, 62 /** CBOR Syntax not well-formed -- a CBOR syntax error. */ 63 ATTEST_TOKEN_ERR_CBOR_NOT_WELL_FORMED, 64 /** Bad CBOR structure, for example not a map when was is 65 required. */ 66 ATTEST_TOKEN_ERR_CBOR_STRUCTURE, 67 /** Bad CBOR type, for example an not a text string, when a text 68 string is required. */ 69 ATTEST_TOKEN_ERR_CBOR_TYPE, 70 /** Integer too large, for example an \c int32_t is required, but 71 value only fits in \c int64_t */ 72 ATTEST_TOKEN_ERR_INTEGER_VALUE, 73 /** Something is wrong with the COSE message structure, missing 74 headers or such. */ 75 ATTEST_TOKEN_ERR_COSE_FORMAT, 76 /** COSE signature or authentication tag is invalid, data 77 is corrupted. */ 78 ATTEST_TOKEN_ERR_COSE_VALIDATION, 79 /** The signing algorithm is not supported. */ 80 ATTEST_TOKEN_ERR_UNSUPPORTED_SIG_ALG, 81 /** Out of memory. */ 82 ATTEST_TOKEN_ERR_INSUFFICIENT_MEMORY, 83 /** Tampering detected in cryptographic function. */ 84 ATTEST_TOKEN_ERR_TAMPERING_DETECTED, 85 /** Signing key is not found or of wrong type. */ 86 ATTEST_TOKEN_ERR_SIGNING_KEY, 87 /** Verification key is not found or of wrong type. */ 88 ATTEST_TOKEN_ERR_VERIFICATION_KEY, 89 /** No token was given or validated */ 90 ATTEST_TOKEN_ERR_NO_VALID_TOKEN, 91 /** Data item with label wasn't found. */ 92 ATTEST_TOKEN_ERR_NOT_FOUND, 93 /** SW Components absence not correctly indicated. */ 94 ATTEST_TOKEN_ERR_SW_COMPONENTS_MISSING 95 }; 96 97 /** 98 * Request that the claims internally generated not be added to the 99 * token. This is a test mode that results in a static token that 100 * never changes. Only the nonce is included. The nonce is under 101 * the callers control unlike the other claims. 102 */ 103 #define TOKEN_OPT_OMIT_CLAIMS 0x40000000 104 105 /** 106 * A special test mode where a proper signature is not produced. In 107 * its place there is a concatenation of hashes of the payload to be 108 * the same size as the signature. This works and can be used to 109 * verify all of the SW stack except the public signature part. The 110 * token has no security value in this mode because anyone can 111 * replicate it. */ 112 #define TOKEN_OPT_SHORT_CIRCUIT_SIGN 0x80000000 113 114 /** 115 * The context for creating an attestation token. The caller of 116 * attest_token_encode must create one of these and pass it to the functions 117 * here. It is small enough that it can go on the stack. It is most of 118 * the memory needed to create a token except the output buffer and 119 * any memory requirements for the cryptographic operations. 120 * 121 * The structure is opaque for the caller. 122 * 123 * This is roughly 148 + 8 + 32 = 188 bytes 124 */ 125 struct attest_token_encode_ctx { 126 /* Private data structure */ 127 QCBOREncodeContext cbor_enc_ctx; 128 uint32_t opt_flags; 129 int32_t key_select; 130 #ifdef SYMMETRIC_INITIAL_ATTESTATION 131 struct t_cose_mac0_sign_ctx mac_ctx; 132 #else 133 struct t_cose_sign1_sign_ctx signer_ctx; 134 #endif 135 }; 136 137 /** 138 * \brief Initialize a token creation context. 139 * 140 * \param[in] me The token creation context to be initialized. 141 * \param[in] opt_flags Flags to select different custom options, 142 * for example \ref TOKEN_OPT_OMIT_CLAIMS. 143 * \param[in] key_select Selects which attestation key to sign with. 144 * \param[in] cose_alg_id The algorithm to sign with. The IDs are 145 * defined in [COSE (RFC 8152)] 146 * (https://tools.ietf.org/html/rfc8152) or 147 * in the [IANA COSE Registry] 148 * (https://www.iana.org/assignments/cose/cose.xhtml). 149 * \param[out] out_buffer The output buffer to write the encoded token into. 150 * 151 * \return one of the \ref attest_token_err_t errors. 152 * 153 * The size of the buffer in \c out_buffer->len 154 * determines the size of the token that can be created. It must be 155 * able to hold the final encoded and signed token. The data encoding 156 * overhead is just that of CBOR. The signing overhead depends on the 157 * signing key size. It is about 150 bytes for 256-bit ECDSA. 158 * 159 * If \c out_buffer->ptr is \c NULL and \c out_buffer_ptr->len is 160 * large like \c UINT32_MAX no token will be created but the length of 161 * the token that would be created will be in \c completed_token as 162 * returned by attest_token_encode_finish(). None of the cryptographic 163 * functions run during this, but the sizes of what they would output 164 * is taken into account. 165 */ 166 enum attest_token_err_t 167 attest_token_encode_start(struct attest_token_encode_ctx *me, 168 uint32_t opt_flags, 169 int32_t key_select, 170 int32_t cose_alg_id, 171 const struct q_useful_buf *out_buffer); 172 173 /** 174 * \brief Get a copy of the CBOR encoding context 175 * 176 * \param[in] me Token creation context. 177 * 178 * \return The CBOR encoding context 179 * 180 * Allows the caller to encode CBOR right into the output buffer using 181 * any of the \c QCBOREncode_AddXXXX() methods. Anything added here 182 * will be part of the payload that gets hashed. This can be used to 183 * make complex CBOR structures. All open arrays and maps must be 184 * close before calling any other \c attest_token_encode methods. \c 185 * QCBOREncode_Finish() should not be closed on this context. 186 */ 187 QCBOREncodeContext * 188 attest_token_encode_borrow_cbor_cntxt(struct attest_token_encode_ctx *me); 189 190 /** 191 * \brief Add a 64-bit signed integer claim 192 * 193 * \param[in] me Token creation context. 194 * \param[in] label Integer label for claim. 195 * \param[in] value The integer claim data. 196 */ 197 void attest_token_encode_add_integer(struct attest_token_encode_ctx *me, 198 int32_t label, 199 int64_t value); 200 201 /** 202 * \brief Add a binary string claim 203 * 204 * \param[in] me Token creation context. 205 * \param[in] label Integer label for claim. 206 * \param[in] value The binary claim data. 207 */ 208 void attest_token_encode_add_bstr(struct attest_token_encode_ctx *me, 209 int32_t label, 210 const struct q_useful_buf_c *value); 211 212 /** 213 * \brief Add a text string claim 214 * 215 * \param[in] me Token creation context. 216 * \param[in] label Integer label for claim. 217 * \param[in] value The text claim data. 218 */ 219 void attest_token_encode_add_tstr(struct attest_token_encode_ctx *me, 220 int32_t label, 221 const struct q_useful_buf_c *value); 222 223 /** 224 * \brief Add some already-encoded CBOR to payload 225 * 226 * \param[in] me Token creation context. 227 * \param[in] label Integer label for claim. 228 * \param[in] encoded The already-encoded CBOR. 229 * 230 * Encoded CBOR must be a full map or full array or a non-aggregate 231 * type. It cannot be a partial map or array. It can be nested maps 232 * and arrays, but they must all be complete. 233 */ 234 void attest_token_encode_add_cbor(struct attest_token_encode_ctx *me, 235 int32_t label, 236 const struct q_useful_buf_c *encoded); 237 238 /** 239 * \brief Finish the token, complete the signing and get the result 240 * 241 * \param[in] me Token Creation Context. 242 * \param[out] completed_token Pointer and length to completed token. 243 * 244 * \return one of the \ref attest_token_err_t errors. 245 * 246 * This completes the token after the payload has been added. When 247 * this is called the signing algorithm is run and the final 248 * formatting of the token is completed. 249 */ 250 enum attest_token_err_t 251 attest_token_encode_finish(struct attest_token_encode_ctx *me, 252 struct q_useful_buf_c *completed_token); 253 254 #ifdef __cplusplus 255 } 256 #endif 257 258 #endif /* __ATTEST_TOKEN_H__ */ 259