Skip to content

Commit

Permalink
Merge pull request #231 from lf-lang/hmac-auth
Browse files Browse the repository at this point in the history
Fix protocol of HMAC authentication to start from federate.
  • Loading branch information
Jakio815 authored Jul 6, 2023
2 parents f05fb5d + 5eaff13 commit 9b2c8f4
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 117 deletions.
92 changes: 51 additions & 41 deletions core/federated/RTI/rti_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -1378,57 +1378,67 @@ int receive_udp_message_and_set_up_clock_sync(int socket_id, uint16_t fed_id) {

#ifdef __RTI_AUTH__
bool authenticate_federate(int socket) {
// Buffer for message type and federation RTI nonce.
size_t message_length = 1 + NONCE_LENGTH;
unsigned char rti_hello_buffer[message_length];
rti_hello_buffer[0] = MSG_TYPE_RTI_NONCE;
unsigned char rti_nonce[NONCE_LENGTH];
RAND_bytes(rti_nonce, NONCE_LENGTH);
memcpy(rti_hello_buffer + 1, rti_nonce, NONCE_LENGTH);
// Send RTI hello with RTI's random nonce.
write_to_socket(socket, message_length, rti_hello_buffer);

// Check HMAC of received FED_RESPONSE message.
// Wait for MSG_TYPE_FED_NONCE from federate.
size_t fed_id_length = sizeof(uint16_t);
unsigned char buffer[1 + fed_id_length + NONCE_LENGTH];
read_from_socket_errexit(socket, 1 + fed_id_length + NONCE_LENGTH, buffer,
"Failed to read MSG_TYPE_FED_NONCE");
if (buffer[0] != MSG_TYPE_FED_NONCE) {
lf_print_error_and_exit(
"Received unexpected response %u from the FED (see net_common.h).",
buffer[0]);
}
unsigned int hmac_length = SHA256_HMAC_LENGTH;
size_t federation_id_length = strnlen(_f_rti->federation_id, 255);
size_t fed_id_length = sizeof(uint16_t);

unsigned char received[1 + NONCE_LENGTH + fed_id_length + hmac_length];
read_from_socket_errexit(socket, 1 + NONCE_LENGTH + fed_id_length + hmac_length, received, "Failed to read RTI response.");
// HMAC tag is created with MSG_TYPE, federate ID, received federate nonce.
unsigned char mac_buf[1 + fed_id_length + NONCE_LENGTH];
mac_buf[0] = MSG_TYPE_RTI_RESPONSE;
memcpy(&mac_buf[1], &buffer[1], fed_id_length);
memcpy(&mac_buf[1 + fed_id_length], &buffer[1 + fed_id_length], NONCE_LENGTH);
unsigned char hmac_tag[hmac_length];
unsigned char * ret = HMAC(EVP_sha256(), _f_rti->federation_id,
federation_id_length, mac_buf, 1 + fed_id_length + NONCE_LENGTH,
hmac_tag, &hmac_length);
if (ret == NULL) {
lf_print_error_and_exit("HMAC construction failed for MSG_TYPE_RTI_RESPONSE.");
}
// Make buffer for message type, RTI's nonce, and HMAC tag.
unsigned char sender[1 + NONCE_LENGTH + hmac_length];
sender[0] = MSG_TYPE_RTI_RESPONSE;
unsigned char rti_nonce[NONCE_LENGTH];
RAND_bytes(rti_nonce, NONCE_LENGTH);
memcpy(&sender[1], rti_nonce, NONCE_LENGTH);
memcpy(&sender[1 + NONCE_LENGTH], hmac_tag, hmac_length);
write_to_socket(socket, 1 + NONCE_LENGTH + hmac_length, sender);

// Wait for MSG_TYPE_FED_RESPONSE
unsigned char received[1 + hmac_length];
read_from_socket_errexit(socket, 1 + hmac_length, received,
"Failed to read federate response.");
if (received[0] != MSG_TYPE_FED_RESPONSE) {
lf_print_error("Received unexpected response %u from the FED (see net_common.h).",
received[0]);
lf_print_error_and_exit(
"Received unexpected response %u from the federate (see net_common.h).",
received[0]);
return false;
}

// Create tag to compare to received tag.
unsigned char buf_to_check[1 + fed_id_length + NONCE_LENGTH];
buf_to_check[0] = MSG_TYPE_FED_RESPONSE;
memcpy(&buf_to_check[1], &received[1 + NONCE_LENGTH], fed_id_length);
memcpy(&buf_to_check[1 + fed_id_length], rti_nonce, NONCE_LENGTH);
// HMAC tag is created with MSG_TYPE_FED_RESPONSE and RTI's nonce.
unsigned char mac_buf2[1 + NONCE_LENGTH];
mac_buf2[0] = MSG_TYPE_FED_RESPONSE;
memcpy(&mac_buf2[1], rti_nonce, NONCE_LENGTH);
unsigned char rti_tag[hmac_length];
HMAC(EVP_sha256(), _f_rti->federation_id, federation_id_length, buf_to_check, 1 + fed_id_length + NONCE_LENGTH,
rti_tag, &hmac_length);

ret = HMAC(EVP_sha256(), _f_rti->federation_id, federation_id_length,
mac_buf2, 1 + NONCE_LENGTH, rti_tag, &hmac_length);
if (ret == NULL) {
lf_print_error_and_exit("HMAC construction failed for MSG_TYPE_FED_RESPONSE.");
}
// Compare received tag and created tag.
if (memcmp(&received[1 + fed_id_length + NONCE_LENGTH], rti_tag, hmac_length) != 0) {
if (memcmp(&received[1], rti_tag, hmac_length) != 0) {
// Federation IDs do not match. Send back a HMAC_DOES_NOT_MATCH message.
lf_print_warning("HMAC authentication failed. Rejecting the federate.");
send_reject(socket, HMAC_DOES_NOT_MATCH);
return false;
}
else{
LF_PRINT_LOG("HMAC verified.");
// HMAC tag is created with MSG_TYPE and received federate nonce.
unsigned char mac_buf[1 + NONCE_LENGTH];
mac_buf[0] = MSG_TYPE_RTI_RESPONSE;
memcpy(&mac_buf[1], &received[1], NONCE_LENGTH);
// Buffer for message type and HMAC tag.
unsigned char sender[1 + hmac_length];
sender[0] = MSG_TYPE_RTI_RESPONSE;
HMAC(EVP_sha256(), _f_rti->federation_id, federation_id_length, mac_buf, 1 + NONCE_LENGTH,
&sender[1], &hmac_length);
write_to_socket(socket, 1 + hmac_length, sender);
} else {
LF_PRINT_LOG("Federate's HMAC verified.");
return true;
}
}
Expand All @@ -1455,7 +1465,7 @@ void connect_to_federates(int socket_descriptor) {
}
}

// Send RTI hello when RTI -a option is on.
// Wait for the first message from the federate when RTI -a option is on.
#ifdef __RTI_AUTH__
if (_f_rti->authentication_enabled) {
if (!authenticate_federate(socket_id)) {
Expand Down
96 changes: 41 additions & 55 deletions core/federated/federate.c
Original file line number Diff line number Diff line change
Expand Up @@ -914,65 +914,40 @@ void connect_to_federate(uint16_t remote_federate_id) {
* @param rti_socket TCP socket for connection with the RTI.
*/
void perform_hmac_authentication(int rti_socket) {
unsigned char buffer[1 + NONCE_LENGTH];
read_from_socket_errexit(rti_socket, 1 + NONCE_LENGTH, buffer,
"Failed to read RTI hello.");
if (buffer[0] != MSG_TYPE_RTI_NONCE) {
lf_print_error_and_exit(
"Received unexpected response %u from the RTI (see net_common.h).",
buffer[0]);
}

// Send buffer including message type, federate ID, federate's nonce.
size_t fed_id_length = sizeof(uint16_t);
size_t message_length = 1 + fed_id_length + NONCE_LENGTH;
unsigned char fed_hello_buf[message_length];
fed_hello_buf[0] = MSG_TYPE_FED_NONCE;
encode_uint16((uint16_t)_lf_my_fed_id, &fed_hello_buf[1]);
unsigned char fed_nonce[NONCE_LENGTH];
RAND_bytes(fed_nonce, NONCE_LENGTH);
memcpy(&fed_hello_buf[1 + fed_id_length], fed_nonce, NONCE_LENGTH);
write_to_socket(rti_socket, message_length, fed_hello_buf);

// Check HMAC of received FED_RESPONSE message.
unsigned int hmac_length = SHA256_HMAC_LENGTH;
size_t federation_id_length = strnlen(federation_metadata.federation_id, 255);
// HMAC tag is created with MSG_TYPE, federate ID, received rti nonce.
unsigned char mac_buf[1 + sizeof(uint16_t) + NONCE_LENGTH];
mac_buf[0] = MSG_TYPE_FED_RESPONSE;
encode_uint16((uint16_t)_lf_my_fed_id, &mac_buf[1]);
memcpy(&mac_buf[1 + sizeof(uint16_t)], &buffer[1], NONCE_LENGTH);
unsigned char hmac_tag[hmac_length];
unsigned char * ret = HMAC(EVP_sha256(), federation_metadata.federation_id,
federation_id_length, mac_buf, 1 + sizeof(uint16_t) + NONCE_LENGTH,
hmac_tag, &hmac_length);
if (ret == NULL) {
lf_print_error_and_exit("HMAC failure for MSG_TYPE_FED_RESPONSE.");
}

// Buffer for message type, federate's nonce, federate ID, and HMAC tag.
unsigned char sender[1 + NONCE_LENGTH + sizeof(uint16_t) + hmac_length];
sender[0] = MSG_TYPE_FED_RESPONSE;
unsigned char federate_nonce[NONCE_LENGTH];
RAND_bytes(federate_nonce, NONCE_LENGTH);
int num_bytes = 1;
memcpy(&sender[num_bytes], federate_nonce, NONCE_LENGTH);
num_bytes += NONCE_LENGTH;
encode_uint16((uint16_t)_lf_my_fed_id, &sender[num_bytes]);
num_bytes += sizeof(uint16_t);
memcpy(&sender[num_bytes], hmac_tag, hmac_length);
num_bytes += hmac_length;
write_to_socket(rti_socket, num_bytes, sender);

// Received MSG_TYPE_RTI_RESPONSE
unsigned char received[1 + hmac_length];
read_from_socket_errexit(rti_socket, 1 + hmac_length, received,
"Failed to read RTI response.");

unsigned char received[1 + NONCE_LENGTH + hmac_length];
read_from_socket_errexit(rti_socket, 1 + NONCE_LENGTH + hmac_length, received, "Failed to read RTI response.");
if (received[0] != MSG_TYPE_RTI_RESPONSE) {
lf_print_error_and_exit(
"Received unexpected response %u from the RTI (see net_common.h).",
received[0]);
}
// HMAC tag is created with MSG_TYPE and federate nonce.
unsigned char mac_buf2[1 + NONCE_LENGTH];
mac_buf2[0] = MSG_TYPE_RTI_RESPONSE;
memcpy(&mac_buf2[1], federate_nonce, NONCE_LENGTH);
lf_print_error("Received unexpected response %u from the RTI (see net_common.h).",
received[0]);
}
// Create tag to compare to received tag.
unsigned char buf_to_check[1 + fed_id_length + NONCE_LENGTH];
buf_to_check[0] = MSG_TYPE_RTI_RESPONSE;
encode_uint16((uint16_t)_lf_my_fed_id, &buf_to_check[1]);
memcpy(&buf_to_check[1 + fed_id_length], fed_nonce, NONCE_LENGTH);
unsigned char fed_tag[hmac_length];
ret = HMAC(EVP_sha256(), federation_metadata.federation_id, federation_id_length,
mac_buf2, 1 + NONCE_LENGTH, fed_tag, &hmac_length);
if (ret == NULL) {
lf_print_error_and_exit("HMAC failure for MSG_TYPE_RTI_RESPONSE.");
}
HMAC(EVP_sha256(), federation_metadata.federation_id, federation_id_length, buf_to_check, 1 + fed_id_length + NONCE_LENGTH,
fed_tag, &hmac_length);

// Compare received tag and created tag.
if (memcmp(&received[1], fed_tag, hmac_length) != 0) {
// Federation IDs do not match. Send back a MSG_TYPE_REJECT message.
if (memcmp(&received[1 + NONCE_LENGTH], fed_tag, hmac_length) != 0) {
// HMAC does not match. Send back a MSG_TYPE_REJECT message.
lf_print_error("HMAC authentication failed.");
unsigned char response[2];
response[0] = MSG_TYPE_REJECT;
Expand All @@ -981,8 +956,19 @@ void perform_hmac_authentication(int rti_socket) {
rti_socket, 2, response,
"Federate failed to write MSG_TYPE_REJECT message on the socket.");
close(rti_socket);
} else {
}
else {
LF_PRINT_LOG("HMAC verified.");
// HMAC tag is created with MSG_TYPE_FED_RESPONSE and received federate nonce.
unsigned char mac_buf[1 + NONCE_LENGTH];
mac_buf[0] = MSG_TYPE_FED_RESPONSE;
memcpy(&mac_buf[1], &received[1], NONCE_LENGTH);
// Buffer for message type and HMAC tag.
unsigned char sender[1 + hmac_length];
sender[0] = MSG_TYPE_FED_RESPONSE;
HMAC(EVP_sha256(), federation_metadata.federation_id, federation_id_length, mac_buf, 1 + NONCE_LENGTH,
&sender[1], &hmac_length);
write_to_socket(rti_socket, 1 + hmac_length, sender);
}
}
#endif
Expand Down
42 changes: 22 additions & 20 deletions include/core/federated/net_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,40 +330,42 @@ THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

/////////// Messages used for authenticated federation. ///////////////
/**
* Byte identifying a message from an RTI to a federate containing
* RTI's 8-byte random nonce for HMAC-based authentication. The RTI sends this
* message to an incoming federate when TCP connection is established
* Byte identifying a message from a federate to an RTI containing
* federate's 8-byte random nonce for HMAC-based authentication. The federate sends this
* message to an incoming RTI when TCP connection is established
* between the RTI and the federate.
* The next eight bytes are RTI's 8-byte nonce (RTI nonce).
* The message contains, in this order:
* * One byte equal to MSG_TYPE_FED_NONCE.
* * Two bytes (ushort) giving the federate ID.
* * Eight bytes for federate's nonce.
*/
#define MSG_TYPE_RTI_NONCE 100
#define MSG_TYPE_FED_NONCE 100

/**
* Byte identifying a message from federate to RTI as a response to the RTI Hello
* message. The federate sends this message to RTI for HMAC-based authentication.
* Byte identifying a message from RTI to federate as a response to the FED_NONCE
* message. The RTI sends this message to federate for HMAC-based authentication.
* The message contains, in this order:
* * One byte equal to MSG_TYPE_FED_RESPONSE.
* * Eight bytes for federate's nonce.
* * Two bytes (ushort) giving the federate ID.
* * One byte equal to MSG_TYPE_RTI_RESPONSE.
* * Eight bytes for RTI's nonce.
* * 32 bytes for HMAC tag based on SHA256.
* The HMAC tag is composed of the following order:
* * One byte equal to MSG_TYPE_FED_RESPONSE.
* * Two bytes (ushort) giving the federate ID.
* * Eight bytes for received RTI's nonce.
* * One byte equal to MSG_TYPE_RTI_RESPONSE.
* * Two bytes (ushort) giving the received federate ID.
* * Eight bytes for received federate's nonce.
*/
#define MSG_TYPE_FED_RESPONSE 101
#define MSG_TYPE_RTI_RESPONSE 101

/**
* Byte identifying a message from RTI to a federate as a response to the FED_RESPONSE
* message. The RTI sends this message to federate for HMAC-based authentication.
* Byte identifying a message from federate to RTI as a response to the RTI_RESPONSE
* message. The federate sends this message to RTI for HMAC-based authentication.
* The message contains, in this order:
* * One byte equal to MSG_TYPE_RTI_RESPONSE.
* * One byte equal to MSG_TYPE_FED_RESPONSE.
* * 32 bytes for HMAC tag based on SHA256.
* The HMAC tag is composed of the following order:
* * One byte equal to MSG_TYPE_RTI_RESPONSE.
* * Eight bytes for received federate's nonce.
* * One byte equal to MSG_TYPE_FED_RESPONSE.
* * Eight bytes for received RTI's nonce.
*/
#define MSG_TYPE_RTI_RESPONSE 102
#define MSG_TYPE_FED_RESPONSE 102

/**
* The randomly created nonce size will be 8 bytes.
Expand Down
2 changes: 1 addition & 1 deletion lingua-franca-ref.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9acca40d53151aa79a5679ed1fcc675f3afb2e45
master

0 comments on commit 9b2c8f4

Please sign in to comment.