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  }