jsonsign.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658
  1. package libtrust
  2. import (
  3. "bytes"
  4. "crypto"
  5. "crypto/x509"
  6. "encoding/base64"
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "sort"
  11. "time"
  12. "unicode"
  13. )
  14. var (
  15. // ErrInvalidSignContent is used when the content to be signed is invalid.
  16. ErrInvalidSignContent = errors.New("invalid sign content")
  17. // ErrInvalidJSONContent is used when invalid json is encountered.
  18. ErrInvalidJSONContent = errors.New("invalid json content")
  19. // ErrMissingSignatureKey is used when the specified signature key
  20. // does not exist in the JSON content.
  21. ErrMissingSignatureKey = errors.New("missing signature key")
  22. )
  23. type jsHeader struct {
  24. JWK PublicKey `json:"jwk,omitempty"`
  25. Algorithm string `json:"alg"`
  26. Chain []string `json:"x5c,omitempty"`
  27. }
  28. type jsSignature struct {
  29. Header jsHeader `json:"header"`
  30. Signature string `json:"signature"`
  31. Protected string `json:"protected,omitempty"`
  32. }
  33. type jsSignaturesSorted []jsSignature
  34. func (jsbkid jsSignaturesSorted) Swap(i, j int) { jsbkid[i], jsbkid[j] = jsbkid[j], jsbkid[i] }
  35. func (jsbkid jsSignaturesSorted) Len() int { return len(jsbkid) }
  36. func (jsbkid jsSignaturesSorted) Less(i, j int) bool {
  37. ki, kj := jsbkid[i].Header.JWK.KeyID(), jsbkid[j].Header.JWK.KeyID()
  38. si, sj := jsbkid[i].Signature, jsbkid[j].Signature
  39. if ki == kj {
  40. return si < sj
  41. }
  42. return ki < kj
  43. }
  44. type signKey struct {
  45. PrivateKey
  46. Chain []*x509.Certificate
  47. }
  48. // JSONSignature represents a signature of a json object.
  49. type JSONSignature struct {
  50. payload string
  51. signatures []jsSignature
  52. indent string
  53. formatLength int
  54. formatTail []byte
  55. }
  56. func newJSONSignature() *JSONSignature {
  57. return &JSONSignature{
  58. signatures: make([]jsSignature, 0, 1),
  59. }
  60. }
  61. // Payload returns the encoded payload of the signature. This
  62. // payload should not be signed directly
  63. func (js *JSONSignature) Payload() ([]byte, error) {
  64. return joseBase64UrlDecode(js.payload)
  65. }
  66. func (js *JSONSignature) protectedHeader() (string, error) {
  67. protected := map[string]interface{}{
  68. "formatLength": js.formatLength,
  69. "formatTail": joseBase64UrlEncode(js.formatTail),
  70. "time": time.Now().UTC().Format(time.RFC3339),
  71. }
  72. protectedBytes, err := json.Marshal(protected)
  73. if err != nil {
  74. return "", err
  75. }
  76. return joseBase64UrlEncode(protectedBytes), nil
  77. }
  78. func (js *JSONSignature) signBytes(protectedHeader string) ([]byte, error) {
  79. buf := make([]byte, len(js.payload)+len(protectedHeader)+1)
  80. copy(buf, protectedHeader)
  81. buf[len(protectedHeader)] = '.'
  82. copy(buf[len(protectedHeader)+1:], js.payload)
  83. return buf, nil
  84. }
  85. // Sign adds a signature using the given private key.
  86. func (js *JSONSignature) Sign(key PrivateKey) error {
  87. protected, err := js.protectedHeader()
  88. if err != nil {
  89. return err
  90. }
  91. signBytes, err := js.signBytes(protected)
  92. if err != nil {
  93. return err
  94. }
  95. sigBytes, algorithm, err := key.Sign(bytes.NewReader(signBytes), crypto.SHA256)
  96. if err != nil {
  97. return err
  98. }
  99. js.signatures = append(js.signatures, jsSignature{
  100. Header: jsHeader{
  101. JWK: key.PublicKey(),
  102. Algorithm: algorithm,
  103. },
  104. Signature: joseBase64UrlEncode(sigBytes),
  105. Protected: protected,
  106. })
  107. return nil
  108. }
  109. // SignWithChain adds a signature using the given private key
  110. // and setting the x509 chain. The public key of the first element
  111. // in the chain must be the public key corresponding with the sign key.
  112. func (js *JSONSignature) SignWithChain(key PrivateKey, chain []*x509.Certificate) error {
  113. // Ensure key.Chain[0] is public key for key
  114. //key.Chain.PublicKey
  115. //key.PublicKey().CryptoPublicKey()
  116. // Verify chain
  117. protected, err := js.protectedHeader()
  118. if err != nil {
  119. return err
  120. }
  121. signBytes, err := js.signBytes(protected)
  122. if err != nil {
  123. return err
  124. }
  125. sigBytes, algorithm, err := key.Sign(bytes.NewReader(signBytes), crypto.SHA256)
  126. if err != nil {
  127. return err
  128. }
  129. header := jsHeader{
  130. Chain: make([]string, len(chain)),
  131. Algorithm: algorithm,
  132. }
  133. for i, cert := range chain {
  134. header.Chain[i] = base64.StdEncoding.EncodeToString(cert.Raw)
  135. }
  136. js.signatures = append(js.signatures, jsSignature{
  137. Header: header,
  138. Signature: joseBase64UrlEncode(sigBytes),
  139. Protected: protected,
  140. })
  141. return nil
  142. }
  143. // Verify verifies all the signatures and returns the list of
  144. // public keys used to sign. Any x509 chains are not checked.
  145. func (js *JSONSignature) Verify() ([]PublicKey, error) {
  146. keys := make([]PublicKey, len(js.signatures))
  147. for i, signature := range js.signatures {
  148. signBytes, err := js.signBytes(signature.Protected)
  149. if err != nil {
  150. return nil, err
  151. }
  152. var publicKey PublicKey
  153. if len(signature.Header.Chain) > 0 {
  154. certBytes, err := base64.StdEncoding.DecodeString(signature.Header.Chain[0])
  155. if err != nil {
  156. return nil, err
  157. }
  158. cert, err := x509.ParseCertificate(certBytes)
  159. if err != nil {
  160. return nil, err
  161. }
  162. publicKey, err = FromCryptoPublicKey(cert.PublicKey)
  163. if err != nil {
  164. return nil, err
  165. }
  166. } else if signature.Header.JWK != nil {
  167. publicKey = signature.Header.JWK
  168. } else {
  169. return nil, errors.New("missing public key")
  170. }
  171. sigBytes, err := joseBase64UrlDecode(signature.Signature)
  172. if err != nil {
  173. return nil, err
  174. }
  175. err = publicKey.Verify(bytes.NewReader(signBytes), signature.Header.Algorithm, sigBytes)
  176. if err != nil {
  177. return nil, err
  178. }
  179. keys[i] = publicKey
  180. }
  181. return keys, nil
  182. }
  183. // VerifyChains verifies all the signatures and the chains associated
  184. // with each signature and returns the list of verified chains.
  185. // Signatures without an x509 chain are not checked.
  186. func (js *JSONSignature) VerifyChains(ca *x509.CertPool) ([][]*x509.Certificate, error) {
  187. chains := make([][]*x509.Certificate, 0, len(js.signatures))
  188. for _, signature := range js.signatures {
  189. signBytes, err := js.signBytes(signature.Protected)
  190. if err != nil {
  191. return nil, err
  192. }
  193. var publicKey PublicKey
  194. if len(signature.Header.Chain) > 0 {
  195. certBytes, err := base64.StdEncoding.DecodeString(signature.Header.Chain[0])
  196. if err != nil {
  197. return nil, err
  198. }
  199. cert, err := x509.ParseCertificate(certBytes)
  200. if err != nil {
  201. return nil, err
  202. }
  203. publicKey, err = FromCryptoPublicKey(cert.PublicKey)
  204. if err != nil {
  205. return nil, err
  206. }
  207. intermediates := x509.NewCertPool()
  208. if len(signature.Header.Chain) > 1 {
  209. intermediateChain := signature.Header.Chain[1:]
  210. for i := range intermediateChain {
  211. certBytes, err := base64.StdEncoding.DecodeString(intermediateChain[i])
  212. if err != nil {
  213. return nil, err
  214. }
  215. intermediate, err := x509.ParseCertificate(certBytes)
  216. if err != nil {
  217. return nil, err
  218. }
  219. intermediates.AddCert(intermediate)
  220. }
  221. }
  222. verifyOptions := x509.VerifyOptions{
  223. Intermediates: intermediates,
  224. Roots: ca,
  225. }
  226. verifiedChains, err := cert.Verify(verifyOptions)
  227. if err != nil {
  228. return nil, err
  229. }
  230. chains = append(chains, verifiedChains...)
  231. sigBytes, err := joseBase64UrlDecode(signature.Signature)
  232. if err != nil {
  233. return nil, err
  234. }
  235. err = publicKey.Verify(bytes.NewReader(signBytes), signature.Header.Algorithm, sigBytes)
  236. if err != nil {
  237. return nil, err
  238. }
  239. }
  240. }
  241. return chains, nil
  242. }
  243. // JWS returns JSON serialized JWS according to
  244. // http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-7.2
  245. func (js *JSONSignature) JWS() ([]byte, error) {
  246. if len(js.signatures) == 0 {
  247. return nil, errors.New("missing signature")
  248. }
  249. sort.Sort(jsSignaturesSorted(js.signatures))
  250. jsonMap := map[string]interface{}{
  251. "payload": js.payload,
  252. "signatures": js.signatures,
  253. }
  254. return json.MarshalIndent(jsonMap, "", " ")
  255. }
  256. func notSpace(r rune) bool {
  257. return !unicode.IsSpace(r)
  258. }
  259. func detectJSONIndent(jsonContent []byte) (indent string) {
  260. if len(jsonContent) > 2 && jsonContent[0] == '{' && jsonContent[1] == '\n' {
  261. quoteIndex := bytes.IndexRune(jsonContent[1:], '"')
  262. if quoteIndex > 0 {
  263. indent = string(jsonContent[2 : quoteIndex+1])
  264. }
  265. }
  266. return
  267. }
  268. type jsParsedHeader struct {
  269. JWK json.RawMessage `json:"jwk"`
  270. Algorithm string `json:"alg"`
  271. Chain []string `json:"x5c"`
  272. }
  273. type jsParsedSignature struct {
  274. Header jsParsedHeader `json:"header"`
  275. Signature string `json:"signature"`
  276. Protected string `json:"protected"`
  277. }
  278. // ParseJWS parses a JWS serialized JSON object into a Json Signature.
  279. func ParseJWS(content []byte) (*JSONSignature, error) {
  280. type jsParsed struct {
  281. Payload string `json:"payload"`
  282. Signatures []jsParsedSignature `json:"signatures"`
  283. }
  284. parsed := &jsParsed{}
  285. err := json.Unmarshal(content, parsed)
  286. if err != nil {
  287. return nil, err
  288. }
  289. if len(parsed.Signatures) == 0 {
  290. return nil, errors.New("missing signatures")
  291. }
  292. payload, err := joseBase64UrlDecode(parsed.Payload)
  293. if err != nil {
  294. return nil, err
  295. }
  296. js, err := NewJSONSignature(payload)
  297. if err != nil {
  298. return nil, err
  299. }
  300. js.signatures = make([]jsSignature, len(parsed.Signatures))
  301. for i, signature := range parsed.Signatures {
  302. header := jsHeader{
  303. Algorithm: signature.Header.Algorithm,
  304. }
  305. if signature.Header.Chain != nil {
  306. header.Chain = signature.Header.Chain
  307. }
  308. if signature.Header.JWK != nil {
  309. publicKey, err := UnmarshalPublicKeyJWK([]byte(signature.Header.JWK))
  310. if err != nil {
  311. return nil, err
  312. }
  313. header.JWK = publicKey
  314. }
  315. js.signatures[i] = jsSignature{
  316. Header: header,
  317. Signature: signature.Signature,
  318. Protected: signature.Protected,
  319. }
  320. }
  321. return js, nil
  322. }
  323. // NewJSONSignature returns a new unsigned JWS from a json byte array.
  324. // JSONSignature will need to be signed before serializing or storing.
  325. // Optionally, one or more signatures can be provided as byte buffers,
  326. // containing serialized JWS signatures, to assemble a fully signed JWS
  327. // package. It is the callers responsibility to ensure uniqueness of the
  328. // provided signatures.
  329. func NewJSONSignature(content []byte, signatures ...[]byte) (*JSONSignature, error) {
  330. var dataMap map[string]interface{}
  331. err := json.Unmarshal(content, &dataMap)
  332. if err != nil {
  333. return nil, err
  334. }
  335. js := newJSONSignature()
  336. js.indent = detectJSONIndent(content)
  337. js.payload = joseBase64UrlEncode(content)
  338. // Find trailing } and whitespace, put in protected header
  339. closeIndex := bytes.LastIndexFunc(content, notSpace)
  340. if content[closeIndex] != '}' {
  341. return nil, ErrInvalidJSONContent
  342. }
  343. lastRuneIndex := bytes.LastIndexFunc(content[:closeIndex], notSpace)
  344. if content[lastRuneIndex] == ',' {
  345. return nil, ErrInvalidJSONContent
  346. }
  347. js.formatLength = lastRuneIndex + 1
  348. js.formatTail = content[js.formatLength:]
  349. if len(signatures) > 0 {
  350. for _, signature := range signatures {
  351. var parsedJSig jsParsedSignature
  352. if err := json.Unmarshal(signature, &parsedJSig); err != nil {
  353. return nil, err
  354. }
  355. // TODO(stevvooe): A lot of the code below is repeated in
  356. // ParseJWS. It will require more refactoring to fix that.
  357. jsig := jsSignature{
  358. Header: jsHeader{
  359. Algorithm: parsedJSig.Header.Algorithm,
  360. },
  361. Signature: parsedJSig.Signature,
  362. Protected: parsedJSig.Protected,
  363. }
  364. if parsedJSig.Header.Chain != nil {
  365. jsig.Header.Chain = parsedJSig.Header.Chain
  366. }
  367. if parsedJSig.Header.JWK != nil {
  368. publicKey, err := UnmarshalPublicKeyJWK([]byte(parsedJSig.Header.JWK))
  369. if err != nil {
  370. return nil, err
  371. }
  372. jsig.Header.JWK = publicKey
  373. }
  374. js.signatures = append(js.signatures, jsig)
  375. }
  376. }
  377. return js, nil
  378. }
  379. // NewJSONSignatureFromMap returns a new unsigned JSONSignature from a map or
  380. // struct. JWS will need to be signed before serializing or storing.
  381. func NewJSONSignatureFromMap(content interface{}) (*JSONSignature, error) {
  382. switch content.(type) {
  383. case map[string]interface{}:
  384. case struct{}:
  385. default:
  386. return nil, errors.New("invalid data type")
  387. }
  388. js := newJSONSignature()
  389. js.indent = " "
  390. payload, err := json.MarshalIndent(content, "", js.indent)
  391. if err != nil {
  392. return nil, err
  393. }
  394. js.payload = joseBase64UrlEncode(payload)
  395. // Remove '\n}' from formatted section, put in protected header
  396. js.formatLength = len(payload) - 2
  397. js.formatTail = payload[js.formatLength:]
  398. return js, nil
  399. }
  400. func readIntFromMap(key string, m map[string]interface{}) (int, bool) {
  401. value, ok := m[key]
  402. if !ok {
  403. return 0, false
  404. }
  405. switch v := value.(type) {
  406. case int:
  407. return v, true
  408. case float64:
  409. return int(v), true
  410. default:
  411. return 0, false
  412. }
  413. }
  414. func readStringFromMap(key string, m map[string]interface{}) (v string, ok bool) {
  415. value, ok := m[key]
  416. if !ok {
  417. return "", false
  418. }
  419. v, ok = value.(string)
  420. return
  421. }
  422. // ParsePrettySignature parses a formatted signature into a
  423. // JSON signature. If the signatures are missing the format information
  424. // an error is thrown. The formatted signature must be created by
  425. // the same method as format signature.
  426. func ParsePrettySignature(content []byte, signatureKey string) (*JSONSignature, error) {
  427. var contentMap map[string]json.RawMessage
  428. err := json.Unmarshal(content, &contentMap)
  429. if err != nil {
  430. return nil, fmt.Errorf("error unmarshalling content: %s", err)
  431. }
  432. sigMessage, ok := contentMap[signatureKey]
  433. if !ok {
  434. return nil, ErrMissingSignatureKey
  435. }
  436. var signatureBlocks []jsParsedSignature
  437. err = json.Unmarshal([]byte(sigMessage), &signatureBlocks)
  438. if err != nil {
  439. return nil, fmt.Errorf("error unmarshalling signatures: %s", err)
  440. }
  441. js := newJSONSignature()
  442. js.signatures = make([]jsSignature, len(signatureBlocks))
  443. for i, signatureBlock := range signatureBlocks {
  444. protectedBytes, err := joseBase64UrlDecode(signatureBlock.Protected)
  445. if err != nil {
  446. return nil, fmt.Errorf("base64 decode error: %s", err)
  447. }
  448. var protectedHeader map[string]interface{}
  449. err = json.Unmarshal(protectedBytes, &protectedHeader)
  450. if err != nil {
  451. return nil, fmt.Errorf("error unmarshalling protected header: %s", err)
  452. }
  453. formatLength, ok := readIntFromMap("formatLength", protectedHeader)
  454. if !ok {
  455. return nil, errors.New("missing formatted length")
  456. }
  457. encodedTail, ok := readStringFromMap("formatTail", protectedHeader)
  458. if !ok {
  459. return nil, errors.New("missing formatted tail")
  460. }
  461. formatTail, err := joseBase64UrlDecode(encodedTail)
  462. if err != nil {
  463. return nil, fmt.Errorf("base64 decode error on tail: %s", err)
  464. }
  465. if js.formatLength == 0 {
  466. js.formatLength = formatLength
  467. } else if js.formatLength != formatLength {
  468. return nil, errors.New("conflicting format length")
  469. }
  470. if len(js.formatTail) == 0 {
  471. js.formatTail = formatTail
  472. } else if bytes.Compare(js.formatTail, formatTail) != 0 {
  473. return nil, errors.New("conflicting format tail")
  474. }
  475. header := jsHeader{
  476. Algorithm: signatureBlock.Header.Algorithm,
  477. Chain: signatureBlock.Header.Chain,
  478. }
  479. if signatureBlock.Header.JWK != nil {
  480. publicKey, err := UnmarshalPublicKeyJWK([]byte(signatureBlock.Header.JWK))
  481. if err != nil {
  482. return nil, fmt.Errorf("error unmarshalling public key: %s", err)
  483. }
  484. header.JWK = publicKey
  485. }
  486. js.signatures[i] = jsSignature{
  487. Header: header,
  488. Signature: signatureBlock.Signature,
  489. Protected: signatureBlock.Protected,
  490. }
  491. }
  492. if js.formatLength > len(content) {
  493. return nil, errors.New("invalid format length")
  494. }
  495. formatted := make([]byte, js.formatLength+len(js.formatTail))
  496. copy(formatted, content[:js.formatLength])
  497. copy(formatted[js.formatLength:], js.formatTail)
  498. js.indent = detectJSONIndent(formatted)
  499. js.payload = joseBase64UrlEncode(formatted)
  500. return js, nil
  501. }
  502. // PrettySignature formats a json signature into an easy to read
  503. // single json serialized object.
  504. func (js *JSONSignature) PrettySignature(signatureKey string) ([]byte, error) {
  505. if len(js.signatures) == 0 {
  506. return nil, errors.New("no signatures")
  507. }
  508. payload, err := joseBase64UrlDecode(js.payload)
  509. if err != nil {
  510. return nil, err
  511. }
  512. payload = payload[:js.formatLength]
  513. sort.Sort(jsSignaturesSorted(js.signatures))
  514. var marshalled []byte
  515. var marshallErr error
  516. if js.indent != "" {
  517. marshalled, marshallErr = json.MarshalIndent(js.signatures, js.indent, js.indent)
  518. } else {
  519. marshalled, marshallErr = json.Marshal(js.signatures)
  520. }
  521. if marshallErr != nil {
  522. return nil, marshallErr
  523. }
  524. buf := bytes.NewBuffer(make([]byte, 0, len(payload)+len(marshalled)+34))
  525. buf.Write(payload)
  526. buf.WriteByte(',')
  527. if js.indent != "" {
  528. buf.WriteByte('\n')
  529. buf.WriteString(js.indent)
  530. buf.WriteByte('"')
  531. buf.WriteString(signatureKey)
  532. buf.WriteString("\": ")
  533. buf.Write(marshalled)
  534. buf.WriteByte('\n')
  535. } else {
  536. buf.WriteByte('"')
  537. buf.WriteString(signatureKey)
  538. buf.WriteString("\":")
  539. buf.Write(marshalled)
  540. }
  541. buf.WriteByte('}')
  542. return buf.Bytes(), nil
  543. }
  544. // Signatures provides the signatures on this JWS as opaque blobs, sorted by
  545. // keyID. These blobs can be stored and reassembled with payloads. Internally,
  546. // they are simply marshaled json web signatures but implementations should
  547. // not rely on this.
  548. func (js *JSONSignature) Signatures() ([][]byte, error) {
  549. sort.Sort(jsSignaturesSorted(js.signatures))
  550. var sb [][]byte
  551. for _, jsig := range js.signatures {
  552. p, err := json.Marshal(jsig)
  553. if err != nil {
  554. return nil, err
  555. }
  556. sb = append(sb, p)
  557. }
  558. return sb, nil
  559. }
  560. // Merge combines the signatures from one or more other signatures into the
  561. // method receiver. If the payloads differ for any argument, an error will be
  562. // returned and the receiver will not be modified.
  563. func (js *JSONSignature) Merge(others ...*JSONSignature) error {
  564. merged := js.signatures
  565. for _, other := range others {
  566. if js.payload != other.payload {
  567. return fmt.Errorf("payloads differ from merge target")
  568. }
  569. merged = append(merged, other.signatures...)
  570. }
  571. js.signatures = merged
  572. return nil
  573. }