fingerprint.go 2.0 KB

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