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