sign.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /*
  2. Package dsse implements the Dead Simple Signing Envelope (DSSE)
  3. https://github.com/secure-systems-lab/dsse
  4. */
  5. package dsse
  6. import (
  7. "encoding/base64"
  8. "errors"
  9. "fmt"
  10. )
  11. // ErrUnknownKey indicates that the implementation does not recognize the
  12. // key.
  13. var ErrUnknownKey = errors.New("unknown key")
  14. // ErrNoSignature indicates that an envelope did not contain any signatures.
  15. var ErrNoSignature = errors.New("no signature found")
  16. // ErrNoSigners indicates that no signer was provided.
  17. var ErrNoSigners = errors.New("no signers provided")
  18. /*
  19. Envelope captures an envelope as described by the Secure Systems Lab
  20. Signing Specification. See here:
  21. https://github.com/secure-systems-lab/signing-spec/blob/master/envelope.md
  22. */
  23. type Envelope struct {
  24. PayloadType string `json:"payloadType"`
  25. Payload string `json:"payload"`
  26. Signatures []Signature `json:"signatures"`
  27. }
  28. /*
  29. DecodeB64Payload returns the serialized body, decoded
  30. from the envelope's payload field. A flexible
  31. decoder is used, first trying standard base64, then
  32. URL-encoded base64.
  33. */
  34. func (e *Envelope) DecodeB64Payload() ([]byte, error) {
  35. return b64Decode(e.Payload)
  36. }
  37. /*
  38. Signature represents a generic in-toto signature that contains the identifier
  39. of the key which was used to create the signature.
  40. The used signature scheme has to be agreed upon by the signer and verifer
  41. out of band.
  42. The signature is a base64 encoding of the raw bytes from the signature
  43. algorithm.
  44. */
  45. type Signature struct {
  46. KeyID string `json:"keyid"`
  47. Sig string `json:"sig"`
  48. }
  49. /*
  50. PAE implementes the DSSE Pre-Authentic Encoding
  51. https://github.com/secure-systems-lab/dsse/blob/master/protocol.md#signature-definition
  52. */
  53. func PAE(payloadType string, payload []byte) []byte {
  54. return []byte(fmt.Sprintf("DSSEv1 %d %s %d %s",
  55. len(payloadType), payloadType,
  56. len(payload), payload))
  57. }
  58. /*
  59. Signer defines the interface for an abstract signing algorithm.
  60. The Signer interface is used to inject signature algorithm implementations
  61. into the EnevelopeSigner. This decoupling allows for any signing algorithm
  62. and key management system can be used.
  63. The full message is provided as the parameter. If the signature algorithm
  64. depends on hashing of the message prior to signature calculation, the
  65. implementor of this interface must perform such hashing.
  66. The function must return raw bytes representing the calculated signature
  67. using the current algorithm, and the key used (if applicable).
  68. For an example see EcdsaSigner in sign_test.go.
  69. */
  70. type Signer interface {
  71. Sign(data []byte) ([]byte, error)
  72. KeyID() (string, error)
  73. }
  74. // SignVerifer provides both the signing and verification interface.
  75. type SignVerifier interface {
  76. Signer
  77. Verifier
  78. }
  79. // EnvelopeSigner creates signed Envelopes.
  80. type EnvelopeSigner struct {
  81. providers []SignVerifier
  82. ev *EnvelopeVerifier
  83. }
  84. /*
  85. NewEnvelopeSigner creates an EnvelopeSigner that uses 1+ Signer
  86. algorithms to sign the data.
  87. Creates a verifier with threshold=1, at least one of the providers must validate signitures successfully.
  88. */
  89. func NewEnvelopeSigner(p ...SignVerifier) (*EnvelopeSigner, error) {
  90. return NewMultiEnvelopeSigner(1, p...)
  91. }
  92. /*
  93. NewMultiEnvelopeSigner creates an EnvelopeSigner that uses 1+ Signer
  94. algorithms to sign the data.
  95. Creates a verifier with threshold.
  96. threashold indicates the amount of providers that must validate the envelope.
  97. */
  98. func NewMultiEnvelopeSigner(threshold int, p ...SignVerifier) (*EnvelopeSigner, error) {
  99. var providers []SignVerifier
  100. for _, sv := range p {
  101. if sv != nil {
  102. providers = append(providers, sv)
  103. }
  104. }
  105. if len(providers) == 0 {
  106. return nil, ErrNoSigners
  107. }
  108. evps := []Verifier{}
  109. for _, p := range providers {
  110. evps = append(evps, p.(Verifier))
  111. }
  112. ev, err := NewMultiEnvelopeVerifier(threshold, evps...)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return &EnvelopeSigner{
  117. providers: providers,
  118. ev: ev,
  119. }, nil
  120. }
  121. /*
  122. SignPayload signs a payload and payload type according to DSSE.
  123. Returned is an envelope as defined here:
  124. https://github.com/secure-systems-lab/dsse/blob/master/envelope.md
  125. One signature will be added for each Signer in the EnvelopeSigner.
  126. */
  127. func (es *EnvelopeSigner) SignPayload(payloadType string, body []byte) (*Envelope, error) {
  128. var e = Envelope{
  129. Payload: base64.StdEncoding.EncodeToString(body),
  130. PayloadType: payloadType,
  131. }
  132. paeEnc := PAE(payloadType, body)
  133. for _, signer := range es.providers {
  134. sig, err := signer.Sign(paeEnc)
  135. if err != nil {
  136. return nil, err
  137. }
  138. keyID, err := signer.KeyID()
  139. if err != nil {
  140. keyID = ""
  141. }
  142. e.Signatures = append(e.Signatures, Signature{
  143. KeyID: keyID,
  144. Sig: base64.StdEncoding.EncodeToString(sig),
  145. })
  146. }
  147. return &e, nil
  148. }
  149. /*
  150. Verify decodes the payload and verifies the signature.
  151. Any domain specific validation such as parsing the decoded body and
  152. validating the payload type is left out to the caller.
  153. Verify returns a list of accepted keys each including a keyid, public and signiture of the accepted provider keys.
  154. */
  155. func (es *EnvelopeSigner) Verify(e *Envelope) ([]AcceptedKey, error) {
  156. return es.ev.Verify(e)
  157. }
  158. /*
  159. Both standard and url encoding are allowed:
  160. https://github.com/secure-systems-lab/dsse/blob/master/envelope.md
  161. */
  162. func b64Decode(s string) ([]byte, error) {
  163. b, err := base64.StdEncoding.DecodeString(s)
  164. if err != nil {
  165. b, err = base64.URLEncoding.DecodeString(s)
  166. if err != nil {
  167. return nil, err
  168. }
  169. }
  170. return b, nil
  171. }