verify.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. package dsse
  2. import (
  3. "crypto"
  4. "errors"
  5. "fmt"
  6. "golang.org/x/crypto/ssh"
  7. )
  8. /*
  9. Verifier verifies a complete message against a signature and key.
  10. If the message was hashed prior to signature generation, the verifier
  11. must perform the same steps.
  12. If KeyID returns successfully, only signature matching the key ID will be verified.
  13. */
  14. type Verifier interface {
  15. Verify(data, sig []byte) error
  16. KeyID() (string, error)
  17. Public() crypto.PublicKey
  18. }
  19. type EnvelopeVerifier struct {
  20. providers []Verifier
  21. threshold int
  22. }
  23. type AcceptedKey struct {
  24. Public crypto.PublicKey
  25. KeyID string
  26. Sig Signature
  27. }
  28. func (ev *EnvelopeVerifier) Verify(e *Envelope) ([]AcceptedKey, error) {
  29. if e == nil {
  30. return nil, errors.New("cannot verify a nil envelope")
  31. }
  32. if len(e.Signatures) == 0 {
  33. return nil, ErrNoSignature
  34. }
  35. // Decode payload (i.e serialized body)
  36. body, err := e.DecodeB64Payload()
  37. if err != nil {
  38. return nil, err
  39. }
  40. // Generate PAE(payloadtype, serialized body)
  41. paeEnc := PAE(e.PayloadType, body)
  42. // If *any* signature is found to be incorrect, it is skipped
  43. var acceptedKeys []AcceptedKey
  44. usedKeyids := make(map[string]string)
  45. unverified_providers := ev.providers
  46. for _, s := range e.Signatures {
  47. sig, err := b64Decode(s.Sig)
  48. if err != nil {
  49. return nil, err
  50. }
  51. // Loop over the providers.
  52. // If provider and signature include key IDs but do not match skip.
  53. // If a provider recognizes the key, we exit
  54. // the loop and use the result.
  55. providers := unverified_providers
  56. for i, v := range providers {
  57. keyID, err := v.KeyID()
  58. // Verifiers that do not provide a keyid will be generated one using public.
  59. if err != nil || keyID == "" {
  60. keyID, err = SHA256KeyID(v.Public())
  61. if err != nil {
  62. keyID = ""
  63. }
  64. }
  65. if s.KeyID != "" && keyID != "" && err == nil && s.KeyID != keyID {
  66. continue
  67. }
  68. err = v.Verify(paeEnc, sig)
  69. if err != nil {
  70. continue
  71. }
  72. acceptedKey := AcceptedKey{
  73. Public: v.Public(),
  74. KeyID: keyID,
  75. Sig: s,
  76. }
  77. unverified_providers = removeIndex(providers, i)
  78. // See https://github.com/in-toto/in-toto/pull/251
  79. if _, ok := usedKeyids[keyID]; ok {
  80. fmt.Printf("Found envelope signed by different subkeys of the same main key, Only one of them is counted towards the step threshold, KeyID=%s\n", keyID)
  81. continue
  82. }
  83. usedKeyids[keyID] = ""
  84. acceptedKeys = append(acceptedKeys, acceptedKey)
  85. break
  86. }
  87. }
  88. // Sanity if with some reflect magic this happens.
  89. if ev.threshold <= 0 || ev.threshold > len(ev.providers) {
  90. return nil, errors.New("Invalid threshold")
  91. }
  92. if len(usedKeyids) < ev.threshold {
  93. return acceptedKeys, errors.New(fmt.Sprintf("Accepted signatures do not match threshold, Found: %d, Expected %d", len(acceptedKeys), ev.threshold))
  94. }
  95. return acceptedKeys, nil
  96. }
  97. func NewEnvelopeVerifier(v ...Verifier) (*EnvelopeVerifier, error) {
  98. return NewMultiEnvelopeVerifier(1, v...)
  99. }
  100. func NewMultiEnvelopeVerifier(threshold int, p ...Verifier) (*EnvelopeVerifier, error) {
  101. if threshold <= 0 || threshold > len(p) {
  102. return nil, errors.New("Invalid threshold")
  103. }
  104. ev := EnvelopeVerifier{
  105. providers: p,
  106. threshold: threshold,
  107. }
  108. return &ev, nil
  109. }
  110. func SHA256KeyID(pub crypto.PublicKey) (string, error) {
  111. // Generate public key fingerprint
  112. sshpk, err := ssh.NewPublicKey(pub)
  113. if err != nil {
  114. return "", err
  115. }
  116. fingerprint := ssh.FingerprintSHA256(sshpk)
  117. return fingerprint, nil
  118. }
  119. func removeIndex(v []Verifier, index int) []Verifier {
  120. return append(v[:index], v[index+1:]...)
  121. }