github.com/glycerine/xcryptossh@v7.0.4+incompatible/certs.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssh
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"net"
    13  	"sort"
    14  	"time"
    15  )
    16  
    17  // These constants from [PROTOCOL.certkeys] represent the algorithm names
    18  // for certificate types supported by this package.
    19  const (
    20  	CertAlgoRSAv01      = "ssh-rsa-cert-v01@openssh.com"
    21  	CertAlgoDSAv01      = "ssh-dss-cert-v01@openssh.com"
    22  	CertAlgoECDSA256v01 = "ecdsa-sha2-nistp256-cert-v01@openssh.com"
    23  	CertAlgoECDSA384v01 = "ecdsa-sha2-nistp384-cert-v01@openssh.com"
    24  	CertAlgoECDSA521v01 = "ecdsa-sha2-nistp521-cert-v01@openssh.com"
    25  	CertAlgoED25519v01  = "ssh-ed25519-cert-v01@openssh.com"
    26  )
    27  
    28  // Certificate types distinguish between host and user
    29  // certificates. The values can be set in the CertType field of
    30  // Certificate.
    31  const (
    32  	UserCert = 1
    33  	HostCert = 2
    34  )
    35  
    36  // Signature represents a cryptographic signature.
    37  type Signature struct {
    38  	Format string
    39  	Blob   []byte
    40  }
    41  
    42  // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
    43  // a certificate does not expire.
    44  const CertTimeInfinity = 1<<64 - 1
    45  
    46  // An Certificate represents an OpenSSH certificate as defined in
    47  // [PROTOCOL.certkeys]?rev=1.8.
    48  type Certificate struct {
    49  	Nonce           []byte
    50  	Key             PublicKey
    51  	Serial          uint64
    52  	CertType        uint32
    53  	KeyId           string
    54  	ValidPrincipals []string
    55  	ValidAfter      uint64
    56  	ValidBefore     uint64
    57  	Permissions
    58  	Reserved     []byte
    59  	SignatureKey PublicKey
    60  	Signature    *Signature
    61  }
    62  
    63  // genericCertData holds the key-independent part of the certificate data.
    64  // Overall, certificates contain an nonce, public key fields and
    65  // key-independent fields.
    66  type genericCertData struct {
    67  	Serial          uint64
    68  	CertType        uint32
    69  	KeyId           string
    70  	ValidPrincipals []byte
    71  	ValidAfter      uint64
    72  	ValidBefore     uint64
    73  	CriticalOptions []byte
    74  	Extensions      []byte
    75  	Reserved        []byte
    76  	SignatureKey    []byte
    77  	Signature       []byte
    78  }
    79  
    80  func marshalStringList(namelist []string) []byte {
    81  	var to []byte
    82  	for _, name := range namelist {
    83  		s := struct{ N string }{name}
    84  		to = append(to, Marshal(&s)...)
    85  	}
    86  	return to
    87  }
    88  
    89  type optionsTuple struct {
    90  	Key   string
    91  	Value []byte
    92  }
    93  
    94  type optionsTupleValue struct {
    95  	Value string
    96  }
    97  
    98  // serialize a map of critical options or extensions
    99  // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
   100  // we need two length prefixes for a non-empty string value
   101  func marshalTuples(tups map[string]string) []byte {
   102  	keys := make([]string, 0, len(tups))
   103  	for key := range tups {
   104  		keys = append(keys, key)
   105  	}
   106  	sort.Strings(keys)
   107  
   108  	var ret []byte
   109  	for _, key := range keys {
   110  		s := optionsTuple{Key: key}
   111  		if value := tups[key]; len(value) > 0 {
   112  			s.Value = Marshal(&optionsTupleValue{value})
   113  		}
   114  		ret = append(ret, Marshal(&s)...)
   115  	}
   116  	return ret
   117  }
   118  
   119  // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
   120  // we need two length prefixes for a non-empty option value
   121  func parseTuples(in []byte) (map[string]string, error) {
   122  	tups := map[string]string{}
   123  	var lastKey string
   124  	var haveLastKey bool
   125  
   126  	for len(in) > 0 {
   127  		var key, val, extra []byte
   128  		var ok bool
   129  
   130  		if key, in, ok = parseString(in); !ok {
   131  			return nil, errShortRead
   132  		}
   133  		keyStr := string(key)
   134  		// according to [PROTOCOL.certkeys], the names must be in
   135  		// lexical order.
   136  		if haveLastKey && keyStr <= lastKey {
   137  			return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
   138  		}
   139  		lastKey, haveLastKey = keyStr, true
   140  		// the next field is a data field, which if non-empty has a string embedded
   141  		if val, in, ok = parseString(in); !ok {
   142  			return nil, errShortRead
   143  		}
   144  		if len(val) > 0 {
   145  			val, extra, ok = parseString(val)
   146  			if !ok {
   147  				return nil, errShortRead
   148  			}
   149  			if len(extra) > 0 {
   150  				return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
   151  			}
   152  			tups[keyStr] = string(val)
   153  		} else {
   154  			tups[keyStr] = ""
   155  		}
   156  	}
   157  	return tups, nil
   158  }
   159  
   160  func parseCert(in []byte, privAlgo string) (*Certificate, error) {
   161  	nonce, rest, ok := parseString(in)
   162  	if !ok {
   163  		return nil, errShortRead
   164  	}
   165  
   166  	key, rest, err := parsePubKey(rest, privAlgo)
   167  	if err != nil {
   168  		return nil, err
   169  	}
   170  
   171  	var g genericCertData
   172  	if err := Unmarshal(rest, &g); err != nil {
   173  		return nil, err
   174  	}
   175  
   176  	c := &Certificate{
   177  		Nonce:       nonce,
   178  		Key:         key,
   179  		Serial:      g.Serial,
   180  		CertType:    g.CertType,
   181  		KeyId:       g.KeyId,
   182  		ValidAfter:  g.ValidAfter,
   183  		ValidBefore: g.ValidBefore,
   184  	}
   185  
   186  	for principals := g.ValidPrincipals; len(principals) > 0; {
   187  		principal, rest, ok := parseString(principals)
   188  		if !ok {
   189  			return nil, errShortRead
   190  		}
   191  		c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
   192  		principals = rest
   193  	}
   194  
   195  	c.CriticalOptions, err = parseTuples(g.CriticalOptions)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  	c.Extensions, err = parseTuples(g.Extensions)
   200  	if err != nil {
   201  		return nil, err
   202  	}
   203  	c.Reserved = g.Reserved
   204  	k, err := ParsePublicKey(g.SignatureKey)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  	c.SignatureKey = k
   210  	c.Signature, rest, ok = parseSignatureBody(g.Signature)
   211  	if !ok || len(rest) > 0 {
   212  		return nil, errors.New("ssh: signature parse error")
   213  	}
   214  
   215  	return c, nil
   216  }
   217  
   218  type openSSHCertSigner struct {
   219  	pub    *Certificate
   220  	signer Signer
   221  }
   222  
   223  // NewCertSigner returns a Signer that signs with the given Certificate, whose
   224  // private key is held by signer. It returns an error if the public key in cert
   225  // doesn't match the key used by signer.
   226  func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) {
   227  	if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 {
   228  		return nil, errors.New("ssh: signer and cert have different public key")
   229  	}
   230  
   231  	return &openSSHCertSigner{cert, signer}, nil
   232  }
   233  
   234  func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
   235  	return s.signer.Sign(rand, data)
   236  }
   237  
   238  func (s *openSSHCertSigner) PublicKey() PublicKey {
   239  	return s.pub
   240  }
   241  
   242  const sourceAddressCriticalOption = "source-address"
   243  
   244  // CertChecker does the work of verifying a certificate. Its methods
   245  // can be plugged into ClientConfig.HostKeyCallback and
   246  // ServerConfig.PublicKeyCallback. For the CertChecker to work,
   247  // minimally, the IsAuthority callback should be set.
   248  type CertChecker struct {
   249  	// SupportedCriticalOptions lists the CriticalOptions that the
   250  	// server application layer understands. These are only used
   251  	// for user certificates.
   252  	SupportedCriticalOptions []string
   253  
   254  	// IsUserAuthority should return true if the key is recognized as an
   255  	// authority for the given user certificate. This allows for
   256  	// certificates to be signed by other certificates. This must be set
   257  	// if this CertChecker will be checking user certificates.
   258  	IsUserAuthority func(auth PublicKey) bool
   259  
   260  	// IsHostAuthority should report whether the key is recognized as
   261  	// an authority for this host. This allows for certificates to be
   262  	// signed by other keys, and for those other keys to only be valid
   263  	// signers for particular hostnames. This must be set if this
   264  	// CertChecker will be checking host certificates.
   265  	IsHostAuthority func(auth PublicKey, address string) bool
   266  
   267  	// Clock is used for verifying time stamps. If nil, time.Now
   268  	// is used.
   269  	Clock func() time.Time
   270  
   271  	// UserKeyFallback is called when CertChecker.Authenticate encounters a
   272  	// public key that is not a certificate. It must implement validation
   273  	// of user keys or else, if nil, all such keys are rejected.
   274  	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
   275  
   276  	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
   277  	// public key that is not a certificate. It must implement host key
   278  	// validation or else, if nil, all such keys are rejected.
   279  	HostKeyFallback HostKeyCallback
   280  
   281  	// IsRevoked is called for each certificate so that revocation checking
   282  	// can be implemented. It should return true if the given certificate
   283  	// is revoked and false otherwise. If nil, no certificates are
   284  	// considered to have been revoked.
   285  	IsRevoked func(cert *Certificate) bool
   286  }
   287  
   288  // CheckHostKey checks a host key certificate. This method can be
   289  // plugged into ClientConfig.HostKeyCallback.
   290  func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
   291  	cert, ok := key.(*Certificate)
   292  	if !ok {
   293  		if c.HostKeyFallback != nil {
   294  			return c.HostKeyFallback(addr, remote, key)
   295  		}
   296  		return errors.New("ssh: non-certificate host key")
   297  	}
   298  	if cert.CertType != HostCert {
   299  		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
   300  	}
   301  	if !c.IsHostAuthority(cert.SignatureKey, addr) {
   302  		return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
   303  	}
   304  
   305  	hostname, _, err := net.SplitHostPort(addr)
   306  	if err != nil {
   307  		return err
   308  	}
   309  
   310  	// Pass hostname only as principal for host certificates (consistent with OpenSSH)
   311  	return c.CheckCert(hostname, cert)
   312  }
   313  
   314  // Authenticate checks a user certificate. Authenticate can be used as
   315  // a value for ServerConfig.PublicKeyCallback.
   316  func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
   317  	cert, ok := pubKey.(*Certificate)
   318  	if !ok {
   319  		if c.UserKeyFallback != nil {
   320  			return c.UserKeyFallback(conn, pubKey)
   321  		}
   322  		return nil, errors.New("ssh: normal key pairs not accepted")
   323  	}
   324  
   325  	if cert.CertType != UserCert {
   326  		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
   327  	}
   328  	if !c.IsUserAuthority(cert.SignatureKey) {
   329  		return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
   330  	}
   331  
   332  	if err := c.CheckCert(conn.User(), cert); err != nil {
   333  		return nil, err
   334  	}
   335  
   336  	return &cert.Permissions, nil
   337  }
   338  
   339  // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
   340  // the signature of the certificate.
   341  func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
   342  	if c.IsRevoked != nil && c.IsRevoked(cert) {
   343  		return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
   344  	}
   345  
   346  	for opt, _ := range cert.CriticalOptions {
   347  		// sourceAddressCriticalOption will be enforced by
   348  		// serverAuthenticate
   349  		if opt == sourceAddressCriticalOption {
   350  			continue
   351  		}
   352  
   353  		found := false
   354  		for _, supp := range c.SupportedCriticalOptions {
   355  			if supp == opt {
   356  				found = true
   357  				break
   358  			}
   359  		}
   360  		if !found {
   361  			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
   362  		}
   363  	}
   364  
   365  	if len(cert.ValidPrincipals) > 0 {
   366  		// By default, certs are valid for all users/hosts.
   367  		found := false
   368  		for _, p := range cert.ValidPrincipals {
   369  			if p == principal {
   370  				found = true
   371  				break
   372  			}
   373  		}
   374  		if !found {
   375  			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
   376  		}
   377  	}
   378  
   379  	clock := c.Clock
   380  	if clock == nil {
   381  		clock = time.Now
   382  	}
   383  
   384  	unixNow := clock().Unix()
   385  	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
   386  		return fmt.Errorf("ssh: cert is not yet valid")
   387  	}
   388  	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
   389  		return fmt.Errorf("ssh: cert has expired")
   390  	}
   391  	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
   392  		return fmt.Errorf("ssh: certificate signature does not verify")
   393  	}
   394  
   395  	return nil
   396  }
   397  
   398  // SignCert sets c.SignatureKey to the authority's public key and stores a
   399  // Signature, by authority, in the certificate.
   400  func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
   401  	c.Nonce = make([]byte, 32)
   402  	if _, err := io.ReadFull(rand, c.Nonce); err != nil {
   403  		return err
   404  	}
   405  	c.SignatureKey = authority.PublicKey()
   406  
   407  	sig, err := authority.Sign(rand, c.bytesForSigning())
   408  	if err != nil {
   409  		return err
   410  	}
   411  	c.Signature = sig
   412  	return nil
   413  }
   414  
   415  var certAlgoNames = map[string]string{
   416  	KeyAlgoRSA:      CertAlgoRSAv01,
   417  	KeyAlgoDSA:      CertAlgoDSAv01,
   418  	KeyAlgoECDSA256: CertAlgoECDSA256v01,
   419  	KeyAlgoECDSA384: CertAlgoECDSA384v01,
   420  	KeyAlgoECDSA521: CertAlgoECDSA521v01,
   421  	KeyAlgoED25519:  CertAlgoED25519v01,
   422  }
   423  
   424  // certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
   425  // Panics if a non-certificate algorithm is passed.
   426  func certToPrivAlgo(algo string) string {
   427  	for privAlgo, pubAlgo := range certAlgoNames {
   428  		if pubAlgo == algo {
   429  			return privAlgo
   430  		}
   431  	}
   432  	panic("unknown cert algorithm")
   433  }
   434  
   435  func (cert *Certificate) bytesForSigning() []byte {
   436  	c2 := *cert
   437  	c2.Signature = nil
   438  	out := c2.Marshal()
   439  	// Drop trailing signature length.
   440  	return out[:len(out)-4]
   441  }
   442  
   443  // Marshal serializes c into OpenSSH's wire format. It is part of the
   444  // PublicKey interface.
   445  func (c *Certificate) Marshal() []byte {
   446  	generic := genericCertData{
   447  		Serial:          c.Serial,
   448  		CertType:        c.CertType,
   449  		KeyId:           c.KeyId,
   450  		ValidPrincipals: marshalStringList(c.ValidPrincipals),
   451  		ValidAfter:      uint64(c.ValidAfter),
   452  		ValidBefore:     uint64(c.ValidBefore),
   453  		CriticalOptions: marshalTuples(c.CriticalOptions),
   454  		Extensions:      marshalTuples(c.Extensions),
   455  		Reserved:        c.Reserved,
   456  		SignatureKey:    c.SignatureKey.Marshal(),
   457  	}
   458  	if c.Signature != nil {
   459  		generic.Signature = Marshal(c.Signature)
   460  	}
   461  	genericBytes := Marshal(&generic)
   462  	keyBytes := c.Key.Marshal()
   463  	_, keyBytes, _ = parseString(keyBytes)
   464  	prefix := Marshal(&struct {
   465  		Name  string
   466  		Nonce []byte
   467  		Key   []byte `ssh:"rest"`
   468  	}{c.Type(), c.Nonce, keyBytes})
   469  
   470  	result := make([]byte, 0, len(prefix)+len(genericBytes))
   471  	result = append(result, prefix...)
   472  	result = append(result, genericBytes...)
   473  	return result
   474  }
   475  
   476  // Type returns the key name. It is part of the PublicKey interface.
   477  func (c *Certificate) Type() string {
   478  	algo, ok := certAlgoNames[c.Key.Type()]
   479  	if !ok {
   480  		panic("unknown cert key type " + c.Key.Type())
   481  	}
   482  	return algo
   483  }
   484  
   485  // Verify verifies a signature against the certificate's public
   486  // key. It is part of the PublicKey interface.
   487  func (c *Certificate) Verify(data []byte, sig *Signature) error {
   488  	return c.Key.Verify(data, sig)
   489  }
   490  
   491  func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
   492  	format, in, ok := parseString(in)
   493  	if !ok {
   494  		return
   495  	}
   496  
   497  	out = &Signature{
   498  		Format: string(format),
   499  	}
   500  
   501  	if out.Blob, in, ok = parseString(in); !ok {
   502  		return
   503  	}
   504  
   505  	return out, in, ok
   506  }
   507  
   508  func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
   509  	sigBytes, rest, ok := parseString(in)
   510  	if !ok {
   511  		return
   512  	}
   513  
   514  	out, trailing, ok := parseSignatureBody(sigBytes)
   515  	if !ok || len(trailing) > 0 {
   516  		return nil, nil, false
   517  	}
   518  	return
   519  }