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 "crypto" 10 "crypto/dsa" 11 "crypto/ecdsa" 12 "crypto/elliptic" 13 "crypto/md5" 14 "crypto/rsa" 15 "crypto/sha256" 16 "crypto/x509" 17 "encoding/asn1" 18 "encoding/base64" 19 "encoding/hex" 20 "encoding/pem" 21 "errors" 22 "fmt" 23 "io" 24 "math/big" 25 "strings" 26 27 "golang.org/x/crypto/ed25519" 28) 29 30// These constants represent the algorithm names for key types supported by this 31// package. 32const ( 33 KeyAlgoRSA = "ssh-rsa" 34 KeyAlgoDSA = "ssh-dss" 35 KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" 36 KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" 37 KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" 38 KeyAlgoED25519 = "ssh-ed25519" 39) 40 41// These constants represent non-default signature algorithms that are supported 42// as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See 43// [PROTOCOL.agent] section 4.5.1 and 44// https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 45const ( 46 SigAlgoRSA = "ssh-rsa" 47 SigAlgoRSASHA2256 = "rsa-sha2-256" 48 SigAlgoRSASHA2512 = "rsa-sha2-512" 49) 50 51// parsePubKey parses a public key of the given algorithm. 52// Use ParsePublicKey for keys with prepended algorithm. 53func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { 54 switch algo { 55 case KeyAlgoRSA: 56 return parseRSA(in) 57 case KeyAlgoDSA: 58 return parseDSA(in) 59 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: 60 return parseECDSA(in) 61 case KeyAlgoED25519: 62 return parseED25519(in) 63 case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01: 64 cert, err := parseCert(in, certToPrivAlgo(algo)) 65 if err != nil { 66 return nil, nil, err 67 } 68 return cert, nil, nil 69 } 70 return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) 71} 72 73// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format 74// (see sshd(8) manual page) once the options and key type fields have been 75// removed. 76func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { 77 in = bytes.TrimSpace(in) 78 79 i := bytes.IndexAny(in, " \t") 80 if i == -1 { 81 i = len(in) 82 } 83 base64Key := in[:i] 84 85 key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) 86 n, err := base64.StdEncoding.Decode(key, base64Key) 87 if err != nil { 88 return nil, "", err 89 } 90 key = key[:n] 91 out, err = ParsePublicKey(key) 92 if err != nil { 93 return nil, "", err 94 } 95 comment = string(bytes.TrimSpace(in[i:])) 96 return out, comment, nil 97} 98 99// ParseKnownHosts parses an entry in the format of the known_hosts file. 100// 101// The known_hosts format is documented in the sshd(8) manual page. This 102// function will parse a single entry from in. On successful return, marker 103// will contain the optional marker value (i.e. "cert-authority" or "revoked") 104// or else be empty, hosts will contain the hosts that this entry matches, 105// pubKey will contain the public key and comment will contain any trailing 106// comment at the end of the line. See the sshd(8) manual page for the various 107// forms that a host string can take. 108// 109// The unparsed remainder of the input will be returned in rest. This function 110// can be called repeatedly to parse multiple entries. 111// 112// If no entries were found in the input then err will be io.EOF. Otherwise a 113// non-nil err value indicates a parse error. 114func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { 115 for len(in) > 0 { 116 end := bytes.IndexByte(in, '\n') 117 if end != -1 { 118 rest = in[end+1:] 119 in = in[:end] 120 } else { 121 rest = nil 122 } 123 124 end = bytes.IndexByte(in, '\r') 125 if end != -1 { 126 in = in[:end] 127 } 128 129 in = bytes.TrimSpace(in) 130 if len(in) == 0 || in[0] == '#' { 131 in = rest 132 continue 133 } 134 135 i := bytes.IndexAny(in, " \t") 136 if i == -1 { 137 in = rest 138 continue 139 } 140 141 // Strip out the beginning of the known_host key. 142 // This is either an optional marker or a (set of) hostname(s). 143 keyFields := bytes.Fields(in) 144 if len(keyFields) < 3 || len(keyFields) > 5 { 145 return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") 146 } 147 148 // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated 149 // list of hosts 150 marker := "" 151 if keyFields[0][0] == '@' { 152 marker = string(keyFields[0][1:]) 153 keyFields = keyFields[1:] 154 } 155 156 hosts := string(keyFields[0]) 157 // keyFields[1] contains the key type (e.g. “ssh-rsa”). 158 // However, that information is duplicated inside the 159 // base64-encoded key and so is ignored here. 160 161 key := bytes.Join(keyFields[2:], []byte(" ")) 162 if pubKey, comment, err = parseAuthorizedKey(key); err != nil { 163 return "", nil, nil, "", nil, err 164 } 165 166 return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil 167 } 168 169 return "", nil, nil, "", nil, io.EOF 170} 171 172// ParseAuthorizedKeys parses a public key from an authorized_keys 173// file used in OpenSSH according to the sshd(8) manual page. 174func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { 175 for len(in) > 0 { 176 end := bytes.IndexByte(in, '\n') 177 if end != -1 { 178 rest = in[end+1:] 179 in = in[:end] 180 } else { 181 rest = nil 182 } 183 184 end = bytes.IndexByte(in, '\r') 185 if end != -1 { 186 in = in[:end] 187 } 188 189 in = bytes.TrimSpace(in) 190 if len(in) == 0 || in[0] == '#' { 191 in = rest 192 continue 193 } 194 195 i := bytes.IndexAny(in, " \t") 196 if i == -1 { 197 in = rest 198 continue 199 } 200 201 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { 202 return out, comment, options, rest, nil 203 } 204 205 // No key type recognised. Maybe there's an options field at 206 // the beginning. 207 var b byte 208 inQuote := false 209 var candidateOptions []string 210 optionStart := 0 211 for i, b = range in { 212 isEnd := !inQuote && (b == ' ' || b == '\t') 213 if (b == ',' && !inQuote) || isEnd { 214 if i-optionStart > 0 { 215 candidateOptions = append(candidateOptions, string(in[optionStart:i])) 216 } 217 optionStart = i + 1 218 } 219 if isEnd { 220 break 221 } 222 if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { 223 inQuote = !inQuote 224 } 225 } 226 for i < len(in) && (in[i] == ' ' || in[i] == '\t') { 227 i++ 228 } 229 if i == len(in) { 230 // Invalid line: unmatched quote 231 in = rest 232 continue 233 } 234 235 in = in[i:] 236 i = bytes.IndexAny(in, " \t") 237 if i == -1 { 238 in = rest 239 continue 240 } 241 242 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { 243 options = candidateOptions 244 return out, comment, options, rest, nil 245 } 246 247 in = rest 248 continue 249 } 250 251 return nil, "", nil, nil, errors.New("ssh: no key found") 252} 253 254// ParsePublicKey parses an SSH public key formatted for use in 255// the SSH wire protocol according to RFC 4253, section 6.6. 256func ParsePublicKey(in []byte) (out PublicKey, err error) { 257 algo, in, ok := parseString(in) 258 if !ok { 259 return nil, errShortRead 260 } 261 var rest []byte 262 out, rest, err = parsePubKey(in, string(algo)) 263 if len(rest) > 0 { 264 return nil, errors.New("ssh: trailing junk in public key") 265 } 266 267 return out, err 268} 269 270// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH 271// authorized_keys file. The return value ends with newline. 272func MarshalAuthorizedKey(key PublicKey) []byte { 273 b := &bytes.Buffer{} 274 b.WriteString(key.Type()) 275 b.WriteByte(' ') 276 e := base64.NewEncoder(base64.StdEncoding, b) 277 e.Write(key.Marshal()) 278 e.Close() 279 b.WriteByte('\n') 280 return b.Bytes() 281} 282 283// PublicKey is an abstraction of different types of public keys. 284type PublicKey interface { 285 // Type returns the key's type, e.g. "ssh-rsa". 286 Type() string 287 288 // Marshal returns the serialized key data in SSH wire format, 289 // with the name prefix. To unmarshal the returned data, use 290 // the ParsePublicKey function. 291 Marshal() []byte 292 293 // Verify that sig is a signature on the given data using this 294 // key. This function will hash the data appropriately first. 295 Verify(data []byte, sig *Signature) error 296} 297 298// CryptoPublicKey, if implemented by a PublicKey, 299// returns the underlying crypto.PublicKey form of the key. 300type CryptoPublicKey interface { 301 CryptoPublicKey() crypto.PublicKey 302} 303 304// A Signer can create signatures that verify against a public key. 305type Signer interface { 306 // PublicKey returns an associated PublicKey instance. 307 PublicKey() PublicKey 308 309 // Sign returns raw signature for the given data. This method 310 // will apply the hash specified for the keytype to the data. 311 Sign(rand io.Reader, data []byte) (*Signature, error) 312} 313 314// A AlgorithmSigner is a Signer that also supports specifying a specific 315// algorithm to use for signing. 316type AlgorithmSigner interface { 317 Signer 318 319 // SignWithAlgorithm is like Signer.Sign, but allows specification of a 320 // non-default signing algorithm. See the SigAlgo* constants in this 321 // package for signature algorithms supported by this package. Callers may 322 // pass an empty string for the algorithm in which case the AlgorithmSigner 323 // will use its default algorithm. 324 SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) 325} 326 327type rsaPublicKey rsa.PublicKey 328 329func (r *rsaPublicKey) Type() string { 330 return "ssh-rsa" 331} 332 333// parseRSA parses an RSA key according to RFC 4253, section 6.6. 334func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { 335 var w struct { 336 E *big.Int 337 N *big.Int 338 Rest []byte `ssh:"rest"` 339 } 340 if err := Unmarshal(in, &w); err != nil { 341 return nil, nil, err 342 } 343 344 if w.E.BitLen() > 24 { 345 return nil, nil, errors.New("ssh: exponent too large") 346 } 347 e := w.E.Int64() 348 if e < 3 || e&1 == 0 { 349 return nil, nil, errors.New("ssh: incorrect exponent") 350 } 351 352 var key rsa.PublicKey 353 key.E = int(e) 354 key.N = w.N 355 return (*rsaPublicKey)(&key), w.Rest, nil 356} 357 358func (r *rsaPublicKey) Marshal() []byte { 359 e := new(big.Int).SetInt64(int64(r.E)) 360 // RSA publickey struct layout should match the struct used by 361 // parseRSACert in the x/crypto/ssh/agent package. 362 wirekey := struct { 363 Name string 364 E *big.Int 365 N *big.Int 366 }{ 367 KeyAlgoRSA, 368 e, 369 r.N, 370 } 371 return Marshal(&wirekey) 372} 373 374func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { 375 var hash crypto.Hash 376 switch sig.Format { 377 case SigAlgoRSA: 378 hash = crypto.SHA1 379 case SigAlgoRSASHA2256: 380 hash = crypto.SHA256 381 case SigAlgoRSASHA2512: 382 hash = crypto.SHA512 383 default: 384 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) 385 } 386 h := hash.New() 387 h.Write(data) 388 digest := h.Sum(nil) 389 return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) 390} 391 392func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { 393 return (*rsa.PublicKey)(r) 394} 395 396type dsaPublicKey dsa.PublicKey 397 398func (k *dsaPublicKey) Type() string { 399 return "ssh-dss" 400} 401 402func checkDSAParams(param *dsa.Parameters) error { 403 // SSH specifies FIPS 186-2, which only provided a single size 404 // (1024 bits) DSA key. FIPS 186-3 allows for larger key 405 // sizes, which would confuse SSH. 406 if l := param.P.BitLen(); l != 1024 { 407 return fmt.Errorf("ssh: unsupported DSA key size %d", l) 408 } 409 410 return nil 411} 412 413// parseDSA parses an DSA key according to RFC 4253, section 6.6. 414func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { 415 var w struct { 416 P, Q, G, Y *big.Int 417 Rest []byte `ssh:"rest"` 418 } 419 if err := Unmarshal(in, &w); err != nil { 420 return nil, nil, err 421 } 422 423 param := dsa.Parameters{ 424 P: w.P, 425 Q: w.Q, 426 G: w.G, 427 } 428 if err := checkDSAParams(¶m); err != nil { 429 return nil, nil, err 430 } 431 432 key := &dsaPublicKey{ 433 Parameters: param, 434 Y: w.Y, 435 } 436 return key, w.Rest, nil 437} 438 439func (k *dsaPublicKey) Marshal() []byte { 440 // DSA publickey struct layout should match the struct used by 441 // parseDSACert in the x/crypto/ssh/agent package. 442 w := struct { 443 Name string 444 P, Q, G, Y *big.Int 445 }{ 446 k.Type(), 447 k.P, 448 k.Q, 449 k.G, 450 k.Y, 451 } 452 453 return Marshal(&w) 454} 455 456func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { 457 if sig.Format != k.Type() { 458 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 459 } 460 h := crypto.SHA1.New() 461 h.Write(data) 462 digest := h.Sum(nil) 463 464 // Per RFC 4253, section 6.6, 465 // The value for 'dss_signature_blob' is encoded as a string containing 466 // r, followed by s (which are 160-bit integers, without lengths or 467 // padding, unsigned, and in network byte order). 468 // For DSS purposes, sig.Blob should be exactly 40 bytes in length. 469 if len(sig.Blob) != 40 { 470 return errors.New("ssh: DSA signature parse error") 471 } 472 r := new(big.Int).SetBytes(sig.Blob[:20]) 473 s := new(big.Int).SetBytes(sig.Blob[20:]) 474 if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { 475 return nil 476 } 477 return errors.New("ssh: signature did not verify") 478} 479 480func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { 481 return (*dsa.PublicKey)(k) 482} 483 484type dsaPrivateKey struct { 485 *dsa.PrivateKey 486} 487 488func (k *dsaPrivateKey) PublicKey() PublicKey { 489 return (*dsaPublicKey)(&k.PrivateKey.PublicKey) 490} 491 492func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { 493 return k.SignWithAlgorithm(rand, data, "") 494} 495 496func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { 497 if algorithm != "" && algorithm != k.PublicKey().Type() { 498 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 499 } 500 501 h := crypto.SHA1.New() 502 h.Write(data) 503 digest := h.Sum(nil) 504 r, s, err := dsa.Sign(rand, k.PrivateKey, digest) 505 if err != nil { 506 return nil, err 507 } 508 509 sig := make([]byte, 40) 510 rb := r.Bytes() 511 sb := s.Bytes() 512 513 copy(sig[20-len(rb):20], rb) 514 copy(sig[40-len(sb):], sb) 515 516 return &Signature{ 517 Format: k.PublicKey().Type(), 518 Blob: sig, 519 }, nil 520} 521 522type ecdsaPublicKey ecdsa.PublicKey 523 524func (k *ecdsaPublicKey) Type() string { 525 return "ecdsa-sha2-" + k.nistID() 526} 527 528func (k *ecdsaPublicKey) nistID() string { 529 switch k.Params().BitSize { 530 case 256: 531 return "nistp256" 532 case 384: 533 return "nistp384" 534 case 521: 535 return "nistp521" 536 } 537 panic("ssh: unsupported ecdsa key size") 538} 539 540type ed25519PublicKey ed25519.PublicKey 541 542func (k ed25519PublicKey) Type() string { 543 return KeyAlgoED25519 544} 545 546func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { 547 var w struct { 548 KeyBytes []byte 549 Rest []byte `ssh:"rest"` 550 } 551 552 if err := Unmarshal(in, &w); err != nil { 553 return nil, nil, err 554 } 555 556 key := ed25519.PublicKey(w.KeyBytes) 557 558 return (ed25519PublicKey)(key), w.Rest, nil 559} 560 561func (k ed25519PublicKey) Marshal() []byte { 562 w := struct { 563 Name string 564 KeyBytes []byte 565 }{ 566 KeyAlgoED25519, 567 []byte(k), 568 } 569 return Marshal(&w) 570} 571 572func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { 573 if sig.Format != k.Type() { 574 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 575 } 576 577 edKey := (ed25519.PublicKey)(k) 578 if ok := ed25519.Verify(edKey, b, sig.Blob); !ok { 579 return errors.New("ssh: signature did not verify") 580 } 581 582 return nil 583} 584 585func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { 586 return ed25519.PublicKey(k) 587} 588 589func supportedEllipticCurve(curve elliptic.Curve) bool { 590 return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() 591} 592 593// ecHash returns the hash to match the given elliptic curve, see RFC 594// 5656, section 6.2.1 595func ecHash(curve elliptic.Curve) crypto.Hash { 596 bitSize := curve.Params().BitSize 597 switch { 598 case bitSize <= 256: 599 return crypto.SHA256 600 case bitSize <= 384: 601 return crypto.SHA384 602 } 603 return crypto.SHA512 604} 605 606// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. 607func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { 608 var w struct { 609 Curve string 610 KeyBytes []byte 611 Rest []byte `ssh:"rest"` 612 } 613 614 if err := Unmarshal(in, &w); err != nil { 615 return nil, nil, err 616 } 617 618 key := new(ecdsa.PublicKey) 619 620 switch w.Curve { 621 case "nistp256": 622 key.Curve = elliptic.P256() 623 case "nistp384": 624 key.Curve = elliptic.P384() 625 case "nistp521": 626 key.Curve = elliptic.P521() 627 default: 628 return nil, nil, errors.New("ssh: unsupported curve") 629 } 630 631 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) 632 if key.X == nil || key.Y == nil { 633 return nil, nil, errors.New("ssh: invalid curve point") 634 } 635 return (*ecdsaPublicKey)(key), w.Rest, nil 636} 637 638func (k *ecdsaPublicKey) Marshal() []byte { 639 // See RFC 5656, section 3.1. 640 keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) 641 // ECDSA publickey struct layout should match the struct used by 642 // parseECDSACert in the x/crypto/ssh/agent package. 643 w := struct { 644 Name string 645 ID string 646 Key []byte 647 }{ 648 k.Type(), 649 k.nistID(), 650 keyBytes, 651 } 652 653 return Marshal(&w) 654} 655 656func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { 657 if sig.Format != k.Type() { 658 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 659 } 660 661 h := ecHash(k.Curve).New() 662 h.Write(data) 663 digest := h.Sum(nil) 664 665 // Per RFC 5656, section 3.1.2, 666 // The ecdsa_signature_blob value has the following specific encoding: 667 // mpint r 668 // mpint s 669 var ecSig struct { 670 R *big.Int 671 S *big.Int 672 } 673 674 if err := Unmarshal(sig.Blob, &ecSig); err != nil { 675 return err 676 } 677 678 if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { 679 return nil 680 } 681 return errors.New("ssh: signature did not verify") 682} 683 684func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { 685 return (*ecdsa.PublicKey)(k) 686} 687 688// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, 689// *ecdsa.PrivateKey or any other crypto.Signer and returns a 690// corresponding Signer instance. ECDSA keys must use P-256, P-384 or 691// P-521. DSA keys must use parameter size L1024N160. 692func NewSignerFromKey(key interface{}) (Signer, error) { 693 switch key := key.(type) { 694 case crypto.Signer: 695 return NewSignerFromSigner(key) 696 case *dsa.PrivateKey: 697 return newDSAPrivateKey(key) 698 default: 699 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 700 } 701} 702 703func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { 704 if err := checkDSAParams(&key.PublicKey.Parameters); err != nil { 705 return nil, err 706 } 707 708 return &dsaPrivateKey{key}, nil 709} 710 711type wrappedSigner struct { 712 signer crypto.Signer 713 pubKey PublicKey 714} 715 716// NewSignerFromSigner takes any crypto.Signer implementation and 717// returns a corresponding Signer interface. This can be used, for 718// example, with keys kept in hardware modules. 719func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { 720 pubKey, err := NewPublicKey(signer.Public()) 721 if err != nil { 722 return nil, err 723 } 724 725 return &wrappedSigner{signer, pubKey}, nil 726} 727 728func (s *wrappedSigner) PublicKey() PublicKey { 729 return s.pubKey 730} 731 732func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 733 return s.SignWithAlgorithm(rand, data, "") 734} 735 736func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { 737 var hashFunc crypto.Hash 738 739 if _, ok := s.pubKey.(*rsaPublicKey); ok { 740 // RSA keys support a few hash functions determined by the requested signature algorithm 741 switch algorithm { 742 case "", SigAlgoRSA: 743 algorithm = SigAlgoRSA 744 hashFunc = crypto.SHA1 745 case SigAlgoRSASHA2256: 746 hashFunc = crypto.SHA256 747 case SigAlgoRSASHA2512: 748 hashFunc = crypto.SHA512 749 default: 750 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 751 } 752 } else { 753 // The only supported algorithm for all other key types is the same as the type of the key 754 if algorithm == "" { 755 algorithm = s.pubKey.Type() 756 } else if algorithm != s.pubKey.Type() { 757 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 758 } 759 760 switch key := s.pubKey.(type) { 761 case *dsaPublicKey: 762 hashFunc = crypto.SHA1 763 case *ecdsaPublicKey: 764 hashFunc = ecHash(key.Curve) 765 case ed25519PublicKey: 766 default: 767 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 768 } 769 } 770 771 var digest []byte 772 if hashFunc != 0 { 773 h := hashFunc.New() 774 h.Write(data) 775 digest = h.Sum(nil) 776 } else { 777 digest = data 778 } 779 780 signature, err := s.signer.Sign(rand, digest, hashFunc) 781 if err != nil { 782 return nil, err 783 } 784 785 // crypto.Signer.Sign is expected to return an ASN.1-encoded signature 786 // for ECDSA and DSA, but that's not the encoding expected by SSH, so 787 // re-encode. 788 switch s.pubKey.(type) { 789 case *ecdsaPublicKey, *dsaPublicKey: 790 type asn1Signature struct { 791 R, S *big.Int 792 } 793 asn1Sig := new(asn1Signature) 794 _, err := asn1.Unmarshal(signature, asn1Sig) 795 if err != nil { 796 return nil, err 797 } 798 799 switch s.pubKey.(type) { 800 case *ecdsaPublicKey: 801 signature = Marshal(asn1Sig) 802 803 case *dsaPublicKey: 804 signature = make([]byte, 40) 805 r := asn1Sig.R.Bytes() 806 s := asn1Sig.S.Bytes() 807 copy(signature[20-len(r):20], r) 808 copy(signature[40-len(s):40], s) 809 } 810 } 811 812 return &Signature{ 813 Format: algorithm, 814 Blob: signature, 815 }, nil 816} 817 818// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, 819// or ed25519.PublicKey returns a corresponding PublicKey instance. 820// ECDSA keys must use P-256, P-384 or P-521. 821func NewPublicKey(key interface{}) (PublicKey, error) { 822 switch key := key.(type) { 823 case *rsa.PublicKey: 824 return (*rsaPublicKey)(key), nil 825 case *ecdsa.PublicKey: 826 if !supportedEllipticCurve(key.Curve) { 827 return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") 828 } 829 return (*ecdsaPublicKey)(key), nil 830 case *dsa.PublicKey: 831 return (*dsaPublicKey)(key), nil 832 case ed25519.PublicKey: 833 return (ed25519PublicKey)(key), nil 834 default: 835 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 836 } 837} 838 839// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports 840// the same keys as ParseRawPrivateKey. 841func ParsePrivateKey(pemBytes []byte) (Signer, error) { 842 key, err := ParseRawPrivateKey(pemBytes) 843 if err != nil { 844 return nil, err 845 } 846 847 return NewSignerFromKey(key) 848} 849 850// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private 851// key and passphrase. It supports the same keys as 852// ParseRawPrivateKeyWithPassphrase. 853func ParsePrivateKeyWithPassphrase(pemBytes, passPhrase []byte) (Signer, error) { 854 key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passPhrase) 855 if err != nil { 856 return nil, err 857 } 858 859 return NewSignerFromKey(key) 860} 861 862// encryptedBlock tells whether a private key is 863// encrypted by examining its Proc-Type header 864// for a mention of ENCRYPTED 865// according to RFC 1421 Section 4.6.1.1. 866func encryptedBlock(block *pem.Block) bool { 867 return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") 868} 869 870// ParseRawPrivateKey returns a private key from a PEM encoded private key. It 871// supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. 872func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { 873 block, _ := pem.Decode(pemBytes) 874 if block == nil { 875 return nil, errors.New("ssh: no key found") 876 } 877 878 if encryptedBlock(block) { 879 return nil, errors.New("ssh: cannot decode encrypted private keys") 880 } 881 882 switch block.Type { 883 case "RSA PRIVATE KEY": 884 return x509.ParsePKCS1PrivateKey(block.Bytes) 885 // RFC5208 - https://tools.ietf.org/html/rfc5208 886 case "PRIVATE KEY": 887 return x509.ParsePKCS8PrivateKey(block.Bytes) 888 case "EC PRIVATE KEY": 889 return x509.ParseECPrivateKey(block.Bytes) 890 case "DSA PRIVATE KEY": 891 return ParseDSAPrivateKey(block.Bytes) 892 case "OPENSSH PRIVATE KEY": 893 return parseOpenSSHPrivateKey(block.Bytes) 894 default: 895 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) 896 } 897} 898 899// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with 900// passphrase from a PEM encoded private key. If wrong passphrase, return 901// x509.IncorrectPasswordError. 902func ParseRawPrivateKeyWithPassphrase(pemBytes, passPhrase []byte) (interface{}, error) { 903 block, _ := pem.Decode(pemBytes) 904 if block == nil { 905 return nil, errors.New("ssh: no key found") 906 } 907 buf := block.Bytes 908 909 if encryptedBlock(block) { 910 if x509.IsEncryptedPEMBlock(block) { 911 var err error 912 buf, err = x509.DecryptPEMBlock(block, passPhrase) 913 if err != nil { 914 if err == x509.IncorrectPasswordError { 915 return nil, err 916 } 917 return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) 918 } 919 } 920 } 921 922 switch block.Type { 923 case "RSA PRIVATE KEY": 924 return x509.ParsePKCS1PrivateKey(buf) 925 case "EC PRIVATE KEY": 926 return x509.ParseECPrivateKey(buf) 927 case "DSA PRIVATE KEY": 928 return ParseDSAPrivateKey(buf) 929 case "OPENSSH PRIVATE KEY": 930 return parseOpenSSHPrivateKey(buf) 931 default: 932 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) 933 } 934} 935 936// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as 937// specified by the OpenSSL DSA man page. 938func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { 939 var k struct { 940 Version int 941 P *big.Int 942 Q *big.Int 943 G *big.Int 944 Pub *big.Int 945 Priv *big.Int 946 } 947 rest, err := asn1.Unmarshal(der, &k) 948 if err != nil { 949 return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) 950 } 951 if len(rest) > 0 { 952 return nil, errors.New("ssh: garbage after DSA key") 953 } 954 955 return &dsa.PrivateKey{ 956 PublicKey: dsa.PublicKey{ 957 Parameters: dsa.Parameters{ 958 P: k.P, 959 Q: k.Q, 960 G: k.G, 961 }, 962 Y: k.Pub, 963 }, 964 X: k.Priv, 965 }, nil 966} 967 968// Implemented based on the documentation at 969// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key 970func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) { 971 const magic = "openssh-key-v1\x00" 972 if len(key) < len(magic) || string(key[:len(magic)]) != magic { 973 return nil, errors.New("ssh: invalid openssh private key format") 974 } 975 remaining := key[len(magic):] 976 977 var w struct { 978 CipherName string 979 KdfName string 980 KdfOpts string 981 NumKeys uint32 982 PubKey []byte 983 PrivKeyBlock []byte 984 } 985 986 if err := Unmarshal(remaining, &w); err != nil { 987 return nil, err 988 } 989 990 if w.KdfName != "none" || w.CipherName != "none" { 991 return nil, errors.New("ssh: cannot decode encrypted private keys") 992 } 993 994 pk1 := struct { 995 Check1 uint32 996 Check2 uint32 997 Keytype string 998 Rest []byte `ssh:"rest"` 999 }{} 1000 1001 if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil { 1002 return nil, err 1003 } 1004 1005 if pk1.Check1 != pk1.Check2 { 1006 return nil, errors.New("ssh: checkint mismatch") 1007 } 1008 1009 // we only handle ed25519 and rsa keys currently 1010 switch pk1.Keytype { 1011 case KeyAlgoRSA: 1012 // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773 1013 key := struct { 1014 N *big.Int 1015 E *big.Int 1016 D *big.Int 1017 Iqmp *big.Int 1018 P *big.Int 1019 Q *big.Int 1020 Comment string 1021 Pad []byte `ssh:"rest"` 1022 }{} 1023 1024 if err := Unmarshal(pk1.Rest, &key); err != nil { 1025 return nil, err 1026 } 1027 1028 for i, b := range key.Pad { 1029 if int(b) != i+1 { 1030 return nil, errors.New("ssh: padding not as expected") 1031 } 1032 } 1033 1034 pk := &rsa.PrivateKey{ 1035 PublicKey: rsa.PublicKey{ 1036 N: key.N, 1037 E: int(key.E.Int64()), 1038 }, 1039 D: key.D, 1040 Primes: []*big.Int{key.P, key.Q}, 1041 } 1042 1043 if err := pk.Validate(); err != nil { 1044 return nil, err 1045 } 1046 1047 pk.Precompute() 1048 1049 return pk, nil 1050 case KeyAlgoED25519: 1051 key := struct { 1052 Pub []byte 1053 Priv []byte 1054 Comment string 1055 Pad []byte `ssh:"rest"` 1056 }{} 1057 1058 if err := Unmarshal(pk1.Rest, &key); err != nil { 1059 return nil, err 1060 } 1061 1062 if len(key.Priv) != ed25519.PrivateKeySize { 1063 return nil, errors.New("ssh: private key unexpected length") 1064 } 1065 1066 for i, b := range key.Pad { 1067 if int(b) != i+1 { 1068 return nil, errors.New("ssh: padding not as expected") 1069 } 1070 } 1071 1072 pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) 1073 copy(pk, key.Priv) 1074 return &pk, nil 1075 default: 1076 return nil, errors.New("ssh: unhandled key type") 1077 } 1078} 1079 1080// FingerprintLegacyMD5 returns the user presentation of the key's 1081// fingerprint as described by RFC 4716 section 4. 1082func FingerprintLegacyMD5(pubKey PublicKey) string { 1083 md5sum := md5.Sum(pubKey.Marshal()) 1084 hexarray := make([]string, len(md5sum)) 1085 for i, c := range md5sum { 1086 hexarray[i] = hex.EncodeToString([]byte{c}) 1087 } 1088 return strings.Join(hexarray, ":") 1089} 1090 1091// FingerprintSHA256 returns the user presentation of the key's 1092// fingerprint as unpadded base64 encoded sha256 hash. 1093// This format was introduced from OpenSSH 6.8. 1094// https://www.openssh.com/txt/release-6.8 1095// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) 1096func FingerprintSHA256(pubKey PublicKey) string { 1097 sha256sum := sha256.Sum256(pubKey.Marshal()) 1098 hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) 1099 return "SHA256:" + hash 1100} 1101