From ad602aa0da1f3691a2d82a681c024a8c7a32191f Mon Sep 17 00:00:00 2001 From: ShouheiNishi <96609867+ShouheiNishi@users.noreply.github.com> Date: Wed, 10 May 2023 12:05:26 +0900 Subject: [PATCH] Add error check and test to MobileIdentity5GS.go (#19) --- nasConvert/AmfId.go | 13 +- nasConvert/MobileIdentity5GS.go | 106 ++++++-- nasConvert/MobileIdentity5GS_test.go | 364 +++++++++++++++++++++++++++ 3 files changed, 466 insertions(+), 17 deletions(-) create mode 100644 nasConvert/MobileIdentity5GS_test.go diff --git a/nasConvert/AmfId.go b/nasConvert/AmfId.go index d5d11b5..17d6fb3 100644 --- a/nasConvert/AmfId.go +++ b/nasConvert/AmfId.go @@ -2,13 +2,24 @@ package nasConvert import ( "encoding/hex" + "fmt" "log" ) func AmfIdToNas(amfId string) (amfRegionId uint8, amfSetId uint16, amfPointer uint8) { + var err error + amfRegionId, amfSetId, amfPointer, err = AmfIdToNasWithError(amfId) + if err != nil { + log.Printf("AmfIdToNas: %+v", err) + return 0, 0, 0 + } + return +} + +func AmfIdToNasWithError(amfId string) (amfRegionId uint8, amfSetId uint16, amfPointer uint8, err error) { amfIdBytes, err := hex.DecodeString(amfId) if err != nil { - log.Printf("amfId decode failed: %+v", err) + return 0, 0, 0, fmt.Errorf("amfId decode failed: %w", err) } amfRegionId = amfIdBytes[0] diff --git a/nasConvert/MobileIdentity5GS.go b/nasConvert/MobileIdentity5GS.go index 152b0fc..2fbcc9f 100644 --- a/nasConvert/MobileIdentity5GS.go +++ b/nasConvert/MobileIdentity5GS.go @@ -2,6 +2,7 @@ package nasConvert import ( "encoding/hex" + "errors" "fmt" "math/bits" "strconv" @@ -22,12 +23,30 @@ func GetTypeOfIdentity(buf byte) uint8 { // "suci-0-${mcc}-${mnc}-${routingIndentifier}-${protectionScheme}-${homeNetworkPublicKeyIdentifier}-${schemeOutput}" // suci(nai) = "nai-${naiString}" func SuciToString(buf []byte) (suci string, plmnId string) { + var err error + suci, plmnId, err = SuciToStringWithError(buf) + if err != nil { + logger.ConvertLog.Warnf("SuciToString: %+v", err) + return "", "" + } + return +} + +func SuciToStringWithError(buf []byte) (suci string, plmnId string, err error) { var mcc, mnc, routingInd, protectionScheme, homeNetworkPublicKeyIdentifier, schemeOutput string + if len(buf) < 1 { + return "", "", errors.New("too short SUCI") + } + supiFormat := (buf[0] & 0xf0) >> 4 if supiFormat == nasMessage.SupiFormatNai { - suci = NaiToString(buf) - return suci, "" + suci, err = naiToString(buf) + return suci, "", err + } + + if len(buf) < 9 { + return "", "", errors.New("too short SUCI") } // Encode buf to SUCI in supi format "IMSI" @@ -83,10 +102,23 @@ func SuciToString(buf []byte) (suci string, plmnId string) { "suci", "0", mcc, mnc, routingInd, protectionScheme, homeNetworkPublicKeyIdentifier, schemeOutput, }, "-") - return suci, plmnId + return suci, plmnId, nil } func NaiToString(buf []byte) (nai string) { + var err error + nai, err = naiToString(buf) + if err != nil { + logger.ConvertLog.Warnf("NaiToString: %+v", err) + return "" + } + return +} + +func naiToString(buf []byte) (nai string, err error) { + if len(buf) < 2 { + return "", errors.New("too short NAI") + } prefix := "nai" naiBytes := buf[1:] naiStr := hex.EncodeToString(naiBytes) @@ -96,6 +128,19 @@ func NaiToString(buf []byte) (nai string) { // nasType: TS 24.501 9.11.3.4 func GutiToString(buf []byte) (guami models.Guami, guti string) { + var err error + guami, guti, err = GutiToStringWithError(buf) + if err != nil { + logger.ConvertLog.Warnf("GutiToString: %+v", err) + return models.Guami{}, "" + } + return +} + +func GutiToStringWithError(buf []byte) (guami models.Guami, guti string, err error) { + if len(buf) != 11 { + return models.Guami{}, "", errors.New("invalid GUTI length") + } plmnID := PlmnIDToString(buf[1:4]) amfID := hex.EncodeToString(buf[4:7]) tmsi5G := hex.EncodeToString(buf[7:]) @@ -109,8 +154,21 @@ func GutiToString(buf []byte) (guami models.Guami, guti string) { } func GutiToNas(guti string) nasType.GUTI5G { + gutiNas, err := GutiToNasWithError(guti) + if err != nil { + logger.ConvertLog.Warnf("GutiToNas: %+v", err) + return nasType.GUTI5G{Len: 11} + } + return gutiNas +} + +func GutiToNasWithError(guti string) (nasType.GUTI5G, error) { var gutiNas nasType.GUTI5G + if len(guti) != 19 && len(guti) != 20 { + return nasType.GUTI5G{}, errors.New("invalid GUTI length") + } + gutiNas.SetLen(11) gutiNas.SetSpare(0) gutiNas.SetSpare2(15) @@ -118,27 +176,27 @@ func GutiToNas(guti string) nasType.GUTI5G { var mcc1, mcc2, mcc3, mnc1, mnc2, mnc3 int if mcc1Tmp, err := strconv.Atoi(string(guti[0])); err != nil { - logger.ConvertLog.Warnf("atoi mcc1 error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi mcc1 error: %w", err) } else { mcc1 = mcc1Tmp } if mcc2Tmp, err := strconv.Atoi(string(guti[1])); err != nil { - logger.ConvertLog.Warnf("atoi mcc2 error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi mcc2 error: %w", err) } else { mcc2 = mcc2Tmp } if mcc3Tmp, err := strconv.Atoi(string(guti[2])); err != nil { - logger.ConvertLog.Warnf("atoi mcc3 error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi mcc3 error: %w", err) } else { mcc3 = mcc3Tmp } if mnc1Tmp, err := strconv.Atoi(string(guti[3])); err != nil { - logger.ConvertLog.Warnf("atoi mnc1 error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi mnc1 error: %w", err) } else { mnc1 = mnc1Tmp } if mnc2Tmp, err := strconv.Atoi(string(guti[4])); err != nil { - logger.ConvertLog.Warnf("atoi mnc2 error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi mnc2 error: %w", err) } else { mnc2 = mnc2Tmp } @@ -147,7 +205,7 @@ func GutiToNas(guti string) nasType.GUTI5G { tmsi := "" if len(guti) == 20 { if mnc3Tmp, err := strconv.Atoi(string(guti[5])); err != nil { - logger.ConvertLog.Warnf("atoi guti error: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("atoi guti error: %w", err) } else { mnc3 = mnc3Tmp } @@ -164,22 +222,38 @@ func GutiToNas(guti string) nasType.GUTI5G { gutiNas.SetMNCDigit2(uint8(mnc2)) gutiNas.SetMNCDigit3(uint8(mnc3)) - amfRegionId, amfSetId, amfPointer := AmfIdToNas(amfId) - gutiNas.SetAMFRegionID(amfRegionId) - gutiNas.SetAMFSetID(amfSetId) - gutiNas.SetAMFPointer(amfPointer) + if amfRegionId, amfSetId, amfPointer, err := AmfIdToNasWithError(amfId); err != nil { + return nasType.GUTI5G{}, fmt.Errorf("decode AMF ID failed: %w", err) + } else { + gutiNas.SetAMFRegionID(amfRegionId) + gutiNas.SetAMFSetID(amfSetId) + gutiNas.SetAMFPointer(amfPointer) + } if tmsiBytes, err := hex.DecodeString(tmsi); err != nil { - logger.ConvertLog.Warnf("Decode TMSI failed: %+v", err) + return nasType.GUTI5G{}, fmt.Errorf("decode TMSI failed: %w", err) } else { copy(gutiNas.Octet[7:11], tmsiBytes[:]) } - return gutiNas + return gutiNas, nil } // PEI: ^(imei-[0-9]{15}|imeisv-[0-9]{16}|.+)$ func PeiToString(buf []byte) string { + pei, err := PeiToStringWithError(buf) + if err != nil { + logger.ConvertLog.Warnf("PeiToString: %+v", err) + return "" + } + return pei +} + +func PeiToStringWithError(buf []byte) (string, error) { var prefix string + if len(buf) < 1 { + return "", errors.New("too short PEI") + } + typeOfIdentity := buf[0] & 0x07 if typeOfIdentity == 0x03 { prefix = "imei-" @@ -208,5 +282,5 @@ func PeiToString(buf []byte) string { digitStr = digitStr[:len(digitStr)-1] // remove the last digit } - return prefix + digitStr + return prefix + digitStr, nil } diff --git a/nasConvert/MobileIdentity5GS_test.go b/nasConvert/MobileIdentity5GS_test.go new file mode 100644 index 0000000..3987982 --- /dev/null +++ b/nasConvert/MobileIdentity5GS_test.go @@ -0,0 +1,364 @@ +package nasConvert + +import ( + "reflect" + "testing" + + "github.com/free5gc/nas/nasType" + "github.com/free5gc/openapi/models" +) + +func TestSuciToStringWithError(t *testing.T) { + type args struct { + buf []byte + } + tests := []struct { + name string + args args + wantSuci string + wantPlmnId string + wantErr bool + }{ + { + name: "SUSI-null", + args: args{ + buf: []byte{0x01, 0x02, 0xf8, 0x39, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1}, + }, + wantSuci: "suci-0-208-93-0-0-0-0000001", + wantPlmnId: "20893", + wantErr: false, + }, + { + name: "SUSI-nonnull", + args: args{ + buf: []byte{0x01, 0x02, 0x58, 0x39, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10}, + }, + wantSuci: "suci-0-208-935-0-1-0-00000010", + wantPlmnId: "208935", + wantErr: false, + }, + { + name: "SUSI-NAI", + args: args{ + buf: []byte{0x11, 0x02, 0x58, 0x39, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x10}, + }, + wantSuci: "nai-1-025839f0ff010000000010", + wantPlmnId: "", + wantErr: false, + }, + { + name: "SUSI-short", + args: args{ + buf: []byte{0x01, 0x02, 0xf8, 0x39, 0xf0, 0xff, 0x00, 0x00, 0x00}, + }, + wantSuci: "suci-0-208-93-0-0-0-00", + wantPlmnId: "20893", + wantErr: false, + }, + { + name: "SUSI-too-short", + args: args{ + buf: []byte{0x01, 0x02, 0xf8, 0x39, 0xf0, 0xff, 0x00, 0x00}, + }, + wantErr: true, + }, + { + name: "SUSI-nil", + args: args{ + buf: nil, + }, + wantErr: true, + }, + { + name: "SUSI-NAI-short", + args: args{ + buf: []byte{0x11, 0x02}, + }, + wantSuci: "nai-1-02", + wantPlmnId: "", + wantErr: false, + }, + { + name: "SUSI-NAI-too-short", + args: args{ + buf: []byte{0x11}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + gotSuci, gotPlmnId, err := SuciToStringWithError(tt.args.buf) + if (err != nil) != tt.wantErr { + t.Errorf("SuciToString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotSuci != tt.wantSuci { + t.Errorf("SuciToString() gotSuci = %v, want %v", gotSuci, tt.wantSuci) + } + if gotPlmnId != tt.wantPlmnId { + t.Errorf("SuciToString() gotPlmnId = %v, want %v", gotPlmnId, tt.wantPlmnId) + } + }) + } +} + +func TestGutiToStringWithError(t *testing.T) { + type args struct { + buf []byte + } + tests := []struct { + name string + args args + wantGuami models.Guami + wantGuti string + wantErr bool + }{ + { + name: "GUTI-MNC2", + args: args{ + buf: []byte{0xf2, 0x02, 0xf8, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23}, + }, + wantGuami: models.Guami{ + PlmnId: &models.PlmnId{ + Mcc: "208", + Mnc: "93", + }, + AmfId: "012345", + }, + wantGuti: "2089301234567890123", + wantErr: false, + }, + { + name: "GUTI-MNC3", + args: args{ + buf: []byte{0xf2, 0x02, 0x58, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23}, + }, + wantGuami: models.Guami{ + PlmnId: &models.PlmnId{ + Mcc: "208", + Mnc: "935", + }, + AmfId: "012345", + }, + wantGuti: "20893501234567890123", + wantErr: false, + }, + { + name: "GUTI-too-long", + args: args{ + buf: []byte{0xf2, 0x02, 0xf8, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45}, + }, + wantErr: true, + }, + { + name: "GUTI-too-short", + args: args{ + buf: []byte{0xf2, 0x02, 0xf8, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + gotGuami, gotGuti, err := GutiToStringWithError(tt.args.buf) + if (err != nil) != tt.wantErr { + t.Errorf("GutiToString() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(gotGuami, tt.wantGuami) { + t.Errorf("GutiToString() gotGuami = %v, want %v", gotGuami, tt.wantGuami) + } + if gotGuti != tt.wantGuti { + t.Errorf("GutiToString() gotGuti = %v, want %v", gotGuti, tt.wantGuti) + } + }) + } +} + +func TestGutiToNasWithError(t *testing.T) { + type args struct { + guti string + } + tests := []struct { + name string + args args + want nasType.GUTI5G + wantErr bool + }{ + { + name: "GUTI-MNC2", + args: args{ + guti: "2089301234567890123", + }, + want: nasType.GUTI5G{ + Iei: 0, + Len: 11, + Octet: [11]uint8{0xf2, 0x02, 0xf8, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23}, + }, + wantErr: false, + }, + { + name: "GUTI-MNC3", + args: args{ + guti: "20893501234567890123", + }, + want: nasType.GUTI5G{ + Iei: 0, + Len: 11, + Octet: [11]uint8{0xf2, 0x02, 0x58, 0x39, 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23}, + }, + wantErr: false, + }, + { + name: "GUTI-too-long", + args: args{ + guti: "208935012345678901234", + }, + wantErr: true, + }, + { + name: "GUTI-too-short", + args: args{ + guti: "208930123456789012", + }, + wantErr: true, + }, + { + name: "GUTI-bad-MCC1", + args: args{ + guti: "x089301234567890123", + }, + wantErr: true, + }, + { + name: "GUTI-bad-MCC2", + args: args{ + guti: "2x89301234567890123", + }, + wantErr: true, + }, + { + name: "GUTI-bad-MCC3", + args: args{ + guti: "20x9301234567890123", + }, + wantErr: true, + }, { + name: "GUTI-bad-MNC1", + args: args{ + guti: "208x301234567890123", + }, + wantErr: true, + }, + { + name: "GUTI-bad-MNC2", + args: args{ + guti: "2089x01234567890123", + }, + wantErr: true, + }, + { + name: "GUTI-bad-MNC3", + args: args{ + guti: "20893x01234567890123", + }, + wantErr: true, + }, + { + name: "GUTI-bad-TMSI", + args: args{ + guti: "208930123456789012x", + }, + wantErr: true, + }, + { + name: "GUTI-bad-AMFID", + args: args{ + guti: "2089301x34567890123", + }, + wantErr: true, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := GutiToNasWithError(tt.args.guti) + if (err != nil) != tt.wantErr { + t.Errorf("GutiToNas() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("GutiToNas() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestPeiToStringWithError(t *testing.T) { + type args struct { + buf []byte + } + tests := []struct { + name string + args args + want string + wantErr bool + }{ + { + name: "PEI-IMEI-even", + args: args{ + buf: []byte{0x3, 0xf1}, + }, + want: "imei-01", + wantErr: false, + }, + { + name: "PEI-IMEISV-odd", + args: args{ + buf: []byte{0xd, 0x21}, + }, + want: "imeisv-012", + wantErr: false, + }, + { + name: "PEI-nil", + wantErr: true, + }, + { + name: "PEI-IMEI-len1", + args: args{ + buf: []byte{0xb}, + }, + want: "imei-0", + wantErr: false, + }, + { + name: "PEI-IMEI-len0", + args: args{ + buf: []byte{0x3}, + }, + want: "imei-", + wantErr: false, + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got, err := PeiToStringWithError(tt.args.buf) + if (err != nil) != tt.wantErr { + t.Errorf("PeiToStringWithError() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("PeiToStringWithError() = %v, want %v", got, tt.want) + } + }) + } +}