fingerprint.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package stun
  4. import (
  5. "errors"
  6. "hash/crc32"
  7. )
  8. // FingerprintAttr represents FINGERPRINT attribute.
  9. //
  10. // RFC 5389 Section 15.5
  11. type FingerprintAttr struct{}
  12. // ErrFingerprintMismatch means that computed fingerprint differs from expected.
  13. var ErrFingerprintMismatch = errors.New("fingerprint check failed")
  14. // Fingerprint is shorthand for FingerprintAttr.
  15. //
  16. // Example:
  17. //
  18. // m := New()
  19. // Fingerprint.AddTo(m)
  20. var Fingerprint FingerprintAttr //nolint:gochecknoglobals
  21. const (
  22. fingerprintXORValue uint32 = 0x5354554e //nolint:staticcheck
  23. fingerprintSize = 4 // 32 bit
  24. )
  25. // FingerprintValue returns CRC-32 of b XOR-ed by 0x5354554e.
  26. //
  27. // The value of the attribute is computed as the CRC-32 of the STUN message
  28. // up to (but excluding) the FINGERPRINT attribute itself, XOR'ed with
  29. // the 32-bit value 0x5354554e (the XOR helps in cases where an
  30. // application packet is also using CRC-32 in it).
  31. func FingerprintValue(b []byte) uint32 {
  32. return crc32.ChecksumIEEE(b) ^ fingerprintXORValue // XOR
  33. }
  34. // AddTo adds fingerprint to message.
  35. func (FingerprintAttr) AddTo(m *Message) error {
  36. l := m.Length
  37. // length in header should include size of fingerprint attribute
  38. m.Length += fingerprintSize + attributeHeaderSize // increasing length
  39. m.WriteLength() // writing Length to Raw
  40. b := make([]byte, fingerprintSize)
  41. val := FingerprintValue(m.Raw)
  42. bin.PutUint32(b, val)
  43. m.Length = l
  44. m.Add(AttrFingerprint, b)
  45. return nil
  46. }
  47. // Check reads fingerprint value from m and checks it, returning error if any.
  48. // Can return *AttrLengthErr, ErrAttributeNotFound, and *CRCMismatch.
  49. func (FingerprintAttr) Check(m *Message) error {
  50. b, err := m.Get(AttrFingerprint)
  51. if err != nil {
  52. return err
  53. }
  54. if err = CheckSize(AttrFingerprint, len(b), fingerprintSize); err != nil {
  55. return err
  56. }
  57. val := bin.Uint32(b)
  58. attrStart := len(m.Raw) - (fingerprintSize + attributeHeaderSize)
  59. expected := FingerprintValue(m.Raw[:attrStart])
  60. return checkFingerprint(val, expected)
  61. }