go 中的 ssh 服务器:如何提供与 rsa 不同的 public 密钥类型?
ssh server in go : how to offer public key types different than rsa?
我正在尝试使用 x/crypto/ssh
模块在 go 中创建一个 ssh 服务器,但我无法使 public 密钥验证工作。
我尝试了 ssh/example_test.go
文件中的 ExampleNewServerConn()
函数(在 https://go.googlesource.com/crypto 存储库中)但是 public 键方法不起作用,看起来服务器没有做广告正确的算法,因为我在尝试连接 ssh 客户端时得到了这条线:
debug1: send_pubkey_test: no mutual signature algorithm
如果我添加 -o PubkeyAcceptedKeyTypes=+ssh-rsa
public 密钥登录有效,但此 rsa 方法已弃用,我想使用另一种 public 密钥类型,我该怎么做?
提前致谢。
编辑:这是我用来测试的代码
package main
import (
"fmt"
"io/ioutil"
"log"
"net"
"golang.org/x/crypto/ssh"
terminal "golang.org/x/term"
)
func main() {
authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
if err != nil {
log.Fatalf("Failed to load authorized_keys, err: %v", err)
}
authorizedKeysMap := map[string]bool{}
for len(authorizedKeysBytes) > 0 {
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
if err != nil {
log.Fatal(err)
}
authorizedKeysMap[string(pubKey.Marshal())] = true
authorizedKeysBytes = rest
}
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "testuser" && string(pass) == "tiger" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
if authorizedKeysMap[string(pubKey.Marshal())] {
return &ssh.Permissions{
// Record the public key used for authentication.
Extensions: map[string]string{
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
},
}, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
},
}
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
config.AddHostKey(private)
listener, err := net.Listen("tcp", "0.0.0.0:2022")
if err != nil {
log.Fatal("failed to listen for connection: ", err)
}
nConn, err := listener.Accept()
if err != nil {
log.Fatal("failed to accept incoming connection: ", err)
}
conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
log.Fatal("failed to handshake: ", err)
}
log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Fatalf("Could not accept channel: %v", err)
}
go func(in <-chan *ssh.Request) {
for req := range in {
req.Reply(req.Type == "shell", nil)
}
}(requests)
term := terminal.NewTerminal(channel, "> ")
go func() {
defer channel.Close()
for {
line, err := term.ReadLine()
if err != nil {
break
}
fmt.Println(line)
}
}()
}
}
这是最简单的方法,让 letsencrypt 为您处理证书:)
func main() {
r := mux.NewRouter()
r.HandleFunc("/index", index)
certManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("www.example.com"), // replace with your domain
Cache: autocert.DirCache("certs"),
}
srv := &http.Server{
Handler: r,
Addr: ":https",
WriteTimeout: 5 * time.Second,
ReadTimeout: 5 * time.Second,
TLSConfig: &tls.Config{
GetCertificate: certManager.GetCertificate,
},
}
go http.ListenAndServe(":http", certManager.HTTPHandler(nil)) //nolint
log.Fatal(srv.ListenAndServeTLS("", ""))
}
我发现为什么客户端和服务器无法通信,x/crypto库中还没有实现rsa-sha2算法。 github 上有一个问题:https://github.com/golang/go/issues/49952 .
一个临时解决方案是添加
replace golang.org/x/crypto => github.com/rmohr/crypto v0.0.0-20211203105847-e4ed9664ac54
在你的 go.mod 文件的末尾,它使用了来自 @rmohr 的一个 x/crypto 分支,它与 rsa-sha2 一起工作。
我正在尝试使用 x/crypto/ssh
模块在 go 中创建一个 ssh 服务器,但我无法使 public 密钥验证工作。
我尝试了 ssh/example_test.go
文件中的 ExampleNewServerConn()
函数(在 https://go.googlesource.com/crypto 存储库中)但是 public 键方法不起作用,看起来服务器没有做广告正确的算法,因为我在尝试连接 ssh 客户端时得到了这条线:
debug1: send_pubkey_test: no mutual signature algorithm
如果我添加 -o PubkeyAcceptedKeyTypes=+ssh-rsa
public 密钥登录有效,但此 rsa 方法已弃用,我想使用另一种 public 密钥类型,我该怎么做?
提前致谢。
编辑:这是我用来测试的代码
package main
import (
"fmt"
"io/ioutil"
"log"
"net"
"golang.org/x/crypto/ssh"
terminal "golang.org/x/term"
)
func main() {
authorizedKeysBytes, err := ioutil.ReadFile("authorized_keys")
if err != nil {
log.Fatalf("Failed to load authorized_keys, err: %v", err)
}
authorizedKeysMap := map[string]bool{}
for len(authorizedKeysBytes) > 0 {
pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(authorizedKeysBytes)
if err != nil {
log.Fatal(err)
}
authorizedKeysMap[string(pubKey.Marshal())] = true
authorizedKeysBytes = rest
}
config := &ssh.ServerConfig{
PasswordCallback: func(c ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
if c.User() == "testuser" && string(pass) == "tiger" {
return nil, nil
}
return nil, fmt.Errorf("password rejected for %q", c.User())
},
PublicKeyCallback: func(c ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
if authorizedKeysMap[string(pubKey.Marshal())] {
return &ssh.Permissions{
// Record the public key used for authentication.
Extensions: map[string]string{
"pubkey-fp": ssh.FingerprintSHA256(pubKey),
},
}, nil
}
return nil, fmt.Errorf("unknown public key for %q", c.User())
},
}
privateBytes, err := ioutil.ReadFile("id_rsa")
if err != nil {
log.Fatal("Failed to load private key: ", err)
}
private, err := ssh.ParsePrivateKey(privateBytes)
if err != nil {
log.Fatal("Failed to parse private key: ", err)
}
config.AddHostKey(private)
listener, err := net.Listen("tcp", "0.0.0.0:2022")
if err != nil {
log.Fatal("failed to listen for connection: ", err)
}
nConn, err := listener.Accept()
if err != nil {
log.Fatal("failed to accept incoming connection: ", err)
}
conn, chans, reqs, err := ssh.NewServerConn(nConn, config)
if err != nil {
log.Fatal("failed to handshake: ", err)
}
log.Printf("logged in with key %s", conn.Permissions.Extensions["pubkey-fp"])
go ssh.DiscardRequests(reqs)
for newChannel := range chans {
if newChannel.ChannelType() != "session" {
newChannel.Reject(ssh.UnknownChannelType, "unknown channel type")
continue
}
channel, requests, err := newChannel.Accept()
if err != nil {
log.Fatalf("Could not accept channel: %v", err)
}
go func(in <-chan *ssh.Request) {
for req := range in {
req.Reply(req.Type == "shell", nil)
}
}(requests)
term := terminal.NewTerminal(channel, "> ")
go func() {
defer channel.Close()
for {
line, err := term.ReadLine()
if err != nil {
break
}
fmt.Println(line)
}
}()
}
}
这是最简单的方法,让 letsencrypt 为您处理证书:)
func main() {
r := mux.NewRouter()
r.HandleFunc("/index", index)
certManager := autocert.Manager{
Prompt: autocert.AcceptTOS,
HostPolicy: autocert.HostWhitelist("www.example.com"), // replace with your domain
Cache: autocert.DirCache("certs"),
}
srv := &http.Server{
Handler: r,
Addr: ":https",
WriteTimeout: 5 * time.Second,
ReadTimeout: 5 * time.Second,
TLSConfig: &tls.Config{
GetCertificate: certManager.GetCertificate,
},
}
go http.ListenAndServe(":http", certManager.HTTPHandler(nil)) //nolint
log.Fatal(srv.ListenAndServeTLS("", ""))
}
我发现为什么客户端和服务器无法通信,x/crypto库中还没有实现rsa-sha2算法。 github 上有一个问题:https://github.com/golang/go/issues/49952 .
一个临时解决方案是添加
replace golang.org/x/crypto => github.com/rmohr/crypto v0.0.0-20211203105847-e4ed9664ac54
在你的 go.mod 文件的末尾,它使用了来自 @rmohr 的一个 x/crypto 分支,它与 rsa-sha2 一起工作。