45#define LOG_MODULE "EDHOC"
46#define LOG_LEVEL LOG_LEVEL_EDHOC
56static coap_timer_t
timer;
58static size_t msg_rx_len;
61static process_event_t new_ecc_event;
64static coap_message_t *request;
65static coap_message_t *response;
67static edhoc_msg_3_t msg3;
69#if EDHOC_TEST == EDHOC_TEST_VECTOR_TRACE_DH
72static const uint8_t eph_pub_x_r[ECC_KEY_LEN] = { 0x41, 0x97, 0x01, 0xd7, 0xf0, 0x0a, 0x26, 0xc2, 0xdc, 0x58, 0x7a, 0x36, 0xdd, 0x75, 0x25, 0x49, 0xf3, 0x37, 0x63, 0xc8, 0x93, 0x42, 0x2c,
73 0x8e, 0xa0, 0xf9, 0x55, 0xa1, 0x3a, 0x4f, 0xf5, 0xd5 };
75static const uint8_t eph_pub_y_r[ECC_KEY_LEN] = { 0x5e, 0x4f, 0x0d, 0xd8, 0xa3, 0xda, 0x0b, 0xaa, 0x16, 0xb9, 0xd3, 0xad, 0x56, 0xa0, 0xc1, 0x86, 0x0a, 0x94, 0x0a, 0xf8, 0x59, 0x14, 0x91,
76 0x5e, 0x25, 0x01, 0x9b, 0x40, 0x24, 0x17, 0xe9, 0x9d };
78static const uint8_t eph_private_r[ECC_KEY_LEN] = { 0xe2, 0xf4, 0x12, 0x67, 0x77, 0x20, 0x5e, 0x85, 0x3b, 0x43, 0x7d, 0x6e, 0xac, 0xa1, 0xe1, 0xf7, 0x53, 0xcd, 0xcc, 0x3e, 0x2c, 0x69, 0xfa,
79 0x88, 0x4b, 0x0a, 0x1a, 0x64, 0x09, 0x77, 0xe4, 0x18 };
83generate_ephemeral_key(uint8_t curve_id, uint8_t *pub_x, uint8_t *pub_y, uint8_t *priv)
86 LOG_ERR(
"Failed to generate ephemeral key pair\n");
90#if EDHOC_TEST == EDHOC_TEST_VECTOR_TRACE_DH
92 memcpy(
edhoc_ctx->creds.ephemeral_key.pub.x, eph_pub_x_r, ECC_KEY_LEN);
93 memcpy(
edhoc_ctx->creds.ephemeral_key.pub.y, eph_pub_y_r, ECC_KEY_LEN);
94 memcpy(
edhoc_ctx->creds.ephemeral_key.priv, eph_private_r, ECC_KEY_LEN);
96 LOG_ERR(
"Test vector key copy failed - invalid context\n");
109 if(ev == new_ecc_event && new_ecc.val == SERV_HANDSHAKE_COMPLETE) {
110 return SERV_HANDSHAKE_COMPLETE;
113 if(ev == new_ecc_event && new_ecc.val == SERV_HANDSHAKE_RESET) {
114 LOG_DBG(
"server callback: SERV_HANDSHAKE_RESET\n");
115 return SERV_HANDSHAKE_RESET;
124 LOG_ERR(
"AD_2 size (%u) exceeds maximum AD size (%d)\n", buf_sz,
EDHOC_MAX_AD_SZ);
125 new_ecc.ad.ad_2_sz = 0;
128 memcpy(new_ecc.ad.ad_2, (
void *)buf, buf_sz);
129 new_ecc.ad.ad_2_sz = buf_sz;
135 memcpy(buf, (
void *)new_ecc.ad.ad_1, new_ecc.ad.ad_1_sz);
136 return new_ecc.ad.ad_1_sz;
142 memcpy(buf, (
void *)new_ecc.ad.ad_3, new_ecc.ad.ad_3_sz);
143 return new_ecc.ad.ad_3_sz;
147reset_handshake_with_error(
void)
151 new_ecc.val = SERV_HANDSHAKE_RESET;
152 process_post(PROCESS_BROADCAST, new_ecc_event, &new_ecc);
156server_timeout_callback(coap_timer_t *
timer)
158 LOG_ERR(
"Timeout\n");
159 reset_handshake_with_error();
164handle_msg1_state(
void)
169 (uint8_t *)new_ecc.ad.ad_1);
172 LOG_WARN(
"error code (%d)\n", err);
173 serv->state = NON_MSG;
174 reset_handshake_with_error();
179 LOG_WARN(
"Send MSG error with code (%d)\n", err);
184 LOG_ERR(
"Failed to generate error message\n");
186 serv->state = TX_MSG_ERR;
188 reset_handshake_with_error();
193 memcpy(&serv->con_ipaddr, &request->src_ep->ipaddr,
sizeof(uip_ipaddr_t));
194 new_ecc.ad.ad_1_sz = err;
195 if(new_ecc.ad.ad_1_sz > 0) {
198 serv->rx_msg1 =
true;
201 generate_ephemeral_key(
edhoc_ctx->config.ecdh_curve,
207 if(result != EDHOC_SUCCESS) {
209 reset_handshake_with_error();
213 serv->state = RX_MSG3;
218handle_msg3_state(
void)
229 serv->state = NON_MSG;
230 reset_handshake_with_error();
239 LOG_ERR(
"Failed to generate error message\n");
241 reset_handshake_with_error();
242 serv->state = TX_MSG_ERR;
246 new_ecc.ad.ad_3_sz = err;
247 if(new_ecc.ad.ad_3_sz > 0) {
251 serv->state = EXP_READY;
252 serv->rx_msg3 =
true;
257handle_exp_ready_state(
void)
259 if(serv->rx_msg1 && serv->rx_msg3) {
263 new_ecc.val = SERV_HANDSHAKE_COMPLETE;
265 process_post(PROCESS_BROADCAST, new_ecc_event, &new_ecc);
268 LOG_ERR(
"Protocol step missed\n");
269 serv->state = NON_MSG;
275setup_coap_response(
void)
277 if(serv->state == NON_MSG) {
278 LOG_ERR(
"RX MSG ERROR response\n");
279 coap_set_payload(response, NULL, 0);
280 coap_set_status_code(response, DELETED_2_02);
284 response->payload = (uint8_t *)
edhoc_ctx->buffers.msg_tx;
285 response->payload_len =
edhoc_ctx->buffers.tx_sz;
286 coap_set_status_code(response, CHANGED_2_04);
288 memset(&(response->options), 0,
sizeof(response->options));
290 if(response->payload_len == 0) {
291 memset(&(request->options), 0,
sizeof(request->options));
293 coap_set_header_block2(response, 0,
294 edhoc_ctx->buffers.tx_sz > COAP_MAX_CHUNK_SIZE ? 1 : 0,
295 COAP_MAX_CHUNK_SIZE);
298 if(serv->state == TX_MSG_ERR) {
299 serv->state = NON_MSG;
311 serv->rx_msg1 =
false;
312 serv->rx_msg3 =
false;
313 serv->state = NON_MSG;
323 LOG_INFO(
"SERVER: EDHOC new\n");
326 LOG_ERR(
"Failed to create EDHOC context\n");
336 LOG_INFO(
"SERVER: CoAP active resource\n");
352 LOG_ERR(
"Message length is zero\n");
353 coap_set_payload(res, NULL, 0);
354 coap_set_status_code(res, BAD_REQUEST_4_00);
359 coap_set_payload(res, NULL, 0);
360 coap_set_status_code(res, BAD_REQUEST_4_00);
364 memcpy(msg_rx, msg, len);
370 if(serv->state == EXP_READY) {
374 if(serv->state != NON_MSG &&
375 memcmp(&serv->con_ipaddr, &request->src_ep->ipaddr,
sizeof(uip_ipaddr_t)) != 0) {
376 LOG_ERR(
"rx request from an error ipaddr\n");
377 coap_set_payload(response, NULL, 0);
378 coap_set_status_code(response, BAD_REQUEST_4_00);
382 switch(serv->state) {
388 if(handle_msg1_state() < 0) {
394 if(handle_msg3_state() < 0) {
399 handle_exp_ready_state();
403 LOG_ERR(
"Unknown server state: %d\n", serv->state);
404 serv->state = NON_MSG;
408 setup_coap_response();
bool ecdh_generate_keypair(uint8_t curve_id, uint8_t *pub_x, uint8_t *pub_y, uint8_t *priv)
Generates a fresh ECDH key pair.
const char * edhoc_error_string(edhoc_error_t error)
Get a human-readable error message for an error code.
edhoc_error_t
Unified error type for EDHOC operations.
@ EDHOC_ERR_SUITE_NOT_SUPPORTED
Cipher suite not supported.
@ EDHOC_ERR_MSG_MALFORMED
Malformed message received.
Declarations for EDHOC message generators.
Declarations for the EDHOC message handlers.
EDHOC server API [RFC9528] with CoAP Block-Wise Transfer [RFC7959].
void edhoc_trace_ephemeral_key(const char *role_label, const uint8_t *pub_x, const uint8_t *pub_y, const uint8_t *priv)
Print ephemeral key generation step.
void edhoc_trace_message(uint8_t msg_num, const uint8_t *msg_data, size_t msg_len, bool is_tx)
Print EDHOC message in RFC 9529 trace format.
void edhoc_trace_session_summary(const edhoc_context_t *ctx)
Print session summary at protocol completion.
EDHOC tracing and logging header.
#define EDHOC_TRACE_STATE(from_state, to_state)
Print protocol state transition.
#define EDHOC_TRACE_STEP(step_name)
Print protocol step header in RFC 9529 style.
#define EDHOC_DBG_VALUE(label, data, len)
Print detailed debug value (only at DBG level).
uint8_t edhoc_setup_suites(edhoc_context_t *ctx)
Initialize the EDHOC Context with the defined EDHOC parameters.
uint8_t edhoc_initialize_context(edhoc_context_t *ctx)
Internal API functions.
int edhoc_authenticate_msg(edhoc_context_t *ctx, uint8_t *ad, bool msg2)
Authenticate the rx message.
edhoc_context_t * edhoc_ctx
EDHOC context struct used in the EDHOC protocol.
uint8_t edhoc_generate_error_message(uint8_t *msg_er, size_t msg_er_sz, const edhoc_context_t *ctx, int8_t err)
Generate the EDHOC ERROR Message.
void edhoc_finalize(edhoc_context_t *ctx)
Close the EDHOC context.
void coap_timer_stop(coap_timer_t *timer)
Stop a pending CoAP timer.
void coap_timer_set(coap_timer_t *timer, uint64_t time)
Set a CoAP timer to expire after the specified time.
static void coap_timer_set_callback(coap_timer_t *timer, void(*callback)(coap_timer_t *))
Set a callback function to be called when a CoAP timer expires.
void coap_activate_resource(coap_resource_t *resource, const char *path)
Makes a resource available under the given URI path.
void edhoc_server_process(coap_message_t *req, coap_message_t *res, edhoc_server_t *ser, uint8_t *msg, size_t len)
Run the EDHOC Responder role process.
int8_t edhoc_server_callback(process_event_t ev, void *data)
Check if an EDHOC server session has finished.
int edhoc_handler_msg_3(edhoc_msg_3_t *msg3, edhoc_context_t *ctx, uint8_t *payload, size_t payload_size)
Handle the EDHOC Message 3 received.
void edhoc_server_close(void)
Close the EDHOC context.
void edhoc_server_set_ad_2(const void *buf, uint8_t buf_sz)
Set the Application Data to be carried in EDHOC message 2.
#define EDHOC_MAX_AD_SZ
The max length of the Application Data.
int edhoc_handler_msg_1(edhoc_context_t *ctx, uint8_t *payload, size_t payload_size, uint8_t *auth_data)
Handle the EDHOC Message 1 received.
struct ecc_data_event ecc_data_event_t
EDHOC server data event struct.
#define EDHOC_MAX_PAYLOAD_LEN
The max length of the EDHOC message.
struct edhoc_server edhoc_server_t
EDHOC Server Struct.
uint8_t edhoc_server_get_ad_3(char *buf)
Get the Application Data received in EDHOC message 3.
#define SERV_TIMEOUT_VAL
Time limit value for EDHOC protocol completion.
void edhoc_server_init(void)
Activate the EDHOC CoAP Resource.
coap_resource_t res_edhoc
CoAP resource.
uint8_t edhoc_server_reset_handshake(void)
Reset the EDHOC handshake state for a new client connection.
#define EDHOC_COAP_URI_PATH
EDHOC resource CoAP URI path.
uint8_t edhoc_server_start(void)
Create a new EDHOC context for a new EDHOC protocol session.
uint8_t edhoc_server_get_ad_1(char *buf)
Get the Application Data received in EDHOC message 1.
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.
int process_post(struct process *p, process_event_t ev, process_data_t data)
Post an asynchronous event.
process_event_t process_alloc_event(void)
Allocate a global event number.
Header file for the logging system.