diff --git a/include/crypto_error.h b/include/crypto_error.h index b9374aff..42094721 100644 --- a/include/crypto_error.h +++ b/include/crypto_error.h @@ -89,5 +89,6 @@ #define CRYPTO_LIB_ERR_NO_ECS_SET_FOR_ENCRYPTION_MODE (-36) #define CRYPTO_LIB_ERR_IV_LEN_SHORTER_THAN_SEC_HEADER_LENGTH (-37) #define CRYPTO_LIB_ERR_ARSN_LEN_SHORTER_THAN_SEC_HEADER_LENGTH (-38) +#define CRYPTO_LIB_ERR_FRAME_COUNTER_DOESNT_MATCH_SA (-39) #endif //_crypto_error_h_ diff --git a/src/src_main/crypto_tc.c b/src/src_main/crypto_tc.c index fb372707..62ec36aa 100644 --- a/src/src_main/crypto_tc.c +++ b/src/src_main/crypto_tc.c @@ -23,8 +23,9 @@ #include // memcpy -/* Helper validate SA function */ +/* Helper functions */ static int32_t crypto_tc_validate_sa(SecurityAssociation_t *sa); +static int32_t crypto_handle_incrementing_nontransmitted_counter(uint8_t* dest, uint8_t* src, int src_full_len,int transmitted_len, int window); /** * @brief Function: Crypto_TC_ApplySecurity @@ -809,21 +810,53 @@ int32_t Crypto_TC_ProcessSecurity(uint8_t* ingest, int *len_ingest, TC_t* tc_sdl } } - // Retrieve non-transmitted portion of IV from SA (if applicable) - memcpy(tc_sdls_processed_frame->tc_sec_header.iv, sa_ptr->iv, sa_ptr->iv_len-sa_ptr->shivf_len); - // Parse transmitted portion of IV + // Parse transmitted portion of IV from received frame (Will be Whole IV if iv_len==shivf_len) memcpy((tc_sdls_processed_frame->tc_sec_header.iv+(sa_ptr->iv_len-sa_ptr->shivf_len)), &(ingest[TC_FRAME_HEADER_SIZE + segment_hdr_len + SPI_LEN]), sa_ptr->shivf_len); + + // Handle non-transmitted IV increment case (transmitted-portion roll-over) + if(sa_ptr->shivf_len < sa_ptr->iv_len && + crypto_config->ignore_anti_replay==TC_IGNORE_ANTI_REPLAY_FALSE && + crypto_config->crypto_increment_nontransmitted_iv==SA_INCREMENT_NONTRANSMITTED_IV_TRUE) + { + status = crypto_handle_incrementing_nontransmitted_counter(tc_sdls_processed_frame->tc_sec_header.iv,sa_ptr->iv,sa_ptr->iv_len,sa_ptr->shivf_len,sa_ptr->arsnw); + if (status != CRYPTO_LIB_SUCCESS) + { + return status; + } + } + else // Not checking IV ARSNW or only non-transmitted portion is static; Note, non-transmitted IV in SA must match frame or will fail MAC check. + { + // Retrieve non-transmitted portion of IV from SA (if applicable) + memcpy(tc_sdls_processed_frame->tc_sec_header.iv, sa_ptr->iv, sa_ptr->iv_len-sa_ptr->shivf_len); + } + #ifdef DEBUG printf("Full IV Value from Frame and SADB (if applicable):\n"); Crypto_hexprint(tc_sdls_processed_frame->tc_sec_header.iv,sa_ptr->iv_len); #endif - // Parse non-transmitted portion of ARSN from SA - memcpy(tc_sdls_processed_frame->tc_sec_header.sn, sa_ptr->arsn, sa_ptr->arsn_len-sa_ptr->shsnf_len); // Parse transmitted portion of ARSN memcpy((tc_sdls_processed_frame->tc_sec_header.sn + (sa_ptr->arsn_len-sa_ptr->shsnf_len)), &(ingest[TC_FRAME_HEADER_SIZE + segment_hdr_len + SPI_LEN + sa_ptr->shivf_len]), sa_ptr->shsnf_len); + + // Handle non-transmitted SN increment case (transmitted-portion roll-over) + if(sa_ptr->shsnf_len < sa_ptr->arsn_len && + crypto_config->ignore_anti_replay==TC_IGNORE_ANTI_REPLAY_FALSE) + { + status = crypto_handle_incrementing_nontransmitted_counter(tc_sdls_processed_frame->tc_sec_header.sn,sa_ptr->arsn,sa_ptr->arsn_len,sa_ptr->shsnf_len,sa_ptr->arsnw); + if (status != CRYPTO_LIB_SUCCESS) + { + return status; + } + } + else // Not checking ARSN in ARSNW + { + // Parse non-transmitted portion of ARSN from SA + memcpy(tc_sdls_processed_frame->tc_sec_header.sn, sa_ptr->arsn, sa_ptr->arsn_len-sa_ptr->shsnf_len); + + } + #ifdef DEBUG printf("Full ARSN Value from Frame and SADB (if applicable):\n"); Crypto_hexprint(tc_sdls_processed_frame->tc_sec_header.sn,sa_ptr->arsn_len); @@ -939,6 +972,18 @@ int32_t Crypto_TC_ProcessSecurity(uint8_t* ingest, int *len_ingest, TC_t* tc_sdl if (crypto_config->ignore_anti_replay == TC_IGNORE_ANTI_REPLAY_FALSE && status == CRYPTO_LIB_SUCCESS) { status = Crypto_Check_Anti_Replay(sa_ptr, tc_sdls_processed_frame->tc_sec_header.sn, tc_sdls_processed_frame->tc_sec_header.iv); + + if(status != CRYPTO_LIB_SUCCESS) + { + return status; + } + + // Only save the SA (IV/ARSN) if checking the anti-replay counter; Otherwise we don't update. + status = sadb_routine->sadb_save_sa(sa_ptr); + if(status != CRYPTO_LIB_SUCCESS) + { + return status; + } } // Extended PDU processing, if applicable @@ -1058,4 +1103,53 @@ static int32_t crypto_tc_validate_sa(SecurityAssociation_t *sa) } return CRYPTO_LIB_SUCCESS; +} + +static int32_t crypto_handle_incrementing_nontransmitted_counter(uint8_t* dest, uint8_t* src, int src_full_len,int transmitted_len, int window) +{ + int32_t status = CRYPTO_LIB_SUCCESS; + // Copy IV to temp + uint8_t* temp_counter = malloc(src_full_len); + memcpy(temp_counter,src,src_full_len); + + // Increment temp_counter Until Transmitted Portion Matches Frame. + uint8_t counter_matches = CRYPTO_TRUE; + for(int i = 0; i < window; i++) + { + Crypto_increment(temp_counter,src_full_len); + for(int x = (src_full_len - transmitted_len); x < src_full_len; x++) + { + //This increment doesn't match the frame! + if(temp_counter[x] != dest[x]) + { + counter_matches = CRYPTO_FALSE; + break; + } + } + if(counter_matches == CRYPTO_TRUE) + { + break; + } + else if (i < window - 1) // Only reset flag if there are more windows to check. + { + counter_matches = CRYPTO_TRUE; // reset the flag, and continue the for loop for the next + continue; + } + + } + + if(counter_matches == CRYPTO_TRUE) + { + // Retrieve non-transmitted portion of incremented counter that matches (and may have rolled over/incremented) + memcpy(dest, temp_counter, src_full_len - transmitted_len); +#ifdef DEBUG + printf("Incremented IV is:\n"); + Crypto_hexprint(temp_counter,src_full_len); +#endif + } + else + { + status = CRYPTO_LIB_ERR_FRAME_COUNTER_DOESNT_MATCH_SA; + } + return status; } \ No newline at end of file diff --git a/src/src_main/sadb_routine_inmemory.template.c b/src/src_main/sadb_routine_inmemory.template.c index 97e7f200..70b8d424 100644 --- a/src/src_main/sadb_routine_inmemory.template.c +++ b/src/src_main/sadb_routine_inmemory.template.c @@ -147,7 +147,7 @@ int32_t sadb_config(void) sa[4].abm = (uint8_t* )calloc(1, sa[4].abm_len * sizeof(uint8_t)); sa[4].arsnw_len = 1; sa[4].arsnw = 5; - sa[4].arsn_len = (sa[4].arsnw * 2) + 1; + sa[4].arsn_len = 0; sa[4].gvcid_tc_blk.tfvn = 0; sa[4].gvcid_tc_blk.scid = SCID & 0x3FF; sa[4].gvcid_tc_blk.vcid = 0; diff --git a/util/src_util/ut_tc_apply.c b/util/src_util/ut_tc_apply.c index a00a1526..db88f215 100644 --- a/util/src_util/ut_tc_apply.c +++ b/util/src_util/ut_tc_apply.c @@ -302,6 +302,92 @@ UTEST(TC_APPLY_SECURITY, HAPPY_PATH_APPLY_STATIC_IV_ROLLOVER) free(ptr_enc_frame); ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); } + +/** + * @brief Unit Test: Nominal Authorized Encryption With Partial ARSN Rollover, increment static ARSN + **/ +UTEST(TC_APPLY_SECURITY, HAPPY_PATH_APPLY_NONTRANSMITTED_INCREMENTING_ARSN_ROLLOVER) +{ + // Setup & Initialize CryptoLib + Crypto_Init_Unit_Test(); + char* raw_tc_sdls_ping_h = "20030015000080d2c70008197f0b00310000b1fe3128"; + char* raw_tc_sdls_ping_b = NULL; + + char* new_arsn_h = "05FFFC"; + char* new_arsn_b = NULL; + + char* expected_arsn_h = "060001"; + char* expected_arsn_b = NULL; + + int raw_tc_sdls_ping_len = 0; + int new_arsn_len = 0; + int expected_arsn_len = 0; + + SadbRoutine sadb_routine = get_sadb_routine_inmemory(); + + hex_conversion(raw_tc_sdls_ping_h, &raw_tc_sdls_ping_b, &raw_tc_sdls_ping_len); + hex_conversion(new_arsn_h, &new_arsn_b, &new_arsn_len); + hex_conversion(expected_arsn_h, &expected_arsn_b, &expected_arsn_len); + uint8_t* ptr_enc_frame = NULL; + uint16_t enc_frame_len = 0; + + int32_t return_val = CRYPTO_LIB_ERROR; + + SecurityAssociation_t* test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + // Expose the SADB Security Association for test edits. + sadb_routine->sadb_get_sa_from_spi(1, &test_association); + test_association->sa_state = SA_NONE; + sadb_routine->sadb_get_sa_from_spi(4, &test_association); + test_association->sa_state = SA_OPERATIONAL; + test_association->shivf_len = 0; + test_association->iv_len = 0; + test_association->est=0; + test_association->ast=1; + test_association->ecs_len=1; + test_association->ecs = calloc(1, test_association->ecs_len * sizeof(uint8_t)); + *test_association->ecs = CRYPTO_CIPHER_NONE; + test_association->acs_len=1; + test_association->acs = calloc(1, test_association->acs_len * sizeof(uint8_t)); + *test_association->acs = CRYPTO_MAC_CMAC_AES256; + test_association->arsn_len = 3; + test_association->shsnf_len = 2; + test_association->arsn = calloc(1,test_association->arsn_len); + memcpy(test_association->arsn, (uint8_t *)new_arsn_b, new_arsn_len); + + return_val = + Crypto_TC_ApplySecurity((uint8_t* )raw_tc_sdls_ping_b, raw_tc_sdls_ping_len, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(CRYPTO_LIB_SUCCESS,return_val); + return_val = + Crypto_TC_ApplySecurity((uint8_t* )raw_tc_sdls_ping_b, raw_tc_sdls_ping_len, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(CRYPTO_LIB_SUCCESS,return_val); + return_val = + Crypto_TC_ApplySecurity((uint8_t* )raw_tc_sdls_ping_b, raw_tc_sdls_ping_len, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(CRYPTO_LIB_SUCCESS,return_val); + return_val = + Crypto_TC_ApplySecurity((uint8_t* )raw_tc_sdls_ping_b, raw_tc_sdls_ping_len, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(CRYPTO_LIB_SUCCESS,return_val); + return_val = + Crypto_TC_ApplySecurity((uint8_t* )raw_tc_sdls_ping_b, raw_tc_sdls_ping_len, &ptr_enc_frame, &enc_frame_len); + ASSERT_EQ(CRYPTO_LIB_SUCCESS,return_val); + + printf("Expected ARSN:\n"); + Crypto_hexprint(expected_arsn_b,expected_arsn_len); + printf("Actual SA ARSN:\n"); + Crypto_hexprint(test_association->arsn,test_association->arsn_len); + + for (int i = 0; i < test_association->arsn_len; i++) + { + printf("[%d] Truth: %02x, Actual: %02x\n", i, expected_arsn_b[i], *(test_association->arsn + i)); + ASSERT_EQ(expected_arsn_b[i], *(test_association->arsn + i)); + } + + //Must shutdown after checking test_association ARSN since that will get freed! + Crypto_Shutdown(); + free(raw_tc_sdls_ping_b); + free(ptr_enc_frame); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); +} + /** * @brief Unit Test: Bad Spacecraft ID * This should pass the flawed hex string, and return CRYPTO_LIB_ERR_INVALID_SCID diff --git a/util/src_util/ut_tc_process.c b/util/src_util/ut_tc_process.c index 7333b17b..81d10ee2 100644 --- a/util/src_util/ut_tc_process.c +++ b/util/src_util/ut_tc_process.c @@ -399,20 +399,108 @@ UTEST(TC_PROCESS, HAPPY_PATH_PROCESS_NONTRANSMITTED_INCREMENTING_IV_ROLLOVER) ASSERT_EQ(test_association->iv[11],0xFF); // test_association->iv[5] = 0x01; return_val = Crypto_TC_ProcessSecurity(dec_test_00_b, &dec_test_00_len, tc_sdls_processed_frame); - //Tc_ProcessSecurity Rollover bug ( https://github.jpl.nasa.gov/ASEC/AMMOS-CryptoLib/issues/57 ), cannot assert this! -// ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); -// ASSERT_EQ(test_association->iv[0] ,0x00); -// ASSERT_EQ(test_association->iv[1] ,0x00); -// ASSERT_EQ(test_association->iv[2] ,0x00); -// ASSERT_EQ(test_association->iv[3] ,0x00); -// ASSERT_EQ(test_association->iv[4] ,0x00); -// ASSERT_EQ(test_association->iv[5] ,0x01); -// ASSERT_EQ(test_association->iv[6] ,0x00); -// ASSERT_EQ(test_association->iv[7] ,0x00); -// ASSERT_EQ(test_association->iv[8] ,0x00); -// ASSERT_EQ(test_association->iv[9] ,0x00); -// ASSERT_EQ(test_association->iv[10],0x00); -// ASSERT_EQ(test_association->iv[11],0x00); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); + ASSERT_EQ(test_association->iv[0] ,0x00); + ASSERT_EQ(test_association->iv[1] ,0x00); + ASSERT_EQ(test_association->iv[2] ,0x00); + ASSERT_EQ(test_association->iv[3] ,0x00); + ASSERT_EQ(test_association->iv[4] ,0x00); + ASSERT_EQ(test_association->iv[5] ,0x01); + ASSERT_EQ(test_association->iv[6] ,0x00); + ASSERT_EQ(test_association->iv[7] ,0x00); + ASSERT_EQ(test_association->iv[8] ,0x00); + ASSERT_EQ(test_association->iv[9] ,0x00); + ASSERT_EQ(test_association->iv[10],0x00); + ASSERT_EQ(test_association->iv[11],0x00); + + Crypto_saPrint(test_association); + + Crypto_Shutdown(); + + free(dec_test_fe_b); + free(dec_test_ff_b); + free(dec_test_00_b); + // free(test_association->ecs); + free(tc_sdls_processed_frame); + // sadb_routine->sadb_close(); +} + +UTEST(TC_PROCESS, HAPPY_PATH_PROCESS_NONTRANSMITTED_INCREMENTING_ARSN_ROLLOVER) +{ + // Setup & Initialize CryptoLib + Crypto_Init_Unit_Test(); + Crypto_Config_CryptoLib(SADB_TYPE_INMEMORY, CRYPTOGRAPHY_TYPE_LIBGCRYPT, CRYPTO_TC_CREATE_FECF_TRUE, TC_PROCESS_SDLS_PDUS_TRUE, TC_HAS_PUS_HDR, + TC_IGNORE_SA_STATE_FALSE, TC_IGNORE_ANTI_REPLAY_FALSE, TC_UNIQUE_SA_PER_MAP_ID_FALSE, + TC_CHECK_FECF_TRUE, 0x3F, SA_INCREMENT_NONTRANSMITTED_IV_TRUE); + + SadbRoutine sadb_routine = get_sadb_routine_inmemory(); + + char* dec_test_fe_h = + "2003002900000004FFFE80D2C70008197F0B00310000B1FE1C9119D059698FFE5AAE811572FA678D0741"; + char* dec_test_ff_h = + "2003002900000004FFFF80D2C70008197F0B00310000B1FE1C9119D059698FFE5AAE811572FA678D8968"; + char* dec_test_00_h = + "2003002900000004000080D2C70008197F0B00310000B1FE1C9119D059698FFE5AAE811572FA678D7824"; + + uint8_t *dec_test_fe_b, *dec_test_ff_b, *dec_test_00_b = NULL; + int dec_test_fe_len, dec_test_ff_len, dec_test_00_len = 0; + + hex_conversion(dec_test_fe_h, (char**) &dec_test_fe_b, &dec_test_fe_len); + hex_conversion(dec_test_ff_h, (char**) &dec_test_ff_b, &dec_test_ff_len); + hex_conversion(dec_test_00_h, (char**) &dec_test_00_b, &dec_test_00_len); + + SecurityAssociation_t* test_association = NULL; + test_association = malloc(sizeof(SecurityAssociation_t) * sizeof(uint8_t)); + + int32_t return_val = -1; + + TC_t* tc_sdls_processed_frame; + tc_sdls_processed_frame = malloc(sizeof(uint8_t) * TC_SIZE); + memset(tc_sdls_processed_frame, 0, (sizeof(uint8_t) * TC_SIZE)); + + // Default SA + // Expose SA 1 for testing + sadb_routine->sadb_get_sa_from_spi(1, &test_association); + test_association->ecs = calloc(1, test_association->ecs_len * sizeof(uint8_t)); + *test_association->ecs = CRYPTO_CIPHER_NONE; + + // Deactive SA 1 + test_association->sa_state = SA_NONE; + + // Expose SA 4 for testing + sadb_routine->sadb_get_sa_from_spi(4, &test_association); + test_association->sa_state = SA_OPERATIONAL; + test_association->shivf_len = 0; + test_association->iv_len = 0; + test_association->est=0; + test_association->ast=1; + test_association->ecs_len=1; + test_association->ecs = calloc(1, test_association->ecs_len * sizeof(uint8_t)); + *test_association->ecs = CRYPTO_CIPHER_NONE; + test_association->acs_len=1; + test_association->acs = calloc(1, test_association->acs_len * sizeof(uint8_t)); + *test_association->acs = CRYPTO_MAC_CMAC_AES256; + test_association->arsn_len = 3; + test_association->shsnf_len = 2; + test_association->arsn = calloc(1,test_association->arsn_len); + // ARSN = "05FFFD" + test_association->arsn[0] = 0x05; + test_association->arsn[1] = 0xFF; + test_association->arsn[2] = 0xFD; + + Crypto_saPrint(test_association); + return_val = Crypto_TC_ProcessSecurity(dec_test_fe_b, &dec_test_fe_len, tc_sdls_processed_frame); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); + ASSERT_EQ(test_association->arsn[2],0xFE); + return_val = Crypto_TC_ProcessSecurity(dec_test_ff_b, &dec_test_ff_len, tc_sdls_processed_frame); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); + ASSERT_EQ(test_association->arsn[2],0xFF); + // test_association->iv[5] = 0x01; + return_val = Crypto_TC_ProcessSecurity(dec_test_00_b, &dec_test_00_len, tc_sdls_processed_frame); + ASSERT_EQ(CRYPTO_LIB_SUCCESS, return_val); + ASSERT_EQ(test_association->arsn[0] ,0x06); + ASSERT_EQ(test_association->arsn[1] ,0x00); + ASSERT_EQ(test_association->arsn[2] ,0x00); Crypto_saPrint(test_association);