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.
27 "golang.org/x/crypto/ed25519"
30 // These constants represent the algorithm names for key types supported by this
33 KeyAlgoRSA = "ssh-rsa"
34 KeyAlgoDSA = "ssh-dss"
35 KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
36 KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
37 KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
38 KeyAlgoED25519 = "ssh-ed25519"
41 // parsePubKey parses a public key of the given algorithm.
42 // Use ParsePublicKey for keys with prepended algorithm.
43 func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
49 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
52 return parseED25519(in)
53 case CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoED25519v01:
54 cert, err := parseCert(in, certToPrivAlgo(algo))
60 return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo)
63 // parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
64 // (see sshd(8) manual page) once the options and key type fields have been
66 func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) {
67 in = bytes.TrimSpace(in)
69 i := bytes.IndexAny(in, " \t")
75 key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
76 n, err := base64.StdEncoding.Decode(key, base64Key)
81 out, err = ParsePublicKey(key)
85 comment = string(bytes.TrimSpace(in[i:]))
86 return out, comment, nil
89 // ParseKnownHosts parses an entry in the format of the known_hosts file.
91 // The known_hosts format is documented in the sshd(8) manual page. This
92 // function will parse a single entry from in. On successful return, marker
93 // will contain the optional marker value (i.e. "cert-authority" or "revoked")
94 // or else be empty, hosts will contain the hosts that this entry matches,
95 // pubKey will contain the public key and comment will contain any trailing
96 // comment at the end of the line. See the sshd(8) manual page for the various
97 // forms that a host string can take.
99 // The unparsed remainder of the input will be returned in rest. This function
100 // can be called repeatedly to parse multiple entries.
102 // If no entries were found in the input then err will be io.EOF. Otherwise a
103 // non-nil err value indicates a parse error.
104 func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) {
106 end := bytes.IndexByte(in, '\n')
114 end = bytes.IndexByte(in, '\r')
119 in = bytes.TrimSpace(in)
120 if len(in) == 0 || in[0] == '#' {
125 i := bytes.IndexAny(in, " \t")
131 // Strip out the beginning of the known_host key.
132 // This is either an optional marker or a (set of) hostname(s).
133 keyFields := bytes.Fields(in)
134 if len(keyFields) < 3 || len(keyFields) > 5 {
135 return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data")
138 // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated
141 if keyFields[0][0] == '@' {
142 marker = string(keyFields[0][1:])
143 keyFields = keyFields[1:]
146 hosts := string(keyFields[0])
147 // keyFields[1] contains the key type (e.g. “ssh-rsa”).
148 // However, that information is duplicated inside the
149 // base64-encoded key and so is ignored here.
151 key := bytes.Join(keyFields[2:], []byte(" "))
152 if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
153 return "", nil, nil, "", nil, err
156 return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
159 return "", nil, nil, "", nil, io.EOF
162 // ParseAuthorizedKeys parses a public key from an authorized_keys
163 // file used in OpenSSH according to the sshd(8) manual page.
164 func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
166 end := bytes.IndexByte(in, '\n')
174 end = bytes.IndexByte(in, '\r')
179 in = bytes.TrimSpace(in)
180 if len(in) == 0 || in[0] == '#' {
185 i := bytes.IndexAny(in, " \t")
191 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
192 return out, comment, options, rest, nil
195 // No key type recognised. Maybe there's an options field at
199 var candidateOptions []string
201 for i, b = range in {
202 isEnd := !inQuote && (b == ' ' || b == '\t')
203 if (b == ',' && !inQuote) || isEnd {
204 if i-optionStart > 0 {
205 candidateOptions = append(candidateOptions, string(in[optionStart:i]))
212 if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
216 for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
220 // Invalid line: unmatched quote
226 i = bytes.IndexAny(in, " \t")
232 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
233 options = candidateOptions
234 return out, comment, options, rest, nil
241 return nil, "", nil, nil, errors.New("ssh: no key found")
244 // ParsePublicKey parses an SSH public key formatted for use in
245 // the SSH wire protocol according to RFC 4253, section 6.6.
246 func ParsePublicKey(in []byte) (out PublicKey, err error) {
247 algo, in, ok := parseString(in)
249 return nil, errShortRead
252 out, rest, err = parsePubKey(in, string(algo))
254 return nil, errors.New("ssh: trailing junk in public key")
260 // MarshalAuthorizedKey serializes key for inclusion in an OpenSSH
261 // authorized_keys file. The return value ends with newline.
262 func MarshalAuthorizedKey(key PublicKey) []byte {
264 b.WriteString(key.Type())
266 e := base64.NewEncoder(base64.StdEncoding, b)
267 e.Write(key.Marshal())
273 // PublicKey is an abstraction of different types of public keys.
274 type PublicKey interface {
275 // Type returns the key's type, e.g. "ssh-rsa".
278 // Marshal returns the serialized key data in SSH wire format,
279 // with the name prefix.
282 // Verify that sig is a signature on the given data using this
283 // key. This function will hash the data appropriately first.
284 Verify(data []byte, sig *Signature) error
287 // CryptoPublicKey, if implemented by a PublicKey,
288 // returns the underlying crypto.PublicKey form of the key.
289 type CryptoPublicKey interface {
290 CryptoPublicKey() crypto.PublicKey
293 // A Signer can create signatures that verify against a public key.
294 type Signer interface {
295 // PublicKey returns an associated PublicKey instance.
296 PublicKey() PublicKey
298 // Sign returns raw signature for the given data. This method
299 // will apply the hash specified for the keytype to the data.
300 Sign(rand io.Reader, data []byte) (*Signature, error)
303 type rsaPublicKey rsa.PublicKey
305 func (r *rsaPublicKey) Type() string {
309 // parseRSA parses an RSA key according to RFC 4253, section 6.6.
310 func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
314 Rest []byte `ssh:"rest"`
316 if err := Unmarshal(in, &w); err != nil {
320 if w.E.BitLen() > 24 {
321 return nil, nil, errors.New("ssh: exponent too large")
324 if e < 3 || e&1 == 0 {
325 return nil, nil, errors.New("ssh: incorrect exponent")
328 var key rsa.PublicKey
331 return (*rsaPublicKey)(&key), w.Rest, nil
334 func (r *rsaPublicKey) Marshal() []byte {
335 e := new(big.Int).SetInt64(int64(r.E))
336 // RSA publickey struct layout should match the struct used by
337 // parseRSACert in the x/crypto/ssh/agent package.
347 return Marshal(&wirekey)
350 func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
351 if sig.Format != r.Type() {
352 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
354 h := crypto.SHA1.New()
357 return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob)
360 func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
361 return (*rsa.PublicKey)(r)
364 type dsaPublicKey dsa.PublicKey
366 func (r *dsaPublicKey) Type() string {
370 // parseDSA parses an DSA key according to RFC 4253, section 6.6.
371 func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
374 Rest []byte `ssh:"rest"`
376 if err := Unmarshal(in, &w); err != nil {
380 key := &dsaPublicKey{
381 Parameters: dsa.Parameters{
388 return key, w.Rest, nil
391 func (k *dsaPublicKey) Marshal() []byte {
392 // DSA publickey struct layout should match the struct used by
393 // parseDSACert in the x/crypto/ssh/agent package.
408 func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
409 if sig.Format != k.Type() {
410 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
412 h := crypto.SHA1.New()
416 // Per RFC 4253, section 6.6,
417 // The value for 'dss_signature_blob' is encoded as a string containing
418 // r, followed by s (which are 160-bit integers, without lengths or
419 // padding, unsigned, and in network byte order).
420 // For DSS purposes, sig.Blob should be exactly 40 bytes in length.
421 if len(sig.Blob) != 40 {
422 return errors.New("ssh: DSA signature parse error")
424 r := new(big.Int).SetBytes(sig.Blob[:20])
425 s := new(big.Int).SetBytes(sig.Blob[20:])
426 if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) {
429 return errors.New("ssh: signature did not verify")
432 func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
433 return (*dsa.PublicKey)(k)
436 type dsaPrivateKey struct {
440 func (k *dsaPrivateKey) PublicKey() PublicKey {
441 return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
444 func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
445 h := crypto.SHA1.New()
448 r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
453 sig := make([]byte, 40)
457 copy(sig[20-len(rb):20], rb)
458 copy(sig[40-len(sb):], sb)
461 Format: k.PublicKey().Type(),
466 type ecdsaPublicKey ecdsa.PublicKey
468 func (key *ecdsaPublicKey) Type() string {
469 return "ecdsa-sha2-" + key.nistID()
472 func (key *ecdsaPublicKey) nistID() string {
473 switch key.Params().BitSize {
481 panic("ssh: unsupported ecdsa key size")
484 type ed25519PublicKey ed25519.PublicKey
486 func (key ed25519PublicKey) Type() string {
487 return KeyAlgoED25519
490 func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
493 Rest []byte `ssh:"rest"`
496 if err := Unmarshal(in, &w); err != nil {
500 key := ed25519.PublicKey(w.KeyBytes)
502 return (ed25519PublicKey)(key), w.Rest, nil
505 func (key ed25519PublicKey) Marshal() []byte {
516 func (key ed25519PublicKey) Verify(b []byte, sig *Signature) error {
517 if sig.Format != key.Type() {
518 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type())
521 edKey := (ed25519.PublicKey)(key)
522 if ok := ed25519.Verify(edKey, b, sig.Blob); !ok {
523 return errors.New("ssh: signature did not verify")
529 func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
530 return ed25519.PublicKey(k)
533 func supportedEllipticCurve(curve elliptic.Curve) bool {
534 return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
537 // ecHash returns the hash to match the given elliptic curve, see RFC
538 // 5656, section 6.2.1
539 func ecHash(curve elliptic.Curve) crypto.Hash {
540 bitSize := curve.Params().BitSize
550 // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
551 func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
555 Rest []byte `ssh:"rest"`
558 if err := Unmarshal(in, &w); err != nil {
562 key := new(ecdsa.PublicKey)
566 key.Curve = elliptic.P256()
568 key.Curve = elliptic.P384()
570 key.Curve = elliptic.P521()
572 return nil, nil, errors.New("ssh: unsupported curve")
575 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
576 if key.X == nil || key.Y == nil {
577 return nil, nil, errors.New("ssh: invalid curve point")
579 return (*ecdsaPublicKey)(key), w.Rest, nil
582 func (key *ecdsaPublicKey) Marshal() []byte {
583 // See RFC 5656, section 3.1.
584 keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y)
585 // ECDSA publickey struct layout should match the struct used by
586 // parseECDSACert in the x/crypto/ssh/agent package.
600 func (key *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
601 if sig.Format != key.Type() {
602 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, key.Type())
605 h := ecHash(key.Curve).New()
609 // Per RFC 5656, section 3.1.2,
610 // The ecdsa_signature_blob value has the following specific encoding:
618 if err := Unmarshal(sig.Blob, &ecSig); err != nil {
622 if ecdsa.Verify((*ecdsa.PublicKey)(key), digest, ecSig.R, ecSig.S) {
625 return errors.New("ssh: signature did not verify")
628 func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
629 return (*ecdsa.PublicKey)(k)
632 // NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
633 // *ecdsa.PrivateKey or any other crypto.Signer and returns a corresponding
634 // Signer instance. ECDSA keys must use P-256, P-384 or P-521.
635 func NewSignerFromKey(key interface{}) (Signer, error) {
636 switch key := key.(type) {
638 return NewSignerFromSigner(key)
639 case *dsa.PrivateKey:
640 return &dsaPrivateKey{key}, nil
642 return nil, fmt.Errorf("ssh: unsupported key type %T", key)
646 type wrappedSigner struct {
651 // NewSignerFromSigner takes any crypto.Signer implementation and
652 // returns a corresponding Signer interface. This can be used, for
653 // example, with keys kept in hardware modules.
654 func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
655 pubKey, err := NewPublicKey(signer.Public())
660 return &wrappedSigner{signer, pubKey}, nil
663 func (s *wrappedSigner) PublicKey() PublicKey {
667 func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
668 var hashFunc crypto.Hash
670 switch key := s.pubKey.(type) {
671 case *rsaPublicKey, *dsaPublicKey:
672 hashFunc = crypto.SHA1
673 case *ecdsaPublicKey:
674 hashFunc = ecHash(key.Curve)
675 case ed25519PublicKey:
677 return nil, fmt.Errorf("ssh: unsupported key type %T", key)
689 signature, err := s.signer.Sign(rand, digest, hashFunc)
694 // crypto.Signer.Sign is expected to return an ASN.1-encoded signature
695 // for ECDSA and DSA, but that's not the encoding expected by SSH, so
697 switch s.pubKey.(type) {
698 case *ecdsaPublicKey, *dsaPublicKey:
699 type asn1Signature struct {
702 asn1Sig := new(asn1Signature)
703 _, err := asn1.Unmarshal(signature, asn1Sig)
708 switch s.pubKey.(type) {
709 case *ecdsaPublicKey:
710 signature = Marshal(asn1Sig)
713 signature = make([]byte, 40)
714 r := asn1Sig.R.Bytes()
715 s := asn1Sig.S.Bytes()
716 copy(signature[20-len(r):20], r)
717 copy(signature[40-len(s):40], s)
722 Format: s.pubKey.Type(),
727 // NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
728 // or ed25519.PublicKey returns a corresponding PublicKey instance.
729 // ECDSA keys must use P-256, P-384 or P-521.
730 func NewPublicKey(key interface{}) (PublicKey, error) {
731 switch key := key.(type) {
733 return (*rsaPublicKey)(key), nil
734 case *ecdsa.PublicKey:
735 if !supportedEllipticCurve(key.Curve) {
736 return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported.")
738 return (*ecdsaPublicKey)(key), nil
740 return (*dsaPublicKey)(key), nil
741 case ed25519.PublicKey:
742 return (ed25519PublicKey)(key), nil
744 return nil, fmt.Errorf("ssh: unsupported key type %T", key)
748 // ParsePrivateKey returns a Signer from a PEM encoded private key. It supports
749 // the same keys as ParseRawPrivateKey.
750 func ParsePrivateKey(pemBytes []byte) (Signer, error) {
751 key, err := ParseRawPrivateKey(pemBytes)
756 return NewSignerFromKey(key)
759 // encryptedBlock tells whether a private key is
760 // encrypted by examining its Proc-Type header
761 // for a mention of ENCRYPTED
762 // according to RFC 1421 Section 4.6.1.1.
763 func encryptedBlock(block *pem.Block) bool {
764 return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED")
767 // ParseRawPrivateKey returns a private key from a PEM encoded private key. It
768 // supports RSA (PKCS#1), DSA (OpenSSL), and ECDSA private keys.
769 func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
770 block, _ := pem.Decode(pemBytes)
772 return nil, errors.New("ssh: no key found")
775 if encryptedBlock(block) {
776 return nil, errors.New("ssh: cannot decode encrypted private keys")
780 case "RSA PRIVATE KEY":
781 return x509.ParsePKCS1PrivateKey(block.Bytes)
782 case "EC PRIVATE KEY":
783 return x509.ParseECPrivateKey(block.Bytes)
784 case "DSA PRIVATE KEY":
785 return ParseDSAPrivateKey(block.Bytes)
786 case "OPENSSH PRIVATE KEY":
787 return parseOpenSSHPrivateKey(block.Bytes)
789 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
793 // ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
794 // specified by the OpenSSL DSA man page.
795 func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
804 rest, err := asn1.Unmarshal(der, &k)
806 return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
809 return nil, errors.New("ssh: garbage after DSA key")
812 return &dsa.PrivateKey{
813 PublicKey: dsa.PublicKey{
814 Parameters: dsa.Parameters{
825 // Implemented based on the documentation at
826 // https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
827 func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
828 magic := append([]byte("openssh-key-v1"), 0)
829 if !bytes.Equal(magic, key[0:len(magic)]) {
830 return nil, errors.New("ssh: invalid openssh private key format")
832 remaining := key[len(magic):]
843 if err := Unmarshal(remaining, &w); err != nil {
854 Pad []byte `ssh:"rest"`
857 if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil {
861 if pk1.Check1 != pk1.Check2 {
862 return nil, errors.New("ssh: checkint mismatch")
865 // we only handle ed25519 keys currently
866 if pk1.Keytype != KeyAlgoED25519 {
867 return nil, errors.New("ssh: unhandled key type")
870 for i, b := range pk1.Pad {
872 return nil, errors.New("ssh: padding not as expected")
876 if len(pk1.Priv) != ed25519.PrivateKeySize {
877 return nil, errors.New("ssh: private key unexpected length")
880 pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
885 // FingerprintLegacyMD5 returns the user presentation of the key's
886 // fingerprint as described by RFC 4716 section 4.
887 func FingerprintLegacyMD5(pubKey PublicKey) string {
888 md5sum := md5.Sum(pubKey.Marshal())
889 hexarray := make([]string, len(md5sum))
890 for i, c := range md5sum {
891 hexarray[i] = hex.EncodeToString([]byte{c})
893 return strings.Join(hexarray, ":")
896 // FingerprintSHA256 returns the user presentation of the key's
897 // fingerprint as unpadded base64 encoded sha256 hash.
898 // This format was introduced from OpenSSH 6.8.
899 // https://www.openssh.com/txt/release-6.8
900 // https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding)
901 func FingerprintSHA256(pubKey PublicKey) string {
902 sha256sum := sha256.Sum256(pubKey.Marshal())
903 hash := base64.RawStdEncoding.EncodeToString(sha256sum[:])
904 return "SHA256:" + hash