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