| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 | 
							- /*-
 
-  * Copyright 2014 Square Inc.
 
-  *
 
-  * Licensed under the Apache License, Version 2.0 (the "License");
 
-  * you may not use this file except in compliance with the License.
 
-  * You may obtain a copy of the License at
 
-  *
 
-  *     http://www.apache.org/licenses/LICENSE-2.0
 
-  *
 
-  * Unless required by applicable law or agreed to in writing, software
 
-  * distributed under the License is distributed on an "AS IS" BASIS,
 
-  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
-  * See the License for the specific language governing permissions and
 
-  * limitations under the License.
 
-  */
 
- package jose
 
- import (
 
- 	"encoding/base64"
 
- 	"fmt"
 
- 	"strings"
 
- 	"gopkg.in/square/go-jose.v2/json"
 
- )
 
- // rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
 
- type rawJSONWebEncryption struct {
 
- 	Protected    *byteBuffer        `json:"protected,omitempty"`
 
- 	Unprotected  *rawHeader         `json:"unprotected,omitempty"`
 
- 	Header       *rawHeader         `json:"header,omitempty"`
 
- 	Recipients   []rawRecipientInfo `json:"recipients,omitempty"`
 
- 	Aad          *byteBuffer        `json:"aad,omitempty"`
 
- 	EncryptedKey *byteBuffer        `json:"encrypted_key,omitempty"`
 
- 	Iv           *byteBuffer        `json:"iv,omitempty"`
 
- 	Ciphertext   *byteBuffer        `json:"ciphertext,omitempty"`
 
- 	Tag          *byteBuffer        `json:"tag,omitempty"`
 
- }
 
- // rawRecipientInfo represents a raw JWE Per-Recipient header JSON object. Used for parsing/serializing.
 
- type rawRecipientInfo struct {
 
- 	Header       *rawHeader `json:"header,omitempty"`
 
- 	EncryptedKey string     `json:"encrypted_key,omitempty"`
 
- }
 
- // JSONWebEncryption represents an encrypted JWE object after parsing.
 
- type JSONWebEncryption struct {
 
- 	Header                   Header
 
- 	protected, unprotected   *rawHeader
 
- 	recipients               []recipientInfo
 
- 	aad, iv, ciphertext, tag []byte
 
- 	original                 *rawJSONWebEncryption
 
- }
 
- // recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
 
- type recipientInfo struct {
 
- 	header       *rawHeader
 
- 	encryptedKey []byte
 
- }
 
- // GetAuthData retrieves the (optional) authenticated data attached to the object.
 
- func (obj JSONWebEncryption) GetAuthData() []byte {
 
- 	if obj.aad != nil {
 
- 		out := make([]byte, len(obj.aad))
 
- 		copy(out, obj.aad)
 
- 		return out
 
- 	}
 
- 	return nil
 
- }
 
- // Get the merged header values
 
- func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
 
- 	out := rawHeader{}
 
- 	out.merge(obj.protected)
 
- 	out.merge(obj.unprotected)
 
- 	if recipient != nil {
 
- 		out.merge(recipient.header)
 
- 	}
 
- 	return out
 
- }
 
- // Get the additional authenticated data from a JWE object.
 
- func (obj JSONWebEncryption) computeAuthData() []byte {
 
- 	var protected string
 
- 	if obj.original != nil && obj.original.Protected != nil {
 
- 		protected = obj.original.Protected.base64()
 
- 	} else if obj.protected != nil {
 
- 		protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
 
- 	} else {
 
- 		protected = ""
 
- 	}
 
- 	output := []byte(protected)
 
- 	if obj.aad != nil {
 
- 		output = append(output, '.')
 
- 		output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
 
- 	}
 
- 	return output
 
- }
 
- // ParseEncrypted parses an encrypted message in compact or full serialization format.
 
- func ParseEncrypted(input string) (*JSONWebEncryption, error) {
 
- 	input = stripWhitespace(input)
 
- 	if strings.HasPrefix(input, "{") {
 
- 		return parseEncryptedFull(input)
 
- 	}
 
- 	return parseEncryptedCompact(input)
 
- }
 
- // parseEncryptedFull parses a message in compact format.
 
- func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
 
- 	var parsed rawJSONWebEncryption
 
- 	err := json.Unmarshal([]byte(input), &parsed)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	return parsed.sanitized()
 
- }
 
- // sanitized produces a cleaned-up JWE object from the raw JSON.
 
- func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
 
- 	obj := &JSONWebEncryption{
 
- 		original:    parsed,
 
- 		unprotected: parsed.Unprotected,
 
- 	}
 
- 	// Check that there is not a nonce in the unprotected headers
 
- 	if parsed.Unprotected != nil {
 
- 		if nonce := parsed.Unprotected.getNonce(); nonce != "" {
 
- 			return nil, ErrUnprotectedNonce
 
- 		}
 
- 	}
 
