config.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. /*
  2. * Copyright (c) 2016, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package server
  20. import (
  21. "crypto/rand"
  22. "crypto/rsa"
  23. "crypto/x509"
  24. "encoding/base64"
  25. "encoding/json"
  26. "encoding/pem"
  27. "fmt"
  28. "math/big"
  29. "strings"
  30. "time"
  31. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon"
  32. "golang.org/x/crypto/ssh"
  33. )
  34. const (
  35. SERVER_CONFIG_FILENAME = "psiphon-server.config"
  36. SERVER_ENTRY_FILENAME = "serverEntry.dat"
  37. DEFAULT_SERVER_IP_ADDRESS = "127.0.0.1"
  38. WEB_SERVER_SECRET_BYTE_LENGTH = 32
  39. WEB_SERVER_CERTIFICATE_RSA_KEY_BITS = 2048
  40. WEB_SERVER_CERTIFICATE_VALIDITY_PERIOD = 10 * 365 * 24 * time.Hour // approx. 10 years
  41. DEFAULT_WEB_SERVER_PORT = 8000
  42. WEB_SERVER_READ_TIMEOUT = 10 * time.Second
  43. WEB_SERVER_WRITE_TIMEOUT = 10 * time.Second
  44. SSH_USERNAME_SUFFIX_BYTE_LENGTH = 8
  45. SSH_PASSWORD_BYTE_LENGTH = 32
  46. SSH_RSA_HOST_KEY_BITS = 2048
  47. DEFAULT_SSH_SERVER_PORT = 2222
  48. SSH_HANDSHAKE_TIMEOUT = 30 * time.Second
  49. SSH_OBFUSCATED_KEY_BYTE_LENGTH = 32
  50. DEFAULT_OBFUSCATED_SSH_SERVER_PORT = 3333
  51. )
  52. type Config struct {
  53. ServerIPAddress string
  54. WebServerPort int
  55. WebServerSecret string
  56. WebServerCertificate string
  57. WebServerPrivateKey string
  58. SSHPrivateKey string
  59. SSHServerVersion string
  60. SSHUserName string
  61. SSHPassword string
  62. SSHServerPort int
  63. ObfuscatedSSHKey string
  64. ObfuscatedSSHServerPort int
  65. }
  66. func LoadConfig(configJson []byte) (*Config, error) {
  67. var config Config
  68. err := json.Unmarshal(configJson, &config)
  69. if err != nil {
  70. return nil, psiphon.ContextError(err)
  71. }
  72. // TODO: config field validation
  73. // TODO: validation case: OSSH requires extra fields
  74. return &config, nil
  75. }
  76. type GenerateConfigParams struct {
  77. ServerIPAddress string
  78. WebServerPort int
  79. SSHServerPort int
  80. ObfuscatedSSHServerPort int
  81. }
  82. func GenerateConfig(params *GenerateConfigParams) ([]byte, []byte, error) {
  83. // TODO: support disabling web server or a subset of protocols
  84. serverIPaddress := params.ServerIPAddress
  85. if serverIPaddress == "" {
  86. serverIPaddress = DEFAULT_SERVER_IP_ADDRESS
  87. }
  88. // Web server config
  89. webServerPort := params.WebServerPort
  90. if webServerPort == 0 {
  91. webServerPort = DEFAULT_WEB_SERVER_PORT
  92. }
  93. webServerSecret, err := psiphon.MakeRandomString(WEB_SERVER_SECRET_BYTE_LENGTH)
  94. if err != nil {
  95. return nil, nil, psiphon.ContextError(err)
  96. }
  97. webServerCertificate, webServerPrivateKey, err := generateWebServerCertificate()
  98. if err != nil {
  99. return nil, nil, psiphon.ContextError(err)
  100. }
  101. // SSH config
  102. sshServerPort := params.SSHServerPort
  103. if sshServerPort == 0 {
  104. sshServerPort = DEFAULT_SSH_SERVER_PORT
  105. }
  106. // TODO: use other key types: anti-fingerprint by varying params
  107. rsaKey, err := rsa.GenerateKey(rand.Reader, SSH_RSA_HOST_KEY_BITS)
  108. if err != nil {
  109. return nil, nil, psiphon.ContextError(err)
  110. }
  111. sshPrivateKey := pem.EncodeToMemory(
  112. &pem.Block{
  113. Type: "RSA PRIVATE KEY",
  114. Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
  115. },
  116. )
  117. signer, err := ssh.NewSignerFromKey(rsaKey)
  118. if err != nil {
  119. return nil, nil, psiphon.ContextError(err)
  120. }
  121. sshPublicKey := signer.PublicKey()
  122. sshUserNameSuffix, err := psiphon.MakeRandomString(SSH_USERNAME_SUFFIX_BYTE_LENGTH)
  123. if err != nil {
  124. return nil, nil, psiphon.ContextError(err)
  125. }
  126. sshUserName := "psiphon_" + sshUserNameSuffix
  127. sshPassword, err := psiphon.MakeRandomString(SSH_PASSWORD_BYTE_LENGTH)
  128. if err != nil {
  129. return nil, nil, psiphon.ContextError(err)
  130. }
  131. // TODO: vary version string for anti-fingerprint
  132. sshServerVersion := "SSH-2.0-Psiphon"
  133. // Obfuscated SSH config
  134. obfuscatedSSHServerPort := params.ObfuscatedSSHServerPort
  135. if obfuscatedSSHServerPort == 0 {
  136. obfuscatedSSHServerPort = DEFAULT_OBFUSCATED_SSH_SERVER_PORT
  137. }
  138. obfuscatedSSHKey, err := psiphon.MakeRandomString(SSH_OBFUSCATED_KEY_BYTE_LENGTH)
  139. if err != nil {
  140. return nil, nil, psiphon.ContextError(err)
  141. }
  142. // Assemble config and server entry
  143. config := &Config{
  144. ServerIPAddress: serverIPaddress,
  145. WebServerPort: webServerPort,
  146. WebServerSecret: webServerSecret,
  147. WebServerCertificate: webServerCertificate,
  148. WebServerPrivateKey: webServerPrivateKey,
  149. SSHPrivateKey: string(sshPrivateKey),
  150. SSHServerVersion: sshServerVersion,
  151. SSHUserName: sshUserName,
  152. SSHPassword: sshPassword,
  153. SSHServerPort: sshServerPort,
  154. ObfuscatedSSHKey: obfuscatedSSHKey,
  155. ObfuscatedSSHServerPort: obfuscatedSSHServerPort,
  156. }
  157. encodedConfig, err := json.Marshal(config)
  158. if err != nil {
  159. return nil, nil, psiphon.ContextError(err)
  160. }
  161. // Server entry format omits the BEGIN/END lines and newlines
  162. lines := strings.Split(webServerCertificate, "\n")
  163. strippedWebServerCertificate := strings.Join(lines[1:len(lines)-2], "")
  164. capabilities := []string{
  165. psiphon.GetCapability(psiphon.TUNNEL_PROTOCOL_SSH),
  166. psiphon.GetCapability(psiphon.TUNNEL_PROTOCOL_OBFUSCATED_SSH),
  167. }
  168. serverEntry := &psiphon.ServerEntry{
  169. IpAddress: serverIPaddress,
  170. WebServerPort: fmt.Sprintf("%d", webServerPort),
  171. WebServerSecret: webServerSecret,
  172. WebServerCertificate: strippedWebServerCertificate,
  173. SshPort: sshServerPort,
  174. SshUsername: sshUserName,
  175. SshPassword: sshPassword,
  176. SshHostKey: base64.RawStdEncoding.EncodeToString(sshPublicKey.Marshal()),
  177. SshObfuscatedPort: obfuscatedSSHServerPort,
  178. SshObfuscatedKey: obfuscatedSSHKey,
  179. Capabilities: capabilities,
  180. Region: "US",
  181. }
  182. encodedServerEntry, err := psiphon.EncodeServerEntry(serverEntry)
  183. if err != nil {
  184. return nil, nil, psiphon.ContextError(err)
  185. }
  186. return encodedConfig, []byte(encodedServerEntry), nil
  187. }
  188. func generateWebServerCertificate() (string, string, error) {
  189. // Based on https://golang.org/src/crypto/tls/generate_cert.go
  190. // TODO: use other key types: anti-fingerprint by varying params
  191. rsaKey, err := rsa.GenerateKey(rand.Reader, WEB_SERVER_CERTIFICATE_RSA_KEY_BITS)
  192. if err != nil {
  193. return "", "", psiphon.ContextError(err)
  194. }
  195. notBefore := time.Now()
  196. notAfter := notBefore.Add(WEB_SERVER_CERTIFICATE_VALIDITY_PERIOD)
  197. // TODO: psi_ops_install sets serial number to 0?
  198. // TOSO: psi_ops_install sets RSA exponent to 3, digest type to 'sha1', and version to 2?
  199. serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
  200. serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
  201. if err != nil {
  202. return "", "", psiphon.ContextError(err)
  203. }
  204. template := x509.Certificate{
  205. // TODO: psi_ops_install leaves subject blank?
  206. /*
  207. Subject: pkix.Name{
  208. Organization: []string{""},
  209. },
  210. IPAddresses: ...
  211. */
  212. SerialNumber: serialNumber,
  213. NotBefore: notBefore,
  214. NotAfter: notAfter,
  215. KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
  216. ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
  217. BasicConstraintsValid: true,
  218. IsCA: true,
  219. }
  220. derCert, err := x509.CreateCertificate(rand.Reader, &template, &template, rsaKey.Public(), rsaKey)
  221. if err != nil {
  222. return "", "", psiphon.ContextError(err)
  223. }
  224. webServerCertificate := pem.EncodeToMemory(
  225. &pem.Block{
  226. Type: "CERTIFICATE",
  227. Bytes: derCert,
  228. },
  229. )
  230. webServerPrivateKey := pem.EncodeToMemory(
  231. &pem.Block{
  232. Type: "RSA PRIVATE KEY",
  233. Bytes: x509.MarshalPKCS1PrivateKey(rsaKey),
  234. },
  235. )
  236. return string(webServerCertificate), string(webServerPrivateKey), nil
  237. }