1
16
17 package jose
18
19 import (
20 "encoding/base64"
21 "fmt"
22 "strings"
23
24 "gopkg.in/square/go-jose.v2/json"
25 )
26
27
28 type rawJSONWebEncryption struct {
29 Protected *byteBuffer `json:"protected,omitempty"`
30 Unprotected *rawHeader `json:"unprotected,omitempty"`
31 Header *rawHeader `json:"header,omitempty"`
32 Recipients []rawRecipientInfo `json:"recipients,omitempty"`
33 Aad *byteBuffer `json:"aad,omitempty"`
34 EncryptedKey *byteBuffer `json:"encrypted_key,omitempty"`
35 Iv *byteBuffer `json:"iv,omitempty"`
36 Ciphertext *byteBuffer `json:"ciphertext,omitempty"`
37 Tag *byteBuffer `json:"tag,omitempty"`
38 }
39
40
41 type rawRecipientInfo struct {
42 Header *rawHeader `json:"header,omitempty"`
43 EncryptedKey string `json:"encrypted_key,omitempty"`
44 }
45
46
47 type JSONWebEncryption struct {
48 Header Header
49 protected, unprotected *rawHeader
50 recipients []recipientInfo
51 aad, iv, ciphertext, tag []byte
52 original *rawJSONWebEncryption
53 }
54
55
56 type recipientInfo struct {
57 header *rawHeader
58 encryptedKey []byte
59 }
60
61
62 func (obj JSONWebEncryption) GetAuthData() []byte {
63 if obj.aad != nil {
64 out := make([]byte, len(obj.aad))
65 copy(out, obj.aad)
66 return out
67 }
68
69 return nil
70 }
71
72
73 func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
74 out := rawHeader{}
75 out.merge(obj.protected)
76 out.merge(obj.unprotected)
77
78 if recipient != nil {
79 out.merge(recipient.header)
80 }
81
82 return out
83 }
84
85
86 func (obj JSONWebEncryption) computeAuthData() []byte {
87 var protected string
88
89 if obj.original != nil && obj.original.Protected != nil {
90 protected = obj.original.Protected.base64()
91 } else if obj.protected != nil {
92 protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
93 } else {
94 protected = ""
95 }
96
97 output := []byte(protected)
98 if obj.aad != nil {
99 output = append(output, '.')
100 output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
101 }
102
103 return output
104 }
105
106
107 func ParseEncrypted(input string) (*JSONWebEncryption, error) {
108 input = stripWhitespace(input)
109 if strings.HasPrefix(input, "{") {
110 return parseEncryptedFull(input)
111 }
112
113 return parseEncryptedCompact(input)
114 }
115
116
117 func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
118 var parsed rawJSONWebEncryption
119 err := json.Unmarshal([]byte(input), &parsed)
120 if err != nil {
121 return nil, err
122 }
123
124 return parsed.sanitized()
125 }
126
127
128 func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
129 obj := &JSONWebEncryption{
130 original: parsed,
131 unprotected: parsed.Unprotected,
132 }
133
134
135 if parsed.Unprotected != nil {
136 if nonce := parsed.Unprotected.getNonce(); nonce != "" {
137 return nil, ErrUnprotectedNonce
138 }
139 }
140 if parsed.Header != nil {
141 if nonce := parsed.Header.getNonce(); nonce != "" {
142 return nil, ErrUnprotectedNonce
143 }
144 }
145
146 if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
147 err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
148 if err != nil {
149 return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
150 }
151 }
152
153
154
155 var err error
156 mergedHeaders := obj.mergedHeaders(nil)
157 obj.Header, err = mergedHeaders.sanitized()
158 if err != nil {
159 return nil, fmt.Errorf("square/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
160 }
161
162 if len(parsed.Recipients) == 0 {
163 obj.recipients = []recipientInfo{
164 {
165 header: parsed.Header,
166 encryptedKey: parsed.EncryptedKey.bytes(),
167 },
168 }
169 } else {
170 obj.recipients = make([]recipientInfo, len(parsed.Recipients))
171 for r := range parsed.Recipients {
172 encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
173 if err != nil {
174 return nil, err
175 }
176
177
178 if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
179 return nil, ErrUnprotectedNonce
180 }
181
182 obj.recipients[r].header = parsed.Recipients[r].Header
183 obj.recipients[r].encryptedKey = encryptedKey
184 }
185 }
186
187 for _, recipient := range obj.recipients {
188 headers := obj.mergedHeaders(&recipient)
189 if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
190 return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
191 }
192 }
193
194 obj.iv = parsed.Iv.bytes()
195 obj.ciphertext = parsed.Ciphertext.bytes()
196 obj.tag = parsed.Tag.bytes()
197 obj.aad = parsed.Aad.bytes()
198
199 return obj, nil
200 }
201
202
203 func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
204 parts := strings.Split(input, ".")
205 if len(parts) != 5 {
206 return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
207 }
208
209 rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
210 if err != nil {
211 return nil, err
212 }
213
214 encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
215 if err != nil {
216 return nil, err
217 }
218
219 iv, err := base64.RawURLEncoding.DecodeString(parts[2])
220 if err != nil {
221 return nil, err
222 }
223
224 ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
225 if err != nil {
226 return nil, err
227 }
228
229 tag, err := base64.RawURLEncoding.DecodeString(parts[4])
230 if err != nil {
231 return nil, err
232 }
233
234 raw := &rawJSONWebEncryption{
235 Protected: newBuffer(rawProtected),
236 EncryptedKey: newBuffer(encryptedKey),
237 Iv: newBuffer(iv),
238 Ciphertext: newBuffer(ciphertext),
239 Tag: newBuffer(tag),
240 }
241
242 return raw.sanitized()
243 }
244
245
246 func (obj JSONWebEncryption) CompactSerialize() (string, error) {
247 if len(obj.recipients) != 1 || obj.unprotected != nil ||
248 obj.protected == nil || obj.recipients[0].header != nil {
249 return "", ErrNotSupported
250 }
251
252 serializedProtected := mustSerializeJSON(obj.protected)
253
254 return fmt.Sprintf(
255 "%s.%s.%s.%s.%s",
256 base64.RawURLEncoding.EncodeToString(serializedProtected),
257 base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
258 base64.RawURLEncoding.EncodeToString(obj.iv),
259 base64.RawURLEncoding.EncodeToString(obj.ciphertext),
260 base64.RawURLEncoding.EncodeToString(obj.tag)), nil
261 }
262
263
264 func (obj JSONWebEncryption) FullSerialize() string {
265 raw := rawJSONWebEncryption{
266 Unprotected: obj.unprotected,
267 Iv: newBuffer(obj.iv),
268 Ciphertext: newBuffer(obj.ciphertext),
269 EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
270 Tag: newBuffer(obj.tag),
271 Aad: newBuffer(obj.aad),
272 Recipients: []rawRecipientInfo{},
273 }
274
275 if len(obj.recipients) > 1 {
276 for _, recipient := range obj.recipients {
277 info := rawRecipientInfo{
278 Header: recipient.header,
279 EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
280 }
281 raw.Recipients = append(raw.Recipients, info)
282 }
283 } else {
284
285 raw.Header = obj.recipients[0].header
286 raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
287 }
288
289 if obj.protected != nil {
290 raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
291 }
292
293 return string(mustSerializeJSON(raw))
294 }
295
View as plain text