Initial working version

This commit is contained in:
2024-07-24 22:57:32 +02:00
commit 44d50d5f7c
789 changed files with 270992 additions and 0 deletions

32
vendor/github.com/xor-gate/sshfp/.gometalinter.conf generated vendored Normal file
View File

@ -0,0 +1,32 @@
{
"Vendor": true,
"LineLength": 120,
"Deadline": "5m",
"Exclude" : [
"examples",
".pb.go"
],
"Enable": [
"maligned",
"deadcode",
"gosec",
"goconst",
"gocyclo",
"gofmt",
"golint",
"ineffassign",
"interfacer",
"lll",
"misspell",
"structcheck",
"unconvert",
"varcheck",
"vet",
"vetshadow"],
"Severity": {
"golint" : "error",
"gotype" : "error",
"vet" : "error",
"vetshadow" : "error"
}
}

36
vendor/github.com/xor-gate/sshfp/.travis.sh generated vendored Normal file
View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -e
GREP_EXCLUDES="vendor\|examples"
LINT_CMD="gometalinter --config .gometalinter.conf"
echo "--- go env"
go env
#echo "--- lint (gometalinter)"
#go get -v -u github.com/alecthomas/gometalinter
#gometalinter --install
#${LINT_CMD} ./...
#echo "--- create build folder ./build"
#mkdir -p build
#echo "--- build and lint examples/*.go"
#for e in $(ls -1 examples/*.go); do
# filename=$(basename $e)
# filename="${filename%.*}"
# echo "* $filename"
# ${LINT_CMD} $e
# go build -o build/$filename $e
#done
echo "--- go test (with race detector and coverage)"
echo "" > coverage.txt
for d in $(go list ./... | grep -v ${GREP_EXCLUDES}); do
go test -race -coverprofile=profile.out -covermode=atomic $d
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done

