ticket.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. // Copyright 2012 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package tls
  5. import (
  6. "bytes"
  7. "crypto/aes"
  8. "crypto/cipher"
  9. "crypto/hmac"
  10. "crypto/sha256"
  11. "crypto/subtle"
  12. "errors"
  13. "io"
  14. "golang.org/x/crypto/cryptobyte"
  15. )
  16. // sessionState contains the information that is serialized into a session
  17. // ticket in order to later resume a connection.
  18. type sessionState struct {
  19. vers uint16
  20. cipherSuite uint16
  21. createdAt uint64
  22. masterSecret []byte // opaque master_secret<1..2^16-1>;
  23. // struct { opaque certificate<1..2^24-1> } Certificate;
  24. certificates [][]byte // Certificate certificate_list<0..2^24-1>;
  25. // usedOldKey is true if the ticket from which this session came from
  26. // was encrypted with an older key and thus should be refreshed.
  27. usedOldKey bool
  28. }
  29. func (m *sessionState) marshal() ([]byte, error) {
  30. var b cryptobyte.Builder
  31. b.AddUint16(m.vers)
  32. b.AddUint16(m.cipherSuite)
  33. addUint64(&b, m.createdAt)
  34. b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
  35. b.AddBytes(m.masterSecret)
  36. })
  37. b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
  38. for _, cert := range m.certificates {
  39. b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
  40. b.AddBytes(cert)
  41. })
  42. }
  43. })
  44. return b.Bytes()
  45. }
  46. func (m *sessionState) unmarshal(data []byte) bool {
  47. *m = sessionState{usedOldKey: m.usedOldKey}
  48. s := cryptobyte.String(data)
  49. if ok := s.ReadUint16(&m.vers) &&
  50. s.ReadUint16(&m.cipherSuite) &&
  51. readUint64(&s, &m.createdAt) &&
  52. readUint16LengthPrefixed(&s, &m.masterSecret) &&
  53. len(m.masterSecret) != 0; !ok {
  54. return false
  55. }
  56. var certList cryptobyte.String
  57. if !s.ReadUint24LengthPrefixed(&certList) {
  58. return false
  59. }
  60. for !certList.Empty() {
  61. var cert []byte
  62. if !readUint24LengthPrefixed(&certList, &cert) {
  63. return false
  64. }
  65. m.certificates = append(m.certificates, cert)
  66. }
  67. return s.Empty()
  68. }
  69. // sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
  70. // version (revision = 0) doesn't carry any of the information needed for 0-RTT
  71. // validation and the nonce is always empty.
  72. type sessionStateTLS13 struct {
  73. // uint8 version = 0x0304;
  74. // uint8 revision = 0;
  75. cipherSuite uint16
  76. createdAt uint64
  77. resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>;
  78. certificate Certificate // CertificateEntry certificate_list<0..2^24-1>;
  79. }
  80. func (m *sessionStateTLS13) marshal() ([]byte, error) {
  81. var b cryptobyte.Builder
  82. b.AddUint16(VersionTLS13)
  83. b.AddUint8(0) // revision
  84. b.AddUint16(m.cipherSuite)
  85. addUint64(&b, m.createdAt)
  86. b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
  87. b.AddBytes(m.resumptionSecret)
  88. })
  89. marshalCertificate(&b, m.certificate)
  90. return b.Bytes()
  91. }
  92. func (m *sessionStateTLS13) unmarshal(data []byte) bool {
  93. *m = sessionStateTLS13{}
  94. s := cryptobyte.String(data)
  95. var version uint16
  96. var revision uint8
  97. return s.ReadUint16(&version) &&
  98. version == VersionTLS13 &&
  99. s.ReadUint8(&revision) &&
  100. revision == 0 &&
  101. s.ReadUint16(&m.cipherSuite) &&
  102. readUint64(&s, &m.createdAt) &&
  103. readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
  104. len(m.resumptionSecret) != 0 &&
  105. unmarshalCertificate(&s, &m.certificate) &&
  106. s.Empty()
  107. }
  108. func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
  109. if len(c.ticketKeys) == 0 {
  110. return nil, errors.New("tls: internal error: session ticket keys unavailable")
  111. }
  112. encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
  113. keyName := encrypted[:ticketKeyNameLen]
  114. iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
  115. macBytes := encrypted[len(encrypted)-sha256.Size:]
  116. if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
  117. return nil, err
  118. }
  119. key := c.ticketKeys[0]
  120. copy(keyName, key.keyName[:])
  121. block, err := aes.NewCipher(key.aesKey[:])
  122. if err != nil {
  123. return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
  124. }
  125. cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state)
  126. mac := hmac.New(sha256.New, key.hmacKey[:])
  127. mac.Write(encrypted[:len(encrypted)-sha256.Size])
  128. mac.Sum(macBytes[:0])
  129. return encrypted, nil
  130. }
  131. // [uTLS] added exported DecryptTicketWith func below
  132. func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
  133. if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
  134. return nil, false
  135. }
  136. keyName := encrypted[:ticketKeyNameLen]
  137. iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
  138. macBytes := encrypted[len(encrypted)-sha256.Size:]
  139. ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
  140. keyIndex := -1
  141. for i, candidateKey := range c.ticketKeys {
  142. if bytes.Equal(keyName, candidateKey.keyName[:]) {
  143. keyIndex = i
  144. break
  145. }
  146. }
  147. if keyIndex == -1 {
  148. return nil, false
  149. }
  150. key := &c.ticketKeys[keyIndex]
  151. mac := hmac.New(sha256.New, key.hmacKey[:])
  152. mac.Write(encrypted[:len(encrypted)-sha256.Size])
  153. expected := mac.Sum(nil)
  154. if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
  155. return nil, false
  156. }
  157. block, err := aes.NewCipher(key.aesKey[:])
  158. if err != nil {
  159. return nil, false
  160. }
  161. plaintext = make([]byte, len(ciphertext))
  162. cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
  163. return plaintext, keyIndex > 0
  164. }
  165. // DecryptTicketWith decrypts an encrypted session ticket
  166. // using a TicketKeys (ie []TicketKey) struct
  167. //
  168. // usedOldKey will be true if the key used for decryption is
  169. // not the first in the []TicketKey slice
  170. //
  171. // [uTLS] changed to be made public and take a TicketKeys and use a fake conn receiver
  172. func DecryptTicketWith(encrypted []byte, tks TicketKeys) (plaintext []byte, usedOldKey bool) {
  173. // create fake conn
  174. c := &Conn{
  175. ticketKeys: tks.ToPrivate(),
  176. }
  177. return c.decryptTicket(encrypted)
  178. }