Skip to content

Commit

Permalink
feat: Add support for SUCI Concealing (Null-Scheme, Profile A and Pro…
Browse files Browse the repository at this point in the history
…file B)

Signed-off-by: Valentin <[email protected]>
  • Loading branch information
linouxis9 committed Feb 25, 2025
1 parent fd83fec commit 3210a26
Show file tree
Hide file tree
Showing 10 changed files with 858 additions and 51 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

----
## Description
PacketRusher is a tool, based upon [my5G-RANTester](https://github.com/my5G/my5G-RANTester), dedicated to the performance testing and automatic validation of 5G Core Networks using simulated UE (user equipment) and gNodeB (5G base station).
#### Now with SUCI Concealing/Deconcealment (Null-Scheme, Profile A (X25519), Profile B (P-256))!

If you have questions or comments, feel free to open an issue.
PacketRusher is a tool dedicated to the performance testing and automatic validation of 5G Core Networks using simulated UE (user equipment) and gNodeB (5G base station).

If you have questions or comments, feel free to open an issue after **a careful** review of existing closed issues.

PacketRusher borrows libraries and data structures from the [free5gc project](https://github.com/free5gc/free5gc).

Expand All @@ -16,6 +18,7 @@ PacketRusher borrows libraries and data structures from the [free5gc project](ht
* Supports both N2 (NGAP) and N1 (NAS) interfaces for stress testing
* --pcap parameter to capture pcap of N1/N2 traffic
* Implements main control plane procedures:
* SUCI Concealing/Deconcealment (Null-Scheme, Profile A (X25519), Profile B (P-256))
* UE attach/detach (registration/identity request/authentification/security mode) procedures
* Create/Delete PDU Sessions, up to 15 PDU Sessions per UE
* Xn handover: UE handover between simulated gNodeB (PathSwitchRequest)
Expand Down Expand Up @@ -110,7 +113,7 @@ If you use this software, you may cite it as below:
## License
© Copyright 2023 Hewlett Packard Enterprise Development LP

© Copyright 2024 Valentin D'Emmanuele
© Copyright 2024-2025 Valentin D'Emmanuele

This project is under the [Apache 2.0 License](LICENSE) license.

Expand Down
85 changes: 70 additions & 15 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
package config

import (
"crypto/ecdh"
"encoding/hex"
"my5G-RANTester/internal/common/sidf"
"net"
"os"
"path"
"path/filepath"
"strconv"

"github.com/free5gc/nas/nasMessage"
"github.com/free5gc/nas/nasType"
"github.com/goccy/go-yaml"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)

// TunnelMode indicates how to create a GTP-U tunnel interface in an UE.
Expand All @@ -33,7 +37,7 @@ var config *Config
type Config struct {
GNodeB GNodeB `yaml:"gnodeb"`
Ue Ue `yaml:"ue"`
AMFs []*AMF `yaml:"amfif"`
AMFs []*AMF `yaml:"amfif"`
Logs Logs `yaml:"logs"`
}

Expand Down Expand Up @@ -64,18 +68,21 @@ type SliceSupportList struct {
}

type Ue struct {
Msin string `yaml:"msin"`
Key string `yaml:"key"`
Opc string `yaml:"opc"`
Amf string `yaml:"amf"`
Sqn string `yaml:"sqn"`
Dnn string `yaml:"dnn"`
RoutingIndicator string `yaml:"routingindicator"`
Hplmn Hplmn `yaml:"hplmn"`
Snssai Snssai `yaml:"snssai"`
Integrity Integrity `yaml:"integrity"`
Ciphering Ciphering `yaml:"ciphering"`
TunnelMode TunnelMode `yaml:"-"`
Msin string `yaml:"msin"`
Key string `yaml:"key"`
Opc string `yaml:"opc"`
Amf string `yaml:"amf"`
Sqn string `yaml:"sqn"`
Dnn string `yaml:"dnn"`
ProtectionScheme int `yaml:"protectionScheme"`
HomeNetworkPublicKey string `yaml:"homeNetworkPublicKey"`
HomeNetworkPublicKeyID uint8 `yaml:"homeNetworkPublicKeyID"`
RoutingIndicator string `yaml:"routingindicator"`
Hplmn Hplmn `yaml:"hplmn"`
Snssai Snssai `yaml:"snssai"`
Integrity Integrity `yaml:"integrity"`
Ciphering Ciphering `yaml:"ciphering"`
TunnelMode TunnelMode `yaml:"-"`
}

type Hplmn struct {
Expand Down Expand Up @@ -136,7 +143,7 @@ func readConfig(configPath string) Config {
}
defer f.Close()

decoder := yaml.NewDecoder(f)
decoder := yaml.NewDecoder(f, yaml.Strict())
err = decoder.Decode(&cfg)
if err != nil {
log.Fatal("Could not unmarshal yaml config at \"", configPath, "\". ", err.Error())
Expand Down Expand Up @@ -217,6 +224,54 @@ func (config *Config) GetUESecurityCapability() *nasType.UESecurityCapability {
return UESecurityCapability
}

func (config *Config) GetHomeNetworkPublicKey() sidf.HomeNetworkPublicKey {
switch config.Ue.ProtectionScheme {
case 0:
config.Ue.HomeNetworkPublicKey = ""
config.Ue.HomeNetworkPublicKeyID = 0
case 1:
key, err := hex.DecodeString(config.Ue.HomeNetworkPublicKey)
if err != nil {
log.Fatalf("Invalid Home Network Public Key in configuration for Profile A: %v", err)
}

publicKey, err := ecdh.X25519().NewPublicKey(key)
if err != nil {
log.Fatalf("Invalid Home Network Public Key in configuration for Profile A: %v", err)
}

return sidf.HomeNetworkPublicKey{
ProtectionScheme: strconv.Itoa(config.Ue.ProtectionScheme),
PublicKey: publicKey,
PublicKeyID: strconv.Itoa(int(config.Ue.HomeNetworkPublicKeyID)),
}
case 2:
key, err := hex.DecodeString(config.Ue.HomeNetworkPublicKey)
if err != nil {
log.Fatalf("Invalid Home Network Public Key in configuration for Profile B: %v", err)
}

publicKey, err := ecdh.P256().NewPublicKey(key)
if err != nil {
log.Fatalf("Invalid Home Network Public Key in configuration for Profile B: %v", err)
}

return sidf.HomeNetworkPublicKey{
ProtectionScheme: strconv.Itoa(config.Ue.ProtectionScheme),
PublicKey: publicKey,
PublicKeyID: strconv.Itoa(int(config.Ue.HomeNetworkPublicKeyID)),
}
default:
log.Fatal("Invalid Protection Scheme for SUCI. Valid values are 0, 1 and 2")
}

return sidf.HomeNetworkPublicKey{
ProtectionScheme: "0",
PublicKey: nil,
PublicKeyID: "0",
}
}

func boolToUint8(boolean bool) uint8 {
if boolean {
return 1
Expand Down
63 changes: 53 additions & 10 deletions config/config.yml
Original file line number Diff line number Diff line change
@@ -1,44 +1,87 @@
# PacketRusher Simulated gNodeB Configuration
gnodeb:
# IP Address on the N2 Interface (e.g. used between the gNodeB and the AMF)
controlif:
ip: "192.168.11.13"
ip: "127.0.0.1"
port: 9487

# IP Address on the N3 Interface (e.g. used between the gNodeB and the UPF)
dataif:
ip: "192.168.11.13"
ip: "127.0.0.1"
port: 2152

# gNodeB's Identity
plmnlist:
mcc: "999"
mnc: "70"
mcc: "208"
mnc: "93"
tac: "000001"
gnbid: "000008"

# gNodeB's Supported Slices
slicesupportlist:
sst: "01"
sd: "000001" # optional, can be removed if not used

# PacketRusher Simulated UE Configuration
ue:
# UE's Identity, frequently called IMSI in 4G and before
# IMSI format is "<mcc><mnc><msin>"
# In 5G, the SUPI of the UE will be "imsi-<mcc><mnc><msin>""
# With default configuration, SUPI will be imsi-208930000000120
hplmn:
mcc: "208"
mnc: "93"
msin: "0000000120"

# In 5G, the UE's identity to the AMF as a SUCI (Subscription Concealed Identifier)
#
# SUCI format is suci-<supi_type>-<MCC>-<MNC>-<routing_indicator>-<protection_scheme>-<public_key_id>-<scheme_output>
# With default configuration, SUCI sent to AMF will be suci-0-999-70-0000-0-0-0000000120
#
# SUCI Routing Indicator allows the AMF to route the UE to the correct UDM
routingindicator: "0000"
#
# SUCI Protection Scheme: 0 for Null-scheme, 1 for Profile A and 2 for Profile B
protectionScheme: 0
#
# Home Network Public Key
# Ignored with default Null-Scheme configuration
homeNetworkPublicKey: "5a8d38864820197c3394b92613b20b91633cbd897119273bf8e4a6f4eec0a650"
#
# Home Network Public Key ID
# Ignored ith default Null-Scheme configuration
homeNetworkPublicKeyID: 1

# UE's SIM credentials
key: "00112233445566778899AABBCCDDEEFF"
opc: "00112233445566778899AABBCCDDEEFF"
amf: "8000"
sqn: "00000000"

# UE will request to establish a data session in this DNN (APN)
dnn: "internet"
routingindicator: "0000"
hplmn:
mcc: "999"
mnc: "70"
# in the following slice
snssai:
sst: 01
sst: "01"
sd: "000001" # optional, can be removed if not used

# The UE's security capabilities that will be advertised to the AMF
integrity:
nia0: false
nia1: false
nia2: true
nia3: false
ciphering:
# For debugging Wireshark traces, NEA0 is recommended, as the NAS messages
# will be sent in cleartext, and be decipherable in Wireshark.
nea0: true
nea1: false
nea2: true
nea3: false

# List of AMF that PacketRusher will try to connect to
amfif:
- ip: "192.168.11.30"
- ip: "127.0.0.1"
port: 38412
logs:
level: 4
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/aead/cmac v0.0.0-20160719120800-7af84192f0b1 // indirect
github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/goccy/go-yaml v1.15.23 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/khirono/go-genl v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/free5gc/aper v1.0.5 h1:sUYFFmOXDLjyL4rU6zFnq81M4YluqP90Pso5e/J4UhA=
github.com/free5gc/aper v1.0.5/go.mod h1:ybHxhYnRqQ9wD4yB9r/3MZdbCYCjtqUyfLpSnJpwWd4=
github.com/free5gc/go-gtp5gnl v1.4.6 h1:xqwyGjrRNRGwo3/HyfXMh/fQ56QnCUzQKP2XR5/i1cE=
github.com/free5gc/go-gtp5gnl v1.4.6/go.mod h1:TT5aXB90NuSPMehuIK9lV2yJFnq6Qjw37ZqNB1QAKh0=
github.com/free5gc/go-gtp5gnl v1.4.7-0.20241008130314-a3088e4cb7fa h1:D5OzFSttS6WY2XRspxtPKoHyCVkRLH9kqteQ1bGfOg0=
github.com/free5gc/go-gtp5gnl v1.4.7-0.20241008130314-a3088e4cb7fa/go.mod h1:TT5aXB90NuSPMehuIK9lV2yJFnq6Qjw37ZqNB1QAKh0=
github.com/free5gc/nas v1.1.3 h1:eYkvT8GGieD06MExw3JLeIPA88Yg89DFjptVBnadIyQ=
Expand All @@ -39,6 +37,8 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo=
github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
Expand Down
Loading

0 comments on commit 3210a26

Please sign in to comment.