24
vendor/github.com/xor-gate/sshfp/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,24 @@
sudo: false
notifications:
email:
on_success: change
on_failure: always
env:
- GO111MODULE=on
language: go
go:
- tip
- "1.14"
- "1.13"
- "1.12"
# Latest golang.org/x/sys/unix requires go 1.12
# Prior to go 1.11 will not work because we need go modules
# Prior to go 1.9 will not work due to github.com/miekg/dns dependency
script:
- ./.travis.sh
after_success:
- bash <(curl -s https://codecov.io/bash)

21
vendor/github.com/xor-gate/sshfp/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Jerry Jacobs <jerry.jacobs@xor-gate.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

33
vendor/github.com/xor-gate/sshfp/Makefile generated vendored Normal file
View File

@ -0,0 +1,33 @@
export CGO_ENABLED=0
export GOPATH?=$(shell go env GOPATH)
export DESTDIR?=$(GOPATH)/bin
export GOBIN?=$(DESTDIR)
all: build
ci: env test
install:
go get ./...
env:
go env
echo "---"
dep:
go get -u ./
build:
go build
go install github.com/xor-gate/sshfp/cmd/sshfp
test:
go test -v $(shell go list ./... | grep -v '^vendor\/')
lint:
gometalinter --config .gometalinter.conf
clean:
#rm -Rf $(TMPDIR)/debpkg*
fmt:
gofmt -s -w .

40
vendor/github.com/xor-gate/sshfp/README.md generated vendored Normal file
View File

@ -0,0 +1,40 @@
# SSHFP resolver for Golang
[![License][License-Image]][License-Url]
[![Gopkg][Gopkg-Image]][Gopkg-Url]
[![ReportCard][ReportCard-Image]][ReportCard-Url]
[![Build][Build-Status-Image]][Build-Status-Url]
[![Coverage][Coverage-Image]][Coverage-Url]
**NOTE: Package is functional but not production ready! It requires at least Golang 1.12 with Go modules**
The sshfp project is a Golang implementation of SSH fingerprints stored in SSHFP DNS records which can be used together
with [golang.org/x/crypto/ssh.Client](https://godoc.org/golang.org/x/crypto/ssh#Client) using a custom
[HostKeyCallback](https://godoc.org/github.com/xor-gate/sshfp#Resolver.HostKeyCallback) with modular caching. Learn more about the DNS SSHFP record type on [Wikipedia](https://en.wikipedia.org/wiki/SSHFP_record).
At least go 1.12 is required
This package is based on the awesome Golang DNS package from [github.com/miekg/dns](https://github.com/miekg/dns).
And implements at least the following RFCs:
* https://www.ietf.org/rfc/rfc1035.txt
* https://tools.ietf.org/rfc/rfc6594.txt
* https://www.ietf.org/rfc/rfc4255.txt
* https://tools.ietf.org/html/rfc7479
# LICENSE
[MIT](LICENSE)
[License-Url]: http://opensource.org/licenses/MIT
[License-Image]: https://img.shields.io/npm/l/express.svg
[Stability-Status-Image]: http://badges.github.io/stability-badges/dist/experimental.svg
[Build-Status-Url]: http://travis-ci.org/xor-gate/sshfp
[Build-Status-Image]: https://travis-ci.org/xor-gate/sshfp.svg?branch=develop
[Gopkg-Url]: https://pkg.go.dev/github.com/xor-gate/sshfp?tab=doc
[Gopkg-Image]: https://img.shields.io/badge/gopkg-documentation-blue
[ReportCard-Url]: http://goreportcard.com/report/xor-gate/sshfp
[ReportCard-Image]: https://goreportcard.com/badge/github.com/xor-gate/sshfp
[Coverage-Url]: https://codecov.io/gh/xor-gate/sshfp
[Coverage-image]: https://codecov.io/gh/xor-gate/sshfp/branch/develop/graph/badge.svg

61
vendor/github.com/xor-gate/sshfp/cache.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
// 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
// Cache for DNS SSHFP entries
type Cache interface {
Add(e ...*Entry) error
Get(hostname string, algo ...Algorithm) (Entries, bool)
Remove(e *Entry) error
}
// MemoryCache is a in-memory cache
type MemoryCache struct {
c map[string]Entries
}
// NewMemoryCache creates a new in-memory cache
func NewMemoryCache() (*MemoryCache, error) {
return &MemoryCache{c: make(map[string]Entries)}, nil
}
func (mc *MemoryCache) add(hostname string, e *Entry) {
entries := mc.c[hostname]
if len(entries) == 0 {
entries = Entries{}
mc.c[hostname] = entries
}
mc.c[hostname] = append(mc.c[hostname], e)
}
// Add entry to the cache
func (mc *MemoryCache) Add(e ...*Entry) error {
for _, entry := range e {
mc.add(entry.Hostname, entry)
}
return nil
}
// Get entries from the cache
func (mc *MemoryCache) Get(hostname string, algo ...Algorithm) (Entries, bool) {
entries, ok := mc.c[hostname]
if len(algo) == 1 {
algorithm := uint8(algo[0])
fentries := Entries{}
for _, entry := range entries {
if entry.Algorithm != algorithm {
continue
}
fentries = append(fentries, entry)
}
entries = fentries
}
return entries, ok
}
// Remove entry from the cache
func (mc *MemoryCache) Remove(e *Entry) error {
return nil
}

15
vendor/github.com/xor-gate/sshfp/doc.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// Package sshfp implements a ssh.HostKeyCallback for resolving SSH host key fingerprints using DNS
//
// Overview
//
// The most basic resolver is created as follows (without error checking):
//
// r := sshfp.NewResolver(sshfp.WithDNSClientConfigFromFile("/etc/resolv.conf"))
//
// sshClientConfig := &ssh.ClientConfig{
// HostKeyCallback: r.HostKeyCallback,
// }
//
// c, err := ssh.Dial("tcp", "remote.example.org:22", sshClientConfig)
// ... Check error and do something with the SSHFP validated connected client
package sshfp

64
vendor/github.com/xor-gate/sshfp/entry.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
package sshfp
import (
"bytes"
"crypto/sha256"
"fmt"
"math"
"time"
"github.com/miekg/dns"
"golang.org/x/crypto/ssh"
)
// Entry wraps a DNS SSHFP entry used for caching
type Entry struct {
*dns.SSHFP
ExpiresAt time.Time
Hostname string
Fingerprint []byte
}
// Entries for a single Hostname
type Entries []*Entry
// Validate checks if the SSH public key is valid
func (e *Entry) Validate(pubKey ssh.PublicKey) bool {
if e.Fingerprint == nil {
return false
}
fp := sha256.Sum256(pubKey.Marshal())
return bytes.Equal(e.Fingerprint, fp[:])
}
// TTL calculates the remaining seconds the entry is valid. When ExpiresAt field is zero then it
// never expires and returns math.MaxUint32.
func (e *Entry) TTL() uint32 {
if e.ExpiresAt.IsZero() {
return math.MaxUint32
}
ttl := time.Until(e.ExpiresAt)
if ttl < 1 {
return 0
}
return uint32(ttl / time.Second)
}
// IsExpired checks if the entry is expired
func (e *Entry) IsExpired() bool {
if e.ExpiresAt.IsZero() {
return false
}
return time.Now().After(e.ExpiresAt)
}
// IsValid checks if the entry is valid
func (e *Entry) IsValid() bool {
return true
}
// String creates a human readable presentation of the SSHFP entry
// <hostname> <algorithm string> <fingerprint type string>
func (e *Entry) String() string {
return fmt.Sprintf("%s %s %s", e.Hostname, Algorithm(e.SSHFP.Algorithm), Type(e.SSHFP.Type))
}

196
vendor/github.com/xor-gate/sshfp/resolver.go generated vendored Normal file
View File

@ -0,0 +1,196 @@
// 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 (
"bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
"io"
"net"
"time"
"github.com/miekg/dns"
"golang.org/x/crypto/ssh"
)
// Resolver resolves DNS SSHFP records
type Resolver struct {
c Cache
cc *dns.ClientConfig
}
// ResolverOption for Resolver
type ResolverOption func(*Resolver) error
// NewResolver creates a new DNS SSHFP resolver
func NewResolver(opts ...ResolverOption) (*Resolver, error) {
r := &Resolver{}
for _, option := range opts {
err := option(r)
if err != nil {
return nil, err
}
}
// Check if a cache is attached, or else we attach one
if r.c == nil {
c, err := NewMemoryCache()
if err != nil {
return nil, err
}
r.c = c
}
return r, nil
}
// WithCache sets a Cache for the Resolver
func WithCache(c Cache) ResolverOption {
return func(r *Resolver) error {
r.c = c
return nil
}
}
// WithDNSClientConfigFromFile loads a resolv.conf(5) like file
func WithDNSClientConfigFromFile(resolvconf string) ResolverOption {
return func(r *Resolver) error {
cc, err := dns.ClientConfigFromFile(resolvconf)
if err != nil {
return err
}
r.cc = cc
return nil
}
}
// WithDNSClientConfigFromReader works like WithDNSClientConfigFromFile but takes an io.Reader as argument
func WithDNSClientConfigFromReader(resolvconf io.Reader) ResolverOption {
return func(r *Resolver) error {
cc, err := dns.ClientConfigFromReader(resolvconf)
if err != nil {
return err
}
r.cc = cc
return nil
}
}
// checkCache checks the cache for a valid fingerprint
func (r *Resolver) checkCache(hostname string, key ssh.PublicKey) error {
centries, ok := r.c.Get(hostname, AlgorithmFromSSHPublicKey(key))
if ok {
for _, ce := range centries {
if ce.IsExpired() {
err := r.c.Remove(ce)
if err != nil {
return err
}
continue
}
if ce.Validate(key) {
return nil
}
}
return ErrHostKeyChanged
}
return ErrNoHostKeyFound
}
// HostKeyCallback with DNS SSHFP entry verification for golang.org/x/crypto/ssh
func (r *Resolver) HostKeyCallback(hostname string, remote net.Addr, key ssh.PublicKey) error {
hostURL, err := ParseHostname(hostname)
if err != nil {
return err
}
hostname = hostURL.Hostname()
// lookup cache
err = r.checkCache(hostname, key)
switch err {
case ErrNoHostKeyFound:
break
case nil:
return nil
default:
return err
}
// lookup dns
entries, err := r.LookupHost(hostname)
if err != nil {
return err
}
// SHA256 checksum of key
// TODO should also support other algos
keyFpSHA256 := sha256.Sum256(key.Marshal())
// TODO very naive way to validate, we should match on key type and algo
// and don't brute force check
for _, entry := range entries {
fp, err := hex.DecodeString(entry.FingerPrint)
if err != nil {
continue
}
if !bytes.Equal(fp, keyFpSHA256[:]) {
continue
}
expiresAt := time.Now().Add(time.Duration(entry.Hdr.Ttl) * time.Second)
e := &Entry{
SSHFP: entry,
ExpiresAt: expiresAt,
Hostname: hostname,
Fingerprint: fp,
}
return r.c.Add(e)
}
return ErrNoHostKeyFound
}
// LookupHost looks up the given host for DNS SSHFP records
func (r *Resolver) LookupHost(hostname string) ([]*dns.SSHFP, error) {
if r.cc == nil {
return nil, ErrNoDNSServer
}
if len(r.cc.Servers) == 0 {
return nil, ErrNoDNSServer
}
c := new(dns.Client)
m := new(dns.Msg)
m.SetQuestion(dns.Fqdn(hostname), dns.TypeSSHFP)
m.RecursionDesired = true
// TODO error on no DNS servers
// TODO loop over r.cc.Servers instead of first entry
resp, _, err := c.Exchange(m, net.JoinHostPort(r.cc.Servers[0], r.cc.Port))
if err != nil {
return nil, err
}
if resp.Rcode != dns.RcodeSuccess {
return nil, fmt.Errorf("sshfp: DNS error (Rcode %d)", resp.Rcode)
}
var l []*dns.SSHFP
for _, a := range resp.Answer {
sshfp, ok := a.(*dns.SSHFP)
if !ok {
continue
}
l = append(l, sshfp)
}
return l, nil
}

148
vendor/github.com/xor-gate/sshfp/sshfp.go generated vendored Normal file
View File

@ -0,0 +1,148 @@
// 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
}