| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503 | // Copyright 2012 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.package sshimport (	"bytes"	"errors"	"fmt"	"io"	"net"	"sort"	"time")// These constants from [PROTOCOL.certkeys] represent the algorithm names// for certificate types supported by this package.const (	CertAlgoRSAv01      = "ssh-rsa-cert-v01@openssh.com"	CertAlgoDSAv01      = "ssh-dss-cert-v01@openssh.com"	CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"	CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"	CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"	CertAlgoED25519v01  = "ssh-ed25519-cert-v01@openssh.com")// Certificate types distinguish between host and user// certificates. The values can be set in the CertType field of// Certificate.const (	UserCert = 1	HostCert = 2)// Signature represents a cryptographic signature.type Signature struct {	Format string	Blob   []byte}// CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that// a certificate does not expire.const CertTimeInfinity = 1<<64 - 1// An Certificate represents an OpenSSH certificate as defined in// [PROTOCOL.certkeys]?rev=1.8.type Certificate struct {	Nonce           []byte	Key             PublicKey	Serial          uint64	CertType        uint32	KeyId           string	ValidPrincipals []string	ValidAfter      uint64	ValidBefore     uint64	Permissions	Reserved     []byte	SignatureKey PublicKey	Signature    *Signature}// genericCertData holds the key-independent part of the certificate data.// Overall, certificates contain an nonce, public key fields and// key-independent fields.type genericCertData struct {	Serial          uint64	CertType        uint32	KeyId           string	ValidPrincipals []byte	ValidAfter      uint64	ValidBefore     uint64	CriticalOptions []byte	Extensions      []byte	Reserved        []byte	SignatureKey    []byte	Signature       []byte}func marshalStringList(namelist []string) []byte {	var to []byte	for _, name := range namelist {		s := struct{ N string }{name}		to = append(to, Marshal(&s)...)	}	return to}type optionsTuple struct {	Key   string	Value []byte}type optionsTupleValue struct {	Value string}// serialize a map of critical options or extensions// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,// we need two length prefixes for a non-empty string valuefunc marshalTuples(tups map[string]string) []byte {	keys := make([]string, 0, len(tups))	for key := range tups {		keys = append(keys, key)	}	sort.Strings(keys)	var ret []byte	for _, key := range keys {		s := optionsTuple{Key: key}		if value := tups[key]; len(value) > 0 {			s.Value = Marshal(&optionsTupleValue{value})		}		ret = append(ret, Marshal(&s)...)	}	return ret}// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,// we need two length prefixes for a non-empty option valuefunc parseTuples(in []byte) (map[string]string, error) {	tups := map[string]string{}	var lastKey string	var haveLastKey bool	for len(in) > 0 {		var key, val, extra []byte		var ok bool		if key, in, ok = parseString(in); !ok {			return nil, errShortRead		}		keyStr := string(key)		// according to [PROTOCOL.certkeys], the names must be in		// lexical order.		if haveLastKey && keyStr <= lastKey {			return nil, fmt.Errorf("ssh: certificate options are not in lexical order")		}		lastKey, haveLastKey = keyStr, true		// the next field is a data field, which if non-empty has a string embedded		if val, in, ok = parseString(in); !ok {			return nil, errShortRead		}		if len(val) > 0 {			val, extra, ok = parseString(val)			if !ok {				return nil, errShortRead			}			if len(extra) > 0 {				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")			}			tups[keyStr] = string(val)		} else {			tups[keyStr] = ""		}	}	return tups, nil}func parseCert(in []byte, privAlgo string) (*Certificate, error) {	nonce, rest, ok := parseString(in)	if !ok {		return nil, errShortRead	}	key, rest, err := parsePubKey(rest, privAlgo)	if err != nil {		return nil, err	}	var g genericCertData	if err := Unmarshal(rest, &g); err != nil {		return nil, err	}	c := &Certificate{		Nonce:       nonce,		Key:         key,		Serial:      g.Serial,		CertType:    g.CertType,		KeyId:       g.KeyId,		ValidAfter:  g.ValidAfter,		ValidBefore: g.ValidBefore,	}	for principals := g.ValidPrincipals; len(principals) > 0; {		principal, rest, ok := parseString(principals)		if !ok {			return nil, errShortRead		}		c.ValidPrincipals = append(c.ValidPrincipals, string(principal))		principals = rest	}	c.CriticalOptions, err = parseTuples(g.CriticalOptions)	if err != nil {		return nil, err	}	c.Extensions, err = parseTuples(g.Extensions)	if err != nil {		return nil, err	}	c.Reserved = g.Reserved	k, err := ParsePublicKey(g.SignatureKey)	if err != nil {		return nil, err	}	c.SignatureKey = k	c.Signature, rest, ok = parseSignatureBody(g.Signature)	if !ok || len(rest) > 0 {		return nil, errors.New("ssh: signature parse error")	}	return c, nil}type openSSHCertSigner struct {	pub    *Certificate	signer Signer}// NewCertSigner returns a Signer that signs with the given Certificate, whose// private key is held by signer. It returns an error if the public key in cert// doesn't match the key used by signer.func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {		return nil, errors.New("ssh: signer and cert have different public key")	}	return &openSSHCertSigner{cert, signer}, nil}func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {	return s.signer.Sign(rand, data)}func (s *openSSHCertSigner) PublicKey() PublicKey {	return s.pub}const sourceAddressCriticalOption = "source-address"// CertChecker does the work of verifying a certificate. Its methods// can be plugged into ClientConfig.HostKeyCallback and// ServerConfig.PublicKeyCallback. For the CertChecker to work,// minimally, the IsAuthority callback should be set.type CertChecker struct {	// SupportedCriticalOptions lists the CriticalOptions that the	// server application layer understands. These are only used	// for user certificates.	SupportedCriticalOptions []string	// IsAuthority should return true if the key is recognized as	// an authority. This allows for certificates to be signed by other	// certificates.	IsAuthority func(auth PublicKey) bool	// Clock is used for verifying time stamps. If nil, time.Now	// is used.	Clock func() time.Time	// UserKeyFallback is called when CertChecker.Authenticate encounters a	// public key that is not a certificate. It must implement validation	// of user keys or else, if nil, all such keys are rejected.	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a	// public key that is not a certificate. It must implement host key	// validation or else, if nil, all such keys are rejected.	HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error	// IsRevoked is called for each certificate so that revocation checking	// can be implemented. It should return true if the given certificate	// is revoked and false otherwise. If nil, no certificates are	// considered to have been revoked.	IsRevoked func(cert *Certificate) bool}// CheckHostKey checks a host key certificate. This method can be// plugged into ClientConfig.HostKeyCallback.func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {	cert, ok := key.(*Certificate)	if !ok {		if c.HostKeyFallback != nil {			return c.HostKeyFallback(addr, remote, key)		}		return errors.New("ssh: non-certificate host key")	}	if cert.CertType != HostCert {		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)	}	return c.CheckCert(addr, cert)}// Authenticate checks a user certificate. Authenticate can be used as// a value for ServerConfig.PublicKeyCallback.func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {	cert, ok := pubKey.(*Certificate)	if !ok {		if c.UserKeyFallback != nil {			return c.UserKeyFallback(conn, pubKey)		}		return nil, errors.New("ssh: normal key pairs not accepted")	}	if cert.CertType != UserCert {		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)	}	if err := c.CheckCert(conn.User(), cert); err != nil {		return nil, err	}	return &cert.Permissions, nil}// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and// the signature of the certificate.func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {	if c.IsRevoked != nil && c.IsRevoked(cert) {		return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)	}	for opt, _ := range cert.CriticalOptions {		// sourceAddressCriticalOption will be enforced by		// serverAuthenticate		if opt == sourceAddressCriticalOption {			continue		}		found := false		for _, supp := range c.SupportedCriticalOptions {			if supp == opt {				found = true				break			}		}		if !found {			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)		}	}	if len(cert.ValidPrincipals) > 0 {		// By default, certs are valid for all users/hosts.		found := false		for _, p := range cert.ValidPrincipals {			if p == principal {				found = true				break			}		}		if !found {			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)		}	}	if !c.IsAuthority(cert.SignatureKey) {		return fmt.Errorf("ssh: certificate signed by unrecognized authority")	}	clock := c.Clock	if clock == nil {		clock = time.Now	}	unixNow := clock().Unix()	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {		return fmt.Errorf("ssh: cert is not yet valid")	}	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {		return fmt.Errorf("ssh: cert has expired")	}	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {		return fmt.Errorf("ssh: certificate signature does not verify")	}	return nil}// SignCert sets c.SignatureKey to the authority's public key and stores a// Signature, by authority, in the certificate.func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {	c.Nonce = make([]byte, 32)	if _, err := io.ReadFull(rand, c.Nonce); err != nil {		return err	}	c.SignatureKey = authority.PublicKey()	sig, err := authority.Sign(rand, c.bytesForSigning())	if err != nil {		return err	}	c.Signature = sig	return nil}var certAlgoNames = map[string]string{	KeyAlgoRSA:      CertAlgoRSAv01,	KeyAlgoDSA:      CertAlgoDSAv01,	KeyAlgoECDSA256: CertAlgoECDSA256v01,	KeyAlgoECDSA384: CertAlgoECDSA384v01,	KeyAlgoECDSA521: CertAlgoECDSA521v01,	KeyAlgoED25519:  CertAlgoED25519v01,}// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.// Panics if a non-certificate algorithm is passed.func certToPrivAlgo(algo string) string {	for privAlgo, pubAlgo := range certAlgoNames {		if pubAlgo == algo {			return privAlgo		}	}	panic("unknown cert algorithm")}func (cert *Certificate) bytesForSigning() []byte {	c2 := *cert	c2.Signature = nil	out := c2.Marshal()	// Drop trailing signature length.	return out[:len(out)-4]}// Marshal serializes c into OpenSSH's wire format. It is part of the// PublicKey interface.func (c *Certificate) Marshal() []byte {	generic := genericCertData{		Serial:          c.Serial,		CertType:        c.CertType,		KeyId:           c.KeyId,		ValidPrincipals: marshalStringList(c.ValidPrincipals),		ValidAfter:      uint64(c.ValidAfter),		ValidBefore:     uint64(c.ValidBefore),		CriticalOptions: marshalTuples(c.CriticalOptions),		Extensions:      marshalTuples(c.Extensions),		Reserved:        c.Reserved,		SignatureKey:    c.SignatureKey.Marshal(),	}	if c.Signature != nil {		generic.Signature = Marshal(c.Signature)	}	genericBytes := Marshal(&generic)	keyBytes := c.Key.Marshal()	_, keyBytes, _ = parseString(keyBytes)	prefix := Marshal(&struct {		Name  string		Nonce []byte		Key   []byte `ssh:"rest"`	}{c.Type(), c.Nonce, keyBytes})	result := make([]byte, 0, len(prefix)+len(genericBytes))	result = append(result, prefix...)	result = append(result, genericBytes...)	return result}// Type returns the key name. It is part of the PublicKey interface.func (c *Certificate) Type() string {	algo, ok := certAlgoNames[c.Key.Type()]	if !ok {		panic("unknown cert key type " + c.Key.Type())	}	return algo}// Verify verifies a signature against the certificate's public// key. It is part of the PublicKey interface.func (c *Certificate) Verify(data []byte, sig *Signature) error {	return c.Key.Verify(data, sig)}func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {	format, in, ok := parseString(in)	if !ok {		return	}	out = &Signature{		Format: string(format),	}	if out.Blob, in, ok = parseString(in); !ok {		return	}	return out, in, ok}func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {	sigBytes, rest, ok := parseString(in)	if !ok {		return	}	out, trailing, ok := parseSignatureBody(sigBytes)	if !ok || len(trailing) > 0 {		return nil, nil, false	}	return}
 |