void test_KineticHMAC_Validate_should_return_false_if_the_HMAC_presence_is_false_for_the_supplied_message_and_key_is_incorrect(void) { KineticHMAC actual; Com__Seagate__Kinetic__Proto__Command__Status status = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__INIT; Com__Seagate__Kinetic__Proto__Command command = COM__SEAGATE__KINETIC__PROTO__COMMAND__INIT; status.code = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__STATUS_CODE__NO_SPACE; status.has_code = true; command.status = &status; Com__Seagate__Kinetic__Proto__Message proto = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT; Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT; uint8_t data[KINETIC_HMAC_MAX_LEN]; ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data}; const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK"); proto.has_commandbytes = true; uint8_t packedCmd[128]; size_t packedLen = com__seagate__kinetic__proto__command__pack(&command, packedCmd); proto.commandbytes = (ProtobufCBinaryData){.data = packedCmd, .len = packedLen}; hmacAuth.identity = 7; hmacAuth.has_identity = true; hmacAuth.hmac = hmac; hmacAuth.has_hmac = true; proto.hmacauth = &hmacAuth; proto.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH; proto.has_authtype = true; KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1); KineticHMAC_Populate(&actual, &proto, key); TEST_ASSERT_TRUE(KineticHMAC_Validate(&proto, key)); // Bork the HMAC hmacAuth.has_hmac = false; TEST_ASSERT_FALSE(KineticHMAC_Validate(&proto, key)); }
void test_KineticHMAC_Populate_should_compute_and_populate_the_SHA1_HMAC_for_the_supplied_message_and_key(void) { KineticHMAC actual; Com__Seagate__Kinetic__Proto__Message msg = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT; Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT; uint8_t data[KINETIC_HMAC_MAX_LEN]; ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data}; const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK"); uint8_t commandBytes[123]; ByteArray commandArray = ByteArray_Create(commandBytes, sizeof(commandBytes)); ByteArray_FillWithDummyData(commandArray); ProtobufCBinaryData dummyCommandData = {.data = commandArray.data, .len = commandArray.len}; msg.commandbytes = dummyCommandData; msg.has_commandbytes = true; msg.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH; msg.has_authtype = true; hmacAuth.has_hmac = true; hmacAuth.hmac = hmac; msg.hmacauth = &hmacAuth; KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1); KineticHMAC_Populate(&actual, &msg, key); TEST_ASSERT_TRUE(msg.hmacauth->has_hmac); TEST_ASSERT_EQUAL_PTR(hmac.data, msg.hmacauth->hmac.data); TEST_ASSERT_EQUAL(KINETIC_HMAC_MAX_LEN, msg.hmacauth->hmac.len); LOG0("Computed HMAC: "); LOGF0(" %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", actual.data[0], actual.data[1], actual.data[2], actual.data[3], actual.data[4], actual.data[5], actual.data[6], actual.data[7]); LOGF0(" %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX", actual.data[8], actual.data[9], actual.data[10], actual.data[11], actual.data[12], actual.data[13], actual.data[14], actual.data[15]); LOGF0(" %02hhX%02hhX%02hhX%02hhX", actual.data[16], actual.data[17], actual.data[18], actual.data[19]); } void test_KineticHMAC_Validate_should_return_true_if_the_HMAC_for_the_supplied_message_and_key_is_correct(void) { KineticHMAC actual; Com__Seagate__Kinetic__Proto__Command__Status status = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__INIT; Com__Seagate__Kinetic__Proto__Command command = COM__SEAGATE__KINETIC__PROTO__COMMAND__INIT; status.code = COM__SEAGATE__KINETIC__PROTO__COMMAND__STATUS__STATUS_CODE__NO_SPACE; status.has_code = true; command.status = &status; Com__Seagate__Kinetic__Proto__Message proto = COM__SEAGATE__KINETIC__PROTO__MESSAGE__INIT; Com__Seagate__Kinetic__Proto__Message__HMACauth hmacAuth = COM__SEAGATE__KINETIC__PROTO__MESSAGE__HMACAUTH__INIT; uint8_t data[KINETIC_HMAC_MAX_LEN]; ProtobufCBinaryData hmac = {.len = KINETIC_HMAC_MAX_LEN, .data = data}; const ByteArray key = ByteArray_CreateWithCString("1234567890ABCDEFGHIJK"); proto.has_commandbytes = true; uint8_t packedCmd[128]; size_t packedLen = com__seagate__kinetic__proto__command__pack(&command, packedCmd); proto.commandbytes = (ProtobufCBinaryData){.data = packedCmd, .len = packedLen}; hmacAuth.identity = 7; hmacAuth.has_identity = true; hmacAuth.hmac = hmac; hmacAuth.has_hmac = true; proto.hmacauth = &hmacAuth; proto.authtype = COM__SEAGATE__KINETIC__PROTO__MESSAGE__AUTH_TYPE__HMACAUTH; proto.has_authtype = true; KineticHMAC_Init(&actual, COM__SEAGATE__KINETIC__PROTO__COMMAND__SECURITY__ACL__HMACALGORITHM__HmacSHA1); KineticHMAC_Populate(&actual, &proto, key); TEST_ASSERT_TRUE(KineticHMAC_Validate(&proto, key)); }
KineticStatus KineticPDU_ReceiveMain(KineticPDU* const response) { assert(response != NULL); assert(response->connection != NULL); const int fd = response->connection->socket; assert(fd >= 0); LOGF1("\nReceiving PDU via fd=%d", fd); KineticStatus status; KineticMessage* msg = &response->protoData.message; // Receive the PDU header ByteBuffer rawHeader = ByteBuffer_Create(&response->headerNBO, sizeof(KineticPDUHeader), 0); status = KineticSocket_Read(fd, &rawHeader, rawHeader.array.len); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU header!"); return status; } else { LOG3("PDU header received successfully"); KineticPDUHeader* headerNBO = &response->headerNBO; response->header = (KineticPDUHeader) { .versionPrefix = headerNBO->versionPrefix, .protobufLength = KineticNBO_ToHostU32(headerNBO->protobufLength), .valueLength = KineticNBO_ToHostU32(headerNBO->valueLength), }; KineticLogger_LogHeader(1, &response->header); } // Receive the protobuf message status = KineticSocket_ReadProtobuf(fd, response); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU protobuf message!"); return status; } else { LOG3("Received PDU protobuf"); KineticLogger_LogProtobuf(2, response->proto); } // Validate the HMAC for the recevied protobuf message if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_HMACAUTH) { if(!KineticHMAC_Validate( response->proto, response->connection->session.hmacKey)) { LOG0("Received PDU protobuf message has invalid HMAC!"); msg->has_command = true; msg->command.status = &msg->status; msg->status.code = KINETIC_PROTO_COMMAND_STATUS_STATUS_CODE_DATA_ERROR; return KINETIC_STATUS_DATA_ERROR; } else { LOG3("Received protobuf HMAC validation succeeded"); } } else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_PINAUTH) { LOG0("PIN-based authentication not yet supported!"); return KINETIC_STATUS_DATA_ERROR; } else if (response->proto->authType == KINETIC_PROTO_MESSAGE_AUTH_TYPE_UNSOLICITEDSTATUS) { LOG3("Unsolicited status message is not authenticated"); } // Extract embedded command, if supplied KineticProto_Message* pMsg = response->proto; if (pMsg->has_commandBytes && pMsg->commandBytes.data != NULL && pMsg->commandBytes.len > 0) { response->command = KineticProto_command__unpack( NULL, pMsg->commandBytes.len, pMsg->commandBytes.data); } status = KineticPDU_GetStatus(response); if (status == KINETIC_STATUS_SUCCESS) { LOG2("PDU received successfully!"); } return status; } KineticStatus KineticPDU_ReceiveValue(int socket_desc, ByteBuffer* value, size_t value_length) { assert(socket_desc >= 0); assert(value != NULL); assert(value->array.data != NULL); // Receive value payload LOGF1("Receiving value payload (%lld bytes)...", value_length); ByteBuffer_Reset(value); KineticStatus status = KineticSocket_Read(socket_desc, value, value_length); if (status != KINETIC_STATUS_SUCCESS) { LOG0("Failed to receive PDU value payload!"); return status; } LOG1("Received value payload successfully"); KineticLogger_LogByteBuffer(3, "Value Buffer", *value); return status; }