jwe.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. "fmt"
  20. "strings"
  21. "gopkg.in/square/go-jose.v2/json"
  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 && obj.original.Protected != nil {
  76. protected = obj.original.Protected.base64()
  77. } else if obj.protected != nil {
  78. protected = base64.RawURLEncoding.EncodeToString(mustSerializeJSON((obj.protected)))
  79. } else {
  80. protected = ""
  81. }
  82. output := []byte(protected)
  83. if obj.aad != nil {
  84. output = append(output, '.')
  85. output = append(output, []byte(base64.RawURLEncoding.EncodeToString(obj.aad))...)
  86. }
  87. return output
  88. }
  89. // ParseEncrypted parses an encrypted message in compact or full serialization format.
  90. func ParseEncrypted(input string) (*JSONWebEncryption, error) {
  91. input = stripWhitespace(input)
  92. if strings.HasPrefix(input, "{") {
  93. return parseEncryptedFull(input)
  94. }
  95. return parseEncryptedCompact(input)
  96. }
  97. // parseEncryptedFull parses a message in compact format.
  98. func parseEncryptedFull(input string) (*JSONWebEncryption, error) {
  99. var parsed rawJSONWebEncryption
  100. err := json.Unmarshal([]byte(input), &parsed)
  101. if err != nil {
  102. return nil, err
  103. }
  104. return parsed.sanitized()
  105. }
  106. // sanitized produces a cleaned-up JWE object from the raw JSON.
  107. func (parsed *rawJSONWebEncryption) sanitized() (*JSONWebEncryption, error) {
  108. obj := &JSONWebEncryption{
  109. original: parsed,
  110. unprotected: parsed.Unprotected,
  111. }
  112. // Check that there is not a nonce in the unprotected headers
  113. if parsed.Unprotected != nil {
  114. if nonce := parsed.Unprotected.getNonce(); nonce != "" {
  115. return nil, ErrUnprotectedNonce
  116. }
  117. }
  118. if parsed.Header != nil {
  119. if nonce := parsed.Header.getNonce(); nonce != "" {
  120. return nil, ErrUnprotectedNonce
  121. }
  122. }
  123. if parsed.Protected != nil && len(parsed.Protected.bytes()) > 0 {
  124. err := json.Unmarshal(parsed.Protected.bytes(), &obj.protected)
  125. if err != nil {
  126. return nil, fmt.Errorf("square/go-jose: invalid protected header: %s, %s", err, parsed.Protected.base64())
  127. }
  128. }
  129. // Note: this must be called _after_ we parse the protected header,
  130. // otherwise fields from the protected header will not get picked up.
  131. var err error
  132. mergedHeaders := obj.mergedHeaders(nil)
  133. obj.Header, err = mergedHeaders.sanitized()
  134. if err != nil {
  135. return nil, fmt.Errorf("square/go-jose: cannot sanitize merged headers: %v (%v)", err, mergedHeaders)
  136. }
  137. if len(parsed.Recipients) == 0 {
  138. obj.recipients = []recipientInfo{
  139. {
  140. header: parsed.Header,
  141. encryptedKey: parsed.EncryptedKey.bytes(),
  142. },
  143. }
  144. } else {
  145. obj.recipients = make([]recipientInfo, len(parsed.Recipients))
  146. for r := range parsed.Recipients {
  147. encryptedKey, err := base64.RawURLEncoding.DecodeString(parsed.Recipients[r].EncryptedKey)
  148. if err != nil {
  149. return nil, err
  150. }
  151. // Check that there is not a nonce in the unprotected header
  152. if parsed.Recipients[r].Header != nil && parsed.Recipients[r].Header.getNonce() != "" {
  153. return nil, ErrUnprotectedNonce
  154. }
  155. obj.recipients[r].header = parsed.Recipients[r].Header
  156. obj.recipients[r].encryptedKey = encryptedKey
  157. }
  158. }
  159. for _, recipient := range obj.recipients {
  160. headers := obj.mergedHeaders(&recipient)
  161. if headers.getAlgorithm() == "" || headers.getEncryption() == "" {
  162. return nil, fmt.Errorf("square/go-jose: message is missing alg/enc headers")
  163. }
  164. }
  165. obj.iv = parsed.Iv.bytes()
  166. obj.ciphertext = parsed.Ciphertext.bytes()
  167. obj.tag = parsed.Tag.bytes()
  168. obj.aad = parsed.Aad.bytes()
  169. return obj, nil
  170. }
  171. // parseEncryptedCompact parses a message in compact format.
  172. func parseEncryptedCompact(input string) (*JSONWebEncryption, error) {
  173. parts := strings.Split(input, ".")
  174. if len(parts) != 5 {
  175. return nil, fmt.Errorf("square/go-jose: compact JWE format must have five parts")
  176. }
  177. rawProtected, err := base64.RawURLEncoding.DecodeString(parts[0])
  178. if err != nil {
  179. return nil, err
  180. }
  181. encryptedKey, err := base64.RawURLEncoding.DecodeString(parts[1])
  182. if err != nil {
  183. return nil, err
  184. }
  185. iv, err := base64.RawURLEncoding.DecodeString(parts[2])
  186. if err != nil {
  187. return nil, err
  188. }
  189. ciphertext, err := base64.RawURLEncoding.DecodeString(parts[3])
  190. if err != nil {
  191. return nil, err
  192. }
  193. tag, err := base64.RawURLEncoding.DecodeString(parts[4])
  194. if err != nil {
  195. return nil, err
  196. }
  197. raw := &rawJSONWebEncryption{
  198. Protected: newBuffer(rawProtected),
  199. EncryptedKey: newBuffer(encryptedKey),
  200. Iv: newBuffer(iv),
  201. Ciphertext: newBuffer(ciphertext),
  202. Tag: newBuffer(tag),
  203. }
  204. return raw.sanitized()
  205. }
  206. // CompactSerialize serializes an object using the compact serialization format.
  207. func (obj JSONWebEncryption) CompactSerialize() (string, error) {
  208. if len(obj.recipients) != 1 || obj.unprotected != nil ||
  209. obj.protected == nil || obj.recipients[0].header != nil {
  210. return "", ErrNotSupported
  211. }
  212. serializedProtected := mustSerializeJSON(obj.protected)
  213. return fmt.Sprintf(
  214. "%s.%s.%s.%s.%s",
  215. base64.RawURLEncoding.EncodeToString(serializedProtected),
  216. base64.RawURLEncoding.EncodeToString(obj.recipients[0].encryptedKey),
  217. base64.RawURLEncoding.EncodeToString(obj.iv),
  218. base64.RawURLEncoding.EncodeToString(obj.ciphertext),
  219. base64.RawURLEncoding.EncodeToString(obj.tag)), nil
  220. }
  221. // FullSerialize serializes an object using the full JSON serialization format.
  222. func (obj JSONWebEncryption) FullSerialize() string {
  223. raw := rawJSONWebEncryption{
  224. Unprotected: obj.unprotected,
  225. Iv: newBuffer(obj.iv),
  226. Ciphertext: newBuffer(obj.ciphertext),
  227. EncryptedKey: newBuffer(obj.recipients[0].encryptedKey),
  228. Tag: newBuffer(obj.tag),
  229. Aad: newBuffer(obj.aad),
  230. Recipients: []rawRecipientInfo{},
  231. }
  232. if len(obj.recipients) > 1 {
  233. for _, recipient := range obj.recipients {
  234. info := rawRecipientInfo{
  235. Header: recipient.header,
  236. EncryptedKey: base64.RawURLEncoding.EncodeToString(recipient.encryptedKey),
  237. }
  238. raw.Recipients = append(raw.Recipients, info)
  239. }
  240. } else {
  241. // Use flattened serialization
  242. raw.Header = obj.recipients[0].header
  243. raw.EncryptedKey = newBuffer(obj.recipients[0].encryptedKey)
  244. }
  245. if obj.protected != nil {
  246. raw.Protected = newBuffer(mustSerializeJSON(obj.protected))
  247. }
  248. return string(mustSerializeJSON(raw))
  249. }