1
16
17 package jose
18
19 import (
20 "bytes"
21 "encoding/base64"
22 "errors"
23 "fmt"
24 "strings"
25
26 "gopkg.in/square/go-jose.v2/json"
27 )
28
29
30 type rawJSONWebSignature struct {
31 Payload *byteBuffer `json:"payload,omitempty"`
32 Signatures []rawSignatureInfo `json:"signatures,omitempty"`
33 Protected *byteBuffer `json:"protected,omitempty"`
34 Header *rawHeader `json:"header,omitempty"`
35 Signature *byteBuffer `json:"signature,omitempty"`
36 }
37
38
39 type rawSignatureInfo struct {
40 Protected *byteBuffer `json:"protected,omitempty"`
41 Header *rawHeader `json:"header,omitempty"`
42 Signature *byteBuffer `json:"signature,omitempty"`
43 }
44
45
46 type JSONWebSignature struct {
47 payload []byte
48
49
50
51 Signatures []Signature
52 }
53
54
55 type Signature struct {
56
57
58
59
60 Header Header
61
62
63
64 Protected Header
65
66
67
68 Unprotected Header
69
70
71 Signature []byte
72
73 protected *rawHeader
74 header *rawHeader
75 original *rawSignatureInfo
76 }
77
78
79 func ParseSigned(signature string) (*JSONWebSignature, error) {
80 signature = stripWhitespace(signature)
81 if strings.HasPrefix(signature, "{") {
82 return parseSignedFull(signature)
83 }
84
85 return parseSignedCompact(signature, nil)
86 }
87
88
89 func ParseDetached(signature string, payload []byte) (*JSONWebSignature, error) {
90 if payload == nil {
91 return nil, errors.New("square/go-jose: nil payload")
92 }
93 return parseSignedCompact(stripWhitespace(signature), payload)
94 }
95
96
97 func (sig Signature) mergedHeaders() rawHeader {
98 out := rawHeader{}
99 out.merge(sig.protected)
100 out.merge(sig.header)
101 return out
102 }
103
104
105 func (obj JSONWebSignature) computeAuthData(payload []byte, signature *Signature) ([]byte, error) {
106 var authData bytes.Buffer
107
108 protectedHeader := new(rawHeader)
109
110 if signature.original != nil && signature.original.Protected != nil {
111 if err := json.Unmarshal(signature.original.Protected.bytes(), protectedHeader); err != nil {
112 return nil, err
113 }
114 authData.WriteString(signature.original.Protected.base64())
115 } else if signature.protected != nil {
116 protectedHeader = signature.protected
117 authData.WriteString(base64.RawURLEncoding.EncodeToString(mustSerializeJSON(protectedHeader)))
118 }
119
120 needsBase64 := true
121
122 if protectedHeader != nil {
123 var err error
124 if needsBase64, err = protectedHeader.getB64(); err != nil {
125 needsBase64 = true
126 }
127 }
128
129 authData.WriteByte('.')
130
131 if needsBase64 {
132 authData.WriteString(base64.RawURLEncoding.EncodeToString(payload))
133 } else {
134 authData.Write(payload)
135 }
136
137 return authData.Bytes(), nil
138 }
139
140
141 func parseSignedFull(input string) (*JSONWebSignature, error) {
142 var parsed rawJSONWebSignature
143 err := json.Unmarshal([]byte(input), &parsed)
144 if err != nil {
145 return nil, err
146 }
147
148 return parsed.sanitized()
149 }
150
151
152 func (parsed *rawJSONWebSignature) sanitized() (*JSONWebSignature, error) {
153 if parsed.Payload == nil {
154 return nil, fmt.Errorf("square/go-jose: missing payload in JWS message")
155 }
156
157 obj := &JSONWebSignature{
158 payload: parsed.Payload.bytes(),
159 Signatures: make([]Signature, len(parsed.Signatures)),
160 }
161
162 if len(parsed.Signatures) == 0 {
163
164 signature := Signature{}
165 if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
166 signature.protected = &rawHeader{}
167 err := json.Unmarshal(parsed.Protected.bytes(), signature.protected)
168 if err != nil {
169 return nil, err
170 }
171 }
172
173
174 if parsed.Header != nil && parsed.Header.getNonce() != "" {
175 return nil, ErrUnprotectedNonce
176 }
177
178 signature.header = parsed.Header
179 signature.Signature = parsed.Signature.bytes()
180
181
182
183
184
185
186
187
188
189 signature.original = &rawSignatureInfo{
190 Protected: parsed.Protected,
191 Header: parsed.Header,
192 Signature: parsed.Signature,
193 }
194
195 var err error
196 signature.Header, err = signature.mergedHeaders().sanitized()
197 if err != nil {
198 return nil, err
199 }
200
201 if signature.header != nil {
202 signature.Unprotected, err = signature.header.sanitized()
203 if err != nil {
204 return nil, err
205 }
206 }
207
208 if signature.protected != nil {
209 signature.Protected, err = signature.protected.sanitized()
210 if err != nil {
211 return nil, err
212 }
213 }
214
215
216 jwk := signature.Header.JSONWebKey
217 if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
218 return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
219 }
220
221 obj.Signatures = append(obj.Signatures, signature)
222 }
223
224 for i, sig := range parsed.Signatures {
225 if sig.Protected != nil && len(sig.Protected.bytes()) > 0 {
226 obj.Signatures[i].protected = &rawHeader{}
227 err := json.Unmarshal(sig.Protected.bytes(), obj.Signatures[i].protected)
228 if err != nil {
229 return nil, err
230 }
231 }
232
233
234 if sig.Header != nil && sig.Header.getNonce() != "" {
235 return nil, ErrUnprotectedNonce
236 }
237
238 var err error
239 obj.Signatures[i].Header, err = obj.Signatures[i].mergedHeaders().sanitized()
240 if err != nil {
241 return nil, err
242 }
243
244 if obj.Signatures[i].header != nil {
245 obj.Signatures[i].Unprotected, err = obj.Signatures[i].header.sanitized()
246 if err != nil {
247 return nil, err
248 }
249 }
250
251 if obj.Signatures[i].protected != nil {
252 obj.Signatures[i].Protected, err = obj.Signatures[i].protected.sanitized()
253 if err != nil {
254 return nil, err
255 }
256 }
257
258 obj.Signatures[i].Signature = sig.Signature.bytes()
259
260
261 jwk := obj.Signatures[i].Header.JSONWebKey
262 if jwk != nil && (!jwk.Valid() || !jwk.IsPublic()) {
263 return nil, errors.New("square/go-jose: invalid embedded jwk, must be public key")
264 }
265
266
267 original := sig
268
269 obj.Signatures[i].header = sig.Header
270 obj.Signatures[i].original = &original
271 }
272
273 return obj, nil
274 }
275
276
277 func parseSignedCompact(input string, payload []byte) (*JSONWebSignature, error) {
278 parts := strings.Split(input, ".")
279 if len(parts) != 3 {
280 return nil, fmt.Errorf("square/go-jose: compact JWS format must have three parts")
281 }
282
283 if parts[1] != "" && payload != nil {
284 return nil, fmt.Errorf("square/go-jose: payload is not detached")
285 }
286
287 rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
288 if err != nil {
289 return nil, err
290 }
291
292 if payload == nil {
293 payload, err = base64.RawURLEncoding.DecodeString(parts[1])
294 if err != nil {
295 return nil, err
296 }
297 }
298
299 signature, err := base64.RawURLEncoding.DecodeString(parts[2])
300 if err != nil {
301 return nil, err
302 }
303
304 raw := &rawJSONWebSignature{
305 Payload: newBuffer(payload),
306 Protected: newBuffer(rawProtected),
307 Signature: newBuffer(signature),
308 }
309 return raw.sanitized()
310 }
311
312 func (obj JSONWebSignature) compactSerialize(detached bool) (string, error) {
313 if len(obj.Signatures) != 1 || obj.Signatures[0].header != nil || obj.Signatures[0].protected == nil {
314 return "", ErrNotSupported
315 }
316
317 serializedProtected := base64.RawURLEncoding.EncodeToString(mustSerializeJSON(obj.Signatures[0].protected))
318 payload := ""
319 signature := base64.RawURLEncoding.EncodeToString(obj.Signatures[0].Signature)
320
321 if !detached {
322 payload = base64.RawURLEncoding.EncodeToString(obj.payload)
323 }
324
325 return fmt.Sprintf("%s.%s.%s", serializedProtected, payload, signature), nil
326 }
327
328
329 func (obj JSONWebSignature) CompactSerialize() (string, error) {
330 return obj.compactSerialize(false)
331 }
332
333
334 func (obj JSONWebSignature) DetachedCompactSerialize() (string, error) {
335 return obj.compactSerialize(true)
336 }
337
338
339 func (obj JSONWebSignature) FullSerialize() string {
340 raw := rawJSONWebSignature{
341 Payload: newBuffer(obj.payload),
342 }
343
344 if len(obj.Signatures) == 1 {
345 if obj.Signatures[0].protected != nil {
346 serializedProtected := mustSerializeJSON(obj.Signatures[0].protected)
347 raw.Protected = newBuffer(serializedProtected)
348 }
349 raw.Header = obj.Signatures[0].header
350 raw.Signature = newBuffer(obj.Signatures[0].Signature)
351 } else {
352 raw.Signatures = make([]rawSignatureInfo, len(obj.Signatures))
353 for i, signature := range obj.Signatures {
354 raw.Signatures[i] = rawSignatureInfo{
355 Header: signature.header,
356 Signature: newBuffer(signature.Signature),
357 }
358
359 if signature.protected != nil {
360 raw.Signatures[i].Protected = newBuffer(mustSerializeJSON(signature.protected))
361 }
362 }
363 }
364
365 return string(mustSerializeJSON(raw))
366 }
367
View as plain text