negotiation.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package mint
  2. import (
  3. "bytes"
  4. "encoding/hex"
  5. "fmt"
  6. "time"
  7. )
  8. func VersionNegotiation(offered, supported []uint16) (bool, uint16) {
  9. for _, offeredVersion := range offered {
  10. for _, supportedVersion := range supported {
  11. logf(logTypeHandshake, "[server] version offered by client [%04x] <> [%04x]", offeredVersion, supportedVersion)
  12. if offeredVersion == supportedVersion {
  13. // XXX: Should probably be highest supported version, but for now, we
  14. // only support one version, so it doesn't really matter.
  15. return true, offeredVersion
  16. }
  17. }
  18. }
  19. return false, 0
  20. }
  21. func DHNegotiation(keyShares []KeyShareEntry, groups []NamedGroup) (bool, NamedGroup, []byte, []byte) {
  22. for _, share := range keyShares {
  23. for _, group := range groups {
  24. if group != share.Group {
  25. continue
  26. }
  27. pub, priv, err := newKeyShare(share.Group)
  28. if err != nil {
  29. // If we encounter an error, just keep looking
  30. continue
  31. }
  32. dhSecret, err := keyAgreement(share.Group, share.KeyExchange, priv)
  33. if err != nil {
  34. // If we encounter an error, just keep looking
  35. continue
  36. }
  37. return true, group, pub, dhSecret
  38. }
  39. }
  40. return false, 0, nil, nil
  41. }
  42. const (
  43. ticketAgeTolerance uint32 = 5 * 1000 // five seconds in milliseconds
  44. )
  45. func PSKNegotiation(identities []PSKIdentity, binders []PSKBinderEntry, context []byte, psks PreSharedKeyCache) (bool, int, *PreSharedKey, CipherSuiteParams, error) {
  46. logf(logTypeNegotiation, "Negotiating PSK offered=[%d] supported=[%d]", len(identities), psks.Size())
  47. for i, id := range identities {
  48. identityHex := hex.EncodeToString(id.Identity)
  49. psk, ok := psks.Get(identityHex)
  50. if !ok {
  51. logf(logTypeNegotiation, "No PSK for identity %x", identityHex)
  52. continue
  53. }
  54. // For resumption, make sure the ticket age is correct
  55. if psk.IsResumption {
  56. extTicketAge := id.ObfuscatedTicketAge - psk.TicketAgeAdd
  57. knownTicketAge := uint32(time.Since(psk.ReceivedAt) / time.Millisecond)
  58. ticketAgeDelta := knownTicketAge - extTicketAge
  59. if knownTicketAge < extTicketAge {
  60. ticketAgeDelta = extTicketAge - knownTicketAge
  61. }
  62. if ticketAgeDelta > ticketAgeTolerance {
  63. logf(logTypeNegotiation, "WARNING potential replay [%x]", psk.Identity)
  64. logf(logTypeNegotiation, "Ticket age exceeds tolerance |%d - %d| = [%d] > [%d]",
  65. extTicketAge, knownTicketAge, ticketAgeDelta, ticketAgeTolerance)
  66. return false, 0, nil, CipherSuiteParams{}, fmt.Errorf("WARNING Potential replay for identity %x", psk.Identity)
  67. }
  68. }
  69. params, ok := cipherSuiteMap[psk.CipherSuite]
  70. if !ok {
  71. err := fmt.Errorf("tls.cryptoinit: Unsupported ciphersuite from PSK [%04x]", psk.CipherSuite)
  72. return false, 0, nil, CipherSuiteParams{}, err
  73. }
  74. // Compute binder
  75. binderLabel := labelExternalBinder
  76. if psk.IsResumption {
  77. binderLabel = labelResumptionBinder
  78. }
  79. h0 := params.Hash.New().Sum(nil)
  80. zero := bytes.Repeat([]byte{0}, params.Hash.Size())
  81. earlySecret := HkdfExtract(params.Hash, zero, psk.Key)
  82. binderKey := deriveSecret(params, earlySecret, binderLabel, h0)
  83. // context = ClientHello[truncated]
  84. // context = ClientHello1 + HelloRetryRequest + ClientHello2[truncated]
  85. ctxHash := params.Hash.New()
  86. ctxHash.Write(context)
  87. binder := computeFinishedData(params, binderKey, ctxHash.Sum(nil))
  88. if !bytes.Equal(binder, binders[i].Binder) {
  89. logf(logTypeNegotiation, "Binder check failed for identity %x; [%x] != [%x]", psk.Identity, binder, binders[i].Binder)
  90. return false, 0, nil, CipherSuiteParams{}, fmt.Errorf("Binder check failed identity %x", psk.Identity)
  91. }
  92. logf(logTypeNegotiation, "Using PSK with identity %x", psk.Identity)
  93. return true, i, &psk, params, nil
  94. }
  95. logf(logTypeNegotiation, "Failed to find a usable PSK")
  96. return false, 0, nil, CipherSuiteParams{}, nil
  97. }
  98. func PSKModeNegotiation(canDoDH, canDoPSK bool, modes []PSKKeyExchangeMode) (bool, bool) {
  99. logf(logTypeNegotiation, "Negotiating PSK modes [%v] [%v] [%+v]", canDoDH, canDoPSK, modes)
  100. dhAllowed := false
  101. dhRequired := true
  102. for _, mode := range modes {
  103. dhAllowed = dhAllowed || (mode == PSKModeDHEKE)
  104. dhRequired = dhRequired && (mode == PSKModeDHEKE)
  105. }
  106. // Use PSK if we can meet DH requirement and modes were provided
  107. usingPSK := canDoPSK && (!dhRequired || canDoDH) && (len(modes) > 0)
  108. // Use DH if allowed
  109. usingDH := canDoDH && (dhAllowed || !usingPSK)
  110. logf(logTypeNegotiation, "Results of PSK mode negotiation: usingDH=[%v] usingPSK=[%v]", usingDH, usingPSK)
  111. return usingDH, usingPSK
  112. }
  113. func CertificateSelection(serverName *string, signatureSchemes []SignatureScheme, certs []*Certificate) (*Certificate, SignatureScheme, error) {
  114. // Select for server name if provided
  115. candidates := certs
  116. if serverName != nil {
  117. candidatesByName := []*Certificate{}
  118. for _, cert := range certs {
  119. for _, name := range cert.Chain[0].DNSNames {
  120. if len(*serverName) > 0 && name == *serverName {
  121. candidatesByName = append(candidatesByName, cert)
  122. }
  123. }
  124. }
  125. if len(candidatesByName) == 0 {
  126. return nil, 0, fmt.Errorf("No certificates available for server name: %s", *serverName)
  127. }
  128. candidates = candidatesByName
  129. }
  130. // Select for signature scheme
  131. for _, cert := range candidates {
  132. for _, scheme := range signatureSchemes {
  133. if !schemeValidForKey(scheme, cert.PrivateKey) {
  134. continue
  135. }
  136. return cert, scheme, nil
  137. }
  138. }
  139. return nil, 0, fmt.Errorf("No certificates compatible with signature schemes")
  140. }
  141. func EarlyDataNegotiation(usingPSK, gotEarlyData, allowEarlyData bool) (using bool, rejected bool) {
  142. using = gotEarlyData && usingPSK && allowEarlyData
  143. rejected = gotEarlyData && !using
  144. logf(logTypeNegotiation, "Early data negotiation (%v, %v, %v) => %v, %v", usingPSK, gotEarlyData, allowEarlyData, using, rejected)
  145. return
  146. }
  147. func CipherSuiteNegotiation(psk *PreSharedKey, offered, supported []CipherSuite) (CipherSuite, error) {
  148. for _, s1 := range offered {
  149. if psk != nil {
  150. if s1 == psk.CipherSuite {
  151. return s1, nil
  152. }
  153. continue
  154. }
  155. for _, s2 := range supported {
  156. if s1 == s2 {
  157. return s1, nil
  158. }
  159. }
  160. }
  161. return 0, fmt.Errorf("No overlap between offered and supproted ciphersuites (psk? [%v])", psk != nil)
  162. }
  163. func ALPNNegotiation(psk *PreSharedKey, offered, supported []string) (string, error) {
  164. for _, p1 := range offered {
  165. if psk != nil {
  166. if p1 != psk.NextProto {
  167. continue
  168. }
  169. }
  170. for _, p2 := range supported {
  171. if p1 == p2 {
  172. return p1, nil
  173. }
  174. }
  175. }
  176. // If the client offers ALPN on resumption, it must match the earlier one
  177. var err error
  178. if psk != nil && psk.IsResumption && (len(offered) > 0) {
  179. err = fmt.Errorf("ALPN for PSK not provided")
  180. }
  181. return "", err
  182. }