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