state-machine.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. package mint
  2. import (
  3. "crypto/x509"
  4. "time"
  5. )
  6. // Marker interface for actions that an implementation should take based on
  7. // state transitions.
  8. type HandshakeAction interface{}
  9. type QueueHandshakeMessage struct {
  10. Message *HandshakeMessage
  11. }
  12. type SendQueuedHandshake struct{}
  13. type SendEarlyData struct{}
  14. type RekeyIn struct {
  15. epoch Epoch
  16. KeySet keySet
  17. }
  18. type RekeyOut struct {
  19. epoch Epoch
  20. KeySet keySet
  21. }
  22. type ResetOut struct {
  23. seq uint64
  24. }
  25. type StorePSK struct {
  26. PSK PreSharedKey
  27. }
  28. type HandshakeState interface {
  29. Next(handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert)
  30. State() State
  31. }
  32. type AppExtensionHandler interface {
  33. Send(hs HandshakeType, el *ExtensionList) error
  34. Receive(hs HandshakeType, el *ExtensionList) error
  35. }
  36. // ConnectionOptions objects represent per-connection settings for a client
  37. // initiating a connection
  38. type ConnectionOptions struct {
  39. ServerName string
  40. NextProtos []string
  41. }
  42. // ConnectionParameters objects represent the parameters negotiated for a
  43. // connection.
  44. type ConnectionParameters struct {
  45. UsingPSK bool
  46. UsingDH bool
  47. ClientSendingEarlyData bool
  48. UsingEarlyData bool
  49. RejectedEarlyData bool
  50. UsingClientAuth bool
  51. CipherSuite CipherSuite
  52. ServerName string
  53. NextProto string
  54. }
  55. // Working state for the handshake.
  56. type HandshakeContext struct {
  57. timeoutMS uint32
  58. timers *timerSet
  59. recvdRecords []uint64
  60. sentFragments []*SentHandshakeFragment
  61. hIn, hOut *HandshakeLayer
  62. waitingNextFlight bool
  63. earlyData []byte
  64. }
  65. func (hc *HandshakeContext) SetVersion(version uint16) {
  66. if hc.hIn.conn != nil {
  67. hc.hIn.conn.SetVersion(version)
  68. }
  69. if hc.hOut.conn != nil {
  70. hc.hOut.conn.SetVersion(version)
  71. }
  72. }
  73. // stateConnected is symmetric between client and server
  74. type stateConnected struct {
  75. Params ConnectionParameters
  76. hsCtx *HandshakeContext
  77. isClient bool
  78. cryptoParams CipherSuiteParams
  79. resumptionSecret []byte
  80. clientTrafficSecret []byte
  81. serverTrafficSecret []byte
  82. exporterSecret []byte
  83. peerCertificates []*x509.Certificate
  84. verifiedChains [][]*x509.Certificate
  85. }
  86. var _ HandshakeState = &stateConnected{}
  87. func (state stateConnected) State() State {
  88. if state.isClient {
  89. return StateClientConnected
  90. }
  91. return StateServerConnected
  92. }
  93. func (state *stateConnected) KeyUpdate(request KeyUpdateRequest) ([]HandshakeAction, Alert) {
  94. var trafficKeys keySet
  95. if state.isClient {
  96. state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
  97. labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
  98. trafficKeys = makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret)
  99. } else {
  100. state.serverTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.serverTrafficSecret,
  101. labelServerApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
  102. trafficKeys = makeTrafficKeys(state.cryptoParams, state.serverTrafficSecret)
  103. }
  104. kum, err := state.hsCtx.hOut.HandshakeMessageFromBody(&KeyUpdateBody{KeyUpdateRequest: request})
  105. if err != nil {
  106. logf(logTypeHandshake, "[StateConnected] Error marshaling key update message: %v", err)
  107. return nil, AlertInternalError
  108. }
  109. toSend := []HandshakeAction{
  110. QueueHandshakeMessage{kum},
  111. SendQueuedHandshake{},
  112. RekeyOut{epoch: EpochUpdate, KeySet: trafficKeys},
  113. }
  114. return toSend, AlertNoAlert
  115. }
  116. func (state *stateConnected) NewSessionTicket(length int, lifetime, earlyDataLifetime uint32) ([]HandshakeAction, Alert) {
  117. tkt, err := NewSessionTicket(length, lifetime)
  118. if err != nil {
  119. logf(logTypeHandshake, "[StateConnected] Error generating NewSessionTicket: %v", err)
  120. return nil, AlertInternalError
  121. }
  122. err = tkt.Extensions.Add(&TicketEarlyDataInfoExtension{earlyDataLifetime})
  123. if err != nil {
  124. logf(logTypeHandshake, "[StateConnected] Error adding extension to NewSessionTicket: %v", err)
  125. return nil, AlertInternalError
  126. }
  127. resumptionKey := HkdfExpandLabel(state.cryptoParams.Hash, state.resumptionSecret,
  128. labelResumption, tkt.TicketNonce, state.cryptoParams.Hash.Size())
  129. newPSK := PreSharedKey{
  130. CipherSuite: state.cryptoParams.Suite,
  131. IsResumption: true,
  132. Identity: tkt.Ticket,
  133. Key: resumptionKey,
  134. NextProto: state.Params.NextProto,
  135. ReceivedAt: time.Now(),
  136. ExpiresAt: time.Now().Add(time.Duration(tkt.TicketLifetime) * time.Second),
  137. TicketAgeAdd: tkt.TicketAgeAdd,
  138. }
  139. tktm, err := state.hsCtx.hOut.HandshakeMessageFromBody(tkt)
  140. if err != nil {
  141. logf(logTypeHandshake, "[StateConnected] Error marshaling NewSessionTicket: %v", err)
  142. return nil, AlertInternalError
  143. }
  144. toSend := []HandshakeAction{
  145. StorePSK{newPSK},
  146. QueueHandshakeMessage{tktm},
  147. SendQueuedHandshake{},
  148. }
  149. return toSend, AlertNoAlert
  150. }
  151. // Next does nothing for this state.
  152. func (state stateConnected) Next(hr handshakeMessageReader) (HandshakeState, []HandshakeAction, Alert) {
  153. return state, nil, AlertNoAlert
  154. }
  155. func (state stateConnected) ProcessMessage(hm *HandshakeMessage) (HandshakeState, []HandshakeAction, Alert) {
  156. if hm == nil {
  157. logf(logTypeHandshake, "[StateConnected] Unexpected message")
  158. return nil, nil, AlertUnexpectedMessage
  159. }
  160. bodyGeneric, err := hm.ToBody()
  161. if err != nil {
  162. logf(logTypeHandshake, "[StateConnected] Error decoding message: %v", err)
  163. return nil, nil, AlertDecodeError
  164. }
  165. switch body := bodyGeneric.(type) {
  166. case *KeyUpdateBody:
  167. var trafficKeys keySet
  168. if !state.isClient {
  169. state.clientTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.clientTrafficSecret,
  170. labelClientApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
  171. trafficKeys = makeTrafficKeys(state.cryptoParams, state.clientTrafficSecret)
  172. } else {
  173. state.serverTrafficSecret = HkdfExpandLabel(state.cryptoParams.Hash, state.serverTrafficSecret,
  174. labelServerApplicationTrafficSecret, []byte{}, state.cryptoParams.Hash.Size())
  175. trafficKeys = makeTrafficKeys(state.cryptoParams, state.serverTrafficSecret)
  176. }
  177. toSend := []HandshakeAction{RekeyIn{epoch: EpochUpdate, KeySet: trafficKeys}}
  178. // If requested, roll outbound keys and send a KeyUpdate
  179. if body.KeyUpdateRequest == KeyUpdateRequested {
  180. logf(logTypeHandshake, "Received key update, update requested", body.KeyUpdateRequest)
  181. moreToSend, alert := state.KeyUpdate(KeyUpdateNotRequested)
  182. if alert != AlertNoAlert {
  183. return nil, nil, alert
  184. }
  185. toSend = append(toSend, moreToSend...)
  186. }
  187. return state, toSend, AlertNoAlert
  188. case *NewSessionTicketBody:
  189. // XXX: Allow NewSessionTicket in both directions?
  190. if !state.isClient {
  191. return nil, nil, AlertUnexpectedMessage
  192. }
  193. resumptionKey := HkdfExpandLabel(state.cryptoParams.Hash, state.resumptionSecret,
  194. labelResumption, body.TicketNonce, state.cryptoParams.Hash.Size())
  195. psk := PreSharedKey{
  196. CipherSuite: state.cryptoParams.Suite,
  197. IsResumption: true,
  198. Identity: body.Ticket,
  199. Key: resumptionKey,
  200. NextProto: state.Params.NextProto,
  201. ReceivedAt: time.Now(),
  202. ExpiresAt: time.Now().Add(time.Duration(body.TicketLifetime) * time.Second),
  203. TicketAgeAdd: body.TicketAgeAdd,
  204. }
  205. toSend := []HandshakeAction{StorePSK{psk}}
  206. return state, toSend, AlertNoAlert
  207. }
  208. logf(logTypeHandshake, "[StateConnected] Unexpected message type %v", hm.msgType)
  209. return nil, nil, AlertUnexpectedMessage
  210. }