5
0
mirror of https://github.com/cwinfo/matterbridge.git synced 2024-11-23 04:41:36 +00:00
matterbridge/vendor/github.com/shazow/ssh-chat/sshd/auth.go
2020-11-22 15:55:57 +01:00

75 lines
2.5 KiB
Go

package sshd
import (
"crypto/sha256"
"encoding/base64"
"errors"
"net"
"github.com/shazow/ssh-chat/internal/sanitize"
"golang.org/x/crypto/ssh"
)
// Auth is used to authenticate connections based on public keys.
type Auth interface {
// Whether to allow connections without a public key.
AllowAnonymous() bool
// Given address and public key and client agent string, returns nil if the connection should be allowed.
Check(net.Addr, ssh.PublicKey, string) error
}
// MakeAuth makes an ssh.ServerConfig which performs authentication against an Auth implementation.
// TODO: Switch to using ssh.AuthMethod instead?
func MakeAuth(auth Auth) *ssh.ServerConfig {
config := ssh.ServerConfig{
NoClientAuth: false,
// Auth-related things should be constant-time to avoid timing attacks.
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
err := auth.Check(conn.RemoteAddr(), key, sanitize.Data(string(conn.ClientVersion()), 64))
if err != nil {
return nil, err
}
perm := &ssh.Permissions{Extensions: map[string]string{
"pubkey": string(key.Marshal()),
}}
return perm, nil
},
KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
if !auth.AllowAnonymous() {
return nil, errors.New("public key authentication required")
}
err := auth.Check(conn.RemoteAddr(), nil, sanitize.Data(string(conn.ClientVersion()), 64))
return nil, err
},
}
return &config
}
// MakeNoAuth makes a simple ssh.ServerConfig which allows all connections.
// Primarily used for testing.
func MakeNoAuth() *ssh.ServerConfig {
config := ssh.ServerConfig{
NoClientAuth: false,
// Auth-related things should be constant-time to avoid timing attacks.
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) {
perm := &ssh.Permissions{Extensions: map[string]string{
"pubkey": string(key.Marshal()),
}}
return perm, nil
},
KeyboardInteractiveCallback: func(conn ssh.ConnMetadata, challenge ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
return nil, nil
},
}
return &config
}
// Fingerprint performs a SHA256 BASE64 fingerprint of the PublicKey, similar to OpenSSH.
// See: https://anongit.mindrot.org/openssh.git/commit/?id=56d1c83cdd1ac
func Fingerprint(k ssh.PublicKey) string {
hash := sha256.Sum256(k.Marshal())
return "SHA256:" + base64.StdEncoding.EncodeToString(hash[:])
}