53#define LOG_MODULE "COSE"
54#define LOG_LEVEL LOG_LEVEL_EDHOC
64#define COSE_STRUCTURE_BUF_LEN (2 * EDHOC_MAX_PAYLOAD_LEN)
67static char enc_header[] =
"Encrypt0";
68static char sig_header[] =
"Signature1";
71encode_enc_structure(
const uint8_t *external_aad,
size_t external_aad_len,
72 uint8_t *out,
size_t out_len)
86encode_sig_structure(
const uint8_t *protected_hdr,
size_t protected_hdr_len,
87 const uint8_t *external_aad,
size_t external_aad_len,
88 const uint8_t *payload,
size_t payload_len,
89 uint8_t *out,
size_t out_len)
104 const uint8_t *key,
const uint8_t *nonce,
105 const uint8_t *external_aad,
size_t external_aad_len,
106 uint8_t *buf,
size_t plaintext_len,
111 LOG_ERR(
"Unsupported COSE AEAD algorithm %u\n", alg);
116 if(plaintext_len > buf_capacity || buf_capacity - plaintext_len < tag_len) {
117 LOG_ERR(
"COSE_Encrypt0 output buffer too small for plaintext + tag\n");
121 uint8_t enc_struct[COSE_STRUCTURE_BUF_LEN];
122 size_t enc_struct_len = encode_enc_structure(external_aad, external_aad_len,
123 enc_struct,
sizeof(enc_struct));
124 if(enc_struct_len == 0) {
125 LOG_ERR(
"Failed to encode Enc_structure for COSE_Encrypt0\n");
131 if(plaintext_len > UINT16_MAX || enc_struct_len > UINT16_MAX) {
132 LOG_ERR(
"COSE_Encrypt0 input too large for the AEAD interface\n");
139 CCM_STAR.set_key(key);
142 enc_struct, enc_struct_len,
143 buf + plaintext_len, tag_len, 1);
145 return plaintext_len + tag_len;
150 const uint8_t *key,
const uint8_t *nonce,
151 const uint8_t *external_aad,
size_t external_aad_len,
152 uint8_t *buf,
size_t ciphertext_len)
156 LOG_ERR(
"Unsupported COSE AEAD algorithm %u\n", alg);
159 if(ciphertext_len < tag_len) {
160 LOG_ERR(
"Ciphertext (%zu) shorter than COSE tag length (%u)\n",
161 ciphertext_len, tag_len);
165 uint8_t enc_struct[COSE_STRUCTURE_BUF_LEN];
166 size_t enc_struct_len = encode_enc_structure(external_aad, external_aad_len,
167 enc_struct,
sizeof(enc_struct));
168 if(enc_struct_len == 0) {
169 LOG_ERR(
"Failed to encode Enc_structure for COSE_Encrypt0\n");
173 size_t plaintext_len = ciphertext_len - tag_len;
177 if(plaintext_len > UINT16_MAX || enc_struct_len > UINT16_MAX) {
178 LOG_ERR(
"COSE_Encrypt0 input too large for the AEAD interface\n");
182 uint8_t expected_tag[COSE_MAX_TAG_LEN];
190 CCM_STAR.set_key(key);
193 enc_struct, enc_struct_len,
194 expected_tag, tag_len, 0);
198 for(uint8_t i = 0; i < tag_len; i++) {
199 diff |= expected_tag[i] ^ buf[plaintext_len + i];
202 LOG_ERR(
"COSE_Encrypt0 authentication tag verification failed\n");
205 return plaintext_len;
210 const uint8_t *protected_hdr,
size_t protected_hdr_len,
211 const uint8_t *external_aad,
size_t external_aad_len,
212 const uint8_t *payload,
size_t payload_len,
216 LOG_ERR(
"Unsupported COSE_Sign1 algorithm %d (only ES256=%d is supported)\n",
221 uint8_t sig_struct[COSE_STRUCTURE_BUF_LEN];
222 size_t sig_struct_len = encode_sig_structure(protected_hdr, protected_hdr_len,
223 external_aad, external_aad_len,
224 payload, payload_len,
225 sig_struct,
sizeof(sig_struct));
226 if(sig_struct_len == 0) {
227 LOG_ERR(
"Failed to encode Sig_structure for COSE_Sign1 signing\n");
231 uint8_t hash[HASH_LEN];
232 sha_256_hash(sig_struct, sig_struct_len, hash);
234 if(!
ecc_sign_hash(EDHOC_CURVE_P256, hash, private_key, signature)) {
235 LOG_ERR(
"COSE_Sign1 signature generation failed\n");
243 const uint8_t *protected_hdr,
size_t protected_hdr_len,
244 const uint8_t *external_aad,
size_t external_aad_len,
245 const uint8_t *payload,
size_t payload_len,
246 const uint8_t *signature,
size_t signature_len)
249 LOG_ERR(
"Unsupported COSE_Sign1 algorithm %d (only ES256=%d is supported)\n",
254 LOG_ERR(
"COSE_Sign1: unexpected signature length %zu (expected %d)\n",
259 uint8_t sig_struct[COSE_STRUCTURE_BUF_LEN];
260 size_t sig_struct_len = encode_sig_structure(protected_hdr, protected_hdr_len,
261 external_aad, external_aad_len,
262 payload, payload_len,
263 sig_struct,
sizeof(sig_struct));
264 if(sig_struct_len == 0) {
265 LOG_ERR(
"Failed to encode Sig_structure for COSE_Sign1 verification\n");
269 uint8_t hash[HASH_LEN];
270 sha_256_hash(sig_struct, sig_struct_len, hash);
273 LOG_ERR(
"COSE_Sign1 signature verification failed\n");
283 case COSE_ALG_AES_CCM_16_64_128:
284 return COSE_ALG_AES_CCM_16_64_128_KEY_LEN;
285 case COSE_ALG_AES_CCM_16_128_128:
286 return COSE_ALG_AES_CCM_16_128_128_KEY_LEN;
288 LOG_ERR(
"Invalid COSE algorithm %d specified\n", alg_id);
297 case COSE_ALG_AES_CCM_16_64_128:
298 return COSE_ALG_AES_CCM_16_64_128_IV_LEN;
299 case COSE_ALG_AES_CCM_16_128_128:
300 return COSE_ALG_AES_CCM_16_128_128_IV_LEN;
302 LOG_ERR(
"Invalid COSE algorithm %d specified\n", alg_id);
311 case COSE_ALG_AES_CCM_16_64_128:
312 return COSE_ALG_AES_CCM_16_64_128_TAG_LEN;
313 case COSE_ALG_AES_CCM_16_128_128:
314 return COSE_ALG_AES_CCM_16_128_128_TAG_LEN;
316 LOG_ERR(
"Invalid COSE algorithm %d specified\n", alg_id);
Public API declarations for COSE (RFC 9052).
bool ecc_sign_hash(uint8_t curve_id, const uint8_t *hash, const uint8_t *private_key, uint8_t *signature)
Generates an ECDSA signature for a message hash.
bool ecc_verify_hash(uint8_t curve_id, const uint8_t *hash, const uint8_t *public_key, const uint8_t *signature)
Verifies an ECDSA signature of a message hash.
ECDH interface for the EDHOC implementation.
uint8_t cose_get_key_len(uint8_t alg_id)
Get the symmetric key length for a COSE AEAD algorithm.
size_t cose_encrypt0_open(uint8_t alg, const uint8_t *key, const uint8_t *nonce, const uint8_t *external_aad, size_t external_aad_len, uint8_t *buf, size_t ciphertext_len)
AEAD-decrypt a buffer in place as a COSE_Encrypt0.
uint8_t cose_get_iv_len(uint8_t alg_id)
Get the nonce/IV length for a COSE AEAD algorithm.
uint8_t cose_get_tag_len(uint8_t alg_id)
Get the authentication tag length for a COSE AEAD algorithm.
size_t cose_encrypt0_seal(uint8_t alg, const uint8_t *key, const uint8_t *nonce, const uint8_t *external_aad, size_t external_aad_len, uint8_t *buf, size_t plaintext_len, size_t buf_capacity)
AEAD-encrypt a buffer in place as a COSE_Encrypt0.
size_t cose_sign1_sign(int8_t alg, const uint8_t *private_key, const uint8_t *protected_hdr, size_t protected_hdr_len, const uint8_t *external_aad, size_t external_aad_len, const uint8_t *payload, size_t payload_len, uint8_t *signature)
Produce a COSE_Sign1 signature.
bool cose_sign1_verify(int8_t alg, const uint8_t *public_key, const uint8_t *protected_hdr, size_t protected_hdr_len, const uint8_t *external_aad, size_t external_aad_len, const uint8_t *payload, size_t payload_len, const uint8_t *signature, size_t signature_len)
Verify a COSE_Sign1 signature.
size_t cbor_end_writer(cbor_writer_state_t *state)
Finishes writing CBOR output.
void cbor_write_text(cbor_writer_state_t *state, const char *text, size_t text_size)
Appends a text string.
void cbor_open_array(cbor_writer_state_t *state)
Adds subsequent CBOR objects to an array.
void cbor_init_writer(cbor_writer_state_t *state, uint8_t *buffer, size_t buffer_size)
Prepares for writing CBOR output.
void cbor_close_array(cbor_writer_state_t *state)
Stops adding subsequent CBOR objects to the innermost array.
void cbor_write_data(cbor_writer_state_t *state, const uint8_t *data, size_t data_size)
Appends a byte string.
#define P256_SIGNATURE_LEN
Length of signatures.
Header file for the logging system.
Platform-independent SHA-256 API.
Structure of the internal state of a CBOR writer.