verify.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. package verify
  2. import (
  3. "encoding/json"
  4. "strings"
  5. "time"
  6. "github.com/DataDog/go-tuf/data"
  7. "github.com/DataDog/go-tuf/internal/roles"
  8. "github.com/secure-systems-lab/go-securesystemslib/cjson"
  9. )
  10. type signedMeta struct {
  11. Type string `json:"_type"`
  12. Expires time.Time `json:"expires"`
  13. Version int64 `json:"version"`
  14. }
  15. func (db *DB) VerifyIgnoreExpiredCheck(s *data.Signed, role string, minVersion int64) error {
  16. if err := db.VerifySignatures(s, role); err != nil {
  17. return err
  18. }
  19. sm := &signedMeta{}
  20. if err := json.Unmarshal(s.Signed, sm); err != nil {
  21. return err
  22. }
  23. if roles.IsTopLevelRole(role) {
  24. // Top-level roles can only sign metadata of the same type (e.g. snapshot
  25. // metadata must be signed by the snapshot role).
  26. if !strings.EqualFold(sm.Type, role) {
  27. return ErrWrongMetaType
  28. }
  29. } else {
  30. // Delegated (non-top-level) roles may only sign targets metadata.
  31. if strings.ToLower(sm.Type) != "targets" {
  32. return ErrWrongMetaType
  33. }
  34. }
  35. if sm.Version < minVersion {
  36. return ErrLowVersion{sm.Version, minVersion}
  37. }
  38. return nil
  39. }
  40. func (db *DB) Verify(s *data.Signed, role string, minVersion int64) error {
  41. // Verify signatures and versions
  42. err := db.VerifyIgnoreExpiredCheck(s, role, minVersion)
  43. if err != nil {
  44. return err
  45. }
  46. sm := &signedMeta{}
  47. if err := json.Unmarshal(s.Signed, sm); err != nil {
  48. return err
  49. }
  50. // Verify expiration
  51. if IsExpired(sm.Expires) {
  52. return ErrExpired{sm.Expires}
  53. }
  54. return nil
  55. }
  56. var IsExpired = func(t time.Time) bool {
  57. return time.Until(t) <= 0
  58. }
  59. func (db *DB) VerifySignatures(s *data.Signed, role string) error {
  60. if len(s.Signatures) == 0 {
  61. return ErrNoSignatures
  62. }
  63. roleData := db.GetRole(role)
  64. if roleData == nil {
  65. return ErrUnknownRole{role}
  66. }
  67. var decoded map[string]interface{}
  68. if err := json.Unmarshal(s.Signed, &decoded); err != nil {
  69. return err
  70. }
  71. msg, err := cjson.EncodeCanonical(decoded)
  72. if err != nil {
  73. return err
  74. }
  75. // Verify that a threshold of keys signed the data. Since keys can have
  76. // multiple key ids, we need to protect against multiple attached
  77. // signatures that just differ on the key id.
  78. seen := make(map[string]struct{})
  79. valid := 0
  80. for _, sig := range s.Signatures {
  81. if !roleData.ValidKey(sig.KeyID) {
  82. continue
  83. }
  84. verifier, err := db.GetVerifier(sig.KeyID)
  85. if err != nil {
  86. continue
  87. }
  88. if err := verifier.Verify(msg, sig.Signature); err != nil {
  89. return ErrInvalid
  90. }
  91. // Only consider this key valid if we haven't seen any of it's
  92. // key ids before.
  93. if _, ok := seen[sig.KeyID]; !ok {
  94. for _, id := range verifier.MarshalPublicKey().IDs() {
  95. seen[id] = struct{}{}
  96. }
  97. valid++
  98. }
  99. }
  100. if valid < roleData.Threshold {
  101. return ErrRoleThreshold{roleData.Threshold, valid}
  102. }
  103. return nil
  104. }
  105. func (db *DB) Unmarshal(b []byte, v interface{}, role string, minVersion int64) error {
  106. s := &data.Signed{}
  107. if err := json.Unmarshal(b, s); err != nil {
  108. return err
  109. }
  110. if err := db.Verify(s, role, minVersion); err != nil {
  111. return err
  112. }
  113. return json.Unmarshal(s.Signed, v)
  114. }
  115. // UnmarshalExpired is exactly like Unmarshal except ignores expired timestamp error.
  116. func (db *DB) UnmarshalIgnoreExpired(b []byte, v interface{}, role string, minVersion int64) error {
  117. s := &data.Signed{}
  118. if err := json.Unmarshal(b, s); err != nil {
  119. return err
  120. }
  121. // Note: If verification fails, then we wont attempt to unmarshal
  122. // unless when verification error is errExpired.
  123. verifyErr := db.Verify(s, role, minVersion)
  124. if verifyErr != nil {
  125. if _, ok := verifyErr.(ErrExpired); !ok {
  126. return verifyErr
  127. }
  128. }
  129. return json.Unmarshal(s.Signed, v)
  130. }
  131. func (db *DB) UnmarshalTrusted(b []byte, v interface{}, role string) error {
  132. s := &data.Signed{}
  133. if err := json.Unmarshal(b, s); err != nil {
  134. return err
  135. }
  136. if err := db.VerifySignatures(s, role); err != nil {
  137. return err
  138. }
  139. return json.Unmarshal(s.Signed, v)
  140. }