🌐 AI搜索 & 代理 主页
blob: b5a6dcdf4db362a8266d1e39aa1debc1549172ac [file] [log] [blame]
Cedric Staub114bcf42014-12-19 06:59:301/*-
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
17package jose
18
19import (
Cedric Staub92a7aaa2016-02-14 23:34:4420 "encoding/base64"
Cedric Staub114bcf42014-12-19 06:59:3021 "fmt"
22 "strings"
Cedric Staub468cf012018-07-25 18:14:5823
24 "gopkg.in/square/go-jose.v2/json"
Cedric Staub114bcf42014-12-19 06:59:3025)
26
Cedric Staubd94ed212016-02-15 01:18:3827// rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
28type rawJSONWebEncryption struct {
Cedric Staub313a2612014-12-23 23:16:0929 Protected *byteBuffer `json:"protected,omitempty"`
30 Unprotected *rawHeader `json:"unprotected,omitempty"`
31 Header *rawHeader `json:"header,omitempty"`
Cedric Staub00b71592014-12-23 20:50:0132 Recipients []rawRecipientInfo `json:"recipients,omitempty"`
Cedric Staub313a2612014-12-23 23:16:0933 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"`
Cedric Staub114bcf42014-12-19 06:59:3038}
39
Cedric Staub313a2612014-12-23 23:16:0940// rawRecipientInfo represents a raw JWE Per-Recipient header JSON object. Used for parsing/serializing.
Cedric Staub114bcf42014-12-19 06:59:3041type rawRecipientInfo struct {
Cedric Staub313a2612014-12-23 23:16:0942 Header *rawHeader `json:"header,omitempty"`
43 EncryptedKey string `json:"encrypted_key,omitempty"`
Cedric Staub114bcf42014-12-19 06:59:3044}
45
Cedric Staubd94ed212016-02-15 01:18:3846// JSONWebEncryption represents an encrypted JWE object after parsing.
47type JSONWebEncryption struct {
48 Header Header
Cedric Staub313a2612014-12-23 23:16:0949 protected, unprotected *rawHeader
Cedric Staub114bcf42014-12-19 06:59:3050 recipients []recipientInfo
51 aad, iv, ciphertext, tag []byte
Cedric Staubd94ed212016-02-15 01:18:3852 original *rawJSONWebEncryption
Cedric Staub114bcf42014-12-19 06:59:3053}
54
Cedric Staub313a2612014-12-23 23:16:0955// recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
Cedric Staub114bcf42014-12-19 06:59:3056type recipientInfo struct {
Cedric Staub313a2612014-12-23 23:16:0957 header *rawHeader
Cedric Staub114bcf42014-12-19 06:59:3058 encryptedKey []byte
59}
60
61// GetAuthData retrieves the (optional) authenticated data attached to the object.
Cedric Staubd94ed212016-02-15 01:18:3862func (obj JSONWebEncryption) GetAuthData() []byte {
Cedric Staub114bcf42014-12-19 06:59:3063 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
Cedric Staub00b71592014-12-23 20:50:0172// Get the merged header values
Cedric Staubd94ed212016-02-15 01:18:3873func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
Cedric Staub313a2612014-12-23 23:16:0974 out := rawHeader{}
Richard Barnes4b2d8212015-10-08 19:47:5375 out.merge(obj.protected)
76 out.merge(obj.unprotected)
Cedric Staub00b71592014-12-23 20:50:0177
78 if recipient != nil {
Richard Barnes4b2d8212015-10-08 19:47:5379 out.merge(recipient.header)
Cedric Staub00b71592014-12-23 20:50:0180 }
81
82 return out
83}
84
Cedric Staub114bcf42014-12-19 06:59:3085// Get the additional authenticated data from a JWE object.
Cedric Staubd94ed212016-02-15 01:18:3886func (obj JSONWebEncryption) computeAuthData() []byte {
Cedric Staub114bcf42014-12-19 06:59:3087 var protected string
88
Cedric Staub8272fb42018-06-26 18:53:3689 if obj.original != nil && obj.original.Protected != nil {
Cedric Staub00b71592014-12-23 20:50:0190 protected = obj.original.Protected.base64()
Cedric Staub8272fb42018-06-26 18:53:3691 } else if obj.protected != nil {
Cedric Staub92a7aaa2016-02-14 23:34:4492 protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
Cedric Staub8272fb42018-06-26 18:53:3693 } else {
94 protected = ""
Cedric Staub114bcf42014-12-19 06:59:3095 }
96
97 output := []byte(protected)
98 if obj.aad != nil {
99 output = append(output, '.')
Cedric Staub92a7aaa2016-02-14 23:34:44100 output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
Cedric Staub114bcf42014-12-19 06:59:30101 }
102
103 return output
104}
105
Cedric Staub114bcf42014-12-19 06:59:30106// ParseEncrypted parses an encrypted message in compact or full serialization format.
Cedric Staubd94ed212016-02-15 01:18:38107func ParseEncrypted(input string) (*JSONWebEncryption, error) {
Cedric Staub114bcf42014-12-19 06:59:30108 input = stripWhitespace(input)
109 if strings.HasPrefix(input, "{") {
110 return parseEncryptedFull(input)
111 }
112
113 return parseEncryptedCompact(input)
114}
115
116// parseEncryptedFull parses a message in compact format.
Cedric Staubd94ed212016-02-15 01:18:38117func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
118 var parsed rawJSONWebEncryption
Cedric Staub1f36a882016-06-01 23:11:57119 err := json.Unmarshal([]byte(input), &parsed)
Cedric Staub114bcf42014-12-19 06:59:30120 if err != nil {
121 return nil, err
122 }
123
Cedric Staub06a25372015-03-04 06:39:47124 return parsed.sanitized()
125}
126
Cedric Staub93972302015-03-26 18:55:42127// sanitized produces a cleaned-up JWE object from the raw JSON.
Cedric Staubd94ed212016-02-15 01:18:38128func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
129 obj := &JSONWebEncryption{
Cedric Staub06a25372015-03-04 06:39:47130 original: parsed,
131 unprotected: parsed.Unprotected,
132 }
133
Richard Barnes4b2d8212015-10-08 19:47:53134 // Check that there is not a nonce in the unprotected headers
Hugo Landau3013e332017-02-08 18:24:40135 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 }
Richard Barnes4b2d8212015-10-08 19:47:53144 }
145
Cedric Staub00b71592014-12-23 20:50:01146 if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
Cedric Staub1f36a882016-06-01 23:11:57147 err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
Cedric Staub114bcf42014-12-19 06:59:30148 if err != nil {
Cedric Staub00b71592014-12-23 20:50:01149 return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
Cedric Staub114bcf42014-12-19 06:59:30150 }
151 }
152
Cedric Staub29c68552015-11-17 01:04:16153 // Note: this must be called _after_ we parse the protected header,
154 // otherwise fields from the protected header will not get picked up.
Hugo Landau3013e332017-02-08 18:24:40155 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 }
Cedric Staub29c68552015-11-17 01:04:16161
Cedric Staub114bcf42014-12-19 06:59:30162 if len(parsed.Recipients) == 0 {
Cedric Staub114bcf42014-12-19 06:59:30163 obj.recipients = []recipientInfo{
Cedric Staub3e5b0502016-02-15 01:06:30164 {
Cedric Staub114bcf42014-12-19 06:59:30165 header: parsed.Header,
Cedric Staub00b71592014-12-23 20:50:01166 encryptedKey: parsed.EncryptedKey.bytes(),
Cedric Staub114bcf42014-12-19 06:59:30167 },
168 }
169 } else {
170 obj.recipients = make([]recipientInfo, len(parsed.Recipients))
171 for r := range parsed.Recipients {
Cedric Staub92a7aaa2016-02-14 23:34:44172 encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
Cedric Staub114bcf42014-12-19 06:59:30173 if err != nil {
174 return nil, err
175 }
176
Richard Barnes4b2d8212015-10-08 19:47:53177 // Check that there is not a nonce in the unprotected header
Hugo Landau3013e332017-02-08 18:24:40178 if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
Richard Barnesabb992d2015-10-08 21:00:24179 return nil, ErrUnprotectedNonce
Richard Barnes4b2d8212015-10-08 19:47:53180 }
181
Cedric Staub114bcf42014-12-19 06:59:30182 obj.recipients[r].header = parsed.Recipients[r].Header
183 obj.recipients[r].encryptedKey = encryptedKey
184 }
185 }
186
Cedric Staub114bcf42014-12-19 06:59:30187 for _, recipient := range obj.recipients {
Cedric Staub00b71592014-12-23 20:50:01188 headers := obj.mergedHeaders(&recipient)
Hugo Landau3013e332017-02-08 18:24:40189 if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
Cedric Staub00b71592014-12-23 20:50:01190 return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
Cedric Staub114bcf42014-12-19 06:59:30191 }
192 }
193
Cedric Staub00b71592014-12-23 20:50:01194 obj.iv = parsed.Iv.bytes()
195 obj.ciphertext = parsed.Ciphertext.bytes()
196 obj.tag = parsed.Tag.bytes()
197 obj.aad = parsed.Aad.bytes()
198
Cedric Staub114bcf42014-12-19 06:59:30199 return obj, nil
200}
201
202// parseEncryptedCompact parses a message in compact format.
Cedric Staubd94ed212016-02-15 01:18:38203func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
Cedric Staub114bcf42014-12-19 06:59:30204 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
Cedric Staub92a7aaa2016-02-14 23:34:44209 rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
Cedric Staub114bcf42014-12-19 06:59:30210 if err != nil {
211 return nil, err
212 }
213
Cedric Staub92a7aaa2016-02-14 23:34:44214 encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
Cedric Staub114bcf42014-12-19 06:59:30215 if err != nil {
216 return nil, err
217 }
218
Cedric Staub92a7aaa2016-02-14 23:34:44219 iv, err := base64.RawURLEncoding.DecodeString(parts[2])
Cedric Staub114bcf42014-12-19 06:59:30220 if err != nil {
221 return nil, err
222 }
223
Cedric Staub92a7aaa2016-02-14 23:34:44224 ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
Cedric Staub114bcf42014-12-19 06:59:30225 if err != nil {
226 return nil, err
227 }
228
Cedric Staub92a7aaa2016-02-14 23:34:44229 tag, err := base64.RawURLEncoding.DecodeString(parts[4])
Cedric Staub114bcf42014-12-19 06:59:30230 if err != nil {
231 return nil, err
232 }
233
Cedric Staubd94ed212016-02-15 01:18:38234 raw := &rawJSONWebEncryption{
Cedric Staub06a25372015-03-04 06:39:47235 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()
Cedric Staub114bcf42014-12-19 06:59:30243}
244
245// CompactSerialize serializes an object using the compact serialization format.
Cedric Staubd94ed212016-02-15 01:18:38246func (obj JSONWebEncryption) CompactSerialize() (string, error) {
Richard Barnes9af74402015-11-17 18:57:04247 if len(obj.recipients) != 1 || obj.unprotected != nil ||
248 obj.protected == nil || obj.recipients[0].header != nil {
Cedric Staub114bcf42014-12-19 06:59:30249 return "", ErrNotSupported
250 }
251
Cedric Staub569deb32014-12-23 01:06:00252 serializedProtected := mustSerializeJSON(obj.protected)
Cedric Staub114bcf42014-12-19 06:59:30253
254 return fmt.Sprintf(
255 "%s.%s.%s.%s.%s",
Cedric Staub92a7aaa2016-02-14 23:34:44256 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
Cedric Staub114bcf42014-12-19 06:59:30261}
262
263// FullSerialize serializes an object using the full JSON serialization format.
Cedric Staubd94ed212016-02-15 01:18:38264func (obj JSONWebEncryption) FullSerialize() string {
265 raw := rawJSONWebEncryption{
Cedric Staub114bcf42014-12-19 06:59:30266 Unprotected: obj.unprotected,
Cedric Staub00b71592014-12-23 20:50:01267 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),
Cedric Staub114bcf42014-12-19 06:59:30272 Recipients: []rawRecipientInfo{},
273 }
274
275 if len(obj.recipients) > 1 {
276 for _, recipient := range obj.recipients {
277 info := rawRecipientInfo{
278 Header: recipient.header,
Cedric Staub92a7aaa2016-02-14 23:34:44279 EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
Cedric Staub114bcf42014-12-19 06:59:30280 }
281 raw.Recipients = append(raw.Recipients, info)
282 }
283 } else {
284 // Use flattened serialization
285 raw.Header = obj.recipients[0].header
Cedric Staub00b71592014-12-23 20:50:01286 raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
Cedric Staub114bcf42014-12-19 06:59:30287 }
288
Richard Barnes9af74402015-11-17 18:57:04289 if obj.protected != nil {
290 raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
291 }
Cedric Staub114bcf42014-12-19 06:59:30292
Cedric Staub569deb32014-12-23 01:06:00293 return string(mustSerializeJSON(raw))
Cedric Staub114bcf42014-12-19 06:59:30294}