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