github.com/glycerine/xcryptossh@v7.0.4+incompatible/certs.go (about) 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 5 package ssh 6 7 import ( 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. 19 const ( 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. 31 const ( 32 UserCert = 1 33 HostCert = 2 34 ) 35 36 // Signature represents a cryptographic signature. 37 type 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. 44 const CertTimeInfinity = 1<<64 - 1 45 46 // An Certificate represents an OpenSSH certificate as defined in 47 // [PROTOCOL.certkeys]?rev=1.8. 48 type Certificate struct { 49 Nonce []byte 50 Key PublicKey 51 Serial uint64 52 CertType uint32 53 KeyId string 54 ValidPrincipals []string 55 ValidAfter uint64 56 ValidBefore uint64 57 Permissions 58 Reserved []byte 59 SignatureKey PublicKey 60 Signature *Signature 61 } 62 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 { 67 Serial uint64 68 CertType uint32 69 KeyId string 70 ValidPrincipals []byte 71 ValidAfter uint64 72 ValidBefore uint64 73 CriticalOptions []byte 74 Extensions []byte 75 Reserved []byte 76 SignatureKey []byte 77 Signature []byte 78 } 79 80 func marshalStringList(namelist []string) []byte { 81 var to []byte 82 for _, name := range namelist { 83 s := struct{ N string }{name} 84 to = append(to, Marshal(&s)...) 85 } 86 return to 87 } 88 89 type optionsTuple struct { 90 Key string 91 Value []byte 92 } 93 94 type optionsTupleValue struct { 95 Value string 96 } 97 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) 105 } 106 sort.Strings(keys) 107 108 var ret []byte 109 for _, key := range keys { 110 s := optionsTuple{Key: key} 111 if value := tups[key]; len(value) > 0 { 112 s.Value = Marshal(&optionsTupleValue{value}) 113 } 114 ret = append(ret, Marshal(&s)...) 115 } 116 return ret 117 } 118 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{} 123 var lastKey string 124 var haveLastKey bool 125 126 for len(in) > 0 { 127 var key, val, extra []byte 128 var ok bool 129 130 if key, in, ok = parseString(in); !ok { 131 return nil, errShortRead 132 } 133 keyStr := string(key) 134 // according to [PROTOCOL.certkeys], the names must be in 135 // lexical order. 136 if haveLastKey && keyStr <= lastKey { 137 return nil, fmt.Errorf("ssh: certificate options are not in lexical order") 138 } 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 143 } 144 if len(val) > 0 { 145 val, extra, ok = parseString(val) 146 if !ok { 147 return nil, errShortRead 148 } 149 if len(extra) > 0 { 150 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") 151 } 152 tups[keyStr] = string(val) 153 } else { 154 tups[keyStr] = "" 155 } 156 } 157 return tups, nil 158 } 159 160 func parseCert(in []byte, privAlgo string) (*Certificate, error) { 161 nonce, rest, ok := parseString(in) 162 if !ok { 163 return nil, errShortRead 164 } 165 166 key, rest, err := parsePubKey(rest, privAlgo) 167 if err != nil { 168 return nil, err 169 } 170 171 var g genericCertData 172 if err := Unmarshal(rest, &g); err != nil { 173 return nil, err 174 } 175 176 c := &Certificate{ 177 Nonce: nonce, 178 Key: key, 179 Serial: g.Serial, 180 CertType: g.CertType, 181 KeyId: g.KeyId, 182 ValidAfter: g.ValidAfter, 183 ValidBefore: g.ValidBefore, 184 } 185 186 for principals := g.ValidPrincipals; len(principals) > 0; { 187 principal, rest, ok := parseString(principals) 188 if !ok { 189 return nil, errShortRead 190 } 191 c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) 192 principals = rest 193 } 194 195 c.CriticalOptions, err = parseTuples(g.CriticalOptions) 196 if err != nil { 197 return nil, err 198 } 199 c.Extensions, err = parseTuples(g.Extensions) 200 if err != nil { 201 return nil, err 202 } 203 c.Reserved = g.Reserved 204 k, err := ParsePublicKey(g.SignatureKey) 205 if err != nil { 206 return nil, err 207 } 208 209 c.SignatureKey = k 210 c.Signature, rest, ok = parseSignatureBody(g.Signature) 211 if !ok || len(rest) > 0 { 212 return nil, errors.New("ssh: signature parse error") 213 } 214 215 return c, nil 216 } 217 218 type openSSHCertSigner struct { 219 pub *Certificate 220 signer Signer 221 } 222 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") 229 } 230 231 return &openSSHCertSigner{cert, signer}, nil 232 } 233 234 func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 235 return s.signer.Sign(rand, data) 236 } 237 238 func (s *openSSHCertSigner) PublicKey() PublicKey { 239 return s.pub 240 } 241 242 const sourceAddressCriticalOption = "source-address" 243 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 253 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 259 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 266 267 // Clock is used for verifying time stamps. If nil, time.Now 268 // is used. 269 Clock func() time.Time 270 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) 275 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 280 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 286 } 287 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) 292 if !ok { 293 if c.HostKeyFallback != nil { 294 return c.HostKeyFallback(addr, remote, key) 295 } 296 return errors.New("ssh: non-certificate host key") 297 } 298 if cert.CertType != HostCert { 299 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) 300 } 301 if !c.IsHostAuthority(cert.SignatureKey, addr) { 302 return fmt.Errorf("ssh: no authorities for hostname: %v", addr) 303 } 304 305 hostname, _, err := net.SplitHostPort(addr) 306 if err != nil { 307 return err 308 } 309 310 // Pass hostname only as principal for host certificates (consistent with OpenSSH) 311 return c.CheckCert(hostname, cert) 312 } 313 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) 318 if !ok { 319 if c.UserKeyFallback != nil { 320 return c.UserKeyFallback(conn, pubKey) 321 } 322 return nil, errors.New("ssh: normal key pairs not accepted") 323 } 324 325 if cert.CertType != UserCert { 326 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) 327 } 328 if !c.IsUserAuthority(cert.SignatureKey) { 329 return nil, fmt.Errorf("ssh: certificate signed by unrecognized authority") 330 } 331 332 if err := c.CheckCert(conn.User(), cert); err != nil { 333 return nil, err 334 } 335 336 return &cert.Permissions, nil 337 } 338 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) 344 } 345 346 for opt, _ := range cert.CriticalOptions { 347 // sourceAddressCriticalOption will be enforced by 348 // serverAuthenticate 349 if opt == sourceAddressCriticalOption { 350 continue 351 } 352 353 found := false 354 for _, supp := range c.SupportedCriticalOptions { 355 if supp == opt { 356 found = true 357 break 358 } 359 } 360 if !found { 361 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) 362 } 363 } 364 365 if len(cert.ValidPrincipals) > 0 { 366 // By default, certs are valid for all users/hosts. 367 found := false 368 for _, p := range cert.ValidPrincipals { 369 if p == principal { 370 found = true 371 break 372 } 373 } 374 if !found { 375 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) 376 } 377 } 378 379 clock := c.Clock 380 if clock == nil { 381 clock = time.Now 382 } 383 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") 387 } 388 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { 389 return fmt.Errorf("ssh: cert has expired") 390 } 391 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { 392 return fmt.Errorf("ssh: certificate signature does not verify") 393 } 394 395 return nil 396 } 397 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 { 403 return err 404 } 405 c.SignatureKey = authority.PublicKey() 406 407 sig, err := authority.Sign(rand, c.bytesForSigning()) 408 if err != nil { 409 return err 410 } 411 c.Signature = sig 412 return nil 413 } 414 415 var certAlgoNames = map[string]string{ 416 KeyAlgoRSA: CertAlgoRSAv01, 417 KeyAlgoDSA: CertAlgoDSAv01, 418 KeyAlgoECDSA256: CertAlgoECDSA256v01, 419 KeyAlgoECDSA384: CertAlgoECDSA384v01, 420 KeyAlgoECDSA521: CertAlgoECDSA521v01, 421 KeyAlgoED25519: CertAlgoED25519v01, 422 } 423 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 { 428 if pubAlgo == algo { 429 return privAlgo 430 } 431 } 432 panic("unknown cert algorithm") 433 } 434 435 func (cert *Certificate) bytesForSigning() []byte { 436 c2 := *cert 437 c2.Signature = nil 438 out := c2.Marshal() 439 // Drop trailing signature length. 440 return out[:len(out)-4] 441 } 442 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{ 447 Serial: c.Serial, 448 CertType: c.CertType, 449 KeyId: c.KeyId, 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(), 457 } 458 if c.Signature != nil { 459 generic.Signature = Marshal(c.Signature) 460 } 461 genericBytes := Marshal(&generic) 462 keyBytes := c.Key.Marshal() 463 _, keyBytes, _ = parseString(keyBytes) 464 prefix := Marshal(&struct { 465 Name string 466 Nonce []byte 467 Key []byte `ssh:"rest"` 468 }{c.Type(), c.Nonce, keyBytes}) 469 470 result := make([]byte, 0, len(prefix)+len(genericBytes)) 471 result = append(result, prefix...) 472 result = append(result, genericBytes...) 473 return result 474 } 475 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()] 479 if !ok { 480 panic("unknown cert key type " + c.Key.Type()) 481 } 482 return algo 483 } 484 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) 489 } 490 491 func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { 492 format, in, ok := parseString(in) 493 if !ok { 494 return 495 } 496 497 out = &Signature{ 498 Format: string(format), 499 } 500 501 if out.Blob, in, ok = parseString(in); !ok { 502 return 503 } 504 505 return out, in, ok 506 } 507 508 func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { 509 sigBytes, rest, ok := parseString(in) 510 if !ok { 511 return 512 } 513 514 out, trailing, ok := parseSignatureBody(sigBytes) 515 if !ok || len(trailing) > 0 { 516 return nil, nil, false 517 } 518 return 519 }