diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c index 99081a5ffc..28cd37f3af 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.c @@ -2124,9 +2124,12 @@ pdcp_config_set_security( pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm); - kRRCenc != NULL ? memcpy(pdcp_pP->kRRCenc, kRRCenc, 32) : memset(pdcp_pP->kRRCenc, 0, 32); - kRRCint != NULL ? memcpy(pdcp_pP->kRRCint, kRRCint, 32) : memset(pdcp_pP->kRRCint, 0, 32); - kUPenc != NULL ? memcpy(pdcp_pP->kUPenc, kUPenc, 32) : memset(pdcp_pP->kUPenc, 0, 32); + kRRCenc != NULL ? memcpy(pdcp_pP->kRRCenc, kRRCenc+16, 16) : memset(pdcp_pP->kRRCenc, 0, 16); + kRRCint != NULL ? memcpy(pdcp_pP->kRRCint, kRRCint+16, 16) : memset(pdcp_pP->kRRCint, 0, 16); + kUPenc != NULL ? memcpy(pdcp_pP->kUPenc, kUPenc+16, 16) : memset(pdcp_pP->kUPenc, 0, 16); + + pdcp_pP->security_container_rrc = stream_security_container_init(pdcp_pP->cipheringAlgorithm, pdcp_pP->integrityProtAlgorithm, pdcp_pP->kRRCenc, pdcp_pP->kRRCint); + pdcp_pP->security_container_up = stream_security_container_init(pdcp_pP->cipheringAlgorithm, 0, pdcp_pP->kUPenc, NULL); /* Activate security */ pdcp_pP->security_activated = 1; @@ -2196,6 +2199,8 @@ void rrc_pdcp_config_req ( pdcp_p->last_submitted_pdcp_rx_sn = 4095; pdcp_p->seq_num_size = 0; pdcp_p->first_missing_pdu = -1; + stream_security_container_delete(pdcp_p->security_container_rrc); + stream_security_container_delete(pdcp_p->security_container_up); pdcp_p->security_activated = 0; h_rc = hashtable_remove(pdcp_coll_p, key); break; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h index 6b0e2499fe..4a7f71b315 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp.h +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp.h @@ -181,9 +181,12 @@ typedef struct pdcp_s { * Control-Plane RRC integrity key * These keys are configured by RRC layer */ - uint8_t kUPenc[32]; - uint8_t kRRCint[32]; - uint8_t kRRCenc[32]; + uint8_t kUPenc[16]; + uint8_t kRRCint[16]; + uint8_t kRRCenc[16]; + + stream_security_container_t *security_container_rrc; + stream_security_container_t *security_container_up; uint8_t security_activated; diff --git a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c index a88d4028ae..e969467231 100644 --- a/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c +++ b/openair2/LAYER2/PDCP_v10.1.0/pdcp_security.c @@ -112,6 +112,7 @@ pdcp_apply_security( { uint8_t *buffer_encrypted = NULL; nas_stream_cipher_t encrypt_params = {0}; + stream_security_container_t *container; DevAssert(pdcp_pP != NULL); DevAssert(pdcp_pdu_buffer != NULL); @@ -122,7 +123,11 @@ pdcp_apply_security( encrypt_params.direction = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK; encrypt_params.bearer = rb_id - 1; encrypt_params.count = pdcp_get_next_count_tx(pdcp_pP, srb_flagP, current_sn); - encrypt_params.key_length = 16; + + if (srb_flagP) + container = pdcp_pP->security_container_rrc; + else + container = pdcp_pP->security_container_up; if (srb_flagP) { /* SRBs */ @@ -133,7 +138,7 @@ pdcp_apply_security( encrypt_params.message = pdcp_pdu_buffer; encrypt_params.blength = (pdcp_header_len + sdu_buffer_size) << 3; - encrypt_params.key = pdcp_pP->kRRCint + 16; // + 128; + encrypt_params.context = container->integrity_context; mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size]; @@ -142,15 +147,13 @@ pdcp_apply_security( stream_compute_integrity(pdcp_pP->integrityProtAlgorithm, &encrypt_params, mac_i); - - encrypt_params.key = pdcp_pP->kRRCenc; // + 128 // bit key } else { LOG_D(PDCP, "[OSA][RB %ld] %s Applying user-plane security\n", rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE"); - - encrypt_params.key = pdcp_pP->kUPenc;// + 128; } + encrypt_params.context = container->ciphering_context; + encrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len]; encrypt_params.blength = sdu_buffer_size << 3; @@ -180,6 +183,7 @@ pdcp_validate_security( { uint8_t *buffer_decrypted = NULL; nas_stream_cipher_t decrypt_params = {0}; + stream_security_container_t *container; DevAssert(pdcp_pP != NULL); @@ -195,17 +199,17 @@ pdcp_validate_security( decrypt_params.count = pdcp_get_next_count_rx(pdcp_pP, srb_flagP, hfn, sn); decrypt_params.message = &pdcp_pdu_buffer[pdcp_header_len]; decrypt_params.blength = (sdu_buffer_size - pdcp_header_len) << 3; - decrypt_params.key_length = 16; if (srb_flagP) { LOG_D(PDCP, "[OSA][RB %ld] %s Validating control-plane security\n", rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB"); - decrypt_params.key = pdcp_pP->kRRCenc;// + 128; + container = pdcp_pP->security_container_rrc; } else { LOG_D(PDCP, "[OSA][RB %ld] %s Validating user-plane security\n", rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB"); - decrypt_params.key = pdcp_pP->kUPenc;// + 128; + container = pdcp_pP->security_container_up; } /* Uncipher the block */ + decrypt_params.context = container->ciphering_context; stream_compute_encrypt(pdcp_pP->cipheringAlgorithm, &decrypt_params, buffer_decrypted); if (!IS_SOFTMODEM_IQPLAYER) { @@ -213,7 +217,7 @@ pdcp_validate_security( /* Now check the integrity of the complete PDU */ decrypt_params.message = pdcp_pdu_buffer; decrypt_params.blength = sdu_buffer_size << 3; - decrypt_params.key = pdcp_pP->kRRCint + 16;// 128; + decrypt_params.context = container->integrity_context; if (pdcp_pP->integrityProtAlgorithm != EIA0_ALG_ID) { uint8_t result[4] = {0}; @@ -221,10 +225,9 @@ pdcp_validate_security( if (memcmp(result, &pdcp_pdu_buffer[sdu_buffer_size], 4) != 0) { LOG_E(PDCP, - "[OSA][RB %ld] %s failed to validate MAC-I (key %llx) of incoming PDU\n", + "[OSA][RB %ld] %s failed to validate MAC-I of incoming PDU\n", rb_id, - (pdcp_pP->is_ue != 0) ? "UE" : "eNB", - ((long long unsigned int *)decrypt_params.key)[0]); + (pdcp_pP->is_ue != 0) ? "UE" : "eNB"); VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT); return -1; } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h index 5d2fd56f70..d26ce83b82 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.h @@ -28,6 +28,7 @@ #include "nr_pdcp_sdu.h" #include "openair2/RRC/NR/rrc_gNB_radio_bearers.h" +#include "openair3/SECU/secu_defs.h" /* PDCP Formats according to clause 6.2 of 3GPP TS 38.323 */ /* SN Size applicable to SRBs, UM DRBs and AM DRBs */ @@ -151,16 +152,17 @@ typedef struct nr_pdcp_entity_t { int integrity_algorithm; unsigned char ciphering_key[16]; unsigned char integrity_key[16]; - void *security_context; - void (*cipher)(void *security_context, + stream_security_context_t *security_context; + void (*cipher)(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, int count, int direction); - void (*free_security)(void *security_context); - void *integrity_context; - void (*integrity)(void *integrity_context, unsigned char *out, + void (*free_security)(stream_security_context_t *security_context); + stream_security_context_t *integrity_context; + void (*integrity)(stream_security_context_t *integrity_context, + unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction); - void (*free_integrity)(void *integrity_context); + void (*free_integrity)(stream_security_context_t *integrity_context); /* security/integrity algorithms need to know uplink/downlink information * which is reverse for gnb and ue, so we need to know if this * pdcp entity is for a gnb or an ue diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c index 3dbf15136b..d21c98610e 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.c @@ -28,24 +28,23 @@ #include "openair3/SECU/secu_defs.h" #include "openair3/SECU/key_nas_deriver.h" -void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key) +stream_security_context_t *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key) { nas_stream_cipher_t *ret; ret = calloc(1, sizeof(*ret)); if (ret == NULL) abort(); - ret->key = malloc(16); if (ret->key == NULL) abort(); - memcpy(ret->key, integrity_key, 16); - ret->key_length = 16; /* unused */ + ret->context = malloc(16); if (ret->context == NULL) abort(); + memcpy(ret->context, integrity_key, 16); - return ret; + return (stream_security_context_t *)ret; } -void nr_pdcp_integrity_nia1_integrity(void *integrity_context, +void nr_pdcp_integrity_nia1_integrity(stream_security_context_t *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction) { - nas_stream_cipher_t *ctx = integrity_context; + nas_stream_cipher_t *ctx = (nas_stream_cipher_t *)integrity_context; ctx->message = buffer; ctx->count = count; @@ -56,9 +55,9 @@ void nr_pdcp_integrity_nia1_integrity(void *integrity_context, stream_compute_integrity(EIA1_128_ALG_ID, ctx, out); } -void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context) +void nr_pdcp_integrity_nia1_free_integrity(stream_security_context_t *integrity_context) { - nas_stream_cipher_t *ctx = integrity_context; - free(ctx->key); + nas_stream_cipher_t *ctx = (nas_stream_cipher_t *)integrity_context; + free(ctx->context); free(ctx); } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h index 5c44bad4a7..89f6d9156a 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia1.h @@ -22,13 +22,15 @@ #ifndef _NR_PDCP_INTEGRITY_NIA1_H_ #define _NR_PDCP_INTEGRITY_NIA1_H_ -void *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key); +#include "openair3/SECU/secu_defs.h" -void nr_pdcp_integrity_nia1_integrity(void *integrity_context, +stream_security_context_t *nr_pdcp_integrity_nia1_init(unsigned char *integrity_key); + +void nr_pdcp_integrity_nia1_integrity(stream_security_context_t *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction); -void nr_pdcp_integrity_nia1_free_integrity(void *integrity_context); +void nr_pdcp_integrity_nia1_free_integrity(stream_security_context_t *integrity_context); #endif /* _NR_PDCP_INTEGRITY_NIA1_H_ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c index 497ed154d5..f6db1b10a6 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.c @@ -30,29 +30,25 @@ #include "openair3/SECU/aes_128.h" #include "openair3/SECU/aes_128_cbc_cmac.h" -void *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]) +stream_security_context_t *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]) { - // This is a hack. Reduce the 3 functions to just cipher? - // No. The overhead is x8 times more. Don't change before measuring - // return integrity_key; cbc_cmac_ctx_t* ctx = calloc(1, sizeof(cbc_cmac_ctx_t)); AssertFatal(ctx, "Memory exhausted"); *ctx = init_aes_128_cbc_cmac(integrity_key); - return ctx; + return (stream_security_context_t *)ctx; } -void nr_pdcp_integrity_nia2_integrity(void *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction) +void nr_pdcp_integrity_nia2_integrity(stream_security_context_t *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction) { DevAssert(integrity_context != NULL); DevAssert(out != NULL); DevAssert(buffer != NULL); DevAssert(length > -1); - // Strange range: [1-32] instead of [0-31] DevAssert(bearer > 0 && bearer < 33); DevAssert(count > -1); - cbc_cmac_ctx_t* ctx = (cbc_cmac_ctx_t*)integrity_context; + cbc_cmac_ctx_t *ctx = (cbc_cmac_ctx_t *)integrity_context; aes_128_t k_iv = {0}; memcpy(&k_iv.key, ctx->key, sizeof(k_iv.key)); @@ -64,18 +60,13 @@ void nr_pdcp_integrity_nia2_integrity(void *integrity_context, unsigned char *ou uint8_t result[16] = {0}; byte_array_t msg = {.buf = buffer, .len = length}; - cipher_aes_128_cbc_cmac((cbc_cmac_ctx_t*)integrity_context, &k_iv, msg, sizeof(result), result); - //aes_128_cbc_cmac(&k_iv, msg, sizeof(result), result); + cipher_aes_128_cbc_cmac(ctx, &k_iv, msg, sizeof(result), result); - // AES CMAC (RFC 4493) outputs 128 bits but NR PDCP PDUs have a MAC-I of - // 32 bits (see 38.323 6.2). RFC 4493 2.1 says to truncate most significant - // bit first (so seems to say 33.401 B.2.3) - // Precondition: out should have enough space... memcpy(out, result, 4); } -void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context) +void nr_pdcp_integrity_nia2_free_integrity(stream_security_context_t *integrity_context) { - free( ( cbc_cmac_ctx_t*) integrity_context); + free_aes_128_cbc_cmac((cbc_cmac_ctx_t *)integrity_context); + free(integrity_context); } - diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.h index 53f117aafb..c9bd6cd881 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_integrity_nia2.h @@ -24,13 +24,15 @@ #include -void *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]); +#include "openair3/SECU/secu_defs.h" -void nr_pdcp_integrity_nia2_integrity(void *integrity_context, +stream_security_context_t *nr_pdcp_integrity_nia2_init(uint8_t integrity_key[16]); + +void nr_pdcp_integrity_nia2_integrity(stream_security_context_t *integrity_context, unsigned char *out, unsigned char *buffer, int length, int bearer, int count, int direction); -void nr_pdcp_integrity_nia2_free_integrity(void *integrity_context); +void nr_pdcp_integrity_nia2_free_integrity(stream_security_context_t *integrity_context); #endif /* _NR_PDCP_INTEGRITY_NIA2_H_ */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c index e54b854125..617d5c3372 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.c @@ -29,14 +29,14 @@ #include #include -void *nr_pdcp_security_nea2_init(unsigned char *ciphering_key) +stream_security_context_t *nr_pdcp_security_nea2_init(unsigned char *ciphering_key) { // This is a hack, IMO init, cipher and free functions should be reduced to cipher. // Test show a ~10% more processing time - return ciphering_key; + return (stream_security_context_t *)ciphering_key; } -void nr_pdcp_security_nea2_cipher(void *security_context, unsigned char *buffer, int length, int bearer, int count, int direction) +void nr_pdcp_security_nea2_cipher(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, int count, int direction) { DevAssert(security_context != NULL); DevAssert(buffer != NULL); @@ -62,7 +62,7 @@ void nr_pdcp_security_nea2_cipher(void *security_context, unsigned char *buffer, memcpy(buffer, out, length); } -void nr_pdcp_security_nea2_free_security(void *security_context) +void nr_pdcp_security_nea2_free_security(stream_security_context_t *security_context) { (void)security_context; } diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.h b/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.h index c3667c93d4..4550e7290d 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.h +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_security_nea2.h @@ -22,12 +22,14 @@ #ifndef _NR_PDCP_SECURITY_NEA2_H_ #define _NR_PDCP_SECURITY_NEA2_H_ -void *nr_pdcp_security_nea2_init(unsigned char *ciphering_key); +#include "openair3/SECU/secu_defs.h" -void nr_pdcp_security_nea2_cipher(void *security_context, +stream_security_context_t *nr_pdcp_security_nea2_init(unsigned char *ciphering_key); + +void nr_pdcp_security_nea2_cipher(stream_security_context_t *security_context, unsigned char *buffer, int length, int bearer, int count, int direction); -void nr_pdcp_security_nea2_free_security(void *security_context); +void nr_pdcp_security_nea2_free_security(stream_security_context_t *security_context); #endif /* _NR_PDCP_SECURITY_NEA2_H_ */ diff --git a/openair3/NAS/COMMON/API/NETWORK/nas_message.c b/openair3/NAS/COMMON/API/NETWORK/nas_message.c index c5a304b84b..32454a13e3 100644 --- a/openair3/NAS/COMMON/API/NETWORK/nas_message.c +++ b/openair3/NAS/COMMON/API/NETWORK/nas_message.c @@ -1009,8 +1009,7 @@ static int _nas_message_decrypt( (direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK", (direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num, count); - stream_cipher.key = emm_security_context->knas_enc.value; - stream_cipher.key_length = AUTH_KNAS_ENC_SIZE; + stream_cipher.context = emm_security_context->security_container->ciphering_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; @@ -1045,15 +1044,14 @@ static int _nas_message_decrypt( (direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK", (direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num, count); - stream_cipher.key = emm_security_context->knas_enc.value; - stream_cipher.key_length = AUTH_KNAS_ENC_SIZE; + stream_cipher.context = emm_security_context->security_container->ciphering_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; stream_cipher.message = (unsigned char *)src; /* length in bits */ stream_cipher.blength = length << 3; - stream_compute_encrypt(EEA1_128_ALG_ID, &stream_cipher, (unsigned char *)dest); + stream_compute_encrypt(EEA2_128_ALG_ID, &stream_cipher, (unsigned char *)dest); /* Decode the first octet (security header type or EPS bearer identity, * and protocol discriminator) */ @@ -1178,8 +1176,7 @@ static int _nas_message_encrypt( (direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK", (direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num, count); - stream_cipher.key = emm_security_context->knas_enc.value; - stream_cipher.key_length = AUTH_KNAS_ENC_SIZE; + stream_cipher.context = emm_security_context->security_container->ciphering_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; @@ -1208,8 +1205,7 @@ static int _nas_message_encrypt( (direction == SECU_DIRECTION_UPLINK) ? "UPLINK":"DOWNLINK", (direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num, count); - stream_cipher.key = emm_security_context->knas_enc.value; - stream_cipher.key_length = AUTH_KNAS_ENC_SIZE; + stream_cipher.context = emm_security_context->security_container->ciphering_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; @@ -1347,8 +1343,7 @@ static uint32_t _nas_message_get_mac( fflush(stderr); #endif - stream_cipher.key = emm_security_context->knas_int.value; - stream_cipher.key_length = AUTH_KNAS_INT_SIZE; + stream_cipher.context = emm_security_context->security_container->integrity_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; @@ -1391,8 +1386,7 @@ static uint32_t _nas_message_get_mac( (direction == SECU_DIRECTION_UPLINK) ? emm_security_context->ul_count.seq_num:emm_security_context->dl_count.seq_num, count); - stream_cipher.key = emm_security_context->knas_int.value; - stream_cipher.key_length = AUTH_KNAS_INT_SIZE; + stream_cipher.context = emm_security_context->security_container->integrity_context; stream_cipher.count = count; stream_cipher.bearer = 0x00; //33.401 section 8.1.1 stream_cipher.direction = direction; diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.c b/openair3/NAS/NR_UE/nr_nas_msg_sim.c index af46cbf6af..97f9ca1aef 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.c +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.c @@ -515,6 +515,10 @@ void generateIdentityResponse(as_nas_info_t *initialNasMsg, uint8_t identitytype static void generateAuthenticationResp(nr_ue_nas_t *nas, as_nas_info_t *initialNasMsg, uint8_t *buf) { derive_ue_keys(buf, nas); + /* todo: as of now, nia2 is hardcoded in derive_ue_keys(), remove this hardcoding, use NAS signalling for getting proper algorithm */ + /* todo: deal with ciphering for this stream_security_container_init() (handle ciphering in general) */ + /* todo: stream_security_container_delete() is not called anywhere, deal with that */ + nas->security_container = stream_security_container_init(0, 2 /* hardcoded: nia2 */, NULL, nas->security.knas_int); OctetString res; res.length = 16; res.value = calloc(1,16); @@ -598,8 +602,7 @@ static void generateSecurityModeComplete(nr_ue_nas_t *nas, as_nas_info_t *initia initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); - stream_cipher.key = nas->security.knas_int; - stream_cipher.key_length = 16; + stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.mm_counter++; stream_cipher.bearer = 1; stream_cipher.direction = 0; @@ -699,8 +702,7 @@ static void generateRegistrationComplete(nr_ue_nas_t *nas, as_nas_info_t *initia } initialNasMsg->length = length; - stream_cipher.key = nas->security.knas_int; - stream_cipher.key_length = 16; + stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.mm_counter++; stream_cipher.bearer = 1; stream_cipher.direction = 0; @@ -762,8 +764,7 @@ static void generateDeregistrationRequest(nr_ue_nas_t *nas, as_nas_info_t *initi initialNasMsg->length = security_header_len + mm_msg_encode(&sp_msg->plain.mm_msg, (uint8_t *)(initialNasMsg->data + security_header_len), size - security_header_len); nas_stream_cipher_t stream_cipher = { - .key = nas->security.knas_int, - .key_length = 16, + .context = nas->security_container->integrity_context, .count = nas->security.mm_counter++, .bearer = 1, .direction = 0, @@ -853,8 +854,7 @@ static void generatePduSessionEstablishRequest(nr_ue_nas_t *nas, as_nas_info_t * initialNasMsg->length = security_header_len + mm_msg_encode(mm_msg, (uint8_t*)(initialNasMsg->data+security_header_len), size-security_header_len); - stream_cipher.key = nas->security.knas_int; - stream_cipher.key_length = 16; + stream_cipher.context = nas->security_container->integrity_context; stream_cipher.count = nas->security.mm_counter++; stream_cipher.bearer = 1; stream_cipher.direction = 0; diff --git a/openair3/NAS/NR_UE/nr_nas_msg_sim.h b/openair3/NAS/NR_UE/nr_nas_msg_sim.h index a892bf1b4b..0d2d8f5cc9 100644 --- a/openair3/NAS/NR_UE/nr_nas_msg_sim.h +++ b/openair3/NAS/NR_UE/nr_nas_msg_sim.h @@ -41,6 +41,7 @@ #include "as_message.h" #include "FGSUplinkNasTransport.h" #include +#include "secu_defs.h" #define PLAIN_5GS_MSG 0b0000 #define INTEGRITY_PROTECTED 0b0001 @@ -98,6 +99,7 @@ typedef struct { typedef struct { uicc_t *uicc; ue_sa_security_key_t security; + stream_security_container_t *security_container; Guti5GSMobileIdentity_t *guti; bool termination_procedure; } nr_ue_nas_t; diff --git a/openair3/NAS/UE/EMM/SecurityModeControl.c b/openair3/NAS/UE/EMM/SecurityModeControl.c index 3386499663..2a18763f50 100644 --- a/openair3/NAS/UE/EMM/SecurityModeControl.c +++ b/openair3/NAS/UE/EMM/SecurityModeControl.c @@ -258,6 +258,7 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, LOG_TRACE(INFO, "EMM-PROC - Update Current security context"); /* Release non-current security context */ + stream_security_container_delete(user->emm_data->security->security_container); _security_release(user->emm_data->security); user->emm_data->security = user->emm_data->non_current; /* Reset the uplink NAS COUNT counter */ @@ -265,6 +266,12 @@ int emm_proc_security_mode_command(nas_user_t *user, int native_ksi, int ksi, user->emm_data->security->ul_count.seq_num = 0; /* Set new security context indicator */ security_context_is_new = true; + /* create contexts */ + user->emm_data->security->security_container = stream_security_container_init( + seea, + seia, + user->emm_data->non_current->knas_enc.value, + user->emm_data->non_current->knas_int.value); } } diff --git a/openair3/NAS/UE/EMM/emmData.h b/openair3/NAS/UE/EMM/emmData.h index 50219b7883..d90820edf9 100644 --- a/openair3/NAS/UE/EMM/emmData.h +++ b/openair3/NAS/UE/EMM/emmData.h @@ -42,6 +42,7 @@ Description Defines internal private data handled by EPS Mobility #include "commonDef.h" #include "networkDef.h" #include "securityDef.h" +#include "openair3/SECU/secu_defs.h" #include "OctetString.h" #include "nas_timer.h" @@ -138,6 +139,7 @@ typedef struct emm_security_context_s { //OctetString ksgsn; /* SGSN security key (mapped context) */ OctetString knas_enc; /* NAS cyphering key */ OctetString knas_int; /* NAS integrity key */ + stream_security_container_t *security_container; /* container for NAS security */ struct count_s{ uint32_t spare:8; uint32_t overflow:16; diff --git a/openair3/SECU/aes_128_cbc_cmac.c b/openair3/SECU/aes_128_cbc_cmac.c index da925f6d1e..3f4ca96e50 100644 --- a/openair3/SECU/aes_128_cbc_cmac.c +++ b/openair3/SECU/aes_128_cbc_cmac.c @@ -31,101 +31,56 @@ // code for version 3.0 or greater #include -static -const char *propq = NULL; - -void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]) -{ - OSSL_LIB_CTX* library_context = OSSL_LIB_CTX_new(); - DevAssert(library_context != NULL); - - /* Fetch the CMAC implementation */ - EVP_MAC* mac = EVP_MAC_fetch(library_context, "CMAC", propq); - DevAssert(mac != NULL); - - /* Create a context for the CMAC operation */ - EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(mac); - DevAssert(mctx != NULL); - - // The underlying cipher to be used - char cipher_name[] = "aes128"; - - OSSL_PARAM params[2] = {0}; - params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name, - sizeof(cipher_name)); - params[1] = OSSL_PARAM_construct_end(); - - /* Initialise the CMAC operation */ - int rc = EVP_MAC_init(mctx, k_iv->key, sizeof(k_iv->key), params); - DevAssert(rc != 0); - - size_t sz_iv = 0; - uint8_t* iv = NULL; - if(k_iv->type == AES_INITIALIZATION_VECTOR_8){ - sz_iv = 8; - iv = (uint8_t*)k_iv->iv8.iv; - } else if(k_iv->type == AES_INITIALIZATION_VECTOR_16) { - sz_iv = 16; - iv = (uint8_t*)k_iv->iv16.iv; - } else { - DevAssert(0!=0 && "Unknwon Initialization vector"); - } - - /* Make one or more calls to process the data to be authenticated */ - rc = EVP_MAC_update(mctx, iv, sz_iv); - DevAssert(rc != 0); - - /* Make one or more calls to process the data to be authenticated */ - rc = EVP_MAC_update(mctx, msg.buf, msg.len); - DevAssert(rc != 0); - - /* Make a call to the final with a NULL buffer to get the length of the MAC */ - size_t out_len = 0; - rc = EVP_MAC_final(mctx, out, &out_len, len_out); - DevAssert(rc != 0); - - EVP_MAC_CTX_free(mctx); - EVP_MAC_free(mac); - OSSL_LIB_CTX_free(library_context); -} - -cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16]) +cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16]) { DevAssert(key != NULL); - OSSL_LIB_CTX* library_context = OSSL_LIB_CTX_new(); - DevAssert(library_context != NULL); - /* Fetch the CMAC implementation */ - EVP_MAC* mac = EVP_MAC_fetch(library_context, "CMAC", propq); - DevAssert(mac != NULL); + EVP_MAC *mac_implementation = EVP_MAC_fetch(NULL, "CMAC", NULL); + DevAssert(mac_implementation != NULL); - cbc_cmac_ctx_t ctx = {.lib_ctx = library_context, .mac = mac }; + /* Create a context for the CMAC operation */ + EVP_MAC_CTX* mac_context = EVP_MAC_CTX_new(mac_implementation); + DevAssert(mac_context != NULL); - assert(16 == sizeof(ctx.key)); + cbc_cmac_ctx_t ctx = { .mac_implementation = mac_implementation, .mac_context = mac_context }; memcpy(ctx.key, key, 16); - return ctx; + // The underlying cipher to be used + char cipher_name[] = "aes128"; + + OSSL_PARAM params[2] = {0}; + params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name, + sizeof(cipher_name)); + params[1] = OSSL_PARAM_construct_end(); + + /* Initialise the CMAC operation */ + int rc = EVP_MAC_init(mac_context, key, 16, params); + DevAssert(rc != 0); + + return ctx; } void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]) { DevAssert(ctx != NULL); DevAssert(k_iv != NULL); - /* Create a context for the CMAC operation */ - EVP_MAC_CTX* mctx = EVP_MAC_CTX_new(ctx->mac); - DevAssert(mctx != NULL); - // The underlying cipher to be used - char cipher_name[] = "aes128"; - - OSSL_PARAM params[2] = {0}; - params[0] = OSSL_PARAM_construct_utf8_string(OSSL_MAC_PARAM_CIPHER, cipher_name, - sizeof(cipher_name)); - params[1] = OSSL_PARAM_construct_end(); - - /* Initialise the CMAC operation */ - int rc = EVP_MAC_init(mctx, k_iv->key, sizeof(k_iv->key), params); + /* reset the CMAC */ + /* There is a bug with version <= 3.0.2 of OpenSSL for which we must + * pass the key to reset. (Some Ubuntu version provide this version.) + * Passing the key has some impact on performance. + * todo: drop support for old versions of openssl. + */ +#if OPENSSL_VERSION_NUMBER <= 0x30000020 + /* todo: when/if we remove this code, don't forget to check use of k_iv->key + * somewhere else in the codebase. + * If not used, remove from aes_128_t* + */ + int rc = EVP_MAC_init(ctx->mac_context, k_iv->key, 16, NULL); +#else + int rc = EVP_MAC_init(ctx->mac_context, NULL, 0, NULL); +#endif DevAssert(rc != 0); size_t sz_iv = 0; @@ -141,74 +96,41 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b } /* Make one or more calls to process the data to be authenticated */ - rc = EVP_MAC_update(mctx, iv, sz_iv); + rc = EVP_MAC_update(ctx->mac_context, iv, sz_iv); DevAssert(rc != 0); /* Make one or more calls to process the data to be authenticated */ - rc = EVP_MAC_update(mctx, msg.buf, msg.len); + rc = EVP_MAC_update(ctx->mac_context, msg.buf, msg.len); DevAssert(rc != 0); /* Make a call to the final with a NULL buffer to get the length of the MAC */ size_t out_len = 0; - rc = EVP_MAC_final(mctx, out, &out_len, len_out); + rc = EVP_MAC_final(ctx->mac_context, out, &out_len, len_out); DevAssert(rc != 0); - - EVP_MAC_CTX_free(mctx); } void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx) { DevAssert(ctx != NULL); - EVP_MAC_free(ctx->mac); - OSSL_LIB_CTX_free(ctx->lib_ctx); + EVP_MAC_CTX_free(ctx->mac_context); + EVP_MAC_free(ctx->mac_implementation); } #else // code for 1.1.x or lower -void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]) -{ - DevAssert(k_iv != NULL); - - CMAC_CTX *ctx = CMAC_CTX_new(); - DevAssert(ctx != NULL); - - CMAC_Init(ctx, k_iv->key, sizeof(k_iv->key), EVP_aes_128_cbc(), NULL); - - size_t sz_iv = 0; - uint8_t* iv = NULL; - if(k_iv->type == AES_INITIALIZATION_VECTOR_8){ - sz_iv = 8; - iv = (uint8_t*)k_iv->iv8.iv; - } else if(k_iv->type == AES_INITIALIZATION_VECTOR_16) { - sz_iv = 16; - iv = (uint8_t*)k_iv->iv16.iv; - } else { - AssertFatal(0 != 0, "Unknwon Initialization vector"); - } - - CMAC_Update(ctx, iv, sz_iv); - - CMAC_Update(ctx, msg.buf, msg.len); - size_t len_res = 0; - CMAC_Final(ctx, out, &len_res); - DevAssert(len_res <= len_out); - - CMAC_CTX_free(ctx); -} - -cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16]) +cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16]) { DevAssert(key != NULL); - cbc_cmac_ctx_t ctx = {.lib_ctx = NULL, .mac = NULL }; + cbc_cmac_ctx_t ctx = {.mac_implementation = NULL, .mac_context = NULL }; - ctx.mac = CMAC_CTX_new(); - DevAssert(ctx.mac != NULL); + ctx.mac_context = CMAC_CTX_new(); + DevAssert(ctx.mac_context != NULL); //assert(16 == sizeof(ctx.key)); memcpy(ctx.key, key, 16); //sizeof(ctx.key)); - CMAC_Init(ctx.mac, ctx.key, 16, EVP_aes_128_cbc(), NULL); + CMAC_Init(ctx.mac_context, ctx.key, 16, EVP_aes_128_cbc(), NULL); return ctx; } @@ -218,11 +140,11 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b DevAssert(k_iv != NULL); //From https://man.openbsd.org/CMAC_Init.3 - //If ctx is already initialized, CMAC_Init() can be called again with key, - //cipher, and impl all set to NULL and key_len set to 0. In that case, any - //data already processed is discarded and ctx is re-initialized to start + //If ctx is already initialized, CMAC_Init() can be called again with key, + //cipher, and impl all set to NULL and key_len set to 0. In that case, any + //data already processed is discarded and ctx is re-initialized to start //reading data anew. - CMAC_Init(ctx->mac, NULL, 0, NULL, NULL); + CMAC_Init(ctx->mac_context, NULL, 0, NULL, NULL); size_t sz_iv = 0; uint8_t* iv = NULL; @@ -236,19 +158,18 @@ void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, b AssertFatal(0 != 0, "Unknwon Initialization vector"); } - CMAC_Update(ctx->mac, iv, sz_iv); + CMAC_Update(ctx->mac_context, iv, sz_iv); - CMAC_Update(ctx->mac, msg.buf, msg.len); + CMAC_Update(ctx->mac_context, msg.buf, msg.len); size_t len_res = 0; - CMAC_Final(ctx->mac, out, &len_res); + CMAC_Final(ctx->mac_context, out, &len_res); DevAssert(len_res <= len_out); } void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx) { DevAssert(ctx != NULL); - CMAC_CTX_free(ctx->mac); + CMAC_CTX_free(ctx->mac_context); } #endif - diff --git a/openair3/SECU/aes_128_cbc_cmac.h b/openair3/SECU/aes_128_cbc_cmac.h index b5118118c3..b906ddf5f3 100644 --- a/openair3/SECU/aes_128_cbc_cmac.h +++ b/openair3/SECU/aes_128_cbc_cmac.h @@ -31,17 +31,13 @@ #include typedef struct { - void* lib_ctx; - void* mac; + void *mac_implementation; + void *mac_context; uint8_t key[16]; } cbc_cmac_ctx_t ; -void aes_128_cbc_cmac(const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]); - -cbc_cmac_ctx_t init_aes_128_cbc_cmac(uint8_t key[16]); - +cbc_cmac_ctx_t init_aes_128_cbc_cmac(const uint8_t key[16]); void cipher_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx, const aes_128_t* k_iv, byte_array_t msg, size_t len_out, uint8_t out[len_out]); - void free_aes_128_cbc_cmac(cbc_cmac_ctx_t const* ctx); #endif diff --git a/openair3/SECU/nas_stream_eea1.c b/openair3/SECU/nas_stream_eea1.c index a4e4b84ca4..027205353b 100644 --- a/openair3/SECU/nas_stream_eea1.c +++ b/openair3/SECU/nas_stream_eea1.c @@ -38,10 +38,9 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t * //uint32_t byte_length; uint32_t *KS; uint32_t K[4],IV[4]; + uint8_t *key = (uint8_t *)stream_cipher->context; DevAssert(stream_cipher != NULL); - DevAssert(stream_cipher->key != NULL); - DevAssert(stream_cipher->key_length == 16); DevAssert(out != NULL); n = ( stream_cipher->blength + 31 ) / 32; @@ -50,22 +49,20 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t * memset(&snow_3g_context, 0, sizeof(snow_3g_context)); /*Initialisation*/ - /* Load the confidentiality key for SNOW 3G initialization as in section - 3.4. */ - memcpy(K+3,stream_cipher->key+0,4); /*K[3] = key[0]; we assume + /* Load the confidentiality key for SNOW 3G initialization as in section 3.4. */ + memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume K[3]=key[0]||key[1]||...||key[31] , with key[0] the * most important bit of key*/ - memcpy(K+2,stream_cipher->key+4,4); /*K[2] = key[1];*/ - memcpy(K+1,stream_cipher->key+8,4); /*K[1] = key[2];*/ - memcpy(K+0,stream_cipher->key+12,4); /*K[0] = key[3]; we assume - K[0]=key[96]||key[97]||...||key[127] , with key[127] the - * least important bit of key*/ + memcpy(K+2,key+4,4); /*K[2] = key[1];*/ + memcpy(K+1,key+8,4); /*K[1] = key[2];*/ + memcpy(K+0,key+12,4); /*K[0] = key[3]; we assume + * K[0]=key[96]||key[97]||...||key[127] , with key[127] the + * least important bit of key*/ K[3] = hton_int32(K[3]); K[2] = hton_int32(K[2]); K[1] = hton_int32(K[1]); K[0] = hton_int32(K[0]); - /* Prepare the initialization vector (IV) for SNOW 3G initialization as in - section 3.4. */ + /* Prepare the initialization vector (IV) for SNOW 3G initialization as in section 3.4. */ IV[3] = stream_cipher->count; IV[2] = ((((uint32_t)stream_cipher->bearer) << 3) | ((((uint32_t)stream_cipher->direction) & 0x1) << 2)) << 24; IV[1] = IV[3]; @@ -104,3 +101,16 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t * out[ceil_index - 1] = stream_cipher->message[ceil_index - 1]; } } + +stream_security_context_t *stream_ciphering_init_eea1(const uint8_t *ciphering_key) +{ + void *ret = calloc(1, 16); + AssertFatal(ret != NULL, "out of memory\n"); + memcpy(ret, ciphering_key, 16); + return (stream_security_context_t *)ret; +} + +void stream_ciphering_free_eea1(stream_security_context_t *ciphering_context) +{ + free(ciphering_context); +} diff --git a/openair3/SECU/nas_stream_eea1.h b/openair3/SECU/nas_stream_eea1.h index d713dc60d3..ebddd7af35 100644 --- a/openair3/SECU/nas_stream_eea1.h +++ b/openair3/SECU/nas_stream_eea1.h @@ -29,4 +29,7 @@ void nas_stream_encrypt_eea1(nas_stream_cipher_t const *stream_cipher, uint8_t *out); +stream_security_context_t *stream_ciphering_init_eea1(const uint8_t *ciphering_key); +void stream_ciphering_free_eea1(stream_security_context_t *ciphering_context); + #endif diff --git a/openair3/SECU/nas_stream_eea2.c b/openair3/SECU/nas_stream_eea2.c index dbdc040883..6600afaace 100644 --- a/openair3/SECU/nas_stream_eea2.c +++ b/openair3/SECU/nas_stream_eea2.c @@ -33,15 +33,13 @@ void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t *out) { DevAssert(stream_cipher != NULL); - DevAssert(stream_cipher->key != NULL); - DevAssert(stream_cipher->key_length == 32); DevAssert(stream_cipher->bearer < 32); DevAssert(stream_cipher->direction < 2); DevAssert(stream_cipher->message != NULL); DevAssert(stream_cipher->blength > 7); aes_128_t p = {0}; - memcpy(p.key, stream_cipher->key, stream_cipher->key_length); + memcpy(p.key, stream_cipher->context, 16); p.type = AES_INITIALIZATION_VECTOR_16; p.iv16.d.count = htonl(stream_cipher->count); p.iv16.d.bearer = stream_cipher->bearer; @@ -54,3 +52,16 @@ void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t * byte_array_t msg = {.buf = stream_cipher->message, .len = byte_lenght}; aes_128_ctr(&p, msg, len_out, out); } + +stream_security_context_t *stream_ciphering_init_eea2(const uint8_t *ciphering_key) +{ + void *ret = calloc(1, 16); + AssertFatal(ret != NULL, "out of memory\n"); + memcpy(ret, ciphering_key, 16); + return (stream_security_context_t *)ret; +} + +void stream_ciphering_free_eea2(stream_security_context_t *ciphering_context) +{ + free(ciphering_context); +} diff --git a/openair3/SECU/nas_stream_eea2.h b/openair3/SECU/nas_stream_eea2.h index c6133c987d..f64fff6c4d 100644 --- a/openair3/SECU/nas_stream_eea2.h +++ b/openair3/SECU/nas_stream_eea2.h @@ -26,40 +26,9 @@ #include "secu_defs.h" #include -/* Rijndael S-box OSA_SR */ - -static const uint8_t OSA_SR[256] = { - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, - 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, - 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, - 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 0xD0, 0xEF, 0xAA, 0xFB, - 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, - 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, - 0x64, 0x5D, 0x19, 0x73, 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D, - 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, - 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, - 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16}; - -/* S-box OSA_SQ */ - -static const uint8_t OSA_SQ[256] = { - 0x25, 0x24, 0x73, 0x67, 0xD7, 0xAE, 0x5C, 0x30, 0xA4, 0xEE, 0x6E, 0xCB, 0x7D, 0xB5, 0x82, 0xDB, 0xE4, 0x8E, 0x48, 0x49, - 0x4F, 0x5D, 0x6A, 0x78, 0x70, 0x88, 0xE8, 0x5F, 0x5E, 0x84, 0x65, 0xE2, 0xD8, 0xE9, 0xCC, 0xED, 0x40, 0x2F, 0x11, 0x28, - 0x57, 0xD2, 0xAC, 0xE3, 0x4A, 0x15, 0x1B, 0xB9, 0xB2, 0x80, 0x85, 0xA6, 0x2E, 0x02, 0x47, 0x29, 0x07, 0x4B, 0x0E, 0xC1, - 0x51, 0xAA, 0x89, 0xD4, 0xCA, 0x01, 0x46, 0xB3, 0xEF, 0xDD, 0x44, 0x7B, 0xC2, 0x7F, 0xBE, 0xC3, 0x9F, 0x20, 0x4C, 0x64, - 0x83, 0xA2, 0x68, 0x42, 0x13, 0xB4, 0x41, 0xCD, 0xBA, 0xC6, 0xBB, 0x6D, 0x4D, 0x71, 0x21, 0xF4, 0x8D, 0xB0, 0xE5, 0x93, - 0xFE, 0x8F, 0xE6, 0xCF, 0x43, 0x45, 0x31, 0x22, 0x37, 0x36, 0x96, 0xFA, 0xBC, 0x0F, 0x08, 0x52, 0x1D, 0x55, 0x1A, 0xC5, - 0x4E, 0x23, 0x69, 0x7A, 0x92, 0xFF, 0x5B, 0x5A, 0xEB, 0x9A, 0x1C, 0xA9, 0xD1, 0x7E, 0x0D, 0xFC, 0x50, 0x8A, 0xB6, 0x62, - 0xF5, 0x0A, 0xF8, 0xDC, 0x03, 0x3C, 0x0C, 0x39, 0xF1, 0xB8, 0xF3, 0x3D, 0xF2, 0xD5, 0x97, 0x66, 0x81, 0x32, 0xA0, 0x00, - 0x06, 0xCE, 0xF6, 0xEA, 0xB7, 0x17, 0xF7, 0x8C, 0x79, 0xD6, 0xA7, 0xBF, 0x8B, 0x3F, 0x1F, 0x53, 0x63, 0x75, 0x35, 0x2C, - 0x60, 0xFD, 0x27, 0xD3, 0x94, 0xA5, 0x7C, 0xA1, 0x05, 0x58, 0x2D, 0xBD, 0xD9, 0xC7, 0xAF, 0x6B, 0x54, 0x0B, 0xE0, 0x38, - 0x04, 0xC8, 0x9D, 0xE7, 0x14, 0xB1, 0x87, 0x9C, 0xDF, 0x6F, 0xF9, 0xDA, 0x2A, 0xC4, 0x59, 0x16, 0x74, 0x91, 0xAB, 0x26, - 0x61, 0x76, 0x34, 0x2B, 0xAD, 0x99, 0xFB, 0x72, 0xEC, 0x33, 0x12, 0xDE, 0x98, 0x3B, 0xC0, 0x9B, 0x3E, 0x18, 0x10, 0x3A, - 0x56, 0xE1, 0x77, 0xC9, 0x1E, 0x9E, 0x95, 0xA3, 0x90, 0x19, 0xA8, 0x6C, 0x09, 0xD0, 0xF0, 0x86}; - void nas_stream_encrypt_eea2(nas_stream_cipher_t const *stream_cipher, uint8_t *out); +stream_security_context_t *stream_ciphering_init_eea2(const uint8_t *ciphering_key); +void stream_ciphering_free_eea2(stream_security_context_t *ciphering_context); + #endif diff --git a/openair3/SECU/nas_stream_eia1.c b/openair3/SECU/nas_stream_eia1.c index f080db7aac..c648ee585f 100644 --- a/openair3/SECU/nas_stream_eia1.c +++ b/openair3/SECU/nas_stream_eia1.c @@ -126,16 +126,17 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o uint64_t M_D_2; int rem_bits; uint32_t mask = 0; - uint32_t *message; + uint32_t *message; + uint8_t *key = (uint8_t *)stream_cipher->context; message = (uint32_t*)stream_cipher->message; /* To operate 32 bit message internally. */ /* Load the Integrity Key for SNOW3G initialization as in section 4.4. */ - memcpy(K+3,stream_cipher->key+0,4); /*K[3] = key[0]; we assume + memcpy(K+3,key+0,4); /*K[3] = key[0]; we assume K[3]=key[0]||key[1]||...||key[31] , with key[0] the * most important bit of key*/ - memcpy(K+2,stream_cipher->key+4,4); /*K[2] = key[1];*/ - memcpy(K+1,stream_cipher->key+8,4); /*K[1] = key[2];*/ - memcpy(K+0,stream_cipher->key+12,4); /*K[0] = key[3]; we assume + memcpy(K+2,key+4,4); /*K[2] = key[1];*/ + memcpy(K+1,key+8,4); /*K[1] = key[2];*/ + memcpy(K+0,key+12,4); /*K[0] = key[3]; we assume K[0]=key[96]||key[97]||...||key[127] , with key[127] the * least important bit of key*/ K[3] = hton_int32(K[3]); @@ -213,3 +214,16 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const *stream_cipher, uint8_t o MAC_I = hton_int32(MAC_I); memcpy(out, &MAC_I, 4); } + +stream_security_context_t *stream_integrity_init_eia1(const uint8_t *integrity_key) +{ + void *ret = calloc(1, 16); + AssertFatal(ret != NULL, "out of memory\n"); + memcpy(ret, integrity_key, 16); + return (stream_security_context_t *)ret; +} + +void stream_integrity_free_eia1(stream_security_context_t *integrity_context) +{ + free(integrity_context); +} diff --git a/openair3/SECU/nas_stream_eia1.h b/openair3/SECU/nas_stream_eia1.h index 58a7f8be99..a385781035 100644 --- a/openair3/SECU/nas_stream_eia1.h +++ b/openair3/SECU/nas_stream_eia1.h @@ -26,4 +26,7 @@ void nas_stream_encrypt_eia1(nas_stream_cipher_t const* stream_cipher, uint8_t out[4]); +stream_security_context_t *stream_integrity_init_eia1(const uint8_t *integrity_key); +void stream_integrity_free_eia1(stream_security_context_t *integrity_context); + #endif diff --git a/openair3/SECU/nas_stream_eia2.c b/openair3/SECU/nas_stream_eia2.c index 2655c8ad81..ee19a8f603 100644 --- a/openair3/SECU/nas_stream_eia2.c +++ b/openair3/SECU/nas_stream_eia2.c @@ -45,11 +45,11 @@ void nas_stream_encrypt_eia2(nas_stream_cipher_t const *stream_cipher, uint8_t o DevAssert(stream_cipher != NULL); DevAssert(stream_cipher->message != NULL); DevAssert(stream_cipher->bearer < 32); - DevAssert(stream_cipher->key_length == 16); DevAssert((stream_cipher->blength & 0x7) == 0); + cbc_cmac_ctx_t *ctx = (cbc_cmac_ctx_t *)stream_cipher->context; aes_128_t k_iv = {0}; - memcpy(k_iv.key, stream_cipher->key, sizeof(k_iv.key)); + memcpy(&k_iv.key, ctx->key, 16); k_iv.type = AES_INITIALIZATION_VECTOR_8; k_iv.iv8.d.bearer = stream_cipher->bearer; k_iv.iv8.d.direction = stream_cipher->direction; @@ -58,8 +58,21 @@ void nas_stream_encrypt_eia2(nas_stream_cipher_t const *stream_cipher, uint8_t o size_t const m_length = stream_cipher->blength >> 3; uint8_t result[16] = {0}; byte_array_t msg = {.buf = stream_cipher->message, .len = m_length }; - aes_128_cbc_cmac(&k_iv, msg, sizeof(result), result); + cipher_aes_128_cbc_cmac(ctx, &k_iv, msg, sizeof(result), result); memcpy(out, result, 4); } +stream_security_context_t *stream_integrity_init_eia2(const uint8_t *integrity_key) +{ + cbc_cmac_ctx_t *ret = calloc(1, sizeof(cbc_cmac_ctx_t)); + AssertFatal(ret != NULL, "out of memory\n"); + *ret = init_aes_128_cbc_cmac(integrity_key); + return (stream_security_context_t *)ret; +} + +void stream_integrity_free_eia2(stream_security_context_t *integrity_context) +{ + free_aes_128_cbc_cmac((cbc_cmac_ctx_t *)integrity_context); + free(integrity_context); +} diff --git a/openair3/SECU/nas_stream_eia2.h b/openair3/SECU/nas_stream_eia2.h index 1349408fb7..b3da1d14a4 100644 --- a/openair3/SECU/nas_stream_eia2.h +++ b/openair3/SECU/nas_stream_eia2.h @@ -26,4 +26,7 @@ void nas_stream_encrypt_eia2(nas_stream_cipher_t const* stream_cipher, uint8_t out[4]); +stream_security_context_t *stream_integrity_init_eia2(const uint8_t *integrity_key); +void stream_integrity_free_eia2(stream_security_context_t *integrity_context); + #endif diff --git a/openair3/SECU/secu_defs.c b/openair3/SECU/secu_defs.c index 58a8754bad..17e3ca96ec 100644 --- a/openair3/SECU/secu_defs.c +++ b/openair3/SECU/secu_defs.c @@ -64,3 +64,70 @@ void stream_compute_encrypt(eea_alg_id_e alg, nas_stream_cipher_t const* stream_ } } +stream_security_context_t *stream_integrity_init(int integrity_algorithm, const uint8_t *integrity_key) +{ + switch (integrity_algorithm) { + case EEA0_ALG_ID: return NULL; + case EEA1_128_ALG_ID: return stream_integrity_init_eia1(integrity_key); + case EEA2_128_ALG_ID: return stream_integrity_init_eia2(integrity_key); + default: AssertFatal(0, "unsupported integrity algorithm\n"); + } +} + +void stream_integrity_free(int integrity_algorithm, stream_security_context_t *integrity_context) +{ + switch (integrity_algorithm) { + case EEA0_ALG_ID: return; + case EEA1_128_ALG_ID: return stream_integrity_free_eia1(integrity_context); + case EEA2_128_ALG_ID: return stream_integrity_free_eia2(integrity_context); + default: AssertFatal(0, "unsupported integrity algorithm\n"); + } +} + +stream_security_context_t *stream_ciphering_init(int ciphering_algorithm, const uint8_t *ciphering_key) +{ + switch (ciphering_algorithm) { + case EEA0_ALG_ID: return NULL; + case EEA1_128_ALG_ID: return stream_ciphering_init_eea1(ciphering_key); + case EEA2_128_ALG_ID: return stream_ciphering_init_eea2(ciphering_key); + default: AssertFatal(0, "unsupported ciphering algorithm\n"); + } +} + +void stream_ciphering_free(int ciphering_algorithm, stream_security_context_t *ciphering_context) +{ + switch (ciphering_algorithm) { + case EEA0_ALG_ID: return; + case EEA1_128_ALG_ID: return stream_ciphering_free_eea1(ciphering_context); + case EEA2_128_ALG_ID: return stream_ciphering_free_eea2(ciphering_context); + default: AssertFatal(0, "unsupported ciphering algorithm\n"); + } +} + +stream_security_container_t *stream_security_container_init(int ciphering_algorithm, + int integrity_algorithm, + const uint8_t *ciphering_key, + const uint8_t *integrity_key) +{ + stream_security_container_t *container = calloc(1, sizeof(*container)); + AssertFatal(container != NULL, "out of memory\n"); + + container->integrity_algorithm = integrity_algorithm; + container->ciphering_algorithm = ciphering_algorithm; + + container->integrity_context = stream_integrity_init(integrity_algorithm, integrity_key); + container->ciphering_context = stream_ciphering_init(ciphering_algorithm, ciphering_key); + + return container; +} + +void stream_security_container_delete(stream_security_container_t *container) +{ + /* passing NULL is accepted */ + if (container == NULL) + return; + + stream_integrity_free(container->integrity_algorithm, container->integrity_context); + stream_ciphering_free(container->ciphering_algorithm, container->ciphering_context); + free(container); +} diff --git a/openair3/SECU/secu_defs.h b/openair3/SECU/secu_defs.h index 7b96544bd5..bfd3a943ce 100644 --- a/openair3/SECU/secu_defs.h +++ b/openair3/SECU/secu_defs.h @@ -28,17 +28,46 @@ #define SECU_DIRECTION_UPLINK 0 #define SECU_DIRECTION_DOWNLINK 1 +/* stream_security_context_t is an opaque structure. + * It is different for each integrity and ciphering algorithm in use. + * Defined as a struct to have compilation time type checking + * (the "context" field is never actually used). + */ typedef struct { - uint8_t *key; - uint32_t key_length; + void *context; +} stream_security_context_t; + +/* stream_security_container_t contains the current configuration + * of integrity and ciphering. It is used by PDCP and NAS. + */ +typedef struct { + int integrity_algorithm; + int ciphering_algorithm; + stream_security_context_t *ciphering_context; + stream_security_context_t *integrity_context; +} stream_security_container_t; + +typedef struct { + stream_security_context_t *context; uint32_t count; uint8_t bearer; uint8_t direction; uint8_t *message; /* length in bits */ - uint32_t blength; + uint32_t blength; } nas_stream_cipher_t; +stream_security_context_t *stream_integrity_init(int integrity_algorithm, const uint8_t *integrity_key); +stream_security_context_t *stream_ciphering_init(int ciphering_algorithm, const uint8_t *ciphering_key); +void stream_integrity_free(int integrity_algorithm, stream_security_context_t *integrity_context); +void stream_ciphering_free(int ciphering_algorithm, stream_security_context_t *ciphering_context); + +stream_security_container_t *stream_security_container_init(int ciphering_algorithm, + int integrity_algorithm, + const uint8_t *ciphering_key, + const uint8_t *integrity_key); +void stream_security_container_delete(stream_security_container_t *container); + /*! * @brief Encrypt/Decrypt a block of data based on the provided algorithm * @param[in] algorithm Algorithm used to encrypt the data