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