example_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. // Copyright 2011 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. package ssh_test
  5. import (
  6. "bufio"
  7. "bytes"
  8. "crypto/rand"
  9. "crypto/rsa"
  10. "fmt"
  11. "log"
  12. "net"
  13. "net/http"
  14. "os"
  15. "path/filepath"
  16. "strings"
  17. "sync"
  18. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
  19. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh/terminal"
  20. )
  21. func ExampleNewServerConn() {
  22. // Public key authentication is done by comparing
  23. // the public key of a received connection
  24. // with the entries in the authorized_keys file.
  25. authorizedKeysBytes, err := os.ReadFile("authorized_keys")
  26. if err != nil {
  27. log.Fatalf("Failed to load authorized_keys, err: %v", err)
  28. }
  29. authorizedKeysMap := map[string]bool{}
  30. for len(authorizedKeysBytes) > 0 {
  31. pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
  32. if err != nil {
  33. log.Fatal(err)
  34. }
  35. authorizedKeysMap[string(pubKey.Marshal())] = true
  36. authorizedKeysBytes = rest
  37. }
  38. // An SSH server is represented by a ServerConfig, which holds
  39. // certificate details and handles authentication of ServerConns.
  40. config := &ssh.ServerConfig{
  41. // Remove to disable password auth.
  42. PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
  43. // Should use constant-time compare (or better, salt+hash) in
  44. // a production setting.
  45. if c.User() == "testuser" && string(pass) == "tiger" {
  46. return nil, nil
  47. }
  48. return nil, fmt.Errorf("password rejected for %q", c.User())
  49. },
  50. // Remove to disable public key auth.
  51. PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
  52. if authorizedKeysMap[string(pubKey.Marshal())] {
  53. return &ssh.Permissions{
  54. // Record the public key used for authentication.
  55. Extensions: map[string]string{
  56. "pubkey-fp": ssh.FingerprintSHA256(pubKey),
  57. },
  58. }, nil
  59. }
  60. return nil, fmt.Errorf("unknown public key for %q", c.User())
  61. },
  62. }
  63. privateBytes, err := os.ReadFile("id_rsa")
  64. if err != nil {
  65. log.Fatal("Failed to load private key: ", err)
  66. }
  67. private, err := ssh.ParsePrivateKey(privateBytes)
  68. if err != nil {
  69. log.Fatal("Failed to parse private key: ", err)
  70. }
  71. config.AddHostKey(private)
  72. // Once a ServerConfig has been configured, connections can be
  73. // accepted.
  74. listener, err := net.Listen("tcp", "0.0.0.0:2022")
  75. if err != nil {
  76. log.Fatal("failed to listen for connection: ", err)
  77. }
  78. nConn, err := listener.Accept()
  79. if err != nil {
  80. log.Fatal("failed to accept incoming connection: ", err)
  81. }
  82. // Before use, a handshake must be performed on the incoming
  83. // net.Conn.
  84. conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
  85. if err != nil {
  86. log.Fatal("failed to handshake: ", err)
  87. }
  88. log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
  89. var wg sync.WaitGroup
  90. defer wg.Wait()
  91. // The incoming Request channel must be serviced.
  92. wg.Add(1)
  93. go func() {
  94. ssh.DiscardRequests(reqs)
  95. wg.Done()
  96. }()
  97. // Service the incoming Channel channel.
  98. for newChannel := range chans {
  99. // Channels have a type, depending on the application level
  100. // protocol intended. In the case of a shell, the type is
  101. // "session" and ServerShell may be used to present a simple
  102. // terminal interface.
  103. if newChannel.ChannelType() != "session" {
  104. newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
  105. continue
  106. }
  107. channel, requests, err := newChannel.Accept()
  108. if err != nil {
  109. log.Fatalf("Could not accept channel: %v", err)
  110. }
  111. // Sessions have out-of-band requests such as "shell",
  112. // "pty-req" and "env". Here we handle only the
  113. // "shell" request.
  114. wg.Add(1)
  115. go func(in <-chan *ssh.Request) {
  116. for req := range in {
  117. req.Reply(req.Type == "shell", nil)
  118. }
  119. wg.Done()
  120. }(requests)
  121. term := terminal.NewTerminal(channel, "> ")
  122. wg.Add(1)
  123. go func() {
  124. defer func() {
  125. channel.Close()
  126. wg.Done()
  127. }()
  128. for {
  129. line, err := term.ReadLine()
  130. if err != nil {
  131. break
  132. }
  133. fmt.Println(line)
  134. }
  135. }()
  136. }
  137. }
  138. func ExampleServerConfig_AddHostKey() {
  139. // Minimal ServerConfig supporting only password authentication.
  140. config := &ssh.ServerConfig{
  141. PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
  142. // Should use constant-time compare (or better, salt+hash) in
  143. // a production setting.
  144. if c.User() == "testuser" && string(pass) == "tiger" {
  145. return nil, nil
  146. }
  147. return nil, fmt.Errorf("password rejected for %q", c.User())
  148. },
  149. }
  150. privateBytes, err := os.ReadFile("id_rsa")
  151. if err != nil {
  152. log.Fatal("Failed to load private key: ", err)
  153. }
  154. private, err := ssh.ParsePrivateKey(privateBytes)
  155. if err != nil {
  156. log.Fatal("Failed to parse private key: ", err)
  157. }
  158. // Restrict host key algorithms to disable ssh-rsa.
  159. signer, err := ssh.NewSignerWithAlgorithms(private.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256, ssh.KeyAlgoRSASHA512})
  160. if err != nil {
  161. log.Fatal("Failed to create private key with restricted algorithms: ", err)
  162. }
  163. config.AddHostKey(signer)
  164. }
  165. func ExampleClientConfig_HostKeyCallback() {
  166. // Every client must provide a host key check. Here is a
  167. // simple-minded parse of OpenSSH's known_hosts file
  168. host := "hostname"
  169. file, err := os.Open(filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts"))
  170. if err != nil {
  171. log.Fatal(err)
  172. }
  173. defer file.Close()
  174. scanner := bufio.NewScanner(file)
  175. var hostKey ssh.PublicKey
  176. for scanner.Scan() {
  177. fields := strings.Split(scanner.Text(), " ")
  178. if len(fields) != 3 {
  179. continue
  180. }
  181. if strings.Contains(fields[0], host) {
  182. var err error
  183. hostKey, _, _, _, err = ssh.ParseAuthorizedKey(scanner.Bytes())
  184. if err != nil {
  185. log.Fatalf("error parsing %q: %v", fields[2], err)
  186. }
  187. break
  188. }
  189. }
  190. if hostKey == nil {
  191. log.Fatalf("no hostkey for %s", host)
  192. }
  193. config := ssh.ClientConfig{
  194. User: os.Getenv("USER"),
  195. HostKeyCallback: ssh.FixedHostKey(hostKey),
  196. }
  197. _, err = ssh.Dial("tcp", host+":22", &config)
  198. log.Println(err)
  199. }
  200. func ExampleDial() {
  201. var hostKey ssh.PublicKey
  202. // An SSH client is represented with a ClientConn.
  203. //
  204. // To authenticate with the remote server you must pass at least one
  205. // implementation of AuthMethod via the Auth field in ClientConfig,
  206. // and provide a HostKeyCallback.
  207. config := &ssh.ClientConfig{
  208. User: "username",
  209. Auth: []ssh.AuthMethod{
  210. ssh.Password("yourpassword"),
  211. },
  212. HostKeyCallback: ssh.FixedHostKey(hostKey),
  213. }
  214. client, err := ssh.Dial("tcp", "yourserver.com:22", config)
  215. if err != nil {
  216. log.Fatal("Failed to dial: ", err)
  217. }
  218. defer client.Close()
  219. // Each ClientConn can support multiple interactive sessions,
  220. // represented by a Session.
  221. session, err := client.NewSession()
  222. if err != nil {
  223. log.Fatal("Failed to create session: ", err)
  224. }
  225. defer session.Close()
  226. // Once a Session is created, you can execute a single command on
  227. // the remote side using the Run method.
  228. var b bytes.Buffer
  229. session.Stdout = &b
  230. if err := session.Run("/usr/bin/whoami"); err != nil {
  231. log.Fatal("Failed to run: " + err.Error())
  232. }
  233. fmt.Println(b.String())
  234. }
  235. func ExamplePublicKeys() {
  236. var hostKey ssh.PublicKey
  237. // A public key may be used to authenticate against the remote
  238. // server by using an unencrypted PEM-encoded private key file.
  239. //
  240. // If you have an encrypted private key, the crypto/x509 package
  241. // can be used to decrypt it.
  242. key, err := os.ReadFile("/home/user/.ssh/id_rsa")
  243. if err != nil {
  244. log.Fatalf("unable to read private key: %v", err)
  245. }
  246. // Create the Signer for this private key.
  247. signer, err := ssh.ParsePrivateKey(key)
  248. if err != nil {
  249. log.Fatalf("unable to parse private key: %v", err)
  250. }
  251. config := &ssh.ClientConfig{
  252. User: "user",
  253. Auth: []ssh.AuthMethod{
  254. // Use the PublicKeys method for remote authentication.
  255. ssh.PublicKeys(signer),
  256. },
  257. HostKeyCallback: ssh.FixedHostKey(hostKey),
  258. }
  259. // Connect to the remote server and perform the SSH handshake.
  260. client, err := ssh.Dial("tcp", "host.com:22", config)
  261. if err != nil {
  262. log.Fatalf("unable to connect: %v", err)
  263. }
  264. defer client.Close()
  265. }
  266. func ExampleClient_Listen() {
  267. var hostKey ssh.PublicKey
  268. config := &ssh.ClientConfig{
  269. User: "username",
  270. Auth: []ssh.AuthMethod{
  271. ssh.Password("password"),
  272. },
  273. HostKeyCallback: ssh.FixedHostKey(hostKey),
  274. }
  275. // Dial your ssh server.
  276. conn, err := ssh.Dial("tcp", "localhost:22", config)
  277. if err != nil {
  278. log.Fatal("unable to connect: ", err)
  279. }
  280. defer conn.Close()
  281. // Request the remote side to open port 8080 on all interfaces.
  282. l, err := conn.Listen("tcp", "0.0.0.0:8080")
  283. if err != nil {
  284. log.Fatal("unable to register tcp forward: ", err)
  285. }
  286. defer l.Close()
  287. // Serve HTTP with your SSH server acting as a reverse proxy.
  288. http.Serve(l, http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
  289. fmt.Fprintf(resp, "Hello world!\n")
  290. }))
  291. }
  292. func ExampleSession_RequestPty() {
  293. var hostKey ssh.PublicKey
  294. // Create client config
  295. config := &ssh.ClientConfig{
  296. User: "username",
  297. Auth: []ssh.AuthMethod{
  298. ssh.Password("password"),
  299. },
  300. HostKeyCallback: ssh.FixedHostKey(hostKey),
  301. }
  302. // Connect to ssh server
  303. conn, err := ssh.Dial("tcp", "localhost:22", config)
  304. if err != nil {
  305. log.Fatal("unable to connect: ", err)
  306. }
  307. defer conn.Close()
  308. // Create a session
  309. session, err := conn.NewSession()
  310. if err != nil {
  311. log.Fatal("unable to create session: ", err)
  312. }
  313. defer session.Close()
  314. // Set up terminal modes
  315. modes := ssh.TerminalModes{
  316. ssh.ECHO: 0, // disable echoing
  317. ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
  318. ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
  319. }
  320. // Request pseudo terminal
  321. if err := session.RequestPty("xterm", 40, 80, modes); err != nil {
  322. log.Fatal("request for pseudo terminal failed: ", err)
  323. }
  324. // Start remote shell
  325. if err := session.Shell(); err != nil {
  326. log.Fatal("failed to start shell: ", err)
  327. }
  328. }
  329. func ExampleCertificate_SignCert() {
  330. // Sign a certificate with a specific algorithm.
  331. privateKey, err := rsa.GenerateKey(rand.Reader, 3072)
  332. if err != nil {
  333. log.Fatal("unable to generate RSA key: ", err)
  334. }
  335. publicKey, err := ssh.NewPublicKey(&privateKey.PublicKey)
  336. if err != nil {
  337. log.Fatal("unable to get RSA public key: ", err)
  338. }
  339. caKey, err := rsa.GenerateKey(rand.Reader, 3072)
  340. if err != nil {
  341. log.Fatal("unable to generate CA key: ", err)
  342. }
  343. signer, err := ssh.NewSignerFromKey(caKey)
  344. if err != nil {
  345. log.Fatal("unable to generate signer from key: ", err)
  346. }
  347. mas, err := ssh.NewSignerWithAlgorithms(signer.(ssh.AlgorithmSigner), []string{ssh.KeyAlgoRSASHA256})
  348. if err != nil {
  349. log.Fatal("unable to create signer with algorithms: ", err)
  350. }
  351. certificate := ssh.Certificate{
  352. Key: publicKey,
  353. CertType: ssh.UserCert,
  354. }
  355. if err := certificate.SignCert(rand.Reader, mas); err != nil {
  356. log.Fatal("unable to sign certificate: ", err)
  357. }
  358. // Save the public key to a file and check that rsa-sha-256 is used for
  359. // signing:
  360. // ssh-keygen -L -f <path to the file>
  361. fmt.Println(string(ssh.MarshalAuthorizedKey(&certificate)))
  362. }