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. The Certificate type implements the 48// PublicKey interface, so it can be unmarshaled using 49// ParsePublicKey. 50type Certificate struct { 51 Nonce []byte 52 Key PublicKey 53 Serial uint64 54 CertType uint32 55 KeyId string 56 ValidPrincipals []string 57 ValidAfter uint64 58 ValidBefore uint64 59 Permissions 60 Reserved []byte 61 SignatureKey PublicKey 62 Signature *Signature 63} 64 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. 68type genericCertData struct { 69 Serial uint64 70 CertType uint32 71 KeyId string 72 ValidPrincipals []byte 73 ValidAfter uint64 74 ValidBefore uint64 75 CriticalOptions []byte 76 Extensions []byte 77 Reserved []byte 78 SignatureKey []byte 79 Signature []byte 80} 81 82func marshalStringList(namelist []string) []byte { 83 var to []byte 84 for _, name := range namelist { 85 s := struct{ N string }{name} 86 to = append(to, Marshal(&s)...) 87 } 88 return to 89} 90 91type optionsTuple struct { 92 Key string 93 Value []byte 94} 95 96type optionsTupleValue struct { 97 Value string 98} 99 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 103func marshalTuples(tups map[string]string) []byte { 104 keys := make([]string, 0, len(tups)) 105 for key := range tups { 106 keys = append(keys, key) 107 } 108 sort.Strings(keys) 109 110 var ret []byte 111 for _, key := range keys { 112 s := optionsTuple{Key: key} 113 if value := tups[key]; len(value) > 0 { 114 s.Value = Marshal(&optionsTupleValue{value}) 115 } 116 ret = append(ret, Marshal(&s)...) 117 } 118 return ret 119} 120 121// issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, 122// we need two length prefixes for a non-empty option value 123func parseTuples(in []byte) (map[string]string, error) { 124 tups := map[string]string{} 125 var lastKey string 126 var haveLastKey bool 127 128 for len(in) > 0 { 129 var key, val, extra []byte 130 var ok bool 131 132 if key, in, ok = parseString(in); !ok { 133 return nil, errShortRead 134 } 135 keyStr := string(key) 136 // according to [PROTOCOL.certkeys], the names must be in 137 // lexical order. 138 if haveLastKey && keyStr <= lastKey { 139 return nil, fmt.Errorf("ssh: certificate options are not in lexical order") 140 } 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 145 } 146 if len(val) > 0 { 147 val, extra, ok = parseString(val) 148 if !ok { 149 return nil, errShortRead 150 } 151 if len(extra) > 0 { 152 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") 153 } 154 tups[keyStr] = string(val) 155 } else { 156 tups[keyStr] = "" 157 } 158 } 159 return tups, nil 160} 161 162func parseCert(in []byte, privAlgo string) (*Certificate, error) { 163 nonce, rest, ok := parseString(in) 164 if !ok { 165 return nil, errShortRead 166 } 167 168 key, rest, err := parsePubKey(rest, privAlgo) 169 if err != nil { 170 return nil, err 171 } 172 173 var g genericCertData 174 if err := Unmarshal(rest, &g); err != nil { 175 return nil, err 176 } 177 178 c := &Certificate{ 179 Nonce: nonce, 180 Key: key, 181 Serial: g.Serial, 182 CertType: g.CertType, 183 KeyId: g.KeyId, 184 ValidAfter: g.ValidAfter, 185 ValidBefore: g.ValidBefore, 186 } 187 188 for principals := g.ValidPrincipals; len(principals) > 0; { 189 principal, rest, ok := parseString(principals) 190 if !ok { 191 return nil, errShortRead 192 } 193 c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) 194 principals = rest 195 } 196 197 c.CriticalOptions, err = parseTuples(g.CriticalOptions) 198 if err != nil { 199 return nil, err 200 } 201 c.Extensions, err = parseTuples(g.Extensions) 202 if err != nil { 203 return nil, err 204 } 205 c.Reserved = g.Reserved 206 k, err := ParsePublicKey(g.SignatureKey) 207 if err != nil { 208 return nil, err 209 } 210 211 c.SignatureKey = k 212 c.Signature, rest, ok = parseSignatureBody(g.Signature) 213 if !ok || len(rest) > 0 { 214 return nil, errors.New("ssh: signature parse error") 215 } 216 217 return c, nil 218} 219 220type openSSHCertSigner struct { 221 pub *Certificate 222 signer Signer 223} 224 225type algorithmOpenSSHCertSigner struct { 226 *openSSHCertSigner 227 algorithmSigner AlgorithmSigner 228} 229 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. 233func 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") 236 } 237 238 if algorithmSigner, ok := signer.(AlgorithmSigner); ok { 239 return &algorithmOpenSSHCertSigner{ 240 &openSSHCertSigner{cert, signer}, algorithmSigner}, nil 241 } else { 242 return &openSSHCertSigner{cert, signer}, nil 243 } 244} 245 246func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 247 return s.signer.Sign(rand, data) 248} 249 250func (s *openSSHCertSigner) PublicKey() PublicKey { 251 return s.pub 252} 253 254func (s *algorithmOpenSSHCertSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { 255 return s.algorithmSigner.SignWithAlgorithm(rand, data, algorithm) 256} 257 258const sourceAddressCriticalOption = "source-address" 259 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. 264type 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 269 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 275 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 282 283 // Clock is used for verifying time stamps. If nil, time.Now 284 // is used. 285 Clock func() time.Time 286 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) 291 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 296 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 302} 303 304// CheckHostKey checks a host key certificate. This method can be 305// plugged into ClientConfig.HostKeyCallback. 306func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { 307 cert, ok := key.(*Certificate) 308 if !ok { 309 if c.HostKeyFallback != nil { 310 return c.HostKeyFallback(addr, remote, key) 311 } 312 return errors.New("ssh: non-certificate host key") 313 } 314 if cert.CertType != HostCert { 315 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) 316 } 317 if !c.IsHostAuthority(cert.SignatureKey, addr) { 318 return fmt.Errorf("ssh: no authorities for hostname: %v", addr) 319 } 320 321 hostname, _, err := net.SplitHostPort(addr) 322 if err != nil { 323 return err 324 } 325 326 // Pass hostname only as principal for host certificates (consistent with OpenSSH) 327 return c.CheckCert(hostname, cert) 328} 329 330// Authenticate checks a user certificate. Authenticate can be used as 331// a value for ServerConfig.PublicKeyCallback. 332func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { 333 cert, ok := pubKey.(*Certificate) 334 if !ok { 335 if c.UserKeyFallback != nil { 336 return c.UserKeyFallback(conn, pubKey) 337 } 338 return nil, errors.New("ssh: normal key pairs not accepted") 339 } 340 341 if cert.CertType != UserCert { 342 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) 343 } 344 if !c.IsUserAuthority(cert.SignatureKey) { 345 return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") 346 } 347 348 if err := c.CheckCert(conn.User(), cert); err != nil { 349 return nil, err 350 } 351 352 return &cert.Permissions, nil 353} 354 355// CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and 356// the signature of the certificate. 357func (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) 360 } 361 362 for opt := range cert.CriticalOptions { 363 // sourceAddressCriticalOption will be enforced by 364 // serverAuthenticate 365 if opt == sourceAddressCriticalOption { 366 continue 367 } 368 369 found := false 370 for _, supp := range c.SupportedCriticalOptions { 371 if supp == opt { 372 found = true 373 break 374 } 375 } 376 if !found { 377 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) 378 } 379 } 380 381 if len(cert.ValidPrincipals) > 0 { 382 // By default, certs are valid for all users/hosts. 383 found := false 384 for _, p := range cert.ValidPrincipals { 385 if p == principal { 386 found = true 387 break 388 } 389 } 390 if !found { 391 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) 392 } 393 } 394 395 clock := c.Clock 396 if clock == nil { 397 clock = time.Now 398 } 399 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") 403 } 404 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { 405 return fmt.Errorf("ssh: cert has expired") 406 } 407 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { 408 return fmt.Errorf("ssh: certificate signature does not verify") 409 } 410 411 return nil 412} 413 414// SignCert sets c.SignatureKey to the authority's public key and stores a 415// Signature, by authority, in the certificate. 416func (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 { 419 return err 420 } 421 c.SignatureKey = authority.PublicKey() 422 423 sig, err := authority.Sign(rand, c.bytesForSigning()) 424 if err != nil { 425 return err 426 } 427 c.Signature = sig 428 return nil 429} 430 431var certAlgoNames = map[string]string{ 432 KeyAlgoRSA: CertAlgoRSAv01, 433 KeyAlgoDSA: CertAlgoDSAv01, 434 KeyAlgoECDSA256: CertAlgoECDSA256v01, 435 KeyAlgoECDSA384: CertAlgoECDSA384v01, 436 KeyAlgoECDSA521: CertAlgoECDSA521v01, 437 KeyAlgoED25519: CertAlgoED25519v01, 438} 439 440// certToPrivAlgo returns the underlying algorithm for a certificate algorithm. 441// Panics if a non-certificate algorithm is passed. 442func certToPrivAlgo(algo string) string { 443 for privAlgo, pubAlgo := range certAlgoNames { 444 if pubAlgo == algo { 445 return privAlgo 446 } 447 } 448 panic("unknown cert algorithm") 449} 450 451func (cert *Certificate) bytesForSigning() []byte { 452 c2 := *cert 453 c2.Signature = nil 454 out := c2.Marshal() 455 // Drop trailing signature length. 456 return out[:len(out)-4] 457} 458 459// Marshal serializes c into OpenSSH's wire format. It is part of the 460// PublicKey interface. 461func (c *Certificate) Marshal() []byte { 462 generic := genericCertData{ 463 Serial: c.Serial, 464 CertType: c.CertType, 465 KeyId: c.KeyId, 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(), 473 } 474 if c.Signature != nil { 475 generic.Signature = Marshal(c.Signature) 476 } 477 genericBytes := Marshal(&generic) 478 keyBytes := c.Key.Marshal() 479 _, keyBytes, _ = parseString(keyBytes) 480 prefix := Marshal(&struct { 481 Name string 482 Nonce []byte 483 Key []byte `ssh:"rest"` 484 }{c.Type(), c.Nonce, keyBytes}) 485 486 result := make([]byte, 0, len(prefix)+len(genericBytes)) 487 result = append(result, prefix...) 488 result = append(result, genericBytes...) 489 return result 490} 491 492// Type returns the key name. It is part of the PublicKey interface. 493func (c *Certificate) Type() string { 494 algo, ok := certAlgoNames[c.Key.Type()] 495 if !ok { 496 panic("unknown cert key type " + c.Key.Type()) 497 } 498 return algo 499} 500 501// Verify verifies a signature against the certificate's public 502// key. It is part of the PublicKey interface. 503func (c *Certificate) Verify(data []byte, sig *Signature) error { 504 return c.Key.Verify(data, sig) 505} 506 507func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { 508 format, in, ok := parseString(in) 509 if !ok { 510 return 511 } 512 513 out = &Signature{ 514 Format: string(format), 515 } 516 517 if out.Blob, in, ok = parseString(in); !ok { 518 return 519 } 520 521 return out, in, ok 522} 523 524func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { 525 sigBytes, rest, ok := parseString(in) 526 if !ok { 527 return 528 } 529 530 out, trailing, ok := parseSignatureBody(sigBytes) 531 if !ok || len(trailing) > 0 { 532 return nil, nil, false 533 } 534 return 535} 536