github.com/trustbloc/kms-go@v1.1.2/doc/jose/jwe.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 // General serialization/deserialization design based off of https://github.com/square/go-jose/blob/master/jwe.go. 8 9 package jose 10 11 import ( 12 "encoding/base64" 13 "encoding/json" 14 "errors" 15 "fmt" 16 "strings" 17 ) 18 19 const ( 20 compactJWERequiredNumOfParts = 5 21 errCompactSerializationCommonText = "unable to compact serialize: " 22 ) 23 24 var ( 25 errWrongNumberOfCompactJWEParts = errors.New("invalid compact JWE: it must have five parts") 26 errEmptyCiphertext = errors.New("ciphertext cannot be empty") 27 errProtectedHeaderMissing = errors.New(errCompactSerializationCommonText + 28 "no protected header found") 29 ) 30 31 var errNotOnlyOneRecipient = errors.New(errCompactSerializationCommonText + 32 "JWE compact serialization only supports JWE with exactly one single recipient") 33 34 var errUnprotectedHeaderUnsupported = errors.New(errCompactSerializationCommonText + 35 "JWE compact serialization does not support a shared unprotected header") 36 37 var errAADHeaderUnsupported = errors.New(errCompactSerializationCommonText + 38 "JWE compact serialization does not support AAD") 39 40 var errPerRecipientHeaderUnsupported = errors.New(errCompactSerializationCommonText + 41 "JWE compact serialization does not support a per-recipient unprotected header") 42 43 // JSONWebEncryption represents a JWE as defined in https://tools.ietf.org/html/rfc7516. 44 type JSONWebEncryption struct { 45 ProtectedHeaders Headers 46 OrigProtectedHders string 47 UnprotectedHeaders Headers 48 Recipients []*Recipient 49 AAD string 50 IV string 51 Ciphertext string 52 Tag string 53 } 54 55 // Recipient is a recipient of a JWE including the shared encryption key. 56 type Recipient struct { 57 Header *RecipientHeaders `json:"header,omitempty"` 58 EncryptedKey string `json:"encrypted_key,omitempty"` 59 } 60 61 // RecipientHeaders are the recipient headers. 62 type RecipientHeaders struct { 63 Alg string `json:"alg,omitempty"` 64 APU string `json:"apu,omitempty"` 65 APV string `json:"apv,omitempty"` 66 IV string `json:"iv,omitempty"` 67 Tag string `json:"tag,omitempty"` 68 KID string `json:"kid,omitempty"` 69 EPK json.RawMessage `json:"epk,omitempty"` 70 } 71 72 // rawJSONWebEncryption represents a RAW JWE that is used for serialization/deserialization. 73 type rawJSONWebEncryption struct { 74 B64ProtectedHeaders string `json:"protected,omitempty"` 75 UnprotectedHeaders json.RawMessage `json:"unprotected,omitempty"` 76 Recipients json.RawMessage `json:"recipients,omitempty"` 77 B64SingleRecipientEncKey string `json:"encrypted_key,omitempty"` 78 SingleRecipientHeader json.RawMessage `json:"header,omitempty"` 79 B64AAD string `json:"aad,omitempty"` 80 B64IV string `json:"iv,omitempty"` 81 B64Ciphertext string `json:"ciphertext,omitempty"` 82 B64Tag string `json:"tag,omitempty"` 83 } 84 85 type marshalFunc func(interface{}) ([]byte, error) 86 87 // FullSerialize serializes the given JWE into JSON as defined in https://tools.ietf.org/html/rfc7516#section-7.2. 88 // The full serialization syntax is used. If there is only one recipient, then the flattened syntax is used. 89 func (e *JSONWebEncryption) FullSerialize(marshal marshalFunc) (string, error) { 90 b64ProtectedHeaders, unprotectedHeaders, err := e.prepareHeaders(marshal) 91 if err != nil { 92 return "", err 93 } 94 95 recipientsJSON, b64SingleRecipientEncKey, singleRecipientHeader, err := e.prepareRecipients(marshal) 96 if err != nil { 97 return "", err 98 } 99 100 b64AAD := base64.RawURLEncoding.EncodeToString([]byte(e.AAD)) 101 102 b64IV := base64.RawURLEncoding.EncodeToString([]byte(e.IV)) 103 104 if e.Ciphertext == "" { 105 return "", errEmptyCiphertext 106 } 107 108 b64Ciphertext := base64.RawURLEncoding.EncodeToString([]byte(e.Ciphertext)) 109 110 b64Tag := base64.RawURLEncoding.EncodeToString([]byte(e.Tag)) 111 112 preparedJWE := rawJSONWebEncryption{ 113 B64ProtectedHeaders: b64ProtectedHeaders, 114 UnprotectedHeaders: unprotectedHeaders, 115 Recipients: recipientsJSON, 116 B64SingleRecipientEncKey: b64SingleRecipientEncKey, 117 SingleRecipientHeader: singleRecipientHeader, 118 B64AAD: b64AAD, 119 B64IV: b64IV, 120 B64Ciphertext: b64Ciphertext, 121 B64Tag: b64Tag, 122 } 123 124 serializedJWE, err := marshal(preparedJWE) 125 if err != nil { 126 return "", err 127 } 128 129 return string(serializedJWE), nil 130 } 131 132 func (e *JSONWebEncryption) prepareHeaders(marshal marshalFunc) (string, json.RawMessage, error) { 133 var b64ProtectedHeaders string 134 135 if e.ProtectedHeaders != nil { 136 protectedHeadersJSON, err := marshal(e.ProtectedHeaders) 137 if err != nil { 138 return "", nil, err 139 } 140 141 b64ProtectedHeaders = base64.RawURLEncoding.EncodeToString(protectedHeadersJSON) 142 } 143 144 var unprotectedHeaders json.RawMessage 145 146 if e.UnprotectedHeaders != nil { 147 unprotectedHeadersJSON, err := marshal(e.UnprotectedHeaders) 148 if err != nil { 149 return "", nil, err 150 } 151 152 unprotectedHeaders = unprotectedHeadersJSON 153 } 154 155 return b64ProtectedHeaders, unprotectedHeaders, nil 156 } 157 158 func (e *JSONWebEncryption) prepareRecipients(marshal marshalFunc) (json.RawMessage, string, []byte, error) { 159 var recipientsJSON json.RawMessage 160 161 var b64SingleRecipientEncKey string 162 163 var singleRecipientHeader []byte 164 165 switch len(e.Recipients) { 166 case 0: 167 // The spec requires that the "recipients" field must always be an array and be present, 168 // even if some or all of the array values are the empty JSON object "{}". 169 recipientsJSON = json.RawMessage("[{}]") 170 case 1: 171 // Use flattened JWE JSON serialization syntax as defined in https://tools.ietf.org/html/rfc7516#section-7.2.2. 172 b64SingleRecipientEncKey = base64.RawURLEncoding.EncodeToString([]byte(e.Recipients[0].EncryptedKey)) 173 174 if e.Recipients[0].Header != nil { 175 var errMarshal error 176 177 singleRecipientHeader, errMarshal = marshal(e.Recipients[0].Header) 178 if errMarshal != nil { 179 return nil, "", nil, errMarshal 180 } 181 } 182 default: 183 // Make copy of Recipients array so we don't change the underlying object 184 recipientsToMarshal := make([]Recipient, len(e.Recipients)) 185 for i, recipient := range e.Recipients { 186 recipientsToMarshal[i].EncryptedKey = base64.RawURLEncoding.EncodeToString([]byte(recipient.EncryptedKey)) 187 recipientsToMarshal[i].Header = recipient.Header 188 } 189 190 nonEmptyRecipientsJSON, errMarshal := marshal(recipientsToMarshal) 191 if errMarshal != nil { 192 return nil, "", nil, errMarshal 193 } 194 195 recipientsJSON = nonEmptyRecipientsJSON 196 } 197 198 return recipientsJSON, b64SingleRecipientEncKey, singleRecipientHeader, nil 199 } 200 201 // CompactSerialize serializes the given JWE into a compact, URL-safe string as defined in 202 // https://tools.ietf.org/html/rfc7516#section-7.1. 203 func (e *JSONWebEncryption) CompactSerialize(marshal marshalFunc) (string, error) { 204 if e.ProtectedHeaders == nil { 205 return "", errProtectedHeaderMissing 206 } 207 208 if len(e.Recipients) != 1 { 209 return "", errNotOnlyOneRecipient 210 } 211 212 if e.UnprotectedHeaders != nil { 213 return "", errUnprotectedHeaderUnsupported 214 } 215 216 if e.AAD != "" { 217 return "", errAADHeaderUnsupported 218 } 219 220 if e.Recipients[0].Header != nil { 221 return "", errPerRecipientHeaderUnsupported 222 } 223 224 protectedHeadersJSON, err := marshal(e.ProtectedHeaders) 225 if err != nil { 226 return "", err 227 } 228 229 b64ProtectedHeader := base64.RawURLEncoding.EncodeToString(protectedHeadersJSON) 230 231 b64EncryptedKey := base64.RawURLEncoding.EncodeToString([]byte(e.Recipients[0].EncryptedKey)) 232 233 b64IV := base64.RawURLEncoding.EncodeToString([]byte(e.IV)) 234 235 b64Ciphertext := base64.RawURLEncoding.EncodeToString([]byte(e.Ciphertext)) 236 237 b64Tag := base64.RawURLEncoding.EncodeToString([]byte(e.Tag)) 238 239 return fmt.Sprintf("%s.%s.%s.%s.%s", b64ProtectedHeader, b64EncryptedKey, b64IV, b64Ciphertext, b64Tag), nil 240 } 241 242 // Deserialize deserializes the given serialized JWE into a JSONWebEncryption object. 243 func Deserialize(serializedJWE string) (*JSONWebEncryption, error) { 244 if strings.HasPrefix(serializedJWE, "{") { 245 return deserializeFull(serializedJWE) 246 } 247 248 return deserializeCompact(serializedJWE) 249 } 250 251 func deserializeFull(serializedJWE string) (*JSONWebEncryption, error) { 252 rawJWE := rawJSONWebEncryption{} 253 254 err := json.Unmarshal([]byte(serializedJWE), &rawJWE) 255 if err != nil { 256 return nil, err 257 } 258 259 return deserializeFromRawJWE(&rawJWE) 260 } 261 262 func deserializeCompact(serializedJWE string) (*JSONWebEncryption, error) { 263 parts := strings.Split(serializedJWE, ".") 264 if len(parts) != compactJWERequiredNumOfParts { 265 return nil, errWrongNumberOfCompactJWEParts 266 } 267 268 rawJWE := rawJSONWebEncryption{ 269 B64ProtectedHeaders: parts[0], 270 B64SingleRecipientEncKey: parts[1], 271 B64IV: parts[2], 272 B64Ciphertext: parts[3], 273 B64Tag: parts[4], 274 } 275 276 return deserializeFromRawJWE(&rawJWE) 277 } 278 279 func deserializeFromRawJWE(rawJWE *rawJSONWebEncryption) (*JSONWebEncryption, error) { 280 protectedHeaders, unprotectedHeaders, err := deserializeAndDecodeHeaders(rawJWE) 281 if err != nil { 282 return nil, err 283 } 284 285 recipients, err := deserializeRecipients(rawJWE) 286 if err != nil { 287 return nil, err 288 } 289 290 aad, err := base64.RawURLEncoding.DecodeString(rawJWE.B64AAD) 291 if err != nil { 292 return nil, err 293 } 294 295 iv, err := base64.RawURLEncoding.DecodeString(rawJWE.B64IV) 296 if err != nil { 297 return nil, err 298 } 299 300 ciphertext, err := base64.RawURLEncoding.DecodeString(rawJWE.B64Ciphertext) 301 if err != nil { 302 return nil, err 303 } 304 305 tag, err := base64.RawURLEncoding.DecodeString(rawJWE.B64Tag) 306 if err != nil { 307 return nil, err 308 } 309 310 deserializedJWE := JSONWebEncryption{ 311 ProtectedHeaders: *protectedHeaders, 312 OrigProtectedHders: rawJWE.B64ProtectedHeaders, 313 UnprotectedHeaders: *unprotectedHeaders, 314 Recipients: recipients, 315 AAD: string(aad), 316 IV: string(iv), 317 Ciphertext: string(ciphertext), 318 Tag: string(tag), 319 } 320 321 return &deserializedJWE, nil 322 } 323 324 func deserializeAndDecodeHeaders(rawJWE *rawJSONWebEncryption) (*Headers, *Headers, error) { 325 protectedHeadersBytes, err := base64.RawURLEncoding.DecodeString(rawJWE.B64ProtectedHeaders) 326 if err != nil { 327 return nil, nil, err 328 } 329 330 var protectedHeaders Headers 331 332 err = json.Unmarshal(protectedHeadersBytes, &protectedHeaders) 333 if err != nil { 334 return nil, nil, err 335 } 336 337 var unprotectedHeaders Headers 338 339 if rawJWE.UnprotectedHeaders != nil { 340 err = json.Unmarshal(rawJWE.UnprotectedHeaders, &unprotectedHeaders) 341 if err != nil { 342 return nil, nil, err 343 } 344 } 345 346 return &protectedHeaders, &unprotectedHeaders, nil 347 } 348 349 func parseDeserializeRecipients(rawJWE *rawJSONWebEncryption) ([]*Recipient, error) { 350 if rawJWE.Recipients != nil { 351 var recipients []*Recipient 352 353 err := json.Unmarshal(rawJWE.Recipients, &recipients) 354 if err != nil { 355 return nil, err 356 } 357 358 return recipients, nil 359 } 360 361 // If there is no recipients field, then we must be deserializing JWE with the flattened syntax as defined in 362 // https://tools.ietf.org/html/rfc7516#section-7.2.2. 363 recipient := &Recipient{EncryptedKey: rawJWE.B64SingleRecipientEncKey} 364 365 if rawJWE.SingleRecipientHeader != nil { 366 err := json.Unmarshal(rawJWE.SingleRecipientHeader, &recipient.Header) 367 if err != nil { 368 return nil, err 369 } 370 } 371 372 return []*Recipient{recipient}, nil 373 } 374 375 func deserializeRecipients(rawJWE *rawJSONWebEncryption) ([]*Recipient, error) { 376 recipients, err := parseDeserializeRecipients(rawJWE) 377 if err != nil { 378 return nil, err 379 } 380 381 for _, recipient := range recipients { 382 decodedEncKey, err := base64.RawURLEncoding.DecodeString(recipient.EncryptedKey) 383 if err != nil { 384 return nil, err 385 } 386 387 recipient.EncryptedKey = string(decodedEncKey) 388 } 389 390 return recipients, nil 391 }