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.
48 type Certificate struct {
54 ValidPrincipals []string
59 SignatureKey PublicKey
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.
66 type genericCertData struct {
70 ValidPrincipals []byte
73 CriticalOptions []byte
80 func marshalStringList(namelist []string) []byte {
82 for _, name := range namelist {
83 s := struct{ N string }{name}
84 to = append(to, Marshal(&s)...)
89 type optionsTuple struct {
94 type optionsTupleValue struct {
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
101 func marshalTuples(tups map[string]string) []byte {
102 keys := make([]string, 0, len(tups))
103 for key := range tups {
104 keys = append(keys, key)
109 for _, key := range keys {
110 s := optionsTuple{Key: key}
111 if value := tups[key]; len(value) > 0 {
112 s.Value = Marshal(&optionsTupleValue{value})
114 ret = append(ret, Marshal(&s)...)
119 // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation,
120 // we need two length prefixes for a non-empty option value
121 func parseTuples(in []byte) (map[string]string, error) {
122 tups := map[string]string{}
127 var key, val, extra []byte
130 if key, in, ok = parseString(in); !ok {
131 return nil, errShortRead
133 keyStr := string(key)
134 // according to [PROTOCOL.certkeys], the names must be in
136 if haveLastKey && keyStr <= lastKey {
137 return nil, fmt.Errorf("ssh: certificate options are not in lexical order")
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
145 val, extra, ok = parseString(val)
147 return nil, errShortRead
150 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value")
152 tups[keyStr] = string(val)
160 func parseCert(in []byte, privAlgo string) (*Certificate, error) {
161 nonce, rest, ok := parseString(in)
163 return nil, errShortRead
166 key, rest, err := parsePubKey(rest, privAlgo)
171 var g genericCertData
172 if err := Unmarshal(rest, &g); err != nil {
180 CertType: g.CertType,
182 ValidAfter: g.ValidAfter,
183 ValidBefore: g.ValidBefore,
186 for principals := g.ValidPrincipals; len(principals) > 0; {
187 principal, rest, ok := parseString(principals)
189 return nil, errShortRead
191 c.ValidPrincipals = append(c.ValidPrincipals, string(principal))
195 c.CriticalOptions, err = parseTuples(g.CriticalOptions)
199 c.Extensions, err = parseTuples(g.Extensions)
203 c.Reserved = g.Reserved
204 k, err := ParsePublicKey(g.SignatureKey)
210 c.Signature, rest, ok = parseSignatureBody(g.Signature)
211 if !ok || len(rest) > 0 {
212 return nil, errors.New("ssh: signature parse error")
218 type openSSHCertSigner struct {
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.
226 func 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")
231 return &openSSHCertSigner{cert, signer}, nil
234 func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
235 return s.signer.Sign(rand, data)
238 func (s *openSSHCertSigner) PublicKey() PublicKey {
242 const sourceAddressCriticalOption = "source-address"
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.
248 type 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
254 // IsUserAuthority should return true if the key is recognized as an
255 // authority for the given user certificate. This allows for
256 // certificates to be signed by other certificates. This must be set
257 // if this CertChecker will be checking user certificates.
258 IsUserAuthority func(auth PublicKey) bool
260 // IsHostAuthority should report whether the key is recognized as
261 // an authority for this host. This allows for certificates to be
262 // signed by other keys, and for those other keys to only be valid
263 // signers for particular hostnames. This must be set if this
264 // CertChecker will be checking host certificates.
265 IsHostAuthority func(auth PublicKey, address string) bool
267 // Clock is used for verifying time stamps. If nil, time.Now
269 Clock func() time.Time
271 // UserKeyFallback is called when CertChecker.Authenticate encounters a
272 // public key that is not a certificate. It must implement validation
273 // of user keys or else, if nil, all such keys are rejected.
274 UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error)
276 // HostKeyFallback is called when CertChecker.CheckHostKey encounters a
277 // public key that is not a certificate. It must implement host key
278 // validation or else, if nil, all such keys are rejected.
279 HostKeyFallback HostKeyCallback
281 // IsRevoked is called for each certificate so that revocation checking
282 // can be implemented. It should return true if the given certificate
283 // is revoked and false otherwise. If nil, no certificates are
284 // considered to have been revoked.
285 IsRevoked func(cert *Certificate) bool
288 // CheckHostKey checks a host key certificate. This method can be
289 // plugged into ClientConfig.HostKeyCallback.
290 func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
291 cert, ok := key.(*Certificate)
293 if c.HostKeyFallback != nil {
294 return c.HostKeyFallback(addr, remote, key)
296 return errors.New("ssh: non-certificate host key")
298 if cert.CertType != HostCert {
299 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
301 if !c.IsHostAuthority(cert.SignatureKey, addr) {
302 return fmt.Errorf("ssh: no authorities for hostname: %v", addr)
305 hostname, _, err := net.SplitHostPort(addr)
310 // Pass hostname only as principal for host certificates (consistent with OpenSSH)
311 return c.CheckCert(hostname, cert)
314 // Authenticate checks a user certificate. Authenticate can be used as
315 // a value for ServerConfig.PublicKeyCallback.
316 func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
317 cert, ok := pubKey.(*Certificate)
319 if c.UserKeyFallback != nil {
320 return c.UserKeyFallback(conn, pubKey)
322 return nil, errors.New("ssh: normal key pairs not accepted")
325 if cert.CertType != UserCert {
326 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
328 if !c.IsUserAuthority(cert.SignatureKey) {
329 return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority")
332 if err := c.CheckCert(conn.User(), cert); err != nil {
336 return &cert.Permissions, nil
339 // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
340 // the signature of the certificate.
341 func (c *CertChecker) CheckCert(principal string, cert *Certificate) error {
342 if c.IsRevoked != nil && c.IsRevoked(cert) {
343 return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial)
346 for opt, _ := range cert.CriticalOptions {
347 // sourceAddressCriticalOption will be enforced by
348 // serverAuthenticate
349 if opt == sourceAddressCriticalOption {
354 for _, supp := range c.SupportedCriticalOptions {
361 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
365 if len(cert.ValidPrincipals) > 0 {
366 // By default, certs are valid for all users/hosts.
368 for _, p := range cert.ValidPrincipals {
375 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
384 unixNow := clock().Unix()
385 if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) {
386 return fmt.Errorf("ssh: cert is not yet valid")
388 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
389 return fmt.Errorf("ssh: cert has expired")
391 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
392 return fmt.Errorf("ssh: certificate signature does not verify")
398 // SignCert sets c.SignatureKey to the authority's public key and stores a
399 // Signature, by authority, in the certificate.
400 func (c *Certificate) SignCert(rand io.Reader, authority Signer) error {
401 c.Nonce = make([]byte, 32)
402 if _, err := io.ReadFull(rand, c.Nonce); err != nil {
405 c.SignatureKey = authority.PublicKey()
407 sig, err := authority.Sign(rand, c.bytesForSigning())
415 var certAlgoNames = map[string]string{
416 KeyAlgoRSA: CertAlgoRSAv01,
417 KeyAlgoDSA: CertAlgoDSAv01,
418 KeyAlgoECDSA256: CertAlgoECDSA256v01,
419 KeyAlgoECDSA384: CertAlgoECDSA384v01,
420 KeyAlgoECDSA521: CertAlgoECDSA521v01,
421 KeyAlgoED25519: CertAlgoED25519v01,
424 // certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
425 // Panics if a non-certificate algorithm is passed.
426 func certToPrivAlgo(algo string) string {
427 for privAlgo, pubAlgo := range certAlgoNames {
432 panic("unknown cert algorithm")
435 func (cert *Certificate) bytesForSigning() []byte {
439 // Drop trailing signature length.
440 return out[:len(out)-4]
443 // Marshal serializes c into OpenSSH's wire format. It is part of the
444 // PublicKey interface.
445 func (c *Certificate) Marshal() []byte {
446 generic := genericCertData{
448 CertType: c.CertType,
450 ValidPrincipals: marshalStringList(c.ValidPrincipals),
451 ValidAfter: uint64(c.ValidAfter),
452 ValidBefore: uint64(c.ValidBefore),
453 CriticalOptions: marshalTuples(c.CriticalOptions),
454 Extensions: marshalTuples(c.Extensions),
455 Reserved: c.Reserved,
456 SignatureKey: c.SignatureKey.Marshal(),
458 if c.Signature != nil {
459 generic.Signature = Marshal(c.Signature)
461 genericBytes := Marshal(&generic)
462 keyBytes := c.Key.Marshal()
463 _, keyBytes, _ = parseString(keyBytes)
464 prefix := Marshal(&struct {
467 Key []byte `ssh:"rest"`
468 }{c.Type(), c.Nonce, keyBytes})
470 result := make([]byte, 0, len(prefix)+len(genericBytes))
471 result = append(result, prefix...)
472 result = append(result, genericBytes...)
476 // Type returns the key name. It is part of the PublicKey interface.
477 func (c *Certificate) Type() string {
478 algo, ok := certAlgoNames[c.Key.Type()]
480 panic("unknown cert key type " + c.Key.Type())
485 // Verify verifies a signature against the certificate's public
486 // key. It is part of the PublicKey interface.
487 func (c *Certificate) Verify(data []byte, sig *Signature) error {
488 return c.Key.Verify(data, sig)
491 func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
492 format, in, ok := parseString(in)
498 Format: string(format),
501 if out.Blob, in, ok = parseString(in); !ok {
508 func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
509 sigBytes, rest, ok := parseString(in)
514 out, trailing, ok := parseSignatureBody(sigBytes)
515 if !ok || len(trailing) > 0 {
516 return nil, nil, false