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 // IsAuthority should return true if the key is recognized as
255 // an authority. This allows for certificates to be signed by other
257 IsAuthority func(auth PublicKey) bool
259 // Clock is used for verifying time stamps. If nil, time.Now
261 Clock func() time.Time
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)
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
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
280 // CheckHostKey checks a host key certificate. This method can be
281 // plugged into ClientConfig.HostKeyCallback.
282 func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error {
283 cert, ok := key.(*Certificate)
285 if c.HostKeyFallback != nil {
286 return c.HostKeyFallback(addr, remote, key)
288 return errors.New("ssh: non-certificate host key")
290 if cert.CertType != HostCert {
291 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType)
294 return c.CheckCert(addr, cert)
297 // Authenticate checks a user certificate. Authenticate can be used as
298 // a value for ServerConfig.PublicKeyCallback.
299 func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) {
300 cert, ok := pubKey.(*Certificate)
302 if c.UserKeyFallback != nil {
303 return c.UserKeyFallback(conn, pubKey)
305 return nil, errors.New("ssh: normal key pairs not accepted")
308 if cert.CertType != UserCert {
309 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType)
312 if err := c.CheckCert(conn.User(), cert); err != nil {
316 return &cert.Permissions, nil
319 // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and
320 // the signature of the certificate.
321 func (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)
326 for opt, _ := range cert.CriticalOptions {
327 // sourceAddressCriticalOption will be enforced by
328 // serverAuthenticate
329 if opt == sourceAddressCriticalOption {
334 for _, supp := range c.SupportedCriticalOptions {
341 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt)
345 if len(cert.ValidPrincipals) > 0 {
346 // By default, certs are valid for all users/hosts.
348 for _, p := range cert.ValidPrincipals {
355 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals)
359 if !c.IsAuthority(cert.SignatureKey) {
360 return fmt.Errorf("ssh: certificate signed by unrecognized authority")
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")
372 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) {
373 return fmt.Errorf("ssh: cert has expired")
375 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil {
376 return fmt.Errorf("ssh: certificate signature does not verify")
382 // SignCert sets c.SignatureKey to the authority's public key and stores a
383 // Signature, by authority, in the certificate.
384 func (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 {
389 c.SignatureKey = authority.PublicKey()
391 sig, err := authority.Sign(rand, c.bytesForSigning())
399 var certAlgoNames = map[string]string{
400 KeyAlgoRSA: CertAlgoRSAv01,
401 KeyAlgoDSA: CertAlgoDSAv01,
402 KeyAlgoECDSA256: CertAlgoECDSA256v01,
403 KeyAlgoECDSA384: CertAlgoECDSA384v01,
404 KeyAlgoECDSA521: CertAlgoECDSA521v01,
405 KeyAlgoED25519: CertAlgoED25519v01,
408 // certToPrivAlgo returns the underlying algorithm for a certificate algorithm.
409 // Panics if a non-certificate algorithm is passed.
410 func certToPrivAlgo(algo string) string {
411 for privAlgo, pubAlgo := range certAlgoNames {
416 panic("unknown cert algorithm")
419 func (cert *Certificate) bytesForSigning() []byte {
423 // Drop trailing signature length.
424 return out[:len(out)-4]
427 // Marshal serializes c into OpenSSH's wire format. It is part of the
428 // PublicKey interface.
429 func (c *Certificate) Marshal() []byte {
430 generic := genericCertData{
432 CertType: c.CertType,
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(),
442 if c.Signature != nil {
443 generic.Signature = Marshal(c.Signature)
445 genericBytes := Marshal(&generic)
446 keyBytes := c.Key.Marshal()
447 _, keyBytes, _ = parseString(keyBytes)
448 prefix := Marshal(&struct {
451 Key []byte `ssh:"rest"`
452 }{c.Type(), c.Nonce, keyBytes})
454 result := make([]byte, 0, len(prefix)+len(genericBytes))
455 result = append(result, prefix...)
456 result = append(result, genericBytes...)
460 // Type returns the key name. It is part of the PublicKey interface.
461 func (c *Certificate) Type() string {
462 algo, ok := certAlgoNames[c.Key.Type()]
464 panic("unknown cert key type " + c.Key.Type())
469 // Verify verifies a signature against the certificate's public
470 // key. It is part of the PublicKey interface.
471 func (c *Certificate) Verify(data []byte, sig *Signature) error {
472 return c.Key.Verify(data, sig)
475 func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) {
476 format, in, ok := parseString(in)
482 Format: string(format),
485 if out.Blob, in, ok = parseString(in); !ok {
492 func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) {
493 sigBytes, rest, ok := parseString(in)
498 out, trailing, ok := parseSignatureBody(sigBytes)
499 if !ok || len(trailing) > 0 {
500 return nil, nil, false