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