ktls_write.go 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2009 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. //go:build linux && go1.25 && badlinkname
  5. package ktls
  6. import (
  7. "crypto/cipher"
  8. "crypto/tls"
  9. "errors"
  10. "net"
  11. )
  12. func (c *Conn) Write(b []byte) (int, error) {
  13. if !c.kernelTx {
  14. return c.Conn.Write(b)
  15. }
  16. // interlock with Close below
  17. for {
  18. x := c.rawConn.ActiveCall.Load()
  19. if x&1 != 0 {
  20. return 0, net.ErrClosed
  21. }
  22. if c.rawConn.ActiveCall.CompareAndSwap(x, x+2) {
  23. break
  24. }
  25. }
  26. defer c.rawConn.ActiveCall.Add(-2)
  27. //if err := c.Conn.HandshakeContext(context.Background()); err != nil {
  28. // return 0, err
  29. //}
  30. c.rawConn.Out.Lock()
  31. defer c.rawConn.Out.Unlock()
  32. if err := *c.rawConn.Out.Err; err != nil {
  33. return 0, err
  34. }
  35. if !c.rawConn.IsHandshakeComplete.Load() {
  36. return 0, tls.AlertError(alertInternalError)
  37. }
  38. if *c.rawConn.CloseNotifySent {
  39. // return 0, errShutdown
  40. return 0, errors.New("tls: protocol is shutdown")
  41. }
  42. // TLS 1.0 is susceptible to a chosen-plaintext
  43. // attack when using block mode ciphers due to predictable IVs.
  44. // This can be prevented by splitting each Application Data
  45. // record into two records, effectively randomizing the RawIV.
  46. //
  47. // https://www.openssl.org/~bodo/tls-cbc.txt
  48. // https://bugzilla.mozilla.org/show_bug.cgi?id=665814
  49. // https://www.imperialviolet.org/2012/01/15/beastfollowup.html
  50. var m int
  51. if len(b) > 1 && *c.rawConn.Vers == tls.VersionTLS10 {
  52. if _, ok := (*c.rawConn.Out.Cipher).(cipher.BlockMode); ok {
  53. n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
  54. if err != nil {
  55. return n, c.rawConn.Out.SetErrorLocked(err)
  56. }
  57. m, b = 1, b[1:]
  58. }
  59. }
  60. n, err := c.writeRecordLocked(recordTypeApplicationData, b)
  61. return n + m, c.rawConn.Out.SetErrorLocked(err)
  62. }
  63. func (c *Conn) writeRecordLocked(typ uint16, data []byte) (n int, err error) {
  64. if !c.kernelTx {
  65. return c.rawConn.WriteRecordLocked(typ, data)
  66. }
  67. /*for len(data) > 0 {
  68. m := len(data)
  69. if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
  70. m = maxPayload
  71. }
  72. _, err = c.writeKernelRecord(typ, data[:m])
  73. if err != nil {
  74. return
  75. }
  76. n += m
  77. data = data[m:]
  78. }*/
  79. return c.writeKernelRecord(typ, data)
  80. }
  81. const (
  82. // tcpMSSEstimate is a conservative estimate of the TCP maximum segment
  83. // size (MSS). A constant is used, rather than querying the kernel for
  84. // the actual MSS, to avoid complexity. The value here is the IPv6
  85. // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
  86. // bytes) and a TCP header with timestamps (32 bytes).
  87. tcpMSSEstimate = 1208
  88. // recordSizeBoostThreshold is the number of bytes of application data
  89. // sent after which the TLS record size will be increased to the
  90. // maximum.
  91. recordSizeBoostThreshold = 128 * 1024
  92. )
  93. func (c *Conn) maxPayloadSizeForWrite(typ uint16) int {
  94. if /*c.config.DynamicRecordSizingDisabled ||*/ typ != recordTypeApplicationData {
  95. return maxPlaintext
  96. }
  97. if *c.rawConn.PacketsSent >= recordSizeBoostThreshold {
  98. return maxPlaintext
  99. }
  100. // Subtract TLS overheads to get the maximum payload size.
  101. payloadBytes := tcpMSSEstimate - recordHeaderLen - c.rawConn.Out.ExplicitNonceLen()
  102. if rawCipher := *c.rawConn.Out.Cipher; rawCipher != nil {
  103. switch ciph := rawCipher.(type) {
  104. case cipher.Stream:
  105. payloadBytes -= (*c.rawConn.Out.Mac).Size()
  106. case cipher.AEAD:
  107. payloadBytes -= ciph.Overhead()
  108. /*case cbcMode:
  109. blockSize := ciph.BlockSize()
  110. // The payload must fit in a multiple of blockSize, with
  111. // room for at least one padding byte.
  112. payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
  113. // The RawMac is appended before padding so affects the
  114. // payload size directly.
  115. payloadBytes -= c.out.mac.Size()*/
  116. default:
  117. panic("unknown cipher type")
  118. }
  119. }
  120. if *c.rawConn.Vers == tls.VersionTLS13 {
  121. payloadBytes-- // encrypted ContentType
  122. }
  123. // Allow packet growth in arithmetic progression up to max.
  124. pkt := *c.rawConn.PacketsSent
  125. *c.rawConn.PacketsSent++
  126. if pkt > 1000 {
  127. return maxPlaintext // avoid overflow in multiply below
  128. }
  129. n := payloadBytes * int(pkt+1)
  130. if n > maxPlaintext {
  131. n = maxPlaintext
  132. }
  133. return n
  134. }