56#define LOG_MODULE "EDHOC"
57#define LOG_LEVEL LOG_LEVEL_EDHOC
61gen_mac(
const edhoc_context_t *ctx, uint8_t mac_len, uint8_t *mac)
63 if(ctx == NULL || mac == NULL) {
69 mac_num = EDHOC_MAC_3;
71 mac_num = EDHOC_MAC_2;
77 LOG_ERR(
"Set MAC error\n");
85gen_plaintext(edhoc_context_t *ctx,
const uint8_t *auth_data,
size_t auth_data_size,
86 bool msg2,
const uint8_t *mac_or_signature,
87 uint8_t mac_or_signature_size,
88 uint8_t *plaintext_buffer,
size_t plaintext_buffer_size)
93 cbor_init_reader(&reader, ctx->buffers.id_cred_x,
sizeof(ctx->buffers.id_cred_x));
105 LOG_ERR(
"error to get bytes\n");
114 if(auth_data_size != 0) {
120 LOG_ERR(
"CBOR encoding failed in plaintext_23 generation\n");
126gen_ciphertext_3(edhoc_context_t *ctx,
const uint8_t *auth_data, uint16_t auth_data_size,
127 const uint8_t *mac_or_signature, uint16_t mac_or_signature_size,
128 uint8_t *ciphertext,
size_t ciphertext_buffer_size)
130 uint8_t alg = ctx->config.aead_alg;
134 if(key_len == 0 || iv_len == 0 || tag_len == 0) {
139 uint16_t plaintext_sz = gen_plaintext(ctx, auth_data, auth_data_size,
false,
140 mac_or_signature, mac_or_signature_size,
142 if(plaintext_sz == 0) {
145 LOG_DBG(
"PLAINTEXT_3 (%d bytes): ", (
int)plaintext_sz);
146 LOG_DBG_BYTES(aead_buf, plaintext_sz);
150 memcpy(ctx->buffers.plaintext, aead_buf, plaintext_sz);
151 ctx->buffers.plaintext_sz = plaintext_sz;
154 uint8_t key[COSE_MAX_KEY_LEN];
155 int16_t err =
edhoc_kdf(ctx->state.prk_3e2m, K_3_LABEL, ctx->state.th,
156 HASH_LEN, key_len, key);
158 LOG_ERR(
"Failed to derive K_3\n");
161 LOG_DBG(
"K_3 (%d bytes): ", (
int)key_len);
162 LOG_DBG_BYTES(key, key_len);
166 uint8_t nonce[COSE_MAX_IV_LEN];
167 err =
edhoc_kdf(ctx->state.prk_3e2m, IV_3_LABEL, ctx->state.th, HASH_LEN,
170 LOG_ERR(
"Failed to derive IV_3\n");
173 LOG_DBG(
"IV_3 (%d bytes): ", (
int)iv_len);
174 LOG_DBG_BYTES(nonce, iv_len);
179 ctx->state.th, HASH_LEN,
180 aead_buf, plaintext_sz,
182 if(ciphertext_sz == 0) {
183 LOG_ERR(
"COSE_Encrypt0 encryption failed\n");
193 LOG_ERR(
"CBOR encoding failed in ciphertext_3 generation\n");
195 return (uint16_t)result;
205 if(ad_sz > 0 && ad == NULL) {
209 if(ctx->config.suite_num == 0) {
214 edhoc_msg_1_t msg1 = {
215 .method = ctx->config.method,
217 .g_x = (uint8_t *)&ctx->creds.ephemeral_key.pub.x,
218 .c_i = ctx->state.cid,
219 .c_i_sz = ctx->state.cid_len,
220 .uad = { .ead_label = 0, .ead_value = ad, .ead_value_sz = ad_sz },
222 memcpy(msg1.suites_i, ctx->config.suite, msg1.suites_i_num *
sizeof(msg1.suites_i[0]));
236 ctx->buffers.tx_sz = size + 1;
237 (ctx->buffers.msg_tx)[0] = 0xF5;
239 LOG_DBG(
"C_I chosen by Initiator (%d bytes): 0x", (
int)msg1.c_i_sz);
240 LOG_DBG_BYTES(msg1.c_i, msg1.c_i_sz);
242 LOG_DBG(
"AD_1 (%d bytes): ", (
int)ad_sz);
243 LOG_DBG_STRING((
char *)ad, ad_sz);
245 for(
int i = 0; i < msg1.suites_i_num; ++i) {
246 LOG_DBG(
"SUITES_I[%d]: %d\n", i, (
int)msg1.suites_i[i]);
249 LOG_DBG(
"message_1 (CBOR Sequence) (%d bytes): ", (
int)ctx->buffers.tx_sz);
250 LOG_DBG_BYTES(ctx->buffers.msg_tx, ctx->buffers.tx_sz);
252 LOG_INFO(
"MSG1 sz: %d\n", (
int)ctx->buffers.tx_sz);
254 return EDHOC_SUCCESS;
264 if(auth_data_size > 0 && auth_data == NULL) {
269 ctx->buffers.msg_rx, ctx->buffers.rx_sz);
271 LOG_ERR(
"Failed to generate TH_2 (%d)\n", ret);
276 ctx->buffers.cred_x_sz =
279 sizeof(ctx->buffers.cred_x));
282 ctx->buffers.id_cred_x_sz =
284 ctx->buffers.id_cred_x,
285 sizeof(ctx->buffers.id_cred_x));
286 LOG_DBG(
"ID_CRED_R (%d bytes): ", (
int)ctx->buffers.id_cred_x_sz);
287 LOG_DBG_BYTES(ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
292 uint8_t mac_or_signature_sz = -1;
296#if (EDHOC_METHOD == EDHOC_METHOD1) || (EDHOC_METHOD == EDHOC_METHOD3)
300 uint8_t edhoc_mac_len = ctx->config.mac_len;
301 uint8_t mac_or_sig[edhoc_mac_len];
302 edhoc_error_t mac_result = gen_mac(ctx, edhoc_mac_len, mac_or_sig);
303 if(mac_result != EDHOC_SUCCESS) {
306 LOG_DBG(
"MAC_2 (%d bytes): ", edhoc_mac_len);
307 LOG_DBG_BYTES(mac_or_sig, edhoc_mac_len);
309 mac_or_signature_sz = edhoc_mac_len;
312#if (EDHOC_METHOD == EDHOC_METHOD0) || (EDHOC_METHOD == EDHOC_METHOD2)
315 memcpy(ctx->state.prk_3e2m, ctx->state.prk_2e, HASH_LEN);
319 edhoc_error_t mac_result = gen_mac(ctx, HASH_LEN, mac_or_sig);
320 if(mac_result != EDHOC_SUCCESS) {
323 LOG_DBG(
"MAC_2 (%d bytes): ", HASH_LEN);
324 LOG_DBG_BYTES(mac_or_sig, HASH_LEN);
336 if(external_aad_sz == 0) {
337 LOG_ERR(
"Failed to encode external AAD for COSE_Sign1\n");
342 ctx->creds.authen_key->ecc.priv,
343 ctx->buffers.id_cred_x,
344 ctx->buffers.id_cred_x_sz,
345 external_aad, external_aad_sz,
346 mac_or_sig, HASH_LEN,
349 LOG_ERR(
"COSE_Sign1 signing failed\n");
353 LOG_DBG(
"Signature from COSE_Sign1 (%zu bytes): ", sig_sz);
354 LOG_DBG_BYTES(mac_or_sig, sig_sz);
357 mac_or_signature_sz = sig_sz;
361 uint16_t plaint_sz = gen_plaintext(ctx, auth_data, auth_data_size,
true, mac_or_sig,
363 ctx->buffers.plaintext,
364 sizeof(ctx->buffers.plaintext));
365 LOG_DBG(
"PLAINTEXT_2 (%d bytes): ", (
int)plaint_sz);
366 LOG_DBG_BYTES(ctx->buffers.plaintext, plaint_sz);
371 ctx->buffers.plaintext_sz = plaint_sz;
374 uint8_t ks_2e[plaint_sz];
378 uint8_t ciphertext[plaint_sz];
379 memcpy(ciphertext, ctx->buffers.plaintext, plaint_sz);
381 LOG_DBG(
"CIPHERTEXT_2 (%d bytes): ", (
int)plaint_sz);
382 LOG_DBG_BYTES(ciphertext, plaint_sz);
387 cbor_init_writer(&writer, ctx->buffers.msg_tx,
sizeof(ctx->buffers.msg_tx));
396 if(ctx->buffers.tx_sz == 0) {
400 LOG_INFO(
"MSG2 sz: %d\n", ctx->buffers.tx_sz);
402 return EDHOC_SUCCESS;
412 if(auth_data_size > 0 && auth_data == NULL) {
417 ctx->buffers.plaintext, ctx->buffers.plaintext_sz);
420 LOG_DBG(
"SK_I (Initiator's private auth key) (%d bytes): ",
422 LOG_DBG_BYTES(ctx->creds.authen_key->ecc.priv, ECC_KEY_LEN);
425 LOG_DBG(
"G_I (x)(Initiator's public auth key) (%d bytes): ",
427 LOG_DBG_BYTES(ctx->creds.authen_key->ecc.pub.x, ECC_KEY_LEN);
430 LOG_DBG(
"G_I (y)(Initiator's public auth key) (%d bytes): ",
432 LOG_DBG_BYTES(ctx->creds.authen_key->ecc.pub.y, ECC_KEY_LEN);
436 ctx->buffers.cred_x_sz =
439 sizeof(ctx->buffers.cred_x));
440 LOG_DBG(
"CRED_I (%d bytes): ", (
int)ctx->buffers.cred_x_sz);
441 LOG_DBG_BYTES(ctx->buffers.cred_x, ctx->buffers.cred_x_sz);
447 ctx->buffers.id_cred_x_sz =
449 ctx->buffers.id_cred_x,
450 sizeof(ctx->buffers.id_cred_x));
451 LOG_DBG(
"ID_CRED_I (%d bytes): ", (
int)ctx->buffers.id_cred_x_sz);
452 LOG_DBG_BYTES(ctx->buffers.id_cred_x, ctx->buffers.id_cred_x_sz);
455 uint8_t mac_or_signature_sz = -1;
457#if ((EDHOC_METHOD == EDHOC_METHOD2) || (EDHOC_METHOD == EDHOC_METHOD3))
461 uint8_t edhoc_mac_len = ctx->config.mac_len;
462 uint8_t mac_or_sig[edhoc_mac_len];
463 edhoc_error_t mac_result = gen_mac(ctx, edhoc_mac_len, mac_or_sig);
464 if(mac_result != EDHOC_SUCCESS) {
467 LOG_DBG(
"MAC 3 (%d bytes): ", edhoc_mac_len);
468 LOG_DBG_BYTES(mac_or_sig, edhoc_mac_len);
470 mac_or_signature_sz = edhoc_mac_len;
473#if (EDHOC_METHOD == EDHOC_METHOD0) || (EDHOC_METHOD == EDHOC_METHOD1)
476 memcpy(ctx->state.prk_4e3m, ctx->state.prk_3e2m, HASH_LEN);
480 edhoc_error_t mac_result = gen_mac(ctx, HASH_LEN, mac_or_sig);
481 if(mac_result != EDHOC_SUCCESS) {
484 LOG_DBG(
"MAC_3 (%d bytes): ", HASH_LEN);
485 LOG_DBG_BYTES(mac_or_sig, HASH_LEN);
497 if(external_aad_sz == 0) {
498 LOG_ERR(
"Failed to encode external AAD for COSE_Sign1\n");
503 ctx->creds.authen_key->ecc.priv,
504 ctx->buffers.id_cred_x,
505 ctx->buffers.id_cred_x_sz,
506 external_aad, external_aad_sz,
507 mac_or_sig, HASH_LEN,
510 LOG_ERR(
"COSE_Sign1 signing failed\n");
514 LOG_DBG(
"Signature from COSE_Sign1 (%zu bytes): ", sig_sz);
515 LOG_DBG_BYTES(mac_or_sig, sig_sz);
518 mac_or_signature_sz = sig_sz;
522 uint16_t ciphertext_sz = gen_ciphertext_3(ctx, auth_data, auth_data_size, mac_or_sig,
524 (ctx->buffers.msg_tx) + 1,
525 sizeof(ctx->buffers.msg_tx) - 1);
526 if(ciphertext_sz == 0) {
531 if(ctx->state.cid_rx_len >
sizeof(ctx->buffers.msg_tx) - ciphertext_sz) {
535 memmove(ctx->buffers.msg_tx + ctx->state.cid_rx_len,
536 ctx->buffers.msg_tx + 1, ciphertext_sz);
538 memcpy(ctx->buffers.msg_tx, ctx->state.cid_rx, ctx->state.cid_rx_len);
539 ctx->buffers.tx_sz = ciphertext_sz + ctx->state.cid_rx_len;
543 ctx->buffers.plaintext, ctx->buffers.plaintext_sz);
545 return EDHOC_SUCCESS;
Public API declarations for COSE (RFC 9052).
EDHOC configuration file.
Error handling module header for EDHOC.
edhoc_error_t
Unified error type for EDHOC operations.
@ EDHOC_ERR_CBOR_ENCODING
CBOR encoding failed.
@ EDHOC_ERR_NULL_POINTER
Null pointer provided.
@ EDHOC_ERR_CRYPTO_HASH
Hash operation failed.
@ EDHOC_ERR_CRYPTO_ENCRYPT
Encryption operation failed.
@ EDHOC_ERR_CRYPTO_AUTHENTICATION
Authentication failed.
@ EDHOC_ERR_INVALID_STATE
Invalid context state.
@ EDHOC_ERR_SUITE_NOT_SUPPORTED
Cipher suite not supported.
@ EDHOC_ERR_BUFFER_TOO_SMALL
Provided buffer is too small.
@ EDHOC_ERR_CRYPTO_SIGN
Digital signature failed.
void edhoc_print_credential(const char *label, const uint8_t *cred, size_t cred_sz)
Print credential (CRED_I/CRED_R) values in readable format.
void cose_print_key(cose_key_t *cose)
Print a key in cose_key_t struct format for debugging.
Declarations for EDHOC message generators.
size_t edhoc_serialize_msg_1(edhoc_msg_1_t *msg, unsigned char *buffer, size_t buffer_sz, bool suite_array)
Serialize EDHOC message 1 to CBOR format.
void edhoc_write_byte_identifier(cbor_writer_state_t *state, const uint8_t *bytes, size_t byte_length)
Write EDHOC byte identifier according to RFC 9528 rules.
EDHOC message serialization and parsing API.
An implementation of Ephemeral Diffie-Hellman Over COSE (EDHOC) (RFC9528).
uint8_t cose_get_key_len(uint8_t alg_id)
Get the symmetric key length for a COSE AEAD algorithm.
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.
int8_t edhoc_generate_transcript_hash_2(edhoc_context_t *ctx, const uint8_t *eph_pub, uint8_t *msg, uint16_t msg_sz)
Generate transcript hash TH_2.
uint8_t edhoc_calc_mac(const edhoc_context_t *ctx, uint8_t mac_num, uint8_t mac_len, uint8_t *mac)
Calculate message authentication code (MAC).
size_t edhoc_generate_id_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
Generate credential identifier ID_CRED_X.
bool edhoc_generate_prk_2e(edhoc_context_t *ctx)
Generate pseudorandom key PRK_2e.
int16_t edhoc_kdf(const uint8_t *prk, uint8_t info_label, const uint8_t *context, uint8_t context_sz, uint16_t length, uint8_t *result)
EDHOC Key Derivation Function (KDF) based on HMAC-based Expand (RFC 5869).
int16_t edhoc_enc_dec_ciphertext_2(const edhoc_context_t *ctx, const uint8_t *ks_2e, uint8_t *plaintext, uint16_t plaintext_sz)
Encrypt/decrypt ciphertext 2 using XOR with keystream.
bool edhoc_generate_prk_4e3m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
Generate pseudorandom key PRK_4e3m.
bool edhoc_generate_prk_3e2m(edhoc_context_t *ctx, const ecc_key_t *auth_key, uint8_t gen)
Generate pseudorandom key PRK_3e2m.
size_t edhoc_generate_cred_x(const cose_key_t *cose, uint8_t *cred, size_t cred_sz)
Generate CBOR-encoded credential CRED_X.
uint8_t edhoc_generate_transcript_hash_3(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz, const uint8_t *plaintext, uint16_t plaintext_sz)
Generate transcript hash TH_3.
int16_t edhoc_generate_keystream_2e(edhoc_context_t *ctx, uint16_t length, uint8_t *ks_2e)
Generate keystream KS_2e for encryption.
uint8_t edhoc_generate_transcript_hash_4(edhoc_context_t *ctx, const uint8_t *cred, uint16_t cred_sz, const uint8_t *plaintext, uint16_t plaintext_sz)
Generate transcript hash TH_4.
size_t cbor_end_writer(cbor_writer_state_t *state)
Finishes writing CBOR output.
void cbor_close_data(cbor_writer_state_t *state)
Stops enclosing subsequent CBOR objects in the innermost byte string.
cbor_size_t cbor_read_unsigned(cbor_reader_state_t *state, uint64_t *value)
Reads an unsigned integer.
void cbor_open_data(cbor_writer_state_t *state)
Encloses subsequent CBOR objects in a byte string.
const uint8_t * cbor_read_data(cbor_reader_state_t *state, size_t *data_size)
Reads a byte string.
void cbor_write_object(cbor_writer_state_t *state, const void *object, size_t object_size)
Appends an arbitrary CBOR object.
void cbor_init_writer(cbor_writer_state_t *state, uint8_t *buffer, size_t buffer_size)
Prepares for writing CBOR output.
void cbor_init_reader(cbor_reader_state_t *state, const uint8_t *cbor, size_t cbor_size)
Prepares for reading CBOR input.
void cbor_write_data(cbor_writer_state_t *state, const uint8_t *data, size_t data_size)
Appends a byte string.
size_t cbor_read_map(cbor_reader_state_t *state)
Reads the number of entries of a map.
static int value(int type)
#define EDHOC_SUITES_MAX_COUNT
The max number of suites.
#define EDHOC_MAX_CRED_LEN
Optimized buffer sizes for credentials based on COSE standard analysis CRED_X: 84-120 bytes typical →...
#define EDHOC_MAX_PAYLOAD_LEN
The max length of the EDHOC message.
#define EDHOC_MAC_OR_SIG_BUF_LEN
Buffer size for mac_or_sig.
edhoc_error_t edhoc_generate_message_1(edhoc_context_t *ctx, uint8_t *ad, size_t ad_sz, bool suite_array)
Generate the EDHOC Message 1 and set it in the EDHOC context.
#define EDHOC_ROLE
Set the EDHOC Protocol role.
edhoc_error_t edhoc_generate_message_3(edhoc_context_t *ctx, const uint8_t *auth_data, size_t auth_data_size)
Generate the EDHOC Message 3 and set it in the EDHOC context.
#define EDHOC_MAX_BUFFER
The max size of the buffers.
edhoc_error_t edhoc_generate_message_2(edhoc_context_t *ctx, const uint8_t *auth_data, size_t auth_data_size)
Generate the EDHOC Message 2 and set it in the EDHOC context.
Header file for the logging system.
Platform-independent SHA-256 API.
Structure of the internal state of a CBOR reader.
Structure of the internal state of a CBOR writer.