jws.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /*-
  2. * Copyright 2014 Square Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package jose
  17. import (
  18. "bytes"
  19. "encoding/base64"
  20. "errors"
  21. "fmt"
  22. "strings"
  23. "gopkg.in/square/go-jose.v2/json"
  24. )
  25. // rawJSONWebSignature represents a raw JWS JSON object. Used for parsing/serializing.
  26. type rawJSONWebSignature struct {
  27. Payload *byteBuffer `json:"payload,omitempty"`
  28. Signatures []rawSignatureInfo `json:"signatures,omitempty"`
  29. Protected *byteBuffer `json:"protected,omitempty"`
  30. Header *rawHeader `json:"header,omitempty"`
  31. Signature *byteBuffer `json:"signature,omitempty"`
  32. }
  33. // rawSignatureInfo represents a single JWS signature over the JWS payload and protected header.
  34. type rawSignatureInfo struct {
  35. Protected *byteBuffer `json:"protected,omitempty"`
  36. Header *rawHeader `json:"header,omitempty"`
  37. Signature *byteBuffer `json:"signature,omitempty"`
  38. }
  39. // JSONWebSignature represents a signed JWS object after parsing.
  40. type JSONWebSignature struct {
  41. payload []byte
  42. // Signatures attached to this object (may be more than one for multi-sig).
  43. // Be careful about accessing these directly, prefer to use Verify() or
  44. // VerifyMulti() to ensure that the data you're getting is verified.
  45. Signatures []Signature
  46. }
  47. // Signature represents a single signature over the JWS payload and protected header.
  48. type Signature struct {
  49. // Merged header fields. Contains both protected and unprotected header
  50. // values. Prefer using Protected and Unprotected fields instead of this.
  51. // Values in this header may or may not have been signed and in general
  52. // should not be trusted.
  53. Header Header
  54. // Protected header. Values in this header were signed and
  55. // will be verified as part of the signature verification process.
  56. Protected Header
  57. // Unprotected header. Values in this header were not signed
  58. // and in general should not be trusted.
  59. Unprotected Header
  60. // The actual signature value
  61. Signature []byte
  62. protected *rawHeader
  63. header *rawHeader
  64. original *rawSignatureInfo
  65. }
  66. // ParseSigned parses a signed message in compact or full serialization format.
  67. func ParseSigned(signature string) (*JSONWebSignature, error) {
  68. signature = stripWhitespace(signature)
  69. if strings.HasPrefix(signature, "{") {
  70. return parseSignedFull(signature)
  71. }
  72. return parseSignedCompact(signature, nil)
  73. }
  74. // ParseDetached parses a signed message in compact serialization format with detached payload.
  75. func ParseDetached(signature string, payload []byte) (*JSONWebSignature, error) {
  76. if payload == nil {
  77. return nil, errors.New("square/go-jose: nil payload")
  78. }
  79. return parseSignedCompact(stripWhitespace(signature), payload)
  80. }
  81. // Get a header value
  82. func (sig Signature) mergedHeaders() rawHeader {
  83. out := rawHeader{}
  84. out.merge(sig.protected)
  85. out.merge(sig.header)
  86. return out
  87. }
  88. // Compute data to be signed
  89. func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) []byte {
  90. var authData bytes.Buffer
  91. protectedHeader := new(rawHeader)
  92. if signature.original != nil && signature.original.Protected != nil {
  93. if err := json.Unmarshal(signature.original.Protected.bytes(), protectedHeader); err != nil {
  94. panic(err)
  95. }
  96. authData.WriteString(signature.original.Protected.base64())
  97. } else if signature.protected != nil {
  98. protectedHeader = signature.protected
  99. authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader)))
  100. }
  101. needsBase64 := true
  102. if protectedHeader != nil {
  103. var err error
  104. if needsBase64, err = protectedHeader.getB64(); err != nil {
  105. needsBase64 = true
  106. }
  107. }
  108. authData.WriteByte('.')
  109. if needsBase64 {
  110. authData.WriteString(base64.RawURLEncoding.EncodeToString(payload))
  111. } else {
  112. authData.Write(payload)
  113. }
  114. return authData.Bytes()
  115. }
  116. // parseSignedFull parses a message in full format.
  117. func parseSignedFull(input string) (*JSONWebSignature, error) {
  118. var parsed rawJSONWebSignature
  119. err := json.Unmarshal([]byte(input), &parsed)
  120. if err != nil {
  121. return nil, err
  122. }
  123. return parsed.sanitized()
  124. }
  125. // sanitized produces a cleaned-up JWS object from the raw JSON.
  126. func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
  127. if parsed.Payload == nil {
  128. return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
  129. }
  130. obj := &JSONWebSignature{
  131. payload: parsed.Payload.bytes(),
  132. Signatures: make([]Signature, len(parsed.Signatures)),
  133. }
  134. if len(parsed.Signatures) == 0 {
  135. // No signatures array, must be flattened serialization
  136. signature := Signature{}
  137. if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
  138. signature.protected = &rawHeader{}
  139. err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
  140. if err != nil {
  141. return nil, err
  142. }
  143. }
  144. // Check that there is not a nonce in the unprotected header
  145. if parsed.Header != nil && parsed.Header.getNonce() != "" {
  146. return nil, ErrUnprotectedNonce
  147. }
  148. signature.header = parsed.Header
  149. signature.Signature = parsed.Signature.bytes()
  150. // Make a fake "original" rawSignatureInfo to store the unprocessed
  151. // Protected header. This is necessary because the Protected header can
  152. // contain arbitrary fields not registered as part of the spec. See
  153. // https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-4
  154. // If we unmarshal Protected into a rawHeader with its explicit list of fields,
  155. // we cannot marshal losslessly. So we have to keep around the original bytes.
  156. // This is used in computeAuthData, which will first attempt to use
  157. // the original bytes of a protected header, and fall back on marshaling the
  158. // header struct only if those bytes are not available.
  159. signature.original = &rawSignatureInfo{
  160. Protected: parsed.Protected,
  161. Header: parsed.Header,
  162. Signature: parsed.Signature,
  163. }
  164. var err error
  165. signature.Header, err = signature.mergedHeaders().sanitized()
  166. if err != nil {
  167. return nil, err
  168. }
  169. if signature.header != nil {
  170. signature.Unprotected, err = signature.header.sanitized()
  171. if err != nil {
  172. return nil, err
  173. }
  174. }
  175. if signature.protected != nil {
  176. signature.Protected, err = signature.protected.sanitized()
  177. if err != nil {
  178. return nil, err
  179. }
  180. }
  181. // As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
  182. jwk := signature.Header.JSONWebKey
  183. if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
  184. return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
  185. }
  186. obj.Signatures = append(obj.Signatures, signature)
  187. }
  188. for i, sig := range parsed.Signatures {
  189. if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
  190. obj.Signatures[i].protected = &rawHeader{}
  191. err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
  192. if err != nil {
  193. return nil, err
  194. }
  195. }
  196. // Check that there is not a nonce in the unprotected header
  197. if sig.Header != nil && sig.Header.getNonce() != "" {
  198. return nil, ErrUnprotectedNonce
  199. }
  200. var err error
  201. obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
  202. if err != nil {
  203. return nil, err
  204. }
  205. if obj.Signatures[i].header != nil {
  206. obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
  207. if err != nil {
  208. return nil, err
  209. }
  210. }
  211. if obj.Signatures[i].protected != nil {
  212. obj.Signatures[i].Protected, err = obj.Signatures[i].protected.sanitized()
  213. if err != nil {
  214. return nil, err
  215. }
  216. }
  217. obj.Signatures[i].Signature = sig.Signature.bytes()
  218. // As per RFC 7515 Section 4.1.3, only public keys are allowed to be embedded.
  219. jwk := obj.Signatures[i].Header.JSONWebKey
  220. if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
  221. return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
  222. }
  223. // Copy value of sig
  224. original := sig
  225. obj.Signatures[i].header = sig.Header
  226. obj.Signatures[i].original = &original
  227. }
  228. return obj, nil
  229. }
  230. // parseSignedCompact parses a message in compact format.
  231. func parseSignedCompact(input string, payload []byte) (*JSONWebSignature, error) {
  232. parts := strings.Split(input, ".")
  233. if len(parts) != 3 {
  234. return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
  235. }
  236. if parts[1] != "" && payload != nil {
  237. return nil, fmt.Errorf("square/go-jose: payload is not detached")
  238. }
  239. rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
  240. if err != nil {
  241. return nil, err
  242. }
  243. if payload == nil {
  244. payload, err = base64.RawURLEncoding.DecodeString(parts[1])
  245. if err != nil {
  246. return nil, err
  247. }
  248. }
  249. signature, err := base64.RawURLEncoding.DecodeString(parts[2])
  250. if err != nil {
  251. return nil, err
  252. }
  253. raw := &rawJSONWebSignature{
  254. Payload: newBuffer(payload),
  255. Protected: newBuffer(rawProtected),
  256. Signature: newBuffer(signature),
  257. }
  258. return raw.sanitized()
  259. }
  260. func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
  261. if len(obj.Signatures) != 1 || obj.Signatures[0].header != nil || obj.Signatures[0].protected == nil {
  262. return "", ErrNotSupported
  263. }
  264. serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected))
  265. payload := ""
  266. signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)
  267. if !detached {
  268. payload = base64.RawURLEncoding.EncodeToString(obj.payload)
  269. }
  270. return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil
  271. }
  272. // CompactSerialize serializes an object using the compact serialization format.
  273. func (obj JSONWebSignature) CompactSerialize() (string, error) {
  274. return obj.compactSerialize(false)
  275. }
  276. // DetachedCompactSerialize serializes an object using the compact serialization format with detached payload.
  277. func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) {
  278. return obj.compactSerialize(true)
  279. }
  280. // FullSerialize serializes an object using the full JSON serialization format.
  281. func (obj JSONWebSignature) FullSerialize() string {
  282. raw := rawJSONWebSignature{
  283. Payload: newBuffer(obj.payload),
  284. }
  285. if len(obj.Signatures) == 1 {
  286. if obj.Signatures[0].protected != nil {
  287. serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
  288. raw.Protected = newBuffer(serializedProtected)
  289. }
  290. raw.Header = obj.Signatures[0].header
  291. raw.Signature = newBuffer(obj.Signatures[0].Signature)
  292. } else {
  293. raw.Signatures = make([]rawSignatureInfo, len(obj.Signatures))
  294. for i, signature := range obj.Signatures {
  295. raw.Signatures[i] = rawSignatureInfo{
  296. Header: signature.header,
  297. Signature: newBuffer(signature.Signature),
  298. }
  299. if signature.protected != nil {
  300. raw.Signatures[i].Protected = newBuffer(mustSerializeJSON(signature.protected))
  301. }
  302. }
  303. }
  304. return string(mustSerializeJSON(raw))
  305. }