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.
17 // These constants from [PROTOCOL.certkeys] represent the algorithm names
18 // for certificate types supported by this package.
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"
28 // Certificate types distinguish between host and user
29 // certificates. The values can be set in the CertType field of
36 // Signature represents a cryptographic signature.
37 type Signature struct {
42 // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that
43 // a certificate does not expire.
44 const CertTimeInfinity = 1<<64 - 1
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
50 type Certificate struct {
56 ValidPrincipals []string
61 SignatureKey PublicKey
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.
68 type genericCertData struct {
72 ValidPrincipals []byte
75 CriticalOptions []byte
82 func marshalStringList(namelist []string) []byte {
84 for _, name := range namelist {
85 s := struct{ N string }{name}
86 to = append(to, Marshal(&s)...)
91 type optionsTuple struct {
96 type optionsTupleValue struct {
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
103 func marshalTuples(tups map[string]string) []byte {
104 keys := make([]string, 0, len(tups))
105 for key := range tups {
106 keys = append(keys, key)
111 for _, key := range keys {
112 s := optionsTuple{Key: key}
113 if value := tups[key]; len(value) > 0 {
114 s.Value = Marshal(&optionsTupleValue{value})
116 ret = append(ret, Marshal(&s)...)
121 // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
122 // we need two length prefixes for a non-empty option value
123 func parseTuples(in []byte) (map[string]string, error) {
124 tups := map[string]string{}
129 var key, val, extra []byte
132 if key, in, ok = parseString(in); !ok {
133 return nil, errShortRead
135 keyStr := string(key)
136 // according to [PROTOCOL.certkeys], the names must be in
138 if haveLastKey && keyStr <= lastKey {
139 return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
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
147 val, extra, ok = parseString(val)
149 return nil, errShortRead
152 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
154 tups[keyStr] = string(val)
162 func parseCert(in []byte, privAlgo string) (*Certificate, error) {
163 nonce, rest, ok := parseString(in)
165 return nil, errShortRead
168 key, rest, err := parsePubKey(rest, privAlgo)
173 var g genericCertData
174 if err := Unmarshal(rest, &g); err != nil {
182 CertType: g.CertType,
184 ValidAfter: g.ValidAfter,
185 ValidBefore: g.ValidBefore,
188 for principals := g.ValidPrincipals; len(principals) > 0; {
189 principal, rest, ok := parseString(principals)
191 return nil, errShortRead
193 c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
197 c.CriticalOptions, err = parseTuples(g.CriticalOptions)
201 c.Extensions, err = parseTuples(g.Extensions)
205 c.Reserved = g.Reserved
206 k, err := ParsePublicKey(g.SignatureKey)
212 c.Signature, rest, ok = parseSignatureBody(g.Signature)
213 if !ok || len(rest) > 0 {
214 return nil, errors.New("ssh: signature parse error")
220 type openSSHCertSigner struct {
225 type algorithmOpenSSHCertSigner struct {
227 algorithmSigner AlgorithmSigner
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.
233 func 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")
238 if algorithmSigner, ok := signer.(AlgorithmSigner); ok {
239 return &algorithmOpenSSHCertSigner{
240 &openSSHCertSigner{cert, signer}, algorithmSigner}, nil
242 return &openSSHCertSigner{cert, signer}, nil
246 func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
247 return s.signer.Sign(rand, data)
250 func (s *openSSHCertSigner) PublicKey() PublicKey {
254 func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
255 return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm)
258 const sourceAddressCriticalOption = "source-address"
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.
264 type 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
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
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
283 // Clock is used for verifying time stamps. If nil, time.Now
285 Clock func() time.Time
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)
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
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
304 // CheckHostKey checks a host key certificate. This method can be
305 // plugged into ClientConfig.HostKeyCallback.
306 func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
307 cert, ok := key.(*Certificate)
309 if c.HostKeyFallback != nil {
310 return c.HostKeyFallback(addr, remote, key)
312 return errors.New("ssh: non-certificate host key")
314 if cert.CertType != HostCert {
315 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
317 if !c.IsHostAuthority(cert.SignatureKey, addr) {
318 return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
321 hostname, _, err := net.SplitHostPort(addr)
326 // Pass hostname only as principal for host certificates (consistent with OpenSSH)
327 return c.CheckCert(hostname, cert)
330 // Authenticate checks a user certificate. Authenticate can be used as
331 // a value for ServerConfig.PublicKeyCallback.
332 func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
333 cert, ok := pubKey.(*Certificate)
335 if c.UserKeyFallback != nil {
336 return c.UserKeyFallback(conn, pubKey)
338 return nil, errors.New("ssh: normal key pairs not accepted")
341 if cert.CertType != UserCert {
342 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
344 if !c.IsUserAuthority(cert.SignatureKey) {
345 return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
348 if err := c.CheckCert(conn.User(), cert); err != nil {
352 return &cert.Permissions, nil
355 // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
356 // the signature of the certificate.
357 func (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)
362 for opt := range cert.CriticalOptions {
363 // sourceAddressCriticalOption will be enforced by
364 // serverAuthenticate
365 if opt == sourceAddressCriticalOption {
370 for _, supp := range c.SupportedCriticalOptions {
377 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
381 if len(cert.ValidPrincipals) > 0 {
382 // By default, certs are valid for all users/hosts.
384 for _, p := range cert.ValidPrincipals {
391 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
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")
404 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
405 return fmt.Errorf("ssh: cert has expired")
407 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
408 return fmt.Errorf("ssh: certificate signature does not verify")
414 // SignCert sets c.SignatureKey to the authority's public key and stores a
415 // Signature, by authority, in the certificate.
416 func (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 {
421 c.SignatureKey = authority.PublicKey()
423 sig, err := authority.Sign(rand, c.bytesForSigning())
431 var certAlgoNames = map[string]string{
432 KeyAlgoRSA: CertAlgoRSAv01,
433 KeyAlgoDSA: CertAlgoDSAv01,
434 KeyAlgoECDSA256: CertAlgoECDSA256v01,
435 KeyAlgoECDSA384: CertAlgoECDSA384v01,
436 KeyAlgoECDSA521: CertAlgoECDSA521v01,
437 KeyAlgoED25519: CertAlgoED25519v01,
440 // certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
441 // Panics if a non-certificate algorithm is passed.
442 func certToPrivAlgo(algo string) string {
443 for privAlgo, pubAlgo := range certAlgoNames {
448 panic("unknown cert algorithm")
451 func (cert *Certificate) bytesForSigning() []byte {
455 // Drop trailing signature length.
456 return out[:len(out)-4]
459 // Marshal serializes c into OpenSSH's wire format. It is part of the
460 // PublicKey interface.
461 func (c *Certificate) Marshal() []byte {
462 generic := genericCertData{
464 CertType: c.CertType,
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(),
474 if c.Signature != nil {
475 generic.Signature = Marshal(c.Signature)
477 genericBytes := Marshal(&generic)
478 keyBytes := c.Key.Marshal()
479 _, keyBytes, _ = parseString(keyBytes)
480 prefix := Marshal(&struct {
483 Key []byte `ssh:"rest"`
484 }{c.Type(), c.Nonce, keyBytes})
486 result := make([]byte, 0, len(prefix)+len(genericBytes))
487 result = append(result, prefix...)
488 result = append(result, genericBytes...)
492 // Type returns the key name. It is part of the PublicKey interface.
493 func (c *Certificate) Type() string {
494 algo, ok := certAlgoNames[c.Key.Type()]
496 panic("unknown cert key type " + c.Key.Type())
501 // Verify verifies a signature against the certificate's public
502 // key. It is part of the PublicKey interface.
503 func (c *Certificate) Verify(data []byte, sig *Signature) error {
504 return c.Key.Verify(data, sig)
507 func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
508 format, in, ok := parseString(in)
514 Format: string(format),
517 if out.Blob, in, ok = parseString(in); !ok {
524 func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
525 sigBytes, rest, ok := parseString(in)
530 out, trailing, ok := parseSignatureBody(sigBytes)
531 if !ok || len(trailing) > 0 {
532 return nil, nil, false