github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/common/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/aes" 11 "crypto/cipher" 12 "crypto/dsa" 13 "crypto/ecdsa" 14 "crypto/elliptic" 15 "crypto/md5" 16 "crypto/rsa" 17 "crypto/sha256" 18 "crypto/x509" 19 "encoding/asn1" 20 "encoding/base64" 21 "encoding/hex" 22 "encoding/pem" 23 "errors" 24 "fmt" 25 "io" 26 "math/big" 27 "strings" 28 29 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh/internal/bcrypt_pbkdf" 30 "golang.org/x/crypto/ed25519" 31 ) 32 33 // These constants represent the algorithm names for key types supported by this 34 // package. 35 const ( 36 KeyAlgoRSA = "ssh-rsa" 37 KeyAlgoDSA = "ssh-dss" 38 KeyAlgoECDSA256 = "ecdsa-sha2-nistp256" 39 KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com" 40 KeyAlgoECDSA384 = "ecdsa-sha2-nistp384" 41 KeyAlgoECDSA521 = "ecdsa-sha2-nistp521" 42 KeyAlgoED25519 = "ssh-ed25519" 43 KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com" 44 ) 45 46 // These constants represent non-default signature algorithms that are supported 47 // as algorithm parameters to AlgorithmSigner.SignWithAlgorithm methods. See 48 // [PROTOCOL.agent] section 4.5.1 and 49 // https://tools.ietf.org/html/draft-ietf-curdle-rsa-sha2-10 50 const ( 51 SigAlgoRSA = "ssh-rsa" 52 SigAlgoRSASHA2256 = "rsa-sha2-256" 53 SigAlgoRSASHA2512 = "rsa-sha2-512" 54 ) 55 56 // parsePubKey parses a public key of the given algorithm. 57 // Use ParsePublicKey for keys with prepended algorithm. 58 func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) { 59 switch algo { 60 case KeyAlgoRSA: 61 return parseRSA(in) 62 case KeyAlgoDSA: 63 return parseDSA(in) 64 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: 65 return parseECDSA(in) 66 case KeyAlgoSKECDSA256: 67 return parseSKECDSA(in) 68 case KeyAlgoED25519: 69 return parseED25519(in) 70 case KeyAlgoSKED25519: 71 return parseSKEd25519(in) 72 case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01: 73 cert, err := parseCert(in, certToPrivAlgo(algo)) 74 if err != nil { 75 return nil, nil, err 76 } 77 return cert, nil, nil 78 } 79 return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo) 80 } 81 82 // parseAuthorizedKey parses a public key in OpenSSH authorized_keys format 83 // (see sshd(8) manual page) once the options and key type fields have been 84 // removed. 85 func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) { 86 in = bytes.TrimSpace(in) 87 88 i := bytes.IndexAny(in, " \t") 89 if i == -1 { 90 i = len(in) 91 } 92 base64Key := in[:i] 93 94 key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key))) 95 n, err := base64.StdEncoding.Decode(key, base64Key) 96 if err != nil { 97 return nil, "", err 98 } 99 key = key[:n] 100 out, err = ParsePublicKey(key) 101 if err != nil { 102 return nil, "", err 103 } 104 comment = string(bytes.TrimSpace(in[i:])) 105 return out, comment, nil 106 } 107 108 // ParseKnownHosts parses an entry in the format of the known_hosts file. 109 // 110 // The known_hosts format is documented in the sshd(8) manual page. This 111 // function will parse a single entry from in. On successful return, marker 112 // will contain the optional marker value (i.e. "cert-authority" or "revoked") 113 // or else be empty, hosts will contain the hosts that this entry matches, 114 // pubKey will contain the public key and comment will contain any trailing 115 // comment at the end of the line. See the sshd(8) manual page for the various 116 // forms that a host string can take. 117 // 118 // The unparsed remainder of the input will be returned in rest. This function 119 // can be called repeatedly to parse multiple entries. 120 // 121 // If no entries were found in the input then err will be io.EOF. Otherwise a 122 // non-nil err value indicates a parse error. 123 func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) { 124 for len(in) > 0 { 125 end := bytes.IndexByte(in, '\n') 126 if end != -1 { 127 rest = in[end+1:] 128 in = in[:end] 129 } else { 130 rest = nil 131 } 132 133 end = bytes.IndexByte(in, '\r') 134 if end != -1 { 135 in = in[:end] 136 } 137 138 in = bytes.TrimSpace(in) 139 if len(in) == 0 || in[0] == '#' { 140 in = rest 141 continue 142 } 143 144 i := bytes.IndexAny(in, " \t") 145 if i == -1 { 146 in = rest 147 continue 148 } 149 150 // Strip out the beginning of the known_host key. 151 // This is either an optional marker or a (set of) hostname(s). 152 keyFields := bytes.Fields(in) 153 if len(keyFields) < 3 || len(keyFields) > 5 { 154 return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data") 155 } 156 157 // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated 158 // list of hosts 159 marker := "" 160 if keyFields[0][0] == '@' { 161 marker = string(keyFields[0][1:]) 162 keyFields = keyFields[1:] 163 } 164 165 hosts := string(keyFields[0]) 166 // keyFields[1] contains the key type (e.g. “ssh-rsa”). 167 // However, that information is duplicated inside the 168 // base64-encoded key and so is ignored here. 169 170 key := bytes.Join(keyFields[2:], []byte(" ")) 171 if pubKey, comment, err = parseAuthorizedKey(key); err != nil { 172 return "", nil, nil, "", nil, err 173 } 174 175 return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil 176 } 177 178 return "", nil, nil, "", nil, io.EOF 179 } 180 181 // ParseAuthorizedKeys parses a public key from an authorized_keys 182 // file used in OpenSSH according to the sshd(8) manual page. 183 func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) { 184 for len(in) > 0 { 185 end := bytes.IndexByte(in, '\n') 186 if end != -1 { 187 rest = in[end+1:] 188 in = in[:end] 189 } else { 190 rest = nil 191 } 192 193 end = bytes.IndexByte(in, '\r') 194 if end != -1 { 195 in = in[:end] 196 } 197 198 in = bytes.TrimSpace(in) 199 if len(in) == 0 || in[0] == '#' { 200 in = rest 201 continue 202 } 203 204 i := bytes.IndexAny(in, " \t") 205 if i == -1 { 206 in = rest 207 continue 208 } 209 210 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { 211 return out, comment, options, rest, nil 212 } 213 214 // No key type recognised. Maybe there's an options field at 215 // the beginning. 216 var b byte 217 inQuote := false 218 var candidateOptions []string 219 optionStart := 0 220 for i, b = range in { 221 isEnd := !inQuote && (b == ' ' || b == '\t') 222 if (b == ',' && !inQuote) || isEnd { 223 if i-optionStart > 0 { 224 candidateOptions = append(candidateOptions, string(in[optionStart:i])) 225 } 226 optionStart = i + 1 227 } 228 if isEnd { 229 break 230 } 231 if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) { 232 inQuote = !inQuote 233 } 234 } 235 for i < len(in) && (in[i] == ' ' || in[i] == '\t') { 236 i++ 237 } 238 if i == len(in) { 239 // Invalid line: unmatched quote 240 in = rest 241 continue 242 } 243 244 in = in[i:] 245 i = bytes.IndexAny(in, " \t") 246 if i == -1 { 247 in = rest 248 continue 249 } 250 251 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil { 252 options = candidateOptions 253 return out, comment, options, rest, nil 254 } 255 256 in = rest 257 continue 258 } 259 260 return nil, "", nil, nil, errors.New("ssh: no key found") 261 } 262 263 // ParsePublicKey parses an SSH public key formatted for use in 264 // the SSH wire protocol according to RFC 4253, section 6.6. 265 func ParsePublicKey(in []byte) (out PublicKey, err error) { 266 algo, in, ok := parseString(in) 267 if !ok { 268 return nil, errShortRead 269 } 270 var rest []byte 271 out, rest, err = parsePubKey(in, string(algo)) 272 if len(rest) > 0 { 273 return nil, errors.New("ssh: trailing junk in public key") 274 } 275 276 return out, err 277 } 278 279 // MarshalAuthorizedKey serializes key for inclusion in an OpenSSH 280 // authorized_keys file. The return value ends with newline. 281 func MarshalAuthorizedKey(key PublicKey) []byte { 282 b := &bytes.Buffer{} 283 b.WriteString(key.Type()) 284 b.WriteByte(' ') 285 e := base64.NewEncoder(base64.StdEncoding, b) 286 e.Write(key.Marshal()) 287 e.Close() 288 b.WriteByte('\n') 289 return b.Bytes() 290 } 291 292 // PublicKey is an abstraction of different types of public keys. 293 type PublicKey interface { 294 // Type returns the key's type, e.g. "ssh-rsa". 295 Type() string 296 297 // Marshal returns the serialized key data in SSH wire format, 298 // with the name prefix. To unmarshal the returned data, use 299 // the ParsePublicKey function. 300 Marshal() []byte 301 302 // Verify that sig is a signature on the given data using this 303 // key. This function will hash the data appropriately first. 304 Verify(data []byte, sig *Signature) error 305 } 306 307 // CryptoPublicKey, if implemented by a PublicKey, 308 // returns the underlying crypto.PublicKey form of the key. 309 type CryptoPublicKey interface { 310 CryptoPublicKey() crypto.PublicKey 311 } 312 313 // A Signer can create signatures that verify against a public key. 314 type Signer interface { 315 // PublicKey returns an associated PublicKey instance. 316 PublicKey() PublicKey 317 318 // Sign returns raw signature for the given data. This method 319 // will apply the hash specified for the keytype to the data. 320 Sign(rand io.Reader, data []byte) (*Signature, error) 321 } 322 323 // A AlgorithmSigner is a Signer that also supports specifying a specific 324 // algorithm to use for signing. 325 type AlgorithmSigner interface { 326 Signer 327 328 // SignWithAlgorithm is like Signer.Sign, but allows specification of a 329 // non-default signing algorithm. See the SigAlgo* constants in this 330 // package for signature algorithms supported by this package. Callers may 331 // pass an empty string for the algorithm in which case the AlgorithmSigner 332 // will use its default algorithm. 333 SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) 334 } 335 336 type rsaPublicKey rsa.PublicKey 337 338 func (r *rsaPublicKey) Type() string { 339 return "ssh-rsa" 340 } 341 342 // parseRSA parses an RSA key according to RFC 4253, section 6.6. 343 func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { 344 var w struct { 345 E *big.Int 346 N *big.Int 347 Rest []byte `ssh:"rest"` 348 } 349 if err := Unmarshal(in, &w); err != nil { 350 return nil, nil, err 351 } 352 353 if w.E.BitLen() > 24 { 354 return nil, nil, errors.New("ssh: exponent too large") 355 } 356 e := w.E.Int64() 357 if e < 3 || e&1 == 0 { 358 return nil, nil, errors.New("ssh: incorrect exponent") 359 } 360 361 var key rsa.PublicKey 362 key.E = int(e) 363 key.N = w.N 364 return (*rsaPublicKey)(&key), w.Rest, nil 365 } 366 367 func (r *rsaPublicKey) Marshal() []byte { 368 e := new(big.Int).SetInt64(int64(r.E)) 369 // RSA publickey struct layout should match the struct used by 370 // parseRSACert in the x/crypto/ssh/agent package. 371 wirekey := struct { 372 Name string 373 E *big.Int 374 N *big.Int 375 }{ 376 KeyAlgoRSA, 377 e, 378 r.N, 379 } 380 return Marshal(&wirekey) 381 } 382 383 func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error { 384 var hash crypto.Hash 385 switch sig.Format { 386 case SigAlgoRSA: 387 hash = crypto.SHA1 388 case SigAlgoRSASHA2256: 389 hash = crypto.SHA256 390 case SigAlgoRSASHA2512: 391 hash = crypto.SHA512 392 default: 393 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type()) 394 } 395 h := hash.New() 396 h.Write(data) 397 digest := h.Sum(nil) 398 return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, sig.Blob) 399 } 400 401 func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { 402 return (*rsa.PublicKey)(r) 403 } 404 405 type dsaPublicKey dsa.PublicKey 406 407 func (k *dsaPublicKey) Type() string { 408 return "ssh-dss" 409 } 410 411 func checkDSAParams(param *dsa.Parameters) error { 412 // SSH specifies FIPS 186-2, which only provided a single size 413 // (1024 bits) DSA key. FIPS 186-3 allows for larger key 414 // sizes, which would confuse SSH. 415 if l := param.P.BitLen(); l != 1024 { 416 return fmt.Errorf("ssh: unsupported DSA key size %d", l) 417 } 418 419 return nil 420 } 421 422 // parseDSA parses an DSA key according to RFC 4253, section 6.6. 423 func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { 424 var w struct { 425 P, Q, G, Y *big.Int 426 Rest []byte `ssh:"rest"` 427 } 428 if err := Unmarshal(in, &w); err != nil { 429 return nil, nil, err 430 } 431 432 param := dsa.Parameters{ 433 P: w.P, 434 Q: w.Q, 435 G: w.G, 436 } 437 if err := checkDSAParams(¶m); err != nil { 438 return nil, nil, err 439 } 440 441 key := &dsaPublicKey{ 442 Parameters: param, 443 Y: w.Y, 444 } 445 return key, w.Rest, nil 446 } 447 448 func (k *dsaPublicKey) Marshal() []byte { 449 // DSA publickey struct layout should match the struct used by 450 // parseDSACert in the x/crypto/ssh/agent package. 451 w := struct { 452 Name string 453 P, Q, G, Y *big.Int 454 }{ 455 k.Type(), 456 k.P, 457 k.Q, 458 k.G, 459 k.Y, 460 } 461 462 return Marshal(&w) 463 } 464 465 func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error { 466 if sig.Format != k.Type() { 467 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 468 } 469 h := crypto.SHA1.New() 470 h.Write(data) 471 digest := h.Sum(nil) 472 473 // Per RFC 4253, section 6.6, 474 // The value for 'dss_signature_blob' is encoded as a string containing 475 // r, followed by s (which are 160-bit integers, without lengths or 476 // padding, unsigned, and in network byte order). 477 // For DSS purposes, sig.Blob should be exactly 40 bytes in length. 478 if len(sig.Blob) != 40 { 479 return errors.New("ssh: DSA signature parse error") 480 } 481 r := new(big.Int).SetBytes(sig.Blob[:20]) 482 s := new(big.Int).SetBytes(sig.Blob[20:]) 483 if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) { 484 return nil 485 } 486 return errors.New("ssh: signature did not verify") 487 } 488 489 func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { 490 return (*dsa.PublicKey)(k) 491 } 492 493 type dsaPrivateKey struct { 494 *dsa.PrivateKey 495 } 496 497 func (k *dsaPrivateKey) PublicKey() PublicKey { 498 return (*dsaPublicKey)(&k.PrivateKey.PublicKey) 499 } 500 501 func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { 502 return k.SignWithAlgorithm(rand, data, "") 503 } 504 505 func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { 506 if algorithm != "" && algorithm != k.PublicKey().Type() { 507 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 508 } 509 510 h := crypto.SHA1.New() 511 h.Write(data) 512 digest := h.Sum(nil) 513 r, s, err := dsa.Sign(rand, k.PrivateKey, digest) 514 if err != nil { 515 return nil, err 516 } 517 518 sig := make([]byte, 40) 519 rb := r.Bytes() 520 sb := s.Bytes() 521 522 copy(sig[20-len(rb):20], rb) 523 copy(sig[40-len(sb):], sb) 524 525 return &Signature{ 526 Format: k.PublicKey().Type(), 527 Blob: sig, 528 }, nil 529 } 530 531 type ecdsaPublicKey ecdsa.PublicKey 532 533 func (k *ecdsaPublicKey) Type() string { 534 return "ecdsa-sha2-" + k.nistID() 535 } 536 537 func (k *ecdsaPublicKey) nistID() string { 538 switch k.Params().BitSize { 539 case 256: 540 return "nistp256" 541 case 384: 542 return "nistp384" 543 case 521: 544 return "nistp521" 545 } 546 panic("ssh: unsupported ecdsa key size") 547 } 548 549 type ed25519PublicKey ed25519.PublicKey 550 551 func (k ed25519PublicKey) Type() string { 552 return KeyAlgoED25519 553 } 554 555 func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { 556 var w struct { 557 KeyBytes []byte 558 Rest []byte `ssh:"rest"` 559 } 560 561 if err := Unmarshal(in, &w); err != nil { 562 return nil, nil, err 563 } 564 565 if l := len(w.KeyBytes); l != ed25519.PublicKeySize { 566 return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) 567 } 568 569 return ed25519PublicKey(w.KeyBytes), w.Rest, nil 570 } 571 572 func (k ed25519PublicKey) Marshal() []byte { 573 w := struct { 574 Name string 575 KeyBytes []byte 576 }{ 577 KeyAlgoED25519, 578 []byte(k), 579 } 580 return Marshal(&w) 581 } 582 583 func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error { 584 if sig.Format != k.Type() { 585 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 586 } 587 if l := len(k); l != ed25519.PublicKeySize { 588 return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) 589 } 590 591 if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok { 592 return errors.New("ssh: signature did not verify") 593 } 594 595 return nil 596 } 597 598 func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { 599 return ed25519.PublicKey(k) 600 } 601 602 func supportedEllipticCurve(curve elliptic.Curve) bool { 603 return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() 604 } 605 606 // ecHash returns the hash to match the given elliptic curve, see RFC 607 // 5656, section 6.2.1 608 func ecHash(curve elliptic.Curve) crypto.Hash { 609 bitSize := curve.Params().BitSize 610 switch { 611 case bitSize <= 256: 612 return crypto.SHA256 613 case bitSize <= 384: 614 return crypto.SHA384 615 } 616 return crypto.SHA512 617 } 618 619 // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. 620 func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { 621 var w struct { 622 Curve string 623 KeyBytes []byte 624 Rest []byte `ssh:"rest"` 625 } 626 627 if err := Unmarshal(in, &w); err != nil { 628 return nil, nil, err 629 } 630 631 key := new(ecdsa.PublicKey) 632 633 switch w.Curve { 634 case "nistp256": 635 key.Curve = elliptic.P256() 636 case "nistp384": 637 key.Curve = elliptic.P384() 638 case "nistp521": 639 key.Curve = elliptic.P521() 640 default: 641 return nil, nil, errors.New("ssh: unsupported curve") 642 } 643 644 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) 645 if key.X == nil || key.Y == nil { 646 return nil, nil, errors.New("ssh: invalid curve point") 647 } 648 return (*ecdsaPublicKey)(key), w.Rest, nil 649 } 650 651 func (k *ecdsaPublicKey) Marshal() []byte { 652 // See RFC 5656, section 3.1. 653 keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) 654 // ECDSA publickey struct layout should match the struct used by 655 // parseECDSACert in the x/crypto/ssh/agent package. 656 w := struct { 657 Name string 658 ID string 659 Key []byte 660 }{ 661 k.Type(), 662 k.nistID(), 663 keyBytes, 664 } 665 666 return Marshal(&w) 667 } 668 669 func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error { 670 if sig.Format != k.Type() { 671 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 672 } 673 674 h := ecHash(k.Curve).New() 675 h.Write(data) 676 digest := h.Sum(nil) 677 678 // Per RFC 5656, section 3.1.2, 679 // The ecdsa_signature_blob value has the following specific encoding: 680 // mpint r 681 // mpint s 682 var ecSig struct { 683 R *big.Int 684 S *big.Int 685 } 686 687 if err := Unmarshal(sig.Blob, &ecSig); err != nil { 688 return err 689 } 690 691 if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) { 692 return nil 693 } 694 return errors.New("ssh: signature did not verify") 695 } 696 697 func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { 698 return (*ecdsa.PublicKey)(k) 699 } 700 701 // skFields holds the additional fields present in U2F/FIDO2 signatures. 702 // See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details. 703 type skFields struct { 704 // Flags contains U2F/FIDO2 flags such as 'user present' 705 Flags byte 706 // Counter is a monotonic signature counter which can be 707 // used to detect concurrent use of a private key, should 708 // it be extracted from hardware. 709 Counter uint32 710 } 711 712 type skECDSAPublicKey struct { 713 // application is a URL-like string, typically "ssh:" for SSH. 714 // see openssh/PROTOCOL.u2f for details. 715 application string 716 ecdsa.PublicKey 717 } 718 719 func (k *skECDSAPublicKey) Type() string { 720 return KeyAlgoSKECDSA256 721 } 722 723 func (k *skECDSAPublicKey) nistID() string { 724 return "nistp256" 725 } 726 727 func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) { 728 var w struct { 729 Curve string 730 KeyBytes []byte 731 Application string 732 Rest []byte `ssh:"rest"` 733 } 734 735 if err := Unmarshal(in, &w); err != nil { 736 return nil, nil, err 737 } 738 739 key := new(skECDSAPublicKey) 740 key.application = w.Application 741 742 if w.Curve != "nistp256" { 743 return nil, nil, errors.New("ssh: unsupported curve") 744 } 745 key.Curve = elliptic.P256() 746 747 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes) 748 if key.X == nil || key.Y == nil { 749 return nil, nil, errors.New("ssh: invalid curve point") 750 } 751 752 return key, w.Rest, nil 753 } 754 755 func (k *skECDSAPublicKey) Marshal() []byte { 756 // See RFC 5656, section 3.1. 757 keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y) 758 w := struct { 759 Name string 760 ID string 761 Key []byte 762 Application string 763 }{ 764 k.Type(), 765 k.nistID(), 766 keyBytes, 767 k.application, 768 } 769 770 return Marshal(&w) 771 } 772 773 func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error { 774 if sig.Format != k.Type() { 775 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 776 } 777 778 h := ecHash(k.Curve).New() 779 h.Write([]byte(k.application)) 780 appDigest := h.Sum(nil) 781 782 h.Reset() 783 h.Write(data) 784 dataDigest := h.Sum(nil) 785 786 var ecSig struct { 787 R *big.Int 788 S *big.Int 789 } 790 if err := Unmarshal(sig.Blob, &ecSig); err != nil { 791 return err 792 } 793 794 var skf skFields 795 if err := Unmarshal(sig.Rest, &skf); err != nil { 796 return err 797 } 798 799 blob := struct { 800 ApplicationDigest []byte `ssh:"rest"` 801 Flags byte 802 Counter uint32 803 MessageDigest []byte `ssh:"rest"` 804 }{ 805 appDigest, 806 skf.Flags, 807 skf.Counter, 808 dataDigest, 809 } 810 811 original := Marshal(blob) 812 813 h.Reset() 814 h.Write(original) 815 digest := h.Sum(nil) 816 817 if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) { 818 return nil 819 } 820 return errors.New("ssh: signature did not verify") 821 } 822 823 type skEd25519PublicKey struct { 824 // application is a URL-like string, typically "ssh:" for SSH. 825 // see openssh/PROTOCOL.u2f for details. 826 application string 827 ed25519.PublicKey 828 } 829 830 func (k *skEd25519PublicKey) Type() string { 831 return KeyAlgoSKED25519 832 } 833 834 func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) { 835 var w struct { 836 KeyBytes []byte 837 Application string 838 Rest []byte `ssh:"rest"` 839 } 840 841 if err := Unmarshal(in, &w); err != nil { 842 return nil, nil, err 843 } 844 845 if l := len(w.KeyBytes); l != ed25519.PublicKeySize { 846 return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l) 847 } 848 849 key := new(skEd25519PublicKey) 850 key.application = w.Application 851 key.PublicKey = ed25519.PublicKey(w.KeyBytes) 852 853 return key, w.Rest, nil 854 } 855 856 func (k *skEd25519PublicKey) Marshal() []byte { 857 w := struct { 858 Name string 859 KeyBytes []byte 860 Application string 861 }{ 862 KeyAlgoSKED25519, 863 []byte(k.PublicKey), 864 k.application, 865 } 866 return Marshal(&w) 867 } 868 869 func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error { 870 if sig.Format != k.Type() { 871 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type()) 872 } 873 if l := len(k.PublicKey); l != ed25519.PublicKeySize { 874 return fmt.Errorf("invalid size %d for Ed25519 public key", l) 875 } 876 877 h := sha256.New() 878 h.Write([]byte(k.application)) 879 appDigest := h.Sum(nil) 880 881 h.Reset() 882 h.Write(data) 883 dataDigest := h.Sum(nil) 884 885 var edSig struct { 886 Signature []byte `ssh:"rest"` 887 } 888 889 if err := Unmarshal(sig.Blob, &edSig); err != nil { 890 return err 891 } 892 893 var skf skFields 894 if err := Unmarshal(sig.Rest, &skf); err != nil { 895 return err 896 } 897 898 blob := struct { 899 ApplicationDigest []byte `ssh:"rest"` 900 Flags byte 901 Counter uint32 902 MessageDigest []byte `ssh:"rest"` 903 }{ 904 appDigest, 905 skf.Flags, 906 skf.Counter, 907 dataDigest, 908 } 909 910 original := Marshal(blob) 911 912 if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok { 913 return errors.New("ssh: signature did not verify") 914 } 915 916 return nil 917 } 918 919 // NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey, 920 // *ecdsa.PrivateKey or any other crypto.Signer and returns a 921 // corresponding Signer instance. ECDSA keys must use P-256, P-384 or 922 // P-521. DSA keys must use parameter size L1024N160. 923 func NewSignerFromKey(key interface{}) (Signer, error) { 924 switch key := key.(type) { 925 case crypto.Signer: 926 return NewSignerFromSigner(key) 927 case *dsa.PrivateKey: 928 return newDSAPrivateKey(key) 929 default: 930 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 931 } 932 } 933 934 func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) { 935 if err := checkDSAParams(&key.PublicKey.Parameters); err != nil { 936 return nil, err 937 } 938 939 return &dsaPrivateKey{key}, nil 940 } 941 942 type rsaSigner struct { 943 AlgorithmSigner 944 defaultAlgorithm string 945 } 946 947 func (s *rsaSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 948 return s.AlgorithmSigner.SignWithAlgorithm(rand, data, s.defaultAlgorithm) 949 } 950 951 type wrappedSigner struct { 952 signer crypto.Signer 953 pubKey PublicKey 954 } 955 956 // NewSignerFromSigner takes any crypto.Signer implementation and 957 // returns a corresponding Signer interface. This can be used, for 958 // example, with keys kept in hardware modules. 959 func NewSignerFromSigner(signer crypto.Signer) (Signer, error) { 960 pubKey, err := NewPublicKey(signer.Public()) 961 if err != nil { 962 return nil, err 963 } 964 965 return &wrappedSigner{signer, pubKey}, nil 966 } 967 968 func (s *wrappedSigner) PublicKey() PublicKey { 969 return s.pubKey 970 } 971 972 func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { 973 return s.SignWithAlgorithm(rand, data, "") 974 } 975 976 func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) { 977 var hashFunc crypto.Hash 978 979 if _, ok := s.pubKey.(*rsaPublicKey); ok { 980 // RSA keys support a few hash functions determined by the requested signature algorithm 981 switch algorithm { 982 case "", SigAlgoRSA: 983 algorithm = SigAlgoRSA 984 hashFunc = crypto.SHA1 985 case SigAlgoRSASHA2256: 986 hashFunc = crypto.SHA256 987 case SigAlgoRSASHA2512: 988 hashFunc = crypto.SHA512 989 default: 990 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 991 } 992 } else { 993 // The only supported algorithm for all other key types is the same as the type of the key 994 if algorithm == "" { 995 algorithm = s.pubKey.Type() 996 } else if algorithm != s.pubKey.Type() { 997 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm) 998 } 999 1000 switch key := s.pubKey.(type) { 1001 case *dsaPublicKey: 1002 hashFunc = crypto.SHA1 1003 case *ecdsaPublicKey: 1004 hashFunc = ecHash(key.Curve) 1005 case ed25519PublicKey: 1006 default: 1007 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 1008 } 1009 } 1010 1011 var digest []byte 1012 if hashFunc != 0 { 1013 h := hashFunc.New() 1014 h.Write(data) 1015 digest = h.Sum(nil) 1016 } else { 1017 digest = data 1018 } 1019 1020 signature, err := s.signer.Sign(rand, digest, hashFunc) 1021 if err != nil { 1022 return nil, err 1023 } 1024 1025 // crypto.Signer.Sign is expected to return an ASN.1-encoded signature 1026 // for ECDSA and DSA, but that's not the encoding expected by SSH, so 1027 // re-encode. 1028 switch s.pubKey.(type) { 1029 case *ecdsaPublicKey, *dsaPublicKey: 1030 type asn1Signature struct { 1031 R, S *big.Int 1032 } 1033 asn1Sig := new(asn1Signature) 1034 _, err := asn1.Unmarshal(signature, asn1Sig) 1035 if err != nil { 1036 return nil, err 1037 } 1038 1039 switch s.pubKey.(type) { 1040 case *ecdsaPublicKey: 1041 signature = Marshal(asn1Sig) 1042 1043 case *dsaPublicKey: 1044 signature = make([]byte, 40) 1045 r := asn1Sig.R.Bytes() 1046 s := asn1Sig.S.Bytes() 1047 copy(signature[20-len(r):20], r) 1048 copy(signature[40-len(s):40], s) 1049 } 1050 } 1051 1052 return &Signature{ 1053 Format: algorithm, 1054 Blob: signature, 1055 }, nil 1056 } 1057 1058 // NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, 1059 // or ed25519.PublicKey returns a corresponding PublicKey instance. 1060 // ECDSA keys must use P-256, P-384 or P-521. 1061 func NewPublicKey(key interface{}) (PublicKey, error) { 1062 switch key := key.(type) { 1063 case *rsa.PublicKey: 1064 return (*rsaPublicKey)(key), nil 1065 case *ecdsa.PublicKey: 1066 if !supportedEllipticCurve(key.Curve) { 1067 return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported") 1068 } 1069 return (*ecdsaPublicKey)(key), nil 1070 case *dsa.PublicKey: 1071 return (*dsaPublicKey)(key), nil 1072 case ed25519.PublicKey: 1073 if l := len(key); l != ed25519.PublicKeySize { 1074 return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l) 1075 } 1076 return ed25519PublicKey(key), nil 1077 default: 1078 return nil, fmt.Errorf("ssh: unsupported key type %T", key) 1079 } 1080 } 1081 1082 // ParsePrivateKey returns a Signer from a PEM encoded private key. It supports 1083 // the same keys as ParseRawPrivateKey. If the private key is encrypted, it 1084 // will return a PassphraseMissingError. 1085 func ParsePrivateKey(pemBytes []byte) (Signer, error) { 1086 key, err := ParseRawPrivateKey(pemBytes) 1087 if err != nil { 1088 return nil, err 1089 } 1090 1091 return NewSignerFromKey(key) 1092 } 1093 1094 // ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private 1095 // key and passphrase. It supports the same keys as 1096 // ParseRawPrivateKeyWithPassphrase. 1097 func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) { 1098 key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase) 1099 if err != nil { 1100 return nil, err 1101 } 1102 1103 return NewSignerFromKey(key) 1104 } 1105 1106 // encryptedBlock tells whether a private key is 1107 // encrypted by examining its Proc-Type header 1108 // for a mention of ENCRYPTED 1109 // according to RFC 1421 Section 4.6.1.1. 1110 func encryptedBlock(block *pem.Block) bool { 1111 return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED") 1112 } 1113 1114 // A PassphraseMissingError indicates that parsing this private key requires a 1115 // passphrase. Use ParsePrivateKeyWithPassphrase. 1116 type PassphraseMissingError struct { 1117 // PublicKey will be set if the private key format includes an unencrypted 1118 // public key along with the encrypted private key. 1119 PublicKey PublicKey 1120 } 1121 1122 func (*PassphraseMissingError) Error() string { 1123 return "ssh: this private key is passphrase protected" 1124 } 1125 1126 // ParseRawPrivateKey returns a private key from a PEM encoded private key. It 1127 // supports RSA (PKCS#1), PKCS#8, DSA (OpenSSL), and ECDSA private keys. If the 1128 // private key is encrypted, it will return a PassphraseMissingError. 1129 func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) { 1130 block, _ := pem.Decode(pemBytes) 1131 if block == nil { 1132 return nil, errors.New("ssh: no key found") 1133 } 1134 1135 if encryptedBlock(block) { 1136 return nil, &PassphraseMissingError{} 1137 } 1138 1139 switch block.Type { 1140 case "RSA PRIVATE KEY": 1141 return x509.ParsePKCS1PrivateKey(block.Bytes) 1142 // RFC5208 - https://tools.ietf.org/html/rfc5208 1143 case "PRIVATE KEY": 1144 return x509.ParsePKCS8PrivateKey(block.Bytes) 1145 case "EC PRIVATE KEY": 1146 return x509.ParseECPrivateKey(block.Bytes) 1147 case "DSA PRIVATE KEY": 1148 return ParseDSAPrivateKey(block.Bytes) 1149 case "OPENSSH PRIVATE KEY": 1150 return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey) 1151 default: 1152 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) 1153 } 1154 } 1155 1156 // ParseRawPrivateKeyWithPassphrase returns a private key decrypted with 1157 // passphrase from a PEM encoded private key. If the passphrase is wrong, it 1158 // will return x509.IncorrectPasswordError. 1159 func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) { 1160 block, _ := pem.Decode(pemBytes) 1161 if block == nil { 1162 return nil, errors.New("ssh: no key found") 1163 } 1164 1165 if block.Type == "OPENSSH PRIVATE KEY" { 1166 return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase)) 1167 } 1168 1169 if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) { 1170 return nil, errors.New("ssh: not an encrypted key") 1171 } 1172 1173 buf, err := x509.DecryptPEMBlock(block, passphrase) 1174 if err != nil { 1175 if err == x509.IncorrectPasswordError { 1176 return nil, err 1177 } 1178 return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err) 1179 } 1180 1181 switch block.Type { 1182 case "RSA PRIVATE KEY": 1183 return x509.ParsePKCS1PrivateKey(buf) 1184 case "EC PRIVATE KEY": 1185 return x509.ParseECPrivateKey(buf) 1186 case "DSA PRIVATE KEY": 1187 return ParseDSAPrivateKey(buf) 1188 default: 1189 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) 1190 } 1191 } 1192 1193 // ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as 1194 // specified by the OpenSSL DSA man page. 1195 func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) { 1196 var k struct { 1197 Version int 1198 P *big.Int 1199 Q *big.Int 1200 G *big.Int 1201 Pub *big.Int 1202 Priv *big.Int 1203 } 1204 rest, err := asn1.Unmarshal(der, &k) 1205 if err != nil { 1206 return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) 1207 } 1208 if len(rest) > 0 { 1209 return nil, errors.New("ssh: garbage after DSA key") 1210 } 1211 1212 return &dsa.PrivateKey{ 1213 PublicKey: dsa.PublicKey{ 1214 Parameters: dsa.Parameters{ 1215 P: k.P, 1216 Q: k.Q, 1217 G: k.G, 1218 }, 1219 Y: k.Pub, 1220 }, 1221 X: k.Priv, 1222 }, nil 1223 } 1224 1225 func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { 1226 if kdfName != "none" || cipherName != "none" { 1227 return nil, &PassphraseMissingError{} 1228 } 1229 if kdfOpts != "" { 1230 return nil, errors.New("ssh: invalid openssh private key") 1231 } 1232 return privKeyBlock, nil 1233 } 1234 1235 func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc { 1236 return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) { 1237 if kdfName == "none" || cipherName == "none" { 1238 return nil, errors.New("ssh: key is not password protected") 1239 } 1240 if kdfName != "bcrypt" { 1241 return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt") 1242 } 1243 1244 var opts struct { 1245 Salt string 1246 Rounds uint32 1247 } 1248 if err := Unmarshal([]byte(kdfOpts), &opts); err != nil { 1249 return nil, err 1250 } 1251 1252 k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16) 1253 if err != nil { 1254 return nil, err 1255 } 1256 key, iv := k[:32], k[32:] 1257 1258 c, err := aes.NewCipher(key) 1259 if err != nil { 1260 return nil, err 1261 } 1262 switch cipherName { 1263 case "aes256-ctr": 1264 ctr := cipher.NewCTR(c, iv) 1265 ctr.XORKeyStream(privKeyBlock, privKeyBlock) 1266 case "aes256-cbc": 1267 if len(privKeyBlock)%c.BlockSize() != 0 { 1268 return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size") 1269 } 1270 cbc := cipher.NewCBCDecrypter(c, iv) 1271 cbc.CryptBlocks(privKeyBlock, privKeyBlock) 1272 default: 1273 return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc") 1274 } 1275 1276 return privKeyBlock, nil 1277 } 1278 } 1279 1280 type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error) 1281 1282 // parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt 1283 // function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used 1284 // as the decrypt function to parse an unencrypted private key. See 1285 // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key. 1286 func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) { 1287 const magic = "openssh-key-v1\x00" 1288 if len(key) < len(magic) || string(key[:len(magic)]) != magic { 1289 return nil, errors.New("ssh: invalid openssh private key format") 1290 } 1291 remaining := key[len(magic):] 1292 1293 var w struct { 1294 CipherName string 1295 KdfName string 1296 KdfOpts string 1297 NumKeys uint32 1298 PubKey []byte 1299 PrivKeyBlock []byte 1300 } 1301 1302 if err := Unmarshal(remaining, &w); err != nil { 1303 return nil, err 1304 } 1305 if w.NumKeys != 1 { 1306 // We only support single key files, and so does OpenSSH. 1307 // https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171 1308 return nil, errors.New("ssh: multi-key files are not supported") 1309 } 1310 1311 privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock) 1312 if err != nil { 1313 if err, ok := err.(*PassphraseMissingError); ok { 1314 pub, errPub := ParsePublicKey(w.PubKey) 1315 if errPub != nil { 1316 return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub) 1317 } 1318 err.PublicKey = pub 1319 } 1320 return nil, err 1321 } 1322 1323 pk1 := struct { 1324 Check1 uint32 1325 Check2 uint32 1326 Keytype string 1327 Rest []byte `ssh:"rest"` 1328 }{} 1329 1330 if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 { 1331 if w.CipherName != "none" { 1332 return nil, x509.IncorrectPasswordError 1333 } 1334 return nil, errors.New("ssh: malformed OpenSSH key") 1335 } 1336 1337 switch pk1.Keytype { 1338 case KeyAlgoRSA: 1339 // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773 1340 key := struct { 1341 N *big.Int 1342 E *big.Int 1343 D *big.Int 1344 Iqmp *big.Int 1345 P *big.Int 1346 Q *big.Int 1347 Comment string 1348 Pad []byte `ssh:"rest"` 1349 }{} 1350 1351 if err := Unmarshal(pk1.Rest, &key); err != nil { 1352 return nil, err 1353 } 1354 1355 if err := checkOpenSSHKeyPadding(key.Pad); err != nil { 1356 return nil, err 1357 } 1358 1359 pk := &rsa.PrivateKey{ 1360 PublicKey: rsa.PublicKey{ 1361 N: key.N, 1362 E: int(key.E.Int64()), 1363 }, 1364 D: key.D, 1365 Primes: []*big.Int{key.P, key.Q}, 1366 } 1367 1368 if err := pk.Validate(); err != nil { 1369 return nil, err 1370 } 1371 1372 pk.Precompute() 1373 1374 return pk, nil 1375 case KeyAlgoED25519: 1376 key := struct { 1377 Pub []byte 1378 Priv []byte 1379 Comment string 1380 Pad []byte `ssh:"rest"` 1381 }{} 1382 1383 if err := Unmarshal(pk1.Rest, &key); err != nil { 1384 return nil, err 1385 } 1386 1387 if len(key.Priv) != ed25519.PrivateKeySize { 1388 return nil, errors.New("ssh: private key unexpected length") 1389 } 1390 1391 if err := checkOpenSSHKeyPadding(key.Pad); err != nil { 1392 return nil, err 1393 } 1394 1395 pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) 1396 copy(pk, key.Priv) 1397 return &pk, nil 1398 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521: 1399 key := struct { 1400 Curve string 1401 Pub []byte 1402 D *big.Int 1403 Comment string 1404 Pad []byte `ssh:"rest"` 1405 }{} 1406 1407 if err := Unmarshal(pk1.Rest, &key); err != nil { 1408 return nil, err 1409 } 1410 1411 if err := checkOpenSSHKeyPadding(key.Pad); err != nil { 1412 return nil, err 1413 } 1414 1415 var curve elliptic.Curve 1416 switch key.Curve { 1417 case "nistp256": 1418 curve = elliptic.P256() 1419 case "nistp384": 1420 curve = elliptic.P384() 1421 case "nistp521": 1422 curve = elliptic.P521() 1423 default: 1424 return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve) 1425 } 1426 1427 X, Y := elliptic.Unmarshal(curve, key.Pub) 1428 if X == nil || Y == nil { 1429 return nil, errors.New("ssh: failed to unmarshal public key") 1430 } 1431 1432 if key.D.Cmp(curve.Params().N) >= 0 { 1433 return nil, errors.New("ssh: scalar is out of range") 1434 } 1435 1436 x, y := curve.ScalarBaseMult(key.D.Bytes()) 1437 if x.Cmp(X) != 0 || y.Cmp(Y) != 0 { 1438 return nil, errors.New("ssh: public key does not match private key") 1439 } 1440 1441 return &ecdsa.PrivateKey{ 1442 PublicKey: ecdsa.PublicKey{ 1443 Curve: curve, 1444 X: X, 1445 Y: Y, 1446 }, 1447 D: key.D, 1448 }, nil 1449 default: 1450 return nil, errors.New("ssh: unhandled key type") 1451 } 1452 } 1453 1454 func checkOpenSSHKeyPadding(pad []byte) error { 1455 for i, b := range pad { 1456 if int(b) != i+1 { 1457 return errors.New("ssh: padding not as expected") 1458 } 1459 } 1460 return nil 1461 } 1462 1463 // FingerprintLegacyMD5 returns the user presentation of the key's 1464 // fingerprint as described by RFC 4716 section 4. 1465 func FingerprintLegacyMD5(pubKey PublicKey) string { 1466 md5sum := md5.Sum(pubKey.Marshal()) 1467 hexarray := make([]string, len(md5sum)) 1468 for i, c := range md5sum { 1469 hexarray[i] = hex.EncodeToString([]byte{c}) 1470 } 1471 return strings.Join(hexarray, ":") 1472 } 1473 1474 // FingerprintSHA256 returns the user presentation of the key's 1475 // fingerprint as unpadded base64 encoded sha256 hash. 1476 // This format was introduced from OpenSSH 6.8. 1477 // https://www.openssh.com/txt/release-6.8 1478 // https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding) 1479 func FingerprintSHA256(pubKey PublicKey) string { 1480 sha256sum := sha256.Sum256(pubKey.Marshal()) 1481 hash := base64.RawStdEncoding.EncodeToString(sha256sum[:]) 1482 return "SHA256:" + hash 1483 }