jwe.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*-
  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. package jose
  17. import (
  18. "encoding/base64"
  19. "encoding/json"
  20. "fmt"
  21. "strings"
  22. )
  23. // rawJSONWebEncryption represents a raw JWE JSON object. Used for parsing/serializing.
  24. type rawJSONWebEncryption struct {
  25. Protected *byteBuffer `json:"protected,omitempty"`
  26. Unprotected *rawHeader `json:"unprotected,omitempty"`
  27. Header *rawHeader `json:"header,omitempty"`
  28. Recipients []rawRecipientInfo `json:"recipients,omitempty"`
  29. Aad *byteBuffer `json:"aad,omitempty"`
  30. EncryptedKey *byteBuffer `json:"encrypted_key,omitempty"`
  31. Iv *byteBuffer `json:"iv,omitempty"`
  32. Ciphertext *byteBuffer `json:"ciphertext,omitempty"`
  33. Tag *byteBuffer `json:"tag,omitempty"`
  34. }
  35. // rawRecipientInfo represents a raw JWE Per-Recipient header JSON object. Used for parsing/serializing.
  36. type rawRecipientInfo struct {
  37. Header *rawHeader `json:"header,omitempty"`
  38. EncryptedKey string `json:"encrypted_key,omitempty"`
  39. }
  40. // JSONWebEncryption represents an encrypted JWE object after parsing.
  41. type JSONWebEncryption struct {
  42. Header Header
  43. protected, unprotected *rawHeader
  44. recipients []recipientInfo
  45. aad, iv, ciphertext, tag []byte
  46. original *rawJSONWebEncryption
  47. }
  48. // recipientInfo represents a raw JWE Per-Recipient header JSON object after parsing.
  49. type recipientInfo struct {
  50. header *rawHeader
  51. encryptedKey []byte
  52. }
  53. // GetAuthData retrieves the (optional) authenticated data attached to the object.
  54. func (obj JSONWebEncryption) GetAuthData() []byte {
  55. if obj.aad != nil {
  56. out := make([]byte, len(obj.aad))
  57. copy(out, obj.aad)
  58. return out
  59. }
  60. return nil
  61. }
  62. // Get the merged header values
  63. func (obj JSONWebEncryption) mergedHeaders(recipient *recipientInfo) rawHeader {
  64. out := rawHeader{}
  65. out.merge(obj.protected)
  66. out.merge(obj.unprotected)
  67. if recipient != nil {
  68. out.merge(recipient.header)
  69. }
  70. return out
  71. }
  72. // Get the additional authenticated data from a JWE object.
  73. func (obj JSONWebEncryption) computeAuthData() []byte {
  74. var protected string
  75. if obj.original != nil {
  76. protected = obj.original.Protected.base64()
  77. } else {
  78. protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
  79. }
  80. output := []byte(protected)
  81. if obj.aad != nil {
  82. output = append(output, '.')
  83. output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
  84. }
  85. return output
  86. }
  87. // ParseEncrypted parses an encrypted message in compact or full serialization format.
  88. func ParseEncrypted(input string) (*JSONWebEncryption, error) {
  89. input = stripWhitespace(input)
  90. if strings.HasPrefix(input, "{") {
  91. return parseEncryptedFull(input)
  92. }
  93. return parseEncryptedCompact(input)
  94. }
  95. // parseEncryptedFull parses a message in compact format.
  96. func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
  97. var parsed rawJSONWebEncryption
  98. err := json.Unmarshal([]byte(input), &parsed)
  99. if err != nil {
  100. return nil, err
  101. }
  102. return parsed.sanitized()
  103. }
  104. // sanitized produces a cleaned-up JWE object from the raw JSON.
  105. func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
  106. obj := &JSONWebEncryption{
  107. original: parsed,
  108. unprotected: parsed.Unprotected,
  109. }
  110. // Check that there is not a nonce in the unprotected headers
  111. if parsed.Unprotected != nil {
  112. if nonce := parsed.Unprotected.getNonce(); nonce != "" {
  113. return nil, ErrUnprotectedNonce
  114. }
  115. }
  116. if parsed.Header != nil {
  117. if nonce := parsed.Header.getNonce(); nonce != "" {
  118. return nil, ErrUnprotectedNonce
  119. }
  120. }
  121. if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
  122. err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
  123. if err != nil {
  124. return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
  125. }
  126. }
  127. // Note: this must be called _after_ we parse the protected header,
  128. // otherwise fields from the protected header will not get picked up.
  129. var err error
  130. mergedHeaders := obj.mergedHeaders(nil)
  131. obj.Header, err = mergedHeaders.sanitized()
  132. if err != nil {
  133. return nil, fmt.Errorf("square/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
  134. }
  135. if len(parsed.Recipients) == 0 {
  136. obj.recipients = []recipientInfo{
  137. {
  138. header: parsed.Header,
  139. encryptedKey: parsed.EncryptedKey.bytes(),
  140. },
  141. }
  142. } else {
  143. obj.recipients = make([]recipientInfo, len(parsed.Recipients))
  144. for r := range parsed.Recipients {
  145. encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
  146. if err != nil {
  147. return nil, err
  148. }
  149. // Check that there is not a nonce in the unprotected header
  150. if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
  151. return nil, ErrUnprotectedNonce
  152. }
  153. obj.recipients[r].header = parsed.Recipients[r].Header
  154. obj.recipients[r].encryptedKey = encryptedKey
  155. }
  156. }
  157. for _, recipient := range obj.recipients {
  158. headers := obj.mergedHeaders(&recipient)
  159. if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
  160. return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
  161. }
  162. }
  163. obj.iv = parsed.Iv.bytes()
  164. obj.ciphertext = parsed.Ciphertext.bytes()
  165. obj.tag = parsed.Tag.bytes()
  166. obj.aad = parsed.Aad.bytes()
  167. return obj, nil
  168. }
  169. // parseEncryptedCompact parses a message in compact format.
  170. func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
  171. parts := strings.Split(input, ".")
  172. if len(parts) != 5 {
  173. return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
  174. }
  175. rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
  176. if err != nil {
  177. return nil, err
  178. }
  179. encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
  180. if err != nil {
  181. return nil, err
  182. }
  183. iv, err := base64.RawURLEncoding.DecodeString(parts[2])
  184. if err != nil {
  185. return nil, err
  186. }
  187. ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
  188. if err != nil {
  189. return nil, err
  190. }
  191. tag, err := base64.RawURLEncoding.DecodeString(parts[4])
  192. if err != nil {
  193. return nil, err
  194. }
  195. raw := &rawJSONWebEncryption{
  196. Protected: newBuffer(rawProtected),
  197. EncryptedKey: newBuffer(encryptedKey),
  198. Iv: newBuffer(iv),
  199. Ciphertext: newBuffer(ciphertext),
  200. Tag: newBuffer(tag),
  201. }
  202. return raw.sanitized()
  203. }
  204. // CompactSerialize serializes an object using the compact serialization format.
  205. func (obj JSONWebEncryption) CompactSerialize() (string, error) {
  206. if len(obj.recipients) != 1 || obj.unprotected != nil ||
  207. obj.protected == nil || obj.recipients[0].header != nil {
  208. return "", ErrNotSupported
  209. }
  210. serializedProtected := mustSerializeJSON(obj.protected)
  211. return fmt.Sprintf(
  212. "%s.%s.%s.%s.%s",
  213. base64.RawURLEncoding.EncodeToString(serializedProtected),
  214. base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
  215. base64.RawURLEncoding.EncodeToString(obj.iv),
  216. base64.RawURLEncoding.EncodeToString(obj.ciphertext),
  217. base64.RawURLEncoding.EncodeToString(obj.tag)), nil
  218. }
  219. // FullSerialize serializes an object using the full JSON serialization format.
  220. func (obj JSONWebEncryption) FullSerialize() string {
  221. raw := rawJSONWebEncryption{
  222. Unprotected: obj.unprotected,
  223. Iv: newBuffer(obj.iv),
  224. Ciphertext: newBuffer(obj.ciphertext),
  225. EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
  226. Tag: newBuffer(obj.tag),
  227. Aad: newBuffer(obj.aad),
  228. Recipients: []rawRecipientInfo{},
  229. }
  230. if len(obj.recipients) > 1 {
  231. for _, recipient := range obj.recipients {
  232. info := rawRecipientInfo{
  233. Header: recipient.header,
  234. EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
  235. }
  236. raw.Recipients = append(raw.Recipients, info)
  237. }
  238. } else {
  239. // Use flattened serialization
  240. raw.Header = obj.recipients[0].header
  241. raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
  242. }
  243. if obj.protected != nil {
  244. raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
  245. }
  246. return string(mustSerializeJSON(raw))
  247. }