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