From 5e1479cc686f058992557669b13fd3761a1b6024 Mon Sep 17 00:00:00 2001 From: Chien-An Hu <52029623+Roy-Hu@users.noreply.github.com> Date: Mon, 8 May 2023 20:27:38 +0800 Subject: [PATCH] Prevent Invalid Curve Attack on 5G SUCI Feature (#20) * Prevent Invalid Curve Attack on 5G SUCI Feature * add test case of detecting invalid cure attack * fix comment * change test case err type --------- Co-authored-by: Roy-Hu Co-authored-by: roy19991013 <80-ChienAn@users.noreply.gitlab.nems.cs.nctu.edu.tw> --- pkg/suci/suci.go | 18 ++++++++++++++++++ pkg/suci/suci_test.go | 35 +++++++++++++++++++++++++---------- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/pkg/suci/suci.go b/pkg/suci/suci.go index e133d77..60d8ef4 100644 --- a/pkg/suci/suci.go +++ b/pkg/suci/suci.go @@ -218,6 +218,20 @@ func profileA(input, supiType, privateKey string) (string, error) { return calcSchemeResult(decryptPlainText, supiType), nil } +func checkOnCurve(curve elliptic.Curve, x, y *big.Int) error { + // (0, 0) is the point at infinity by convention. It's ok to operate on it, + // although IsOnCurve is documented to return false for it. See Issue 37294. + if x.Sign() == 0 && y.Sign() == 0 { + return nil + } + + if !curve.IsOnCurve(x, y) { + return fmt.Errorf("crypto/elliptic: attempted operation on invalid point") + } + + return nil +} + func profileB(input, supiType, privateKey string) (string, error) { logger.SuciLog.Infoln("SuciToSupi Profile B") s, hexDecodeErr := hex.DecodeString(input) @@ -271,6 +285,10 @@ func profileB(input, supiType, privateKey string) (string, error) { } // fmt.Printf("xUncom: %x\nyUncom: %x\n", xUncompressed, yUncompressed) + if err := checkOnCurve(elliptic.P256(), xUncompressed, yUncompressed); err != nil { + return "", err + } + // x-coordinate is the shared key decryptSharedKey, _ := elliptic.P256().ScalarMult(xUncompressed, yUncompressed, bHNPriv) // fmt.Printf("deShared: %x\n", decryptSharedKey.Bytes()) diff --git a/pkg/suci/suci_test.go b/pkg/suci/suci_test.go index 0594321..4e72ed4 100644 --- a/pkg/suci/suci_test.go +++ b/pkg/suci/suci_test.go @@ -1,6 +1,9 @@ package suci -import "testing" +import ( + "fmt" + "testing" +) func TestToSupi(t *testing.T) { suciProfiles := []SuciProfile{ @@ -17,30 +20,42 @@ func TestToSupi(t *testing.T) { }, } testCases := []struct { - suci string - expected string + suci string + expectedSupi string + expectedErr error }{ { - suci: "suci-0-208-93-0-0-0-00007487", - expected: "imsi-2089300007487", + suci: "suci-0-208-93-0-0-0-00007487", + expectedSupi: "imsi-2089300007487", + expectedErr: nil, }, { suci: "suci-0-208-93-0-1-1-b2e92f836055a255837debf850b528997ce0201cb82a" + "dfe4be1f587d07d8457dcb02352410cddd9e730ef3fa87", - expected: "imsi-20893001002086", + expectedSupi: "imsi-20893001002086", + expectedErr: nil, }, { suci: "suci-0-208-93-0-2-2-039aab8376597021e855679a9778ea0b67396e68c66d" + "f32c0f41e9acca2da9b9d146a33fc2716ac7dae96aa30a4d", - expected: "imsi-20893001002086", + expectedSupi: "imsi-20893001002086", + expectedErr: nil, + }, + { + suci: "suci-0-208-93-0-2-2-0434a66778799d52fedd9326db4b690d092e05c9ba0ace5b413da" + + "fc0a40aa28ee00a79f790fa4da6a2ece892423adb130dc1b30e270b7d0088bdd716b93894891d5221a74c810d6b9350cc067c76", + expectedSupi: "", + expectedErr: fmt.Errorf("crypto/elliptic: attempted operation on invalid point"), }, } for i, tc := range testCases { supi, err := ToSupi(tc.suci, suciProfiles) if err != nil { - t.Errorf("TC%d err: %+v\n", i, err) - } else if supi != tc.expected { - t.Errorf("TC%d fail: supi[%s], expected[%s]\n", i, supi, tc.expected) + if err.Error() != tc.expectedErr.Error() { + t.Errorf("TC%d fail: err[%s], expected[%s]\n", i, err, tc.expectedErr) + } + } else if supi != tc.expectedSupi { + t.Errorf("TC%d fail: supi[%s], expected[%s]\n", i, supi, tc.expectedSupi) } } }