- 	if parsed.Header != nil {
 
- 		if nonce := parsed.Header.getNonce(); nonce != "" {
 
- 			return nil, ErrUnprotectedNonce
 
- 		}
 
- 	}
 
- 	if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
 
- 		err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
 
- 		if err != nil {
 
- 			return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
 
- 		}
 
- 	}
 
- 	// Note: this must be called _after_ we parse the protected header,
 
- 	// otherwise fields from the protected header will not get picked up.
 
- 	var err error
 
- 	mergedHeaders := obj.mergedHeaders(nil)
 
- 	obj.Header, err = mergedHeaders.sanitized()
 
- 	if err != nil {
 
- 		return nil, fmt.Errorf("square/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
 
- 	}
 
- 	if len(parsed.Recipients) == 0 {
 
- 		obj.recipients = []recipientInfo{
 
- 			{
 
- 				header:       parsed.Header,
 
- 				encryptedKey: parsed.EncryptedKey.bytes(),
 
- 			},
 
- 		}
 
- 	} else {
 
- 		obj.recipients = make([]recipientInfo, len(parsed.Recipients))
 
- 		for r := range parsed.Recipients {
 
- 			encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
 
- 			if err != nil {
 
- 				return nil, err
 
- 			}
 
- 			// Check that there is not a nonce in the unprotected header
 
- 			if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
 
- 				return nil, ErrUnprotectedNonce
 
- 			}
 
- 			obj.recipients[r].header = parsed.Recipients[r].Header
 
- 			obj.recipients[r].encryptedKey = encryptedKey
 
- 		}
 
- 	}
 
- 	for _, recipient := range obj.recipients {
 
- 		headers := obj.mergedHeaders(&recipient)
 
- 		if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
 
- 			return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
 
- 		}
 
- 	}
 
- 	obj.iv = parsed.Iv.bytes()
 
- 	obj.ciphertext = parsed.Ciphertext.bytes()
 
- 	obj.tag = parsed.Tag.bytes()
 
- 	obj.aad = parsed.Aad.bytes()
 
- 	return obj, nil
 
- }
 
- // parseEncryptedCompact parses a message in compact format.
 
- func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
 
- 	parts := strings.Split(input, ".")
 
- 	if len(parts) != 5 {
 
- 		return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
 
- 	}
 
- 	rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	iv, err := base64.RawURLEncoding.DecodeString(parts[2])
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	tag, err := base64.RawURLEncoding.DecodeString(parts[4])
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	raw := &rawJSONWebEncryption{
 
- 		Protected:    newBuffer(rawProtected),
 
- 		EncryptedKey: newBuffer(encryptedKey),
 
- 		Iv:           newBuffer(iv),
 
- 		Ciphertext:   newBuffer(ciphertext),
 
- 		Tag:          newBuffer(tag),
 
- 	}
 
- 	return raw.sanitized()
 
- }
 
- // CompactSerialize serializes an object using the compact serialization format.
 
- func (obj JSONWebEncryption) CompactSerialize() (string, error) {
 
- 	if len(obj.recipients) != 1 || obj.unprotected != nil ||
 
- 		obj.protected == nil || obj.recipients[0].header != nil {
 
- 		return "", ErrNotSupported
 
- 	}
 
- 	serializedProtected := mustSerializeJSON(obj.protected)
 
- 	return fmt.Sprintf(
 
- 		"%s.%s.%s.%s.%s",
 
- 		base64.RawURLEncoding.EncodeToString(serializedProtected),
 
- 		base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
 
- 		base64.RawURLEncoding.EncodeToString(obj.iv),
 
- 		base64.RawURLEncoding.EncodeToString(obj.ciphertext),
 
- 		base64.RawURLEncoding.EncodeToString(obj.tag)), nil
 
- }
 
- // FullSerialize serializes an object using the full JSON serialization format.
 
- func (obj JSONWebEncryption) FullSerialize() string {
 
- 	raw := rawJSONWebEncryption{
 
- 		Unprotected:  obj.unprotected,
 
- 		Iv:           newBuffer(obj.iv),
 
- 		Ciphertext:   newBuffer(obj.ciphertext),
 
- 		EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
 
- 		Tag:          newBuffer(obj.tag),
 
- 		Aad:          newBuffer(obj.aad),
 
- 		Recipients:   []rawRecipientInfo{},
 
- 	}
 
- 	if len(obj.recipients) > 1 {
 
- 		for _, recipient := range obj.recipients {
 
- 			info := rawRecipientInfo{
 
- 				Header:       recipient.header,
 
- 				EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
 
- 			}
 
- 			raw.Recipients = append(raw.Recipients, info)
 
- 		}
 
- 	} else {
 
- 		// Use flattened serialization
 
- 		raw.Header = obj.recipients[0].header
 
- 		raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
 
- 	}
 
- 	if obj.protected != nil {
 
- 		raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
 
- 	}
 
- 	return string(mustSerializeJSON(raw))
 
- }
 
 
  |