tlsutil.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright (C) 2014 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package tlsutil
  7. import (
  8. "crypto/ecdsa"
  9. "crypto/ed25519"
  10. "crypto/elliptic"
  11. "crypto/rsa"
  12. "crypto/tls"
  13. "crypto/x509"
  14. "crypto/x509/pkix"
  15. "encoding/pem"
  16. "errors"
  17. "fmt"
  18. "math/big"
  19. "net"
  20. "os"
  21. "time"
  22. "github.com/syncthing/syncthing/lib/rand"
  23. )
  24. var (
  25. ErrIdentificationFailed = errors.New("failed to identify socket type")
  26. // The list of cipher suites we will use / suggest for TLS 1.2 connections.
  27. cipherSuites = []uint16{
  28. // Suites that are good and fast on hardware *without* AES-NI.
  29. tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
  30. tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
  31. // Suites that are good and fast on hardware with AES-NI. These are
  32. // reordered from the Go default to put the 256 bit ciphers above the
  33. // 128 bit ones - because that looks cooler, even though there is
  34. // probably no relevant difference in strength yet.
  35. tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
  36. tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
  37. tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
  38. tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
  39. // The rest of the suites, minus DES stuff.
  40. tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
  41. tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
  42. tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
  43. tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
  44. tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
  45. tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
  46. tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
  47. tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
  48. tls.TLS_RSA_WITH_AES_128_CBC_SHA256,
  49. tls.TLS_RSA_WITH_AES_128_CBC_SHA,
  50. tls.TLS_RSA_WITH_AES_256_CBC_SHA,
  51. }
  52. )
  53. // SecureDefault returns a tls.Config with reasonable, secure defaults set.
  54. // This variant allows only TLS 1.3.
  55. func SecureDefaultTLS13() *tls.Config {
  56. return &tls.Config{
  57. // TLS 1.3 is the minimum we accept
  58. MinVersion: tls.VersionTLS13,
  59. ClientSessionCache: tls.NewLRUClientSessionCache(0),
  60. }
  61. }
  62. // SecureDefaultWithTLS12 returns a tls.Config with reasonable, secure
  63. // defaults set. This variant allows TLS 1.2.
  64. func SecureDefaultWithTLS12() *tls.Config {
  65. // paranoia
  66. cs := make([]uint16, len(cipherSuites))
  67. copy(cs, cipherSuites)
  68. return &tls.Config{
  69. // TLS 1.2 is the minimum we accept
  70. MinVersion: tls.VersionTLS12,
  71. // The cipher suite lists built above. These are ignored in TLS 1.3.
  72. CipherSuites: cs,
  73. // We've put some thought into this choice and would like it to
  74. // matter.
  75. PreferServerCipherSuites: true,
  76. ClientSessionCache: tls.NewLRUClientSessionCache(0),
  77. }
  78. }
  79. // generateCertificate generates a PEM formatted key pair and self-signed
  80. // certificate in memory. The compatible flag indicates whether we aim for
  81. // compatibility (browsers) or maximum efficiency/security (sync
  82. // connections).
  83. func generateCertificate(commonName string, lifetimeDays int, compatible bool) (*pem.Block, *pem.Block, error) {
  84. var pub, priv any
  85. var err error
  86. var sigAlgo x509.SignatureAlgorithm
  87. if compatible {
  88. // For browser connections we prefer ECDSA-P256
  89. sigAlgo = x509.ECDSAWithSHA256
  90. var pk *ecdsa.PrivateKey
  91. pk, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
  92. if err == nil {
  93. priv = pk
  94. pub = pk.Public()
  95. }
  96. } else {
  97. // For sync connections we use Ed25519
  98. sigAlgo = x509.PureEd25519
  99. pub, priv, err = ed25519.GenerateKey(rand.Reader)
  100. }
  101. if err != nil {
  102. return nil, nil, fmt.Errorf("generate key: %w", err)
  103. }
  104. notBefore := time.Now().Truncate(24 * time.Hour)
  105. notAfter := notBefore.Add(time.Duration(lifetimeDays*24) * time.Hour)
  106. // NOTE: update lib/api.shouldRegenerateCertificate() appropriately if
  107. // you add or change attributes in here, especially DNSNames or
  108. // IPAddresses.
  109. template := x509.Certificate{
  110. SerialNumber: new(big.Int).SetUint64(rand.Uint64()),
  111. Subject: pkix.Name{
  112. CommonName: commonName,
  113. Organization: []string{"Syncthing"},
  114. OrganizationalUnit: []string{"Automatically Generated"},
  115. },
  116. DNSNames: []string{commonName},
  117. NotBefore: notBefore,
  118. NotAfter: notAfter,
  119. SignatureAlgorithm: sigAlgo,
  120. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
  121. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
  122. BasicConstraintsValid: true,
  123. }
  124. derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv)
  125. if err != nil {
  126. return nil, nil, fmt.Errorf("create cert: %w", err)
  127. }
  128. certBlock := &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}
  129. keyBlock, err := pemBlockForKey(priv)
  130. if err != nil {
  131. return nil, nil, fmt.Errorf("save key: %w", err)
  132. }
  133. return certBlock, keyBlock, nil
  134. }
  135. // NewCertificate generates and returns a new TLS certificate, saved to the
  136. // given PEM files. The compatible flag indicates whether we aim for
  137. // compatibility (browsers) or maximum efficiency/security (sync
  138. // connections).
  139. func NewCertificate(certFile, keyFile string, commonName string, lifetimeDays int, compatible bool) (tls.Certificate, error) {
  140. certBlock, keyBlock, err := generateCertificate(commonName, lifetimeDays, compatible)
  141. if err != nil {
  142. return tls.Certificate{}, err
  143. }
  144. certOut, err := os.Create(certFile)
  145. if err != nil {
  146. return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
  147. }
  148. if err = pem.Encode(certOut, certBlock); err != nil {
  149. return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
  150. }
  151. if err = certOut.Close(); err != nil {
  152. return tls.Certificate{}, fmt.Errorf("save cert: %w", err)
  153. }
  154. keyOut, err := os.OpenFile(keyFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0o600)
  155. if err != nil {
  156. return tls.Certificate{}, fmt.Errorf("save key: %w", err)
  157. }
  158. if err = pem.Encode(keyOut, keyBlock); err != nil {
  159. return tls.Certificate{}, fmt.Errorf("save key: %w", err)
  160. }
  161. if err = keyOut.Close(); err != nil {
  162. return tls.Certificate{}, fmt.Errorf("save key: %w", err)
  163. }
  164. return tls.X509KeyPair(pem.EncodeToMemory(certBlock), pem.EncodeToMemory(keyBlock))
  165. }
  166. // NewCertificateInMemory generates and returns a new TLS certificate, kept
  167. // only in memory.
  168. func NewCertificateInMemory(commonName string, lifetimeDays int) (tls.Certificate, error) {
  169. certBlock, keyBlock, err := generateCertificate(commonName, lifetimeDays, false)
  170. if err != nil {
  171. return tls.Certificate{}, err
  172. }
  173. return tls.X509KeyPair(pem.EncodeToMemory(certBlock), pem.EncodeToMemory(keyBlock))
  174. }
  175. type DowngradingListener struct {
  176. net.Listener
  177. TLSConfig *tls.Config
  178. }
  179. func (l *DowngradingListener) Accept() (net.Conn, error) {
  180. conn, isTLS, err := l.AcceptNoWrapTLS()
  181. // We failed to identify the socket type, pretend that everything is fine,
  182. // and pass it to the underlying handler, and let them deal with it.
  183. if err == ErrIdentificationFailed {
  184. return conn, nil
  185. }
  186. if err != nil {
  187. return conn, err
  188. }
  189. if isTLS {
  190. return tls.Server(conn, l.TLSConfig), nil
  191. }
  192. return conn, nil
  193. }
  194. func (l *DowngradingListener) AcceptNoWrapTLS() (net.Conn, bool, error) {
  195. conn, err := l.Listener.Accept()
  196. if err != nil {
  197. return nil, false, err
  198. }
  199. union := &UnionedConnection{Conn: conn}
  200. conn.SetReadDeadline(time.Now().Add(1 * time.Second))
  201. n, err := conn.Read(union.first[:])
  202. conn.SetReadDeadline(time.Time{})
  203. if err != nil || n == 0 {
  204. // We hit a read error here, but the Accept() call succeeded so we must not return an error.
  205. // We return the connection as is with a special error which handles this
  206. // special case in Accept().
  207. return conn, false, ErrIdentificationFailed
  208. }
  209. return union, union.first[0] == 0x16, nil
  210. }
  211. type UnionedConnection struct {
  212. first [1]byte
  213. firstDone bool
  214. net.Conn
  215. }
  216. func (c *UnionedConnection) Read(b []byte) (n int, err error) {
  217. if !c.firstDone {
  218. if len(b) == 0 {
  219. // this probably doesn't happen, but handle it anyway
  220. return 0, nil
  221. }
  222. b[0] = c.first[0]
  223. c.firstDone = true
  224. return 1, nil
  225. }
  226. return c.Conn.Read(b)
  227. }
  228. func pemBlockForKey(priv interface{}) (*pem.Block, error) {
  229. switch k := priv.(type) {
  230. case *rsa.PrivateKey:
  231. return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)}, nil
  232. case *ecdsa.PrivateKey:
  233. b, err := x509.MarshalECPrivateKey(k)
  234. if err != nil {
  235. return nil, err
  236. }
  237. return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
  238. case ed25519.PrivateKey:
  239. bs, err := x509.MarshalPKCS8PrivateKey(k)
  240. if err != nil {
  241. return nil, err
  242. }
  243. return &pem.Block{Type: "PRIVATE KEY", Bytes: bs}, nil
  244. default:
  245. return nil, fmt.Errorf("unknown key type: %T", priv)
  246. }
  247. }