github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/crypto/ssh/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 ) 26 27 // Certificate types distinguish between host and user 28 // certificates. The values can be set in the CertType field of 29 // Certificate. 30 const ( 31 UserCert = 1 32 HostCert = 2 33 ) 34 35 // Signature represents a cryptographic signature. 36 type Signature struct { 37 Format string 38 Blob []byte 39 } 40 41 // CertTimeInfinity can be used for OpenSSHCertV01.ValidBefore to indicate that 42 // a certificate does not expire. 43 const CertTimeInfinity = 1<<64 - 1 44 45 // An Certificate represents an OpenSSH certificate as defined in 46 // [PROTOCOL.certkeys]?rev=1.8. 47 type Certificate struct { 48 Nonce []byte 49 Key PublicKey 50 Serial uint64 51 CertType uint32 52 KeyId string 53 ValidPrincipals []string 54 ValidAfter uint64 55 ValidBefore uint64 56 Permissions 57 Reserved []byte 58 SignatureKey PublicKey 59 Signature *Signature 60 } 61 62 // genericCertData holds the key-independent part of the certificate data. 63 // Overall, certificates contain an nonce, public key fields and 64 // key-independent fields. 65 type genericCertData struct { 66 Serial uint64 67 CertType uint32 68 KeyId string 69 ValidPrincipals []byte 70 ValidAfter uint64 71 ValidBefore uint64 72 CriticalOptions []byte 73 Extensions []byte 74 Reserved []byte 75 SignatureKey []byte 76 Signature []byte 77 } 78 79 func marshalStringList(namelist []string) []byte { 80 var to []byte 81 for _, name := range namelist { 82 s := struct{ N string }{name} 83 to = append(to, Marshal(&s)...) 84 } 85 return to 86 } 87 88 type optionsTuple struct { 89 Key string 90 Value []byte 91 } 92 93 type optionsTupleValue struct { 94 Value string 95 } 96 97 // serialize a map of critical options or extensions 98 // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, 99 // we need two length prefixes for a non-empty string value 100 func marshalTuples(tups map[string]string) []byte { 101 keys := make([]string, 0, len(tups)) 102 for key := range tups { 103 keys = append(keys, key) 104 } 105 sort.Strings(keys) 106 107 var ret []byte 108 for _, key := range keys { 109 s := optionsTuple{Key: key} 110 if value := tups[key]; len(value) > 0 { 111 s.Value = Marshal(&optionsTupleValue{value}) 112 } 113 ret = append(ret, Marshal(&s)...) 114 } 115 return ret 116 } 117 118 // issue #10569 - per [PROTOCOL.certkeys] and SSH implementation, 119 // we need two length prefixes for a non-empty option value 120 func parseTuples(in []byte) (map[string]string, error) { 121 tups := map[string]string{} 122 var lastKey string 123 var haveLastKey bool 124 125 for len(in) > 0 { 126 var key, val, extra []byte 127 var ok bool 128 129 if key, in, ok = parseString(in); !ok { 130 return nil, errShortRead 131 } 132 keyStr := string(key) 133 // according to [PROTOCOL.certkeys], the names must be in 134 // lexical order. 135 if haveLastKey && keyStr <= lastKey { 136 return nil, fmt.Errorf("ssh: certificate options are not in lexical order") 137 } 138 lastKey, haveLastKey = keyStr, true 139 // the next field is a data field, which if non-empty has a string embedded 140 if val, in, ok = parseString(in); !ok { 141 return nil, errShortRead 142 } 143 if len(val) > 0 { 144 val, extra, ok = parseString(val) 145 if !ok { 146 return nil, errShortRead 147 } 148 if len(extra) > 0 { 149 return nil, fmt.Errorf("ssh: unexpected trailing data after certificate option value") 150 } 151 tups[keyStr] = string(val) 152 } else { 153 tups[keyStr] = "" 154 } 155 } 156 return tups, nil 157 } 158 159 func parseCert(in []byte, privAlgo string) (*Certificate, error) { 160 nonce, rest, ok := parseString(in) 161 if !ok { 162 return nil, errShortRead 163 } 164 165 key, rest, err := parsePubKey(rest, privAlgo) 166 if err != nil { 167 return nil, err 168 } 169 170 var g genericCertData 171 if err := Unmarshal(rest, &g); err != nil { 172 return nil, err 173 } 174 175 c := &Certificate{ 176 Nonce: nonce, 177 Key: key, 178 Serial: g.Serial, 179 CertType: g.CertType, 180 KeyId: g.KeyId, 181 ValidAfter: g.ValidAfter, 182 ValidBefore: g.ValidBefore, 183 } 184 185 for principals := g.ValidPrincipals; len(principals) > 0; { 186 principal, rest, ok := parseString(principals) 187 if !ok { 188 return nil, errShortRead 189 } 190 c.ValidPrincipals = append(c.ValidPrincipals, string(principal)) 191 principals = rest 192 } 193 194 c.CriticalOptions, err = parseTuples(g.CriticalOptions) 195 if err != nil { 196 return nil, err 197 } 198 c.Extensions, err = parseTuples(g.Extensions) 199 if err != nil { 200 return nil, err 201 } 202 c.Reserved = g.Reserved 203 k, err := ParsePublicKey(g.SignatureKey) 204 if err != nil { 205 return nil, err 206 } 207 208 c.SignatureKey = k 209 c.Signature, rest, ok = parseSignatureBody(g.Signature) 210 if !ok || len(rest) > 0 { 211 return nil, errors.New("ssh: signature parse error") 212 } 213 214 return c, nil 215 } 216 217 type openSSHCertSigner struct { 218 pub *Certificate 219 signer Signer 220 } 221 222 // NewCertSigner returns a Signer that signs with the given Certificate, whose 223 // private key is held by signer. It returns an error if the public key in cert 224 // doesn't match the key used by signer. 225 func NewCertSigner(cert *Certificate, signer Signer) (Signer, error) { 226 if bytes.Compare(cert.Key.Marshal(), signer.PublicKey().Marshal()) != 0 { 227 return nil, errors.New("ssh: signer and cert have different public key") 228 } 229 230 return &openSSHCertSigner{cert, signer}, nil 231 } 232 233 func (s *openSSHCertSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 234 return s.signer.Sign(rand, data) 235 } 236 237 func (s *openSSHCertSigner) PublicKey() PublicKey { 238 return s.pub 239 } 240 241 const sourceAddressCriticalOption = "source-address" 242 243 // CertChecker does the work of verifying a certificate. Its methods 244 // can be plugged into ClientConfig.HostKeyCallback and 245 // ServerConfig.PublicKeyCallback. For the CertChecker to work, 246 // minimally, the IsAuthority callback should be set. 247 type CertChecker struct { 248 // SupportedCriticalOptions lists the CriticalOptions that the 249 // server application layer understands. These are only used 250 // for user certificates. 251 SupportedCriticalOptions []string 252 253 // IsAuthority should return true if the key is recognized as 254 // an authority. This allows for certificates to be signed by other 255 // certificates. 256 IsAuthority func(auth PublicKey) bool 257 258 // Clock is used for verifying time stamps. If nil, time.Now 259 // is used. 260 Clock func() time.Time 261 262 // UserKeyFallback is called when CertChecker.Authenticate encounters a 263 // public key that is not a certificate. It must implement validation 264 // of user keys or else, if nil, all such keys are rejected. 265 UserKeyFallback func(conn ConnMetadata, key PublicKey) (*Permissions, error) 266 267 // HostKeyFallback is called when CertChecker.CheckHostKey encounters a 268 // public key that is not a certificate. It must implement host key 269 // validation or else, if nil, all such keys are rejected. 270 HostKeyFallback func(addr string, remote net.Addr, key PublicKey) error 271 272 // IsRevoked is called for each certificate so that revocation checking 273 // can be implemented. It should return true if the given certificate 274 // is revoked and false otherwise. If nil, no certificates are 275 // considered to have been revoked. 276 IsRevoked func(cert *Certificate) bool 277 } 278 279 // CheckHostKey checks a host key certificate. This method can be 280 // plugged into ClientConfig.HostKeyCallback. 281 func (c *CertChecker) CheckHostKey(addr string, remote net.Addr, key PublicKey) error { 282 cert, ok := key.(*Certificate) 283 if !ok { 284 if c.HostKeyFallback != nil { 285 return c.HostKeyFallback(addr, remote, key) 286 } 287 return errors.New("ssh: non-certificate host key") 288 } 289 if cert.CertType != HostCert { 290 return fmt.Errorf("ssh: certificate presented as a host key has type %d", cert.CertType) 291 } 292 293 return c.CheckCert(addr, cert) 294 } 295 296 // Authenticate checks a user certificate. Authenticate can be used as 297 // a value for ServerConfig.PublicKeyCallback. 298 func (c *CertChecker) Authenticate(conn ConnMetadata, pubKey PublicKey) (*Permissions, error) { 299 cert, ok := pubKey.(*Certificate) 300 if !ok { 301 if c.UserKeyFallback != nil { 302 return c.UserKeyFallback(conn, pubKey) 303 } 304 return nil, errors.New("ssh: normal key pairs not accepted") 305 } 306 307 if cert.CertType != UserCert { 308 return nil, fmt.Errorf("ssh: cert has type %d", cert.CertType) 309 } 310 311 if err := c.CheckCert(conn.User(), cert); err != nil { 312 return nil, err 313 } 314 315 return &cert.Permissions, nil 316 } 317 318 // CheckCert checks CriticalOptions, ValidPrincipals, revocation, timestamp and 319 // the signature of the certificate. 320 func (c *CertChecker) CheckCert(principal string, cert *Certificate) error { 321 if c.IsRevoked != nil && c.IsRevoked(cert) { 322 return fmt.Errorf("ssh: certicate serial %d revoked", cert.Serial) 323 } 324 325 for opt, _ := range cert.CriticalOptions { 326 // sourceAddressCriticalOption will be enforced by 327 // serverAuthenticate 328 if opt == sourceAddressCriticalOption { 329 continue 330 } 331 332 found := false 333 for _, supp := range c.SupportedCriticalOptions { 334 if supp == opt { 335 found = true 336 break 337 } 338 } 339 if !found { 340 return fmt.Errorf("ssh: unsupported critical option %q in certificate", opt) 341 } 342 } 343 344 if len(cert.ValidPrincipals) > 0 { 345 // By default, certs are valid for all users/hosts. 346 found := false 347 for _, p := range cert.ValidPrincipals { 348 if p == principal { 349 found = true 350 break 351 } 352 } 353 if !found { 354 return fmt.Errorf("ssh: principal %q not in the set of valid principals for given certificate: %q", principal, cert.ValidPrincipals) 355 } 356 } 357 358 if !c.IsAuthority(cert.SignatureKey) { 359 return fmt.Errorf("ssh: certificate signed by unrecognized authority") 360 } 361 362 clock := c.Clock 363 if clock == nil { 364 clock = time.Now 365 } 366 367 unixNow := clock().Unix() 368 if after := int64(cert.ValidAfter); after < 0 || unixNow < int64(cert.ValidAfter) { 369 return fmt.Errorf("ssh: cert is not yet valid") 370 } 371 if before := int64(cert.ValidBefore); cert.ValidBefore != uint64(CertTimeInfinity) && (unixNow >= before || before < 0) { 372 return fmt.Errorf("ssh: cert has expired") 373 } 374 if err := cert.SignatureKey.Verify(cert.bytesForSigning(), cert.Signature); err != nil { 375 return fmt.Errorf("ssh: certificate signature does not verify") 376 } 377 378 return nil 379 } 380 381 // SignCert sets c.SignatureKey to the authority's public key and stores a 382 // Signature, by authority, in the certificate. 383 func (c *Certificate) SignCert(rand io.Reader, authority Signer) error { 384 c.Nonce = make([]byte, 32) 385 if _, err := io.ReadFull(rand, c.Nonce); err != nil { 386 return err 387 } 388 c.SignatureKey = authority.PublicKey() 389 390 sig, err := authority.Sign(rand, c.bytesForSigning()) 391 if err != nil { 392 return err 393 } 394 c.Signature = sig 395 return nil 396 } 397 398 var certAlgoNames = map[string]string{ 399 KeyAlgoRSA: CertAlgoRSAv01, 400 KeyAlgoDSA: CertAlgoDSAv01, 401 KeyAlgoECDSA256: CertAlgoECDSA256v01, 402 KeyAlgoECDSA384: CertAlgoECDSA384v01, 403 KeyAlgoECDSA521: CertAlgoECDSA521v01, 404 } 405 406 // certToPrivAlgo returns the underlying algorithm for a certificate algorithm. 407 // Panics if a non-certificate algorithm is passed. 408 func certToPrivAlgo(algo string) string { 409 for privAlgo, pubAlgo := range certAlgoNames { 410 if pubAlgo == algo { 411 return privAlgo 412 } 413 } 414 panic("unknown cert algorithm") 415 } 416 417 func (cert *Certificate) bytesForSigning() []byte { 418 c2 := *cert 419 c2.Signature = nil 420 out := c2.Marshal() 421 // Drop trailing signature length. 422 return out[:len(out)-4] 423 } 424 425 // Marshal serializes c into OpenSSH's wire format. It is part of the 426 // PublicKey interface. 427 func (c *Certificate) Marshal() []byte { 428 generic := genericCertData{ 429 Serial: c.Serial, 430 CertType: c.CertType, 431 KeyId: c.KeyId, 432 ValidPrincipals: marshalStringList(c.ValidPrincipals), 433 ValidAfter: uint64(c.ValidAfter), 434 ValidBefore: uint64(c.ValidBefore), 435 CriticalOptions: marshalTuples(c.CriticalOptions), 436 Extensions: marshalTuples(c.Extensions), 437 Reserved: c.Reserved, 438 SignatureKey: c.SignatureKey.Marshal(), 439 } 440 if c.Signature != nil { 441 generic.Signature = Marshal(c.Signature) 442 } 443 genericBytes := Marshal(&generic) 444 keyBytes := c.Key.Marshal() 445 _, keyBytes, _ = parseString(keyBytes) 446 prefix := Marshal(&struct { 447 Name string 448 Nonce []byte 449 Key []byte `ssh:"rest"` 450 }{c.Type(), c.Nonce, keyBytes}) 451 452 result := make([]byte, 0, len(prefix)+len(genericBytes)) 453 result = append(result, prefix...) 454 result = append(result, genericBytes...) 455 return result 456 } 457 458 // Type returns the key name. It is part of the PublicKey interface. 459 func (c *Certificate) Type() string { 460 algo, ok := certAlgoNames[c.Key.Type()] 461 if !ok { 462 panic("unknown cert key type") 463 } 464 return algo 465 } 466 467 // Verify verifies a signature against the certificate's public 468 // key. It is part of the PublicKey interface. 469 func (c *Certificate) Verify(data []byte, sig *Signature) error { 470 return c.Key.Verify(data, sig) 471 } 472 473 func parseSignatureBody(in []byte) (out *Signature, rest []byte, ok bool) { 474 format, in, ok := parseString(in) 475 if !ok { 476 return 477 } 478 479 out = &Signature{ 480 Format: string(format), 481 } 482 483 if out.Blob, in, ok = parseString(in); !ok { 484 return 485 } 486 487 return out, in, ok 488 } 489 490 func parseSignature(in []byte) (out *Signature, rest []byte, ok bool) { 491 sigBytes, rest, ok := parseString(in) 492 if !ok { 493 return 494 } 495 496 out, trailing, ok := parseSignatureBody(sigBytes) 497 if !ok || len(trailing) > 0 { 498 return nil, nil, false 499 } 500 return 501 }