diff --git a/api/stun1.txt b/api/stun1.txt index 2f05693..8bd0929 100644 --- a/api/stun1.txt +++ b/api/stun1.txt @@ -134,7 +134,6 @@ pkg github.com/gortc/stun, method (*Client) Do(*Message, time.Time, func(Event)) pkg github.com/gortc/stun, method (*Client) Indicate(*Message) error pkg github.com/gortc/stun, method (*Client) Start(*Message, time.Time, Handler) error pkg github.com/gortc/stun, method (*ErrorCodeAttribute) GetFrom(*Message) error -pkg github.com/gortc/stun, method (*IntegrityErr) Error() string pkg github.com/gortc/stun, method (*MappedAddress) AddTo(*Message) error pkg github.com/gortc/stun, method (*MappedAddress) GetFrom(*Message) error pkg github.com/gortc/stun, method (*Message) Add(AttrType, []uint8) @@ -274,9 +273,6 @@ pkg github.com/gortc/stun, type Getter interface, GetFrom(*Message) error pkg github.com/gortc/stun, type Handler interface { HandleEvent } pkg github.com/gortc/stun, type Handler interface, HandleEvent(Event) pkg github.com/gortc/stun, type HandlerFunc func(Event) -pkg github.com/gortc/stun, type IntegrityErr struct -pkg github.com/gortc/stun, type IntegrityErr struct, Actual []uint8 -pkg github.com/gortc/stun, type IntegrityErr struct, Expected []uint8 pkg github.com/gortc/stun, type MappedAddress struct pkg github.com/gortc/stun, type MappedAddress struct, IP net.IP pkg github.com/gortc/stun, type MappedAddress struct, Port int @@ -322,6 +318,7 @@ pkg github.com/gortc/stun, var ErrClientClosed error pkg github.com/gortc/stun, var ErrClientNotInitialized error pkg github.com/gortc/stun, var ErrDecodeToNil error pkg github.com/gortc/stun, var ErrFingerprintBeforeIntegrity error +pkg github.com/gortc/stun, var ErrIntegrityMismatch error pkg github.com/gortc/stun, var ErrNoConnection error pkg github.com/gortc/stun, var ErrNoDefaultReason error pkg github.com/gortc/stun, var ErrTransactionExists error diff --git a/checksize.go b/checks.go similarity index 56% rename from checksize.go rename to checks.go index 0f376f5..10e604d 100644 --- a/checksize.go +++ b/checks.go @@ -2,6 +2,8 @@ package stun +import "github.com/gortc/stun/internal/hmac" + // CheckSize returns ErrAttrSizeInvalid if got is not equal to expected. func CheckSize(_ AttrType, got, expected int) error { if got == expected { @@ -9,3 +11,10 @@ func CheckSize(_ AttrType, got, expected int) error { } return ErrAttrSizeInvalid } + +func checkHMAC(got, expected []byte) error { + if hmac.Equal(got, expected) { + return nil + } + return ErrIntegrityMismatch +} diff --git a/checksize_debug.go b/checks_debug.go similarity index 57% rename from checksize_debug.go rename to checks_debug.go index ee7328a..4a1a73f 100644 --- a/checksize_debug.go +++ b/checks_debug.go @@ -2,6 +2,8 @@ package stun +import "github.com/gortc/stun/internal/hmac" + // CheckSize returns *AttrLengthError if got is not equal to expected. func CheckSize(a AttrType, got, expected int) error { if got == expected { @@ -13,3 +15,13 @@ func CheckSize(a AttrType, got, expected int) error { Attr: a, } } + +func checkHMAC(got, expected []byte) error { + if hmac.Equal(got, expected) { + return nil + } + return &IntegrityErr{ + Expected: expected, + Actual: got, + } +} diff --git a/go.test.sh b/go.test.sh index 66c0ea4..8c3b012 100755 --- a/go.test.sh +++ b/go.test.sh @@ -9,6 +9,9 @@ go test -tags gofuzz -run TestFuzz -v . # quick-test without -race go test ./... +# test with "debug" tag +go test -tags debug ./... + for d in $(go list ./... | grep -v vendor); do go test -race -coverprofile=profile.out -covermode=atomic "$d" if [ -f profile.out ]; then diff --git a/integrity.go b/integrity.go index a03032c..d83535b 100644 --- a/integrity.go +++ b/integrity.go @@ -85,18 +85,8 @@ func (i MessageIntegrity) AddTo(m *Message) error { return nil } -// IntegrityErr occurs when computed HMAC differs from expected. -type IntegrityErr struct { - Expected []byte - Actual []byte -} - -func (i *IntegrityErr) Error() string { - return fmt.Sprintf( - "Integrity check failed: 0x%x (expected) !- 0x%x (actual)", - i.Expected, i.Actual, - ) -} +// ErrIntegrityMismatch means that computed HMAC differs from expected. +var ErrIntegrityMismatch = errors.New("integrity check failed") func newHMAC(key, message, buf []byte) []byte { mac := hmac.AcquireSHA1(key) @@ -137,11 +127,8 @@ func (i MessageIntegrity) Check(m *Message) error { expected := newHMAC(i, b, m.Raw[len(m.Raw):]) m.Length = length m.WriteLength() // writing length back - if !hmac.Equal(v, expected) { - return &IntegrityErr{ - Expected: expected, - Actual: v, - } + if err = checkHMAC(v, expected); err != nil { + return err } return nil } diff --git a/integrity_debug.go b/integrity_debug.go new file mode 100644 index 0000000..6b8a303 --- /dev/null +++ b/integrity_debug.go @@ -0,0 +1,18 @@ +// +build debug + +package stun + +import "fmt" + +// IntegrityErr occurs when computed HMAC differs from expected. +type IntegrityErr struct { + Expected []byte + Actual []byte +} + +func (i *IntegrityErr) Error() string { + return fmt.Sprintf( + "Integrity check failed: 0x%x (expected) !- 0x%x (actual)", + i.Expected, i.Actual, + ) +} diff --git a/integrity_test.go b/integrity_test.go index ba5f23f..1bd64db 100644 --- a/integrity_test.go +++ b/integrity_test.go @@ -3,7 +3,6 @@ package stun import ( "bytes" "encoding/hex" - "fmt" "testing" ) @@ -14,10 +13,7 @@ func TestMessageIntegrity_AddTo_Simple(t *testing.T) { t.Fatal(err) } if !bytes.Equal(expected, i) { - t.Error(&IntegrityErr{ - Expected: expected, - Actual: i, - }) + t.Error(ErrIntegrityMismatch) } t.Run("Check", func(t *testing.T) { m := new(Message) @@ -36,8 +32,8 @@ func TestMessageIntegrity_AddTo_Simple(t *testing.T) { t.Error(err) } dM.Raw[24] += 12 // HMAC now invalid - if err, ok := i.Check(dM).(*IntegrityErr); !ok { - t.Error(err, "should be *IntegrityErr") + if i.Check(dM) == nil { + t.Error("should be invalid") } }) } @@ -64,12 +60,8 @@ func TestMessageIntegrityWithFingerprint(t *testing.T) { t.Fatal(err) } m.Raw[24] = 33 - errStr := fmt.Sprintf("Integrity check failed: 0x%s (expected) !- 0x%s (actual)", - "19985afb819c098acfe1c2771881227f14c70eaf", - "ef9da0e0caf0b0e4ff321e7b56f1e114c802cb7e", - ) - if err := i.Check(m); err.Error() != errStr { - t.Fatal(err, "!=", errStr) + if err := i.Check(m); err == nil { + t.Fatal("mismatch expected") } } diff --git a/message_test.go b/message_test.go index f329ceb..7e16edc 100644 --- a/message_test.go +++ b/message_test.go @@ -707,14 +707,6 @@ func ExampleMessage() { fmt.Println("for corrupted message:") decoded.Raw[22] = 33 fmt.Println("fingerprint:", Fingerprint.Check(decoded)) - iErr, ok := i.Check(decoded).(*IntegrityErr) - if ok { - fmt.Println("integrity check failed") - fmt.Printf("got: %x\n", iErr.Actual) - fmt.Printf("want: %x\n", iErr.Expected) - } else { - fmt.Println("assertion failed") - } // Output: // binding request l=48 attrs=3 id=AQIDBAUGBwgJAAEA buff length: 68 @@ -726,9 +718,6 @@ func ExampleMessage() { // integrity ok // for corrupted message: // fingerprint: CRC mismatch: b36d2c38 (expected) != 8ef13141 (actual) - // integrity check failed - // got: 06f0692c159f4256c14b9442927889e341256ac2 - // want: c1105962efee5c96f4f194cc91b4eb8ab7667c7a } func TestAllocations(t *testing.T) {