mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Implement SUCI Profile Scheme A for 5G UE
Extend UICC configuration parsing to provide: routing_indicator, protection_scheme, home_network_public_key, and home_network_public_key_id. Use the protection_scheme value to decide what SUCI Profile Scheme to apply during SUCI generation. Add support for Profile Scheme A which provides ECIES-based encryption using Curve25519 and X9.63 KDF as outlined in TS 33.501 Section C.3.4.1 Profile A. When a configuration file specifies an unsupported Profile Scheme, the NAS layer triggers a fatal error. This occurs either because Profile Scheme B is unimplemented or the build uses OpenSSL < 3.0, which lacks Curve25519 and X9.63 KDF support, ensuring users are informed of the incompatibility.
This commit is contained in:
@@ -674,6 +674,8 @@ target_link_libraries(UTIL PUBLIC instrumentation)
|
||||
|
||||
set(SECURITY_SRC
|
||||
${OPENAIR3_DIR}/SECU/secu_defs.c
|
||||
${OPENAIR3_DIR}/SECU/curve_25519.c
|
||||
${OPENAIR3_DIR}/SECU/x963_kdf.c
|
||||
${OPENAIR3_DIR}/SECU/kdf.c
|
||||
${OPENAIR3_DIR}/SECU/aes_128_ctr.c
|
||||
${OPENAIR3_DIR}/SECU/aes_128_cbc_cmac.c
|
||||
@@ -1911,7 +1913,7 @@ target_link_libraries(nr-uesoftmodem PRIVATE
|
||||
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE pthread m CONFIG_LIB rt nr_ue_phy_meas)
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE ${T_LIB})
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE nr_nas lib_uicc usim_lib)
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE nr_nas lib_uicc usim_lib SECURITY)
|
||||
target_link_libraries(nr-uesoftmodem PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
# force the generation of ASN.1 so that we don't need to wait during the build
|
||||
|
||||
@@ -80,6 +80,8 @@ add_boolean_option(NAS_BUILT_IN_UE False "UE NAS layer present in this
|
||||
# SECU LIB
|
||||
################################################################################
|
||||
set(secu_cn_SRC
|
||||
${OPENAIR3_DIR}/SECU/curve_25519.c
|
||||
${OPENAIR3_DIR}/SECU/x963_kdf.c
|
||||
${OPENAIR3_DIR}/SECU/aes_128_ctr.c
|
||||
${OPENAIR3_DIR}/SECU/aes_128_cbc_cmac.c
|
||||
${OPENAIR3_DIR}/SECU/sha_256_hmac.c
|
||||
|
||||
@@ -94,6 +94,51 @@ char *itoa(int i) {
|
||||
return strdup(buffer);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** **
|
||||
** Name: digit_string_to_bcd_value() **
|
||||
** **
|
||||
** Description: Converts a decimal ASCII coded string into its BCD encoded**
|
||||
** value. **
|
||||
** **
|
||||
** Inputs: bcd_value: Output buffer **
|
||||
** digit_string: Input digit string **
|
||||
** size: Size of bcd_value in bytes **
|
||||
** **
|
||||
** Outputs: bcd_value: Converted BCD value **
|
||||
** Return: 0 on success, -1 on error **
|
||||
** **
|
||||
***************************************************************************/
|
||||
int digit_string_to_bcd_value(uint8_t *bcd_value, const char *digit_string, int size)
|
||||
{
|
||||
int i;
|
||||
uint8_t len = strlen(digit_string);
|
||||
|
||||
/* Accept even (size*2) or odd (size*2 - 1) digit counts */
|
||||
if (len < size * 2 - 1 || len > size * 2) {
|
||||
fprintf(stderr, "the string '%s' should be of length %d or %d\n", digit_string, size * 2 - 1, size * 2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
uint8_t low = digit_string[2 * i] - '0';
|
||||
uint8_t high = (2 * i + 1 < len) ? digit_string[2 * i + 1] - '0' : 0xF;
|
||||
|
||||
if (low > 9 || (high > 9 && high != 0xF))
|
||||
goto error;
|
||||
|
||||
bcd_value[i] = (high << 4) | low;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
fprintf(stderr, "the string '%s' is not a valid digit string\n", digit_string);
|
||||
for (i = 0; i < size; i++)
|
||||
bcd_value[i] = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Convert a version string x.y.z into numbers.
|
||||
*
|
||||
|
||||
@@ -123,6 +123,8 @@ static inline void *malloc_or_fail(size_t size)
|
||||
int hex_char_to_hex_value (char c);
|
||||
// Converts an hexadecimal ASCII coded string into its value.**
|
||||
int hex_string_to_hex_value (uint8_t *hex_value, const char *hex_string, int size);
|
||||
// Converts a decimal ASCII coded string into its BCD encoded value.
|
||||
int digit_string_to_bcd_value(uint8_t *bcd_value, const char *digit_string, int size);
|
||||
|
||||
/* Map task id to printable name. */
|
||||
typedef struct {
|
||||
|
||||
62
doc/5Gnas.md
62
doc/5Gnas.md
@@ -78,18 +78,22 @@ The simulation reads values from a named section in the config file.
|
||||
|
||||
**Config options in the `uicc` section**:
|
||||
|
||||
| Parameter | Description | Default value |
|
||||
|---------------|-----------------------------------|--------------------------------------------|
|
||||
| `imsi` | User IMSI | `2089900007487` |
|
||||
| `nmc_size` | Number of digits in NMC | `2` |
|
||||
| `key` | Subscription key (Ki) | `fec86ba6eb707ed08905757b1bb44b8f` |
|
||||
| `opc` | OPc value | `c42449363bbad02b66d16bc975d77cc1` |
|
||||
| `amf` | AMF value | `8000` |
|
||||
| `sqn` | Sequence number | `000000` |
|
||||
| `dnn` | Default DNN (APN) | `oai` |
|
||||
| `nssai_sst` | NSSAI slice/service type | `1` |
|
||||
| `nssai_sd` | NSSAI slice differentiator | `0xffffff` |
|
||||
| `imeisv` | IMEISV string | `6754567890123413` |
|
||||
| Parameter | Description | Default value |
|
||||
|------------------------------|-----------------------------------|--------------------------------------------------------------------|
|
||||
| `imsi` | User IMSI | `2089900007487` |
|
||||
| `nmc_size` | Number of digits in NMC | `2` |
|
||||
| `key` | Subscription key (Ki) | `fec86ba6eb707ed08905757b1bb44b8f` |
|
||||
| `opc` | OPc value | `c42449363bbad02b66d16bc975d77cc1` |
|
||||
| `amf` | AMF value | `8000` |
|
||||
| `sqn` | Sequence number | `000000` |
|
||||
| `dnn` | Default DNN (APN) | `oai` |
|
||||
| `nssai_sst` | NSSAI slice/service type | `1` |
|
||||
| `nssai_sd` | NSSAI slice differentiator | `0xffffff` |
|
||||
| `imeisv` | IMEISV string | `6754567890123413` |
|
||||
| `routing_indicator` | Routing Indicator | `0000` |
|
||||
| `protection_scheme` | SUCI Profile Scheme | `0` |
|
||||
| `home_network_public_key_id` | Home Network Public Key ID | `1` |
|
||||
| `home_network_public_key` | Home Network Public Key | `5a8d38864820197c3394b92613b20b91633cbd897119273bf8e4a6f4eec0a650` |
|
||||
|
||||
These are parsed and stored in the `uicc_t` structure.
|
||||
|
||||
@@ -116,3 +120,37 @@ The **IMEISV**, is encoded using the `fill_imeisv()` helper. This function extra
|
||||
|
||||
See TS 24.501 §4.4 for reference.
|
||||
|
||||
#### SUCI (Subscription Concealed Identifier)
|
||||
|
||||
The **SUCI**, is generated using the `fill_suci()` helper. This function extracts the MCC, MNC, and MSIN from the configured `imsi` with the use of `nmc_size` in the UICC context and populates the mobile identity structure.
|
||||
|
||||
Contains:
|
||||
* MCC and MNC (public network identity)
|
||||
* Routing Indicator
|
||||
* Protection Scheme ID
|
||||
* Home Network Public Key ID
|
||||
* Concealed or clear MSIN depending on the protection scheme
|
||||
|
||||
If the UE is unable to generate SUCI due to configuration or crypto limitations, the UE will fail to generate a `Registration Request`.
|
||||
|
||||
###### 0. Null Scheme (TS 33.501 §C.2)
|
||||
|
||||
MSIN in cleartext.
|
||||
|
||||
###### 1. Profile A (TS 33.501 §C.3.4.1)
|
||||
|
||||
MSIN is concealed using elliptic curve cryptography.
|
||||
Based on:
|
||||
* Curve25519 for key agreement
|
||||
* X9.63 KDF for key derivation
|
||||
|
||||
(requires OpenSSL ≥ 3.0)
|
||||
|
||||
###### 2. Profile B (TS 33.501 §C.3.4.2)
|
||||
|
||||
MSIN is concealed using elliptic curve cryptography.
|
||||
Based on:
|
||||
* P-256 for key agreement
|
||||
* X9.63 KDF for key derivation
|
||||
|
||||
(currently not supported)
|
||||
|
||||
@@ -1066,6 +1066,8 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NGAP/ngap_gNB_overload.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/NGAP/ngap_gNB_default_values.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/secu_defs.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/curve_25519.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/x963_kdf.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/sha_256_hmac.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/nas_stream_eea0.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/aes_128_ecb.h \
|
||||
@@ -1088,6 +1090,8 @@ INPUT = \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/aes_128_ctr.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/nas_stream_eia2.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/snow3g.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/curve_25519.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/x963_kdf.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/sha_256_hmac.c \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/aes_128_cbc_cmac.h \
|
||||
@CMAKE_CURRENT_SOURCE_DIR@/../openair3/SECU/nas_stream_eia1.c \
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
static int decode_guti_5gs_mobile_identity(Guti5GSMobileIdentity_t *guti, const uint8_t *buffer);
|
||||
|
||||
static int encode_guti_5gs_mobile_identity(const Guti5GSMobileIdentity_t *guti, uint8_t *buffer);
|
||||
static int encode_suci_5gs_mobile_identity(const Suci5GSMobileIdentity_t *suci, uint8_t *buffer);
|
||||
static int encode_suci_5gs_mobile_identity(const Suci5GSMobileIdentity_t *suci, uint8_t *buffer, uint32_t len);
|
||||
static int encode_imeisv_5gs_mobile_identity(const Imeisv5GSMobileIdentity_t *imeisv, uint8_t *buffer);
|
||||
|
||||
int encode_stmsi_5gs_mobile_identity(uint8_t *buffer, const Stmsi5GSMobileIdentity_t *stmsi, uint32_t len)
|
||||
@@ -121,7 +121,7 @@ int encode_5gs_mobile_identity(const FGSMobileIdentity *fgsmobileidentity, uint8
|
||||
}
|
||||
|
||||
if (fgsmobileidentity->suci.typeofidentity == FGS_MOBILE_IDENTITY_SUCI) {
|
||||
encoded_rc = encode_suci_5gs_mobile_identity(&fgsmobileidentity->suci, buffer + encoded);
|
||||
encoded_rc = encode_suci_5gs_mobile_identity(&fgsmobileidentity->suci, buffer + encoded, len);
|
||||
}
|
||||
|
||||
if (fgsmobileidentity->imeisv.typeofidentity == FGS_MOBILE_IDENTITY_IMEISV) {
|
||||
@@ -218,9 +218,13 @@ static int encode_guti_5gs_mobile_identity(const Guti5GSMobileIdentity_t *guti,
|
||||
return encoded;
|
||||
}
|
||||
|
||||
static int encode_suci_5gs_mobile_identity(const Suci5GSMobileIdentity_t *suci, uint8_t *buffer)
|
||||
static int encode_suci_5gs_mobile_identity(const Suci5GSMobileIdentity_t *suci, uint8_t *buffer, uint32_t len)
|
||||
{
|
||||
uint32_t encoded = 0;
|
||||
|
||||
if (len < 8)
|
||||
return -1;
|
||||
|
||||
*(buffer + encoded) = (suci->supiformat << 4) | (suci->typeofidentity);
|
||||
encoded++;
|
||||
*(buffer + encoded) = ((suci->mccdigit2 & 0xf) << 4) | (suci->mccdigit1 & 0xf);
|
||||
@@ -242,15 +246,34 @@ static int encode_suci_5gs_mobile_identity(const Suci5GSMobileIdentity_t *suci,
|
||||
*(buffer + encoded) = suci->homenetworkpki;
|
||||
encoded++;
|
||||
|
||||
const char *ptr = suci->schemeoutput;
|
||||
while (ptr < suci->schemeoutput + strlen(suci->schemeoutput)) {
|
||||
buffer[encoded] = ((*(ptr + 1) - '0') << 4) | (*(ptr) - '0');
|
||||
encoded++;
|
||||
ptr += 2;
|
||||
}
|
||||
DevAssert(suci->schemeoutput);
|
||||
size_t rawlen = strlen(suci->schemeoutput);
|
||||
size_t outlen = (rawlen + 1) / 2;
|
||||
|
||||
if (strlen(suci->schemeoutput) % 2 == 1)
|
||||
buffer[encoded++] = ((*(ptr - 1) - '0')) | 0xF0;
|
||||
if (len - encoded < outlen)
|
||||
return -1;
|
||||
|
||||
if (suci->protectionschemeId == 0) {
|
||||
AssertFatal(suci->homenetworkpki == 0,
|
||||
"Invalid SUCI: homenetworkpki=%u with null protection scheme (must be 0)\n",
|
||||
suci->homenetworkpki);
|
||||
int rc = digit_string_to_bcd_value(buffer + encoded, suci->schemeoutput, outlen);
|
||||
AssertFatal(rc == 0,
|
||||
"BCD encoding failed (rc=%d, input=\"%s\", len=%zu, out_len=%zu)\n",
|
||||
rc,
|
||||
suci->schemeoutput,
|
||||
rawlen,
|
||||
outlen);
|
||||
} else {
|
||||
int rc = hex_string_to_hex_value(buffer + encoded, suci->schemeoutput, outlen);
|
||||
AssertFatal(rc == 0,
|
||||
"Encoding SUCI schemeoutput failed (rc=%d, input=\"%s\", len=%zu, out_len=%zu)\n",
|
||||
rc,
|
||||
suci->schemeoutput,
|
||||
rawlen,
|
||||
outlen);
|
||||
}
|
||||
encoded += outlen;
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct {
|
||||
uint8_t spare6: 1;
|
||||
uint8_t protectionschemeId: 4;
|
||||
uint8_t homenetworkpki;
|
||||
char schemeoutput[32];
|
||||
char schemeoutput[128];
|
||||
} Suci5GSMobileIdentity_t;
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "nr_nas_msg.h"
|
||||
#include <netinet/in.h>
|
||||
#include "NR_NAS_defs.h"
|
||||
#include <openssl/opensslv.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -53,6 +54,18 @@
|
||||
#include "key_nas_deriver.h"
|
||||
#include "nr-uesoftmodem.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#include "curve_25519.h"
|
||||
#include "aes_128_ctr.h"
|
||||
#include "x963_kdf.h"
|
||||
#include "sha_256_hmac.h"
|
||||
static const char hex[] = "0123456789abcdef";
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
#define MY_OPENSSL_VERSION_STR OpenSSL_version(OPENSSL_VERSION)
|
||||
#else
|
||||
#define MY_OPENSSL_VERSION_STR SSLeay_version(SSLEAY_VERSION)
|
||||
#endif
|
||||
|
||||
static nr_ue_nas_t nr_ue_nas[MAX_NUM_NR_UE_INST] = {0};
|
||||
|
||||
nr_ue_nas_t *get_nr_ue_nas_info(uint8_t ue_inst)
|
||||
@@ -388,6 +401,83 @@ static security_state_t nas_security_rx_process(nr_ue_nas_t *nas, byte_array_t b
|
||||
return NAS_SECURITY_INTEGRITY_PASSED;
|
||||
}
|
||||
|
||||
static void suci_profile_scheme_a_generate_output(const uint8_t home_network_public_key[32],
|
||||
const char *msin,
|
||||
const size_t msin_len,
|
||||
char *schemeoutput)
|
||||
{
|
||||
/* 1> Eph. key pair generation */
|
||||
uint8_t eph_priv[32] = {0};
|
||||
uint8_t eph_pub[32] = {0};
|
||||
x25519_generate_keypair(eph_priv, eph_pub);
|
||||
|
||||
/* 2> Key agreement */
|
||||
uint8_t eph_shared_key[32] = {0};
|
||||
x25519_shared_secret(eph_priv, home_network_public_key, eph_shared_key);
|
||||
|
||||
explicit_bzero(eph_priv, 32);
|
||||
|
||||
/* 3> Key derivation */
|
||||
uint8_t kdf_output[64] = {0};
|
||||
byte_array_t kdf_secret = {.buf = eph_shared_key, .len = 32};
|
||||
byte_array_t kdf_info = {.buf = eph_pub, .len = 32};
|
||||
x963_kdf(kdf_secret, kdf_info, 64, kdf_output);
|
||||
|
||||
explicit_bzero(eph_shared_key, 32);
|
||||
|
||||
aes_128_t aes_ctx;
|
||||
aes_ctx.type = AES_INITIALIZATION_VECTOR_16;
|
||||
memcpy(aes_ctx.key, kdf_output, 16);
|
||||
memcpy(aes_ctx.iv16.iv, kdf_output + 16, 16);
|
||||
|
||||
uint8_t eph_mac_key[32] = {0};
|
||||
memcpy(eph_mac_key, kdf_output + 32, 32);
|
||||
|
||||
explicit_bzero(kdf_output, 64);
|
||||
|
||||
/* 4> Symmetric encryption */
|
||||
size_t msin_bcd_len = (msin_len + 1) / 2;
|
||||
uint8_t msin_bcd[msin_bcd_len];
|
||||
memset(msin_bcd, 0, msin_bcd_len);
|
||||
|
||||
int rc = digit_string_to_bcd_value(msin_bcd, msin, msin_bcd_len);
|
||||
AssertFatal(rc == 0, "Encoding MSIN failed (rc=%d, input=\"%s\", len=%zu, out_len=%zu)", rc, msin, msin_len, msin_bcd_len);
|
||||
|
||||
byte_array_t payload = {.buf = msin_bcd, .len = msin_bcd_len};
|
||||
uint8_t ciphertext[msin_bcd_len];
|
||||
aes_128_ctr(&aes_ctx, payload, msin_bcd_len, ciphertext);
|
||||
|
||||
explicit_bzero(aes_ctx.key, 16);
|
||||
explicit_bzero(aes_ctx.iv16.iv, 16);
|
||||
explicit_bzero(msin_bcd, msin_bcd_len);
|
||||
|
||||
/* 5> MAC function */
|
||||
uint8_t mac_full[32] = {0};
|
||||
byte_array_t mac_input = {.buf = ciphertext, .len = msin_bcd_len};
|
||||
sha_256_hmac(eph_mac_key, mac_input, 32, mac_full);
|
||||
|
||||
explicit_bzero(eph_mac_key, 32);
|
||||
|
||||
/* Build SUCI scheme output --- */
|
||||
/* eph_pub (32 bytes -> 64 hex chars) */
|
||||
for (int i = 0; i < 32; i++) {
|
||||
*schemeoutput++ = hex[eph_pub[i] >> 4];
|
||||
*schemeoutput++ = hex[eph_pub[i] & 0x0F];
|
||||
}
|
||||
|
||||
/* ciphertext (~45 bytes -> ~90 hex chars) */
|
||||
for (int i = 0; i < msin_bcd_len; i++) {
|
||||
*schemeoutput++ = hex[ciphertext[i] >> 4];
|
||||
*schemeoutput++ = hex[ciphertext[i] & 0x0F];
|
||||
}
|
||||
|
||||
/* MAC (8 bytes -> 16 hex chars) */
|
||||
for (int i = 0; i < 8; i++) {
|
||||
*schemeoutput++ = hex[mac_full[i] >> 4];
|
||||
*schemeoutput++ = hex[mac_full[i] & 0x0F];
|
||||
}
|
||||
}
|
||||
|
||||
static int fill_suci(FGSMobileIdentity *mi, const uicc_t *uicc)
|
||||
{
|
||||
mi->suci.typeofidentity = FGS_MOBILE_IDENTITY_SUCI;
|
||||
@@ -397,7 +487,50 @@ static int fill_suci(FGSMobileIdentity *mi, const uicc_t *uicc)
|
||||
mi->suci.mccdigit1 = uicc->imsiStr[0] - '0';
|
||||
mi->suci.mccdigit2 = uicc->imsiStr[1] - '0';
|
||||
mi->suci.mccdigit3 = uicc->imsiStr[2] - '0';
|
||||
memcpy(mi->suci.schemeoutput, uicc->imsiStr + 3 + uicc->nmc_size, strlen(uicc->imsiStr) - (3 + uicc->nmc_size));
|
||||
|
||||
mi->suci.routingindicatordigit1 = uicc->routing_indicatorStr[0] - '0';
|
||||
mi->suci.routingindicatordigit2 = uicc->routing_indicatorStr[1] - '0';
|
||||
mi->suci.routingindicatordigit3 = uicc->routing_indicatorStr[2] - '0';
|
||||
mi->suci.routingindicatordigit4 = uicc->routing_indicatorStr[3] - '0';
|
||||
|
||||
char *msin = uicc->imsiStr + 3 + uicc->nmc_size;
|
||||
uint8_t msin_len = strlen(msin);
|
||||
|
||||
mi->suci.protectionschemeId = uicc->protection_scheme;
|
||||
switch (uicc->protection_scheme) {
|
||||
case 0: /* Null scheme (TS 33.501 C.2) */
|
||||
{
|
||||
mi->suci.homenetworkpki = 0;
|
||||
memcpy(mi->suci.schemeoutput, msin, msin_len);
|
||||
break;
|
||||
}
|
||||
case 1: /* Profile A (TS 33.501 C.3.4.1) */
|
||||
{
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
mi->suci.homenetworkpki = uicc->home_network_public_key_id;
|
||||
suci_profile_scheme_a_generate_output(uicc->home_network_public_key, msin, msin_len, mi->suci.schemeoutput);
|
||||
#else
|
||||
AssertFatal(false,
|
||||
"Protection Scheme not supported when using a version below OpenSSL 3.0 %d (OpenSSL version: %s)\n",
|
||||
uicc->protection_scheme,
|
||||
MY_OPENSSL_VERSION_STR);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
case 2: /* Profile B (TS 33.501 C.3.4.2) */
|
||||
{
|
||||
mi->suci.homenetworkpki = uicc->home_network_public_key_id;
|
||||
|
||||
AssertFatal(false, "Unsupported Protection Scheme in UICC %d\n", uicc->protection_scheme);
|
||||
|
||||
break;
|
||||
}
|
||||
default: // Unknown schemes
|
||||
{
|
||||
AssertFatal(false, "Unknown Protection Scheme in UICC %d\n", uicc->protection_scheme);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_D(NAS,
|
||||
"SUCI in registration request: SUPI type: %d Type of Identity: %u MCC: %u%u%u, MNC: %u%u%u, \
|
||||
Routing Indicator %d%d%d%d Protection Scheme ID: %u, Home Network PKI: %u, Scheme Output: %s\n",
|
||||
|
||||
74
openair3/SECU/curve_25519.c
Normal file
74
openair3/SECU/curve_25519.c
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "curve_25519.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/* code for version 3.0 or greater */
|
||||
|
||||
#include "common/utils/assertions.h"
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/core_names.h>
|
||||
|
||||
void x25519_generate_keypair(uint8_t priv[32], uint8_t pub[32])
|
||||
{
|
||||
DevAssert(priv != NULL);
|
||||
DevAssert(pub != NULL);
|
||||
|
||||
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_X25519, NULL);
|
||||
DevAssert(pctx != NULL);
|
||||
|
||||
int rc = EVP_PKEY_keygen_init(pctx);
|
||||
DevAssert(rc == 1);
|
||||
|
||||
EVP_PKEY *pkey = NULL;
|
||||
rc = EVP_PKEY_keygen(pctx, &pkey);
|
||||
DevAssert(rc == 1);
|
||||
|
||||
EVP_PKEY_CTX_free(pctx);
|
||||
|
||||
size_t len = 32;
|
||||
|
||||
rc = EVP_PKEY_get_raw_private_key(pkey, priv, &len);
|
||||
DevAssert(rc == 1 && len == 32);
|
||||
|
||||
rc = EVP_PKEY_get_raw_public_key(pkey, pub, &len);
|
||||
DevAssert(rc == 1 && len == 32);
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
|
||||
void x25519_shared_secret(const uint8_t priv[32], const uint8_t peer_pub[32], uint8_t secret[32])
|
||||
{
|
||||
DevAssert(priv != NULL);
|
||||
DevAssert(peer_pub != NULL);
|
||||
DevAssert(secret != NULL);
|
||||
|
||||
EVP_PKEY *pkey = EVP_PKEY_new_raw_private_key(EVP_PKEY_X25519, NULL, priv, 32);
|
||||
DevAssert(pkey != NULL);
|
||||
|
||||
EVP_PKEY *peerkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_X25519, NULL, peer_pub, 32);
|
||||
DevAssert(peerkey != NULL);
|
||||
|
||||
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||
DevAssert(ctx != NULL);
|
||||
|
||||
int rc = EVP_PKEY_derive_init(ctx);
|
||||
DevAssert(rc == 1);
|
||||
|
||||
rc = EVP_PKEY_derive_set_peer(ctx, peerkey);
|
||||
DevAssert(rc == 1);
|
||||
|
||||
size_t len = 32;
|
||||
rc = EVP_PKEY_derive(ctx, secret, &len);
|
||||
DevAssert(rc == 1 && len == 32);
|
||||
|
||||
EVP_PKEY_free(pkey);
|
||||
EVP_PKEY_free(peerkey);
|
||||
EVP_PKEY_CTX_free(ctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
23
openair3/SECU/curve_25519.h
Normal file
23
openair3/SECU/curve_25519.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef CURVE_25519_OAI_H
|
||||
#define CURVE_25519_OAI_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/* code for version 3.0 or greater */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
void x25519_generate_keypair(uint8_t priv[32], uint8_t pub[32]);
|
||||
|
||||
void x25519_shared_secret(const uint8_t priv[32], const uint8_t peer_pub[32], uint8_t secret[32]);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
49
openair3/SECU/x963_kdf.c
Normal file
49
openair3/SECU/x963_kdf.c
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#include "x963_kdf.h"
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/* code for version 3.0 or greater */
|
||||
|
||||
#include <string.h>
|
||||
#include "common/utils/assertions.h"
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
#include <openssl/core_names.h>
|
||||
|
||||
void x963_kdf(const byte_array_t sharedsecret, const byte_array_t sharedinfo, size_t len, uint8_t out[len])
|
||||
{
|
||||
DevAssert(sharedsecret.buf != NULL);
|
||||
DevAssert(sharedsecret.len > 0);
|
||||
DevAssert(out != NULL);
|
||||
DevAssert(len > 0);
|
||||
|
||||
EVP_KDF *kdf = EVP_KDF_fetch(NULL, "X963KDF", NULL);
|
||||
DevAssert(kdf != NULL);
|
||||
|
||||
EVP_KDF_CTX *kctx = EVP_KDF_CTX_new(kdf);
|
||||
DevAssert(kctx != NULL);
|
||||
|
||||
EVP_KDF_free(kdf);
|
||||
|
||||
OSSL_PARAM params[4], *p = params;
|
||||
|
||||
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST, SN_sha256, strlen(SN_sha256));
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY, sharedsecret.buf, sharedsecret.len);
|
||||
|
||||
if (sharedinfo.buf != NULL && sharedinfo.len > 0) {
|
||||
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO, sharedinfo.buf, sharedinfo.len);
|
||||
}
|
||||
|
||||
*p = OSSL_PARAM_construct_end();
|
||||
|
||||
int rc = EVP_KDF_derive(kctx, out, len, params);
|
||||
DevAssert(rc == 1);
|
||||
|
||||
EVP_KDF_CTX_free(kctx);
|
||||
}
|
||||
|
||||
#endif
|
||||
23
openair3/SECU/x963_kdf.h
Normal file
23
openair3/SECU/x963_kdf.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: LicenseRef-CSSL-1.0
|
||||
*/
|
||||
|
||||
#ifndef x963_KDF_OAI_H
|
||||
#define x963_KDF_OAI_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
|
||||
/* code for version 3.0 or greater */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "byte_array.h"
|
||||
|
||||
void x963_kdf(const byte_array_t sharedsecret, const byte_array_t sharedinfo, size_t len, uint8_t out[len]);
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -14,21 +14,26 @@ extern uint16_t NB_UE_INST;
|
||||
" key: cyphering key\n"\
|
||||
" opc: cyphering OPc\n"\
|
||||
" imiesv: string with IMEISV value\n"
|
||||
#define DEFAULT_HOME_NETWORK_PUBLIC_KEY "5a8d38864820197c3394b92613b20b91633cbd897119273bf8e4a6f4eec0a650"
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
/* configuration parameters for the rfsimulator device */
|
||||
/* optname helpstr paramflags XXXptr defXXXval type numelt */
|
||||
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
|
||||
#define UICC_PARAMS_DESC { \
|
||||
{"imsi", "USIM IMSI\n", 0, .strptr=&uicc->imsiStr, .defstrval="2089900007487", TYPE_STRING, 0 }, \
|
||||
{"nmc_size" "number of digits in NMC", 0, .iptr=&uicc->nmc_size, .defintval=2, TYPE_INT, 0 }, \
|
||||
{"key", "USIM Ki\n", 0, .strptr=&uicc->keyStr, .defstrval="fec86ba6eb707ed08905757b1bb44b8f", TYPE_STRING, 0 }, \
|
||||
{"opc", "USIM OPc\n", 0, .strptr=&uicc->opcStr, .defstrval="c42449363bbad02b66d16bc975d77cc1", TYPE_STRING, 0 }, \
|
||||
{"amf", "USIM amf\n", 0, .strptr=&uicc->amfStr, .defstrval="8000", TYPE_STRING, 0 }, \
|
||||
{"sqn", "USIM sqn\n", 0, .strptr=&uicc->sqnStr, .defstrval="000000", TYPE_STRING, 0 }, \
|
||||
{"dnn", "UE dnn (apn)\n", 0, .strptr=&uicc->dnnStr, .defstrval="oai", TYPE_STRING, 0 }, \
|
||||
{"nssai_sst", "UE nssai\n", 0, .iptr=&uicc->nssai_sst, .defintval=1, TYPE_INT, 0 }, \
|
||||
{"nssai_sd", "UE nssai\n", 0, .iptr=&uicc->nssai_sd, .defintval=0xffffff, TYPE_INT, 0 }, \
|
||||
{"imeisv", "IMEISV\n", 0, .strptr=&uicc->imeisvStr, .defstrval="6754567890123413", TYPE_STRING, 0 }, \
|
||||
#define UICC_PARAMS_DESC { \
|
||||
{"imsi", "USIM IMSI\n", 0, .strptr=&uicc->imsiStr, .defstrval="2089900007487", TYPE_STRING, 0}, \
|
||||
{"nmc_size", "number of digits in NMC", 0, .iptr=&uicc->nmc_size, .defintval=2, TYPE_INT, 0}, \
|
||||
{"key", "USIM Ki\n", 0, .strptr=&uicc->keyStr, .defstrval="fec86ba6eb707ed08905757b1bb44b8f", TYPE_STRING, 0}, \
|
||||
{"opc", "USIM OPc\n", 0, .strptr=&uicc->opcStr, .defstrval="c42449363bbad02b66d16bc975d77cc1", TYPE_STRING, 0}, \
|
||||
{"amf", "USIM amf\n", 0, .strptr=&uicc->amfStr, .defstrval="8000", TYPE_STRING, 0}, \
|
||||
{"sqn", "USIM sqn\n", 0, .strptr=&uicc->sqnStr, .defstrval="000000", TYPE_STRING, 0}, \
|
||||
{"dnn", "UE dnn (apn)\n", 0, .strptr=&uicc->dnnStr, .defstrval="oai", TYPE_STRING, 0}, \
|
||||
{"nssai_sst", "UE nssai\n", 0, .iptr=&uicc->nssai_sst, .defintval=1, TYPE_INT, 0}, \
|
||||
{"nssai_sd", "UE nssai\n", 0, .iptr=&uicc->nssai_sd, .defintval=0xffffff, TYPE_INT, 0}, \
|
||||
{"imeisv", "IMEISV\n", 0, .strptr=&uicc->imeisvStr, .defstrval="6754567890123413", TYPE_STRING, 0}, \
|
||||
{"routing_indicator", "Routing Indicator\n", 0, .strptr = &uicc->routing_indicatorStr, .defstrval="0000", TYPE_STRING, 0}, \
|
||||
{"protection_scheme", "SUCI Profile Scheme\n", 0, .iptr = &uicc->protection_scheme, .defintval=0, TYPE_INT, 0}, \
|
||||
{"home_network_public_key_id", "Home Network Public Key ID\n", 0, .iptr=&uicc->home_network_public_key_id, .defintval=1, TYPE_INT, 0}, \
|
||||
{"home_network_public_key", "Home Network Public Key\n", 0, .strptr=&uicc->home_network_public_keyStr, .defstrval=DEFAULT_HOME_NETWORK_PUBLIC_KEY, TYPE_STRING, 0}, \
|
||||
};
|
||||
|
||||
static uicc_t** uiccArray=NULL;
|
||||
@@ -62,6 +67,7 @@ uicc_t *init_uicc(char *sectionName) {
|
||||
to_hex(uicc->opcStr,uicc->opc, sizeof(uicc->opc) );
|
||||
to_hex(uicc->sqnStr,uicc->sqn, sizeof(uicc->sqn) );
|
||||
to_hex(uicc->amfStr,uicc->amf, sizeof(uicc->amf) );
|
||||
to_hex(uicc->home_network_public_keyStr, uicc->home_network_public_key, sizeof(uicc->home_network_public_key));
|
||||
return uicc;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ typedef struct {
|
||||
int nssai_sd;
|
||||
pdu_session_config_t pdu_sessions[256];
|
||||
int n_pdu_sessions;
|
||||
char *routing_indicatorStr;
|
||||
int protection_scheme;
|
||||
char *home_network_public_keyStr;
|
||||
int home_network_public_key_id;
|
||||
uint8_t key[16];
|
||||
uint8_t opc[16];
|
||||
uint8_t amf[2];
|
||||
@@ -49,6 +53,7 @@ typedef struct {
|
||||
uint8_t ck[16];
|
||||
uint8_t ik[16];
|
||||
uint8_t milenage_res[8];
|
||||
uint8_t home_network_public_key[32];
|
||||
} uicc_t;
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user