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.
48type 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.
66type 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
80func 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
89type optionsTuple struct {
90	Key   string
91	Value []byte
92}
93
94type 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
101func 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
121func 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
160func 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
218type 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.
226func 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
234func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
235	return s.signer.Sign(rand, data)
236}
237
238func (s *openSSHCertSigner) PublicKey() PublicKey {
239	return s.pub
240}
241
242const 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.
248type 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	// IsAuthority should return true if the key is recognized as
255	// an authority. This allows for certificates to be signed by other
256	// certificates.
257	IsAuthority func(auth PublicKey) bool
258
259	// Clock is used for verifying time stamps. If nil, time.Now
260	// is used.
261	Clock func() time.Time
262
263	// UserKeyFallback is called when CertChecker.Authenticate encounters a
264	// public key that is not a certificate. It must implement validation
265	// of user keys or else, if nil, all such keys are rejected.
266	UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
267
268	// HostKeyFallback is called when CertChecker.CheckHostKey encounters a
269	// public key that is not a certificate. It must implement host key
270	// validation or else, if nil, all such keys are rejected.
271	HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error
272
273	// IsRevoked is called for each certificate so that revocation checking
274	// can be implemented. It should return true if the given certificate
275	// is revoked and false otherwise. If nil, no certificates are
276	// considered to have been revoked.
277	IsRevoked func(cert *Certificate) bool
278}
279
280// CheckHostKey checks a host key certificate. This method can be
281// plugged into ClientConfig.HostKeyCallback.
282func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
283	cert, ok := key.(*Certificate)
284	if !ok {
285		if c.HostKeyFallback != nil {
286			return c.HostKeyFallback(addr, remote, key)
287		}
288		return errors.New("ssh: non-certificate host key")
289	}
290	if cert.CertType != HostCert {
291		return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
292	}
293
294	return c.CheckCert(addr, cert)
295}
296
297// Authenticate checks a user certificate. Authenticate can be used as
298// a value for ServerConfig.PublicKeyCallback.
299func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
300	cert, ok := pubKey.(*Certificate)
301	if !ok {
302		if c.UserKeyFallback != nil {
303			return c.UserKeyFallback(conn, pubKey)
304		}
305		return nil, errors.New("ssh: normal key pairs not accepted")
306	}
307
308	if cert.CertType != UserCert {
309		return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
310	}
311
312	if err := c.CheckCert(conn.User(), cert); err != nil {
313		return nil, err
314	}
315
316	return &cert.Permissions, nil
317}
318
319// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
320// the signature of the certificate.
321func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
322	if c.IsRevoked != nil && c.IsRevoked(cert) {
323		return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
324	}
325
326	for opt, _ := range cert.CriticalOptions {
327		// sourceAddressCriticalOption will be enforced by
328		// serverAuthenticate
329		if opt == sourceAddressCriticalOption {
330			continue
331		}
332
333		found := false
334		for _, supp := range c.SupportedCriticalOptions {
335			if supp == opt {
336				found = true
337				break
338			}
339		}
340		if !found {
341			return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
342		}
343	}
344
345	if len(cert.ValidPrincipals) > 0 {
346		// By default, certs are valid for all users/hosts.
347		found := false
348		for _, p := range cert.ValidPrincipals {
349			if p == principal {
350				found = true
351				break
352			}
353		}
354		if !found {
355			return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
356		}
357	}
358
359	if !c.IsAuthority(cert.SignatureKey) {
360		return fmt.Errorf("ssh: certificate signed by unrecognized authority")
361	}
362
363	clock := c.Clock
364	if clock == nil {
365		clock = time.Now
366	}
367
368	unixNow := clock().Unix()
369	if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
370		return fmt.Errorf("ssh: cert is not yet valid")
371	}
372	if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
373		return fmt.Errorf("ssh: cert has expired")
374	}
375	if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
376		return fmt.Errorf("ssh: certificate signature does not verify")
377	}
378
379	return nil
380}
381
382// SignCert sets c.SignatureKey to the authority's public key and stores a
383// Signature, by authority, in the certificate.
384func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
385	c.Nonce = make([]byte, 32)
386	if _, err := io.ReadFull(rand, c.Nonce); err != nil {
387		return err
388	}
389	c.SignatureKey = authority.PublicKey()
390
391	sig, err := authority.Sign(rand, c.bytesForSigning())
392	if err != nil {
393		return err
394	}
395	c.Signature = sig
396	return nil
397}
398
399var certAlgoNames = map[string]string{
400	KeyAlgoRSA:      CertAlgoRSAv01,
401	KeyAlgoDSA:      CertAlgoDSAv01,
402	KeyAlgoECDSA256: CertAlgoECDSA256v01,
403	KeyAlgoECDSA384: CertAlgoECDSA384v01,
404	KeyAlgoECDSA521: CertAlgoECDSA521v01,
405	KeyAlgoED25519:  CertAlgoED25519v01,
406}
407
408// certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
409// Panics if a non-certificate algorithm is passed.
410func certToPrivAlgo(algo string) string {
411	for privAlgo, pubAlgo := range certAlgoNames {
412		if pubAlgo == algo {
413			return privAlgo
414		}
415	}
416	panic("unknown cert algorithm")
417}
418
419func (cert *Certificate) bytesForSigning() []byte {
420	c2 := *cert
421	c2.Signature = nil
422	out := c2.Marshal()
423	// Drop trailing signature length.
424	return out[:len(out)-4]
425}
426
427// Marshal serializes c into OpenSSH's wire format. It is part of the
428// PublicKey interface.
429func (c *Certificate) Marshal() []byte {
430	generic := genericCertData{
431		Serial:          c.Serial,
432		CertType:        c.CertType,
433		KeyId:           c.KeyId,
434		ValidPrincipals: marshalStringList(c.ValidPrincipals),
435		ValidAfter:      uint64(c.ValidAfter),
436		ValidBefore:     uint64(c.ValidBefore),
437		CriticalOptions: marshalTuples(c.CriticalOptions),
438		Extensions:      marshalTuples(c.Extensions),
439		Reserved:        c.Reserved,
440		SignatureKey:    c.SignatureKey.Marshal(),
441	}
442	if c.Signature != nil {
443		generic.Signature = Marshal(c.Signature)
444	}
445	genericBytes := Marshal(&generic)
446	keyBytes := c.Key.Marshal()
447	_, keyBytes, _ = parseString(keyBytes)
448	prefix := Marshal(&struct {
449		Name  string
450		Nonce []byte
451		Key   []byte `ssh:"rest"`
452	}{c.Type(), c.Nonce, keyBytes})
453
454	result := make([]byte, 0, len(prefix)+len(genericBytes))
455	result = append(result, prefix...)
456	result = append(result, genericBytes...)
457	return result
458}
459
460// Type returns the key name. It is part of the PublicKey interface.
461func (c *Certificate) Type() string {
462	algo, ok := certAlgoNames[c.Key.Type()]
463	if !ok {
464		panic("unknown cert key type " + c.Key.Type())
465	}
466	return algo
467}
468
469// Verify verifies a signature against the certificate's public
470// key. It is part of the PublicKey interface.
471func (c *Certificate) Verify(data []byte, sig *Signature) error {
472	return c.Key.Verify(data, sig)
473}
474
475func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
476	format, in, ok := parseString(in)
477	if !ok {
478		return
479	}
480
481	out = &Signature{
482		Format: string(format),
483	}
484
485	if out.Blob, in, ok = parseString(in); !ok {
486		return
487	}
488
489	return out, in, ok
490}
491
492func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
493	sigBytes, rest, ok := parseString(in)
494	if !ok {
495		return
496	}
497
498	out, trailing, ok := parseSignatureBody(sigBytes)
499	if !ok || len(trailing) > 0 {
500		return nil, nil, false
501	}
502	return
503}
504