go-socks5-ssh-proxy/vendor/github.com/xor-gate/sshfp/sshfp.go

149 lines
3.6 KiB
Go

// Copyright 2018 sshfp authors. All rights reserved.
// Use of this source code is governed by the MIT
// license that can be found in the LICENSE file.
package sshfp
import (
"encoding/hex"
"fmt"
"io"
"net/url"
"strings"
"github.com/miekg/dns"
"golang.org/x/crypto/ssh"
)
// ErrHostKeyChanged when the SSH server host key has changed
var ErrHostKeyChanged = fmt.Errorf("sshfp: host key changed")
// ErrNoHostKeyFound when no host key is found in DNS (or cache)
var ErrNoHostKeyFound = fmt.Errorf("sshfp: no host key found")
// ErrNoDNSServer when no DNS servers is available
var ErrNoDNSServer = fmt.Errorf("sshfp: no dns server available")
// ErrInvalidURLScheme when the hostname URL scheme is invalid
var ErrInvalidURLScheme = fmt.Errorf("sshfp: invalid url scheme")
// SSHURLScheme is the URL scheme for SSH hostname urls
const SSHURLScheme = "ssh"
// Algorithm of the host public key
type Algorithm uint8
// golint: nolint
const (
AlgorithmReserved Algorithm = 0
AlgorithmRSA Algorithm = 1
AlgorithmDSS Algorithm = 2
AlgorithmECDSA Algorithm = 3
AlgorithmEd25519 Algorithm = 4
)
// Type of the fingerprint checksum
type Type uint8
// golint: nolint
const (
TypeReserved Type = 0
TypeSHA1 Type = 1
TypeSHA256 Type = 2
)
// String gets the algorithm string as defined in RFC. Reserved or unknown algorithms return "AlgorithmReserved"
func (a Algorithm) String() string {
switch a {
case AlgorithmRSA:
return "RSA"
case AlgorithmDSS:
return "DSS"
case AlgorithmECDSA:
return "ECDSA"
case AlgorithmEd25519:
return "Ed25519"
}
return "AlgorithmReserved"
}
// String gets the fingerprint type string as defined in RFC. Reserved or unknown algorithms return "TypeReserved"
func (fp Type) String() string {
switch fp {
case TypeSHA1:
return "SHA-1"
case TypeSHA256:
return "SHA-256"
}
return "TypeReserved"
}
// ParseZone parses a RFC 1035 zonefile and creates a slice of Entry elements.
// This is compatible with the entries the command `ssh-keygen -r <hostname>` generates.
func ParseZone(r io.Reader) (Entries, error) {
var entries Entries
tokenC := dns.ParseZone(r, "", "")
for token := range tokenC {
if token.Error != nil {
return nil, token.Error
}
r, ok := token.RR.(*dns.SSHFP)
if !ok {
continue
}
fingerprint, err := hex.DecodeString(r.FingerPrint)
if err != nil {
continue
}
e := &Entry{
SSHFP: r,
Hostname: strings.Join(dns.SplitDomainName(r.Hdr.Name), "."),
Fingerprint: fingerprint,
}
entries = append(entries, e)
}
return entries, nil
}
// ParseHostname parses the hostname into a url.URL it automaticlly appends the SSHURLScheme
// when not the hostname is not prefixed with a scheme. The URL scheme must be empty or
// "ssh" else the function returns ErrInvalidURLScheme
func ParseHostname(hostname string) (*url.URL, error) {
// url.Parse needs a scheme so we provide it
if !strings.Contains(hostname, "://") {
hostname = fmt.Sprintf("ssh://%s", hostname)
}
u, err := url.Parse(hostname)
if err != nil {
return nil, err
}
switch u.Scheme {
case SSHURLScheme:
default:
return nil, ErrInvalidURLScheme
}
return u, nil
}
// AlgorithmFromSSHPublicKey calculates the Algorithm based on the ssh.PublicKey.Type() (ssh.KeyAlgo* string)
func AlgorithmFromSSHPublicKey(pubKey ssh.PublicKey) Algorithm {
switch pubKey.Type() {
case ssh.KeyAlgoRSA:
return AlgorithmRSA
case ssh.KeyAlgoDSA:
return AlgorithmDSS
case ssh.KeyAlgoED25519:
return AlgorithmEd25519
case ssh.KeyAlgoECDSA256, ssh.KeyAlgoECDSA384, ssh.KeyAlgoECDSA521:
return AlgorithmECDSA
}
return AlgorithmReserved
}