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/aes"
11 "crypto/cipher"
12 "crypto/dsa"
13 "crypto/ecdsa"
14 "crypto/ed25519"
15 "crypto/elliptic"
16 "crypto/md5"
17 "crypto/rand"
18 "crypto/rsa"
19 "crypto/sha256"
20 "crypto/x509"
21 "encoding/asn1"
22 "encoding/base64"
23 "encoding/binary"
24 "encoding/hex"
25 "encoding/pem"
26 "errors"
27 "fmt"
28 "io"
29 "math/big"
30 "slices"
31 "strings"
32
33 "golang.org/x/crypto/ssh/internal/bcrypt_pbkdf"
34)
35
36// Public key algorithms names. These values can appear in PublicKey.Type,
37// ClientConfig.HostKeyAlgorithms, Signature.Format, or as AlgorithmSigner
38// arguments.
39const (
40 KeyAlgoRSA = "ssh-rsa"
41 // Deprecated: DSA is only supported at insecure key sizes, and was removed
42 // from major implementations.
43 KeyAlgoDSA = InsecureKeyAlgoDSA
44 // Deprecated: DSA is only supported at insecure key sizes, and was removed
45 // from major implementations.
46 InsecureKeyAlgoDSA = "ssh-dss"
47 KeyAlgoECDSA256 = "ecdsa-sha2-nistp256"
48 KeyAlgoSKECDSA256 = "sk-ecdsa-sha2-nistp256@openssh.com"
49 KeyAlgoECDSA384 = "ecdsa-sha2-nistp384"
50 KeyAlgoECDSA521 = "ecdsa-sha2-nistp521"
51 KeyAlgoED25519 = "ssh-ed25519"
52 KeyAlgoSKED25519 = "sk-ssh-ed25519@openssh.com"
53
54 // KeyAlgoRSASHA256 and KeyAlgoRSASHA512 are only public key algorithms, not
55 // public key formats, so they can't appear as a PublicKey.Type. The
56 // corresponding PublicKey.Type is KeyAlgoRSA. See RFC 8332, Section 2.
57 KeyAlgoRSASHA256 = "rsa-sha2-256"
58 KeyAlgoRSASHA512 = "rsa-sha2-512"
59)
60
61const (
62 // Deprecated: use KeyAlgoRSA.
63 SigAlgoRSA = KeyAlgoRSA
64 // Deprecated: use KeyAlgoRSASHA256.
65 SigAlgoRSASHA2256 = KeyAlgoRSASHA256
66 // Deprecated: use KeyAlgoRSASHA512.
67 SigAlgoRSASHA2512 = KeyAlgoRSASHA512
68)
69
70// parsePubKey parses a public key of the given algorithm.
71// Use ParsePublicKey for keys with prepended algorithm.
72func parsePubKey(in []byte, algo string) (pubKey PublicKey, rest []byte, err error) {
73 switch algo {
74 case KeyAlgoRSA:
75 return parseRSA(in)
76 case InsecureKeyAlgoDSA:
77 return parseDSA(in)
78 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
79 return parseECDSA(in)
80 case KeyAlgoSKECDSA256:
81 return parseSKECDSA(in)
82 case KeyAlgoED25519:
83 return parseED25519(in)
84 case KeyAlgoSKED25519:
85 return parseSKEd25519(in)
86 case CertAlgoRSAv01, InsecureCertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
87 cert, err := parseCert(in, certKeyAlgoNames[algo])
88 if err != nil {
89 return nil, nil, err
90 }
91 return cert, nil, nil
92 }
93 if keyFormat := keyFormatForAlgorithm(algo); keyFormat != "" {
94 return nil, nil, fmt.Errorf("ssh: signature algorithm %q isn't a key format; key is malformed and should be re-encoded with type %q",
95 algo, keyFormat)
96 }
97
98 return nil, nil, fmt.Errorf("ssh: unknown key algorithm: %v", algo)
99}
100
101// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format
102// (see sshd(8) manual page) once the options and key type fields have been
103// removed.
104func parseAuthorizedKey(in []byte) (out PublicKey, comment string, err error) {
105 in = bytes.TrimSpace(in)
106
107 i := bytes.IndexAny(in, " \t")
108 if i == -1 {
109 i = len(in)
110 }
111 base64Key := in[:i]
112
113 key := make([]byte, base64.StdEncoding.DecodedLen(len(base64Key)))
114 n, err := base64.StdEncoding.Decode(key, base64Key)
115 if err != nil {
116 return nil, "", err
117 }
118 key = key[:n]
119 out, err = ParsePublicKey(key)
120 if err != nil {
121 return nil, "", err
122 }
123 comment = string(bytes.TrimSpace(in[i:]))
124 return out, comment, nil
125}
126
127// ParseKnownHosts parses an entry in the format of the known_hosts file.
128//
129// The known_hosts format is documented in the sshd(8) manual page. This
130// function will parse a single entry from in. On successful return, marker
131// will contain the optional marker value (i.e. "cert-authority" or "revoked")
132// or else be empty, hosts will contain the hosts that this entry matches,
133// pubKey will contain the public key and comment will contain any trailing
134// comment at the end of the line. See the sshd(8) manual page for the various
135// forms that a host string can take.
136//
137// The unparsed remainder of the input will be returned in rest. This function
138// can be called repeatedly to parse multiple entries.
139//
140// If no entries were found in the input then err will be io.EOF. Otherwise a
141// non-nil err value indicates a parse error.
142func ParseKnownHosts(in []byte) (marker string, hosts []string, pubKey PublicKey, comment string, rest []byte, err error) {
143 for len(in) > 0 {
144 end := bytes.IndexByte(in, '\n')
145 if end != -1 {
146 rest = in[end+1:]
147 in = in[:end]
148 } else {
149 rest = nil
150 }
151
152 end = bytes.IndexByte(in, '\r')
153 if end != -1 {
154 in = in[:end]
155 }
156
157 in = bytes.TrimSpace(in)
158 if len(in) == 0 || in[0] == '#' {
159 in = rest
160 continue
161 }
162
163 i := bytes.IndexAny(in, " \t")
164 if i == -1 {
165 in = rest
166 continue
167 }
168
169 // Strip out the beginning of the known_host key.
170 // This is either an optional marker or a (set of) hostname(s).
171 keyFields := bytes.Fields(in)
172 if len(keyFields) < 3 || len(keyFields) > 5 {
173 return "", nil, nil, "", nil, errors.New("ssh: invalid entry in known_hosts data")
174 }
175
176 // keyFields[0] is either "@cert-authority", "@revoked" or a comma separated
177 // list of hosts
178 marker := ""
179 if keyFields[0][0] == '@' {
180 marker = string(keyFields[0][1:])
181 keyFields = keyFields[1:]
182 }
183
184 hosts := string(keyFields[0])
185 // keyFields[1] contains the key type (e.g. “ssh-rsa”).
186 // However, that information is duplicated inside the
187 // base64-encoded key and so is ignored here.
188
189 key := bytes.Join(keyFields[2:], []byte(" "))
190 if pubKey, comment, err = parseAuthorizedKey(key); err != nil {
191 return "", nil, nil, "", nil, err
192 }
193
194 return marker, strings.Split(hosts, ","), pubKey, comment, rest, nil
195 }
196
197 return "", nil, nil, "", nil, io.EOF
198}
199
200// ParseAuthorizedKey parses a public key from an authorized_keys file used in
201// OpenSSH according to the sshd(8) manual page. Invalid lines are ignored.
202func ParseAuthorizedKey(in []byte) (out PublicKey, comment string, options []string, rest []byte, err error) {
203 var lastErr error
204 for len(in) > 0 {
205 end := bytes.IndexByte(in, '\n')
206 if end != -1 {
207 rest = in[end+1:]
208 in = in[:end]
209 } else {
210 rest = nil
211 }
212
213 end = bytes.IndexByte(in, '\r')
214 if end != -1 {
215 in = in[:end]
216 }
217
218 in = bytes.TrimSpace(in)
219 if len(in) == 0 || in[0] == '#' {
220 in = rest
221 continue
222 }
223
224 i := bytes.IndexAny(in, " \t")
225 if i == -1 {
226 in = rest
227 continue
228 }
229
230 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
231 return out, comment, options, rest, nil
232 } else {
233 lastErr = err
234 }
235
236 // No key type recognised. Maybe there's an options field at
237 // the beginning.
238 var b byte
239 inQuote := false
240 var candidateOptions []string
241 optionStart := 0
242 for i, b = range in {
243 isEnd := !inQuote && (b == ' ' || b == '\t')
244 if (b == ',' && !inQuote) || isEnd {
245 if i-optionStart > 0 {
246 candidateOptions = append(candidateOptions, string(in[optionStart:i]))
247 }
248 optionStart = i + 1
249 }
250 if isEnd {
251 break
252 }
253 if b == '"' && (i == 0 || (i > 0 && in[i-1] != '\\')) {
254 inQuote = !inQuote
255 }
256 }
257 for i < len(in) && (in[i] == ' ' || in[i] == '\t') {
258 i++
259 }
260 if i == len(in) {
261 // Invalid line: unmatched quote
262 in = rest
263 continue
264 }
265
266 in = in[i:]
267 i = bytes.IndexAny(in, " \t")
268 if i == -1 {
269 in = rest
270 continue
271 }
272
273 if out, comment, err = parseAuthorizedKey(in[i:]); err == nil {
274 options = candidateOptions
275 return out, comment, options, rest, nil
276 } else {
277 lastErr = err
278 }
279
280 in = rest
281 continue
282 }
283
284 if lastErr != nil {
285 return nil, "", nil, nil, fmt.Errorf("ssh: no key found; last parsing error for ignored line: %w", lastErr)
286 }
287
288 return nil, "", nil, nil, errors.New("ssh: no key found")
289}
290
291// ParsePublicKey parses an SSH public key or certificate formatted for use in
292// the SSH wire protocol according to RFC 4253, section 6.6.
293func ParsePublicKey(in []byte) (out PublicKey, err error) {
294 algo, in, ok := parseString(in)
295 if !ok {
296 return nil, errShortRead
297 }
298 var rest []byte
299 out, rest, err = parsePubKey(in, string(algo))
300 if len(rest) > 0 {
301 return nil, errors.New("ssh: trailing junk in public key")
302 }
303
304 return out, err
305}
306
307// MarshalAuthorizedKey serializes key for inclusion in an OpenSSH
308// authorized_keys file. The return value ends with newline.
309func MarshalAuthorizedKey(key PublicKey) []byte {
310 b := &bytes.Buffer{}
311 b.WriteString(key.Type())
312 b.WriteByte(' ')
313 e := base64.NewEncoder(base64.StdEncoding, b)
314 e.Write(key.Marshal())
315 e.Close()
316 b.WriteByte('\n')
317 return b.Bytes()
318}
319
320// MarshalPrivateKey returns a PEM block with the private key serialized in the
321// OpenSSH format.
322func MarshalPrivateKey(key crypto.PrivateKey, comment string) (*pem.Block, error) {
323 return marshalOpenSSHPrivateKey(key, comment, unencryptedOpenSSHMarshaler)
324}
325
326// MarshalPrivateKeyWithPassphrase returns a PEM block holding the encrypted
327// private key serialized in the OpenSSH format.
328func MarshalPrivateKeyWithPassphrase(key crypto.PrivateKey, comment string, passphrase []byte) (*pem.Block, error) {
329 return marshalOpenSSHPrivateKey(key, comment, passphraseProtectedOpenSSHMarshaler(passphrase))
330}
331
332// PublicKey represents a public key using an unspecified algorithm.
333//
334// Some PublicKeys provided by this package also implement CryptoPublicKey.
335type PublicKey interface {
336 // Type returns the key format name, e.g. "ssh-rsa".
337 Type() string
338
339 // Marshal returns the serialized key data in SSH wire format, with the name
340 // prefix. To unmarshal the returned data, use the ParsePublicKey function.
341 Marshal() []byte
342
343 // Verify that sig is a signature on the given data using this key. This
344 // method will hash the data appropriately first. sig.Format is allowed to
345 // be any signature algorithm compatible with the key type, the caller
346 // should check if it has more stringent requirements.
347 Verify(data []byte, sig *Signature) error
348}
349
350// CryptoPublicKey, if implemented by a PublicKey,
351// returns the underlying crypto.PublicKey form of the key.
352type CryptoPublicKey interface {
353 CryptoPublicKey() crypto.PublicKey
354}
355
356// A Signer can create signatures that verify against a public key.
357//
358// Some Signers provided by this package also implement MultiAlgorithmSigner.
359type Signer interface {
360 // PublicKey returns the associated PublicKey.
361 PublicKey() PublicKey
362
363 // Sign returns a signature for the given data. This method will hash the
364 // data appropriately first. The signature algorithm is expected to match
365 // the key format returned by the PublicKey.Type method (and not to be any
366 // alternative algorithm supported by the key format).
367 Sign(rand io.Reader, data []byte) (*Signature, error)
368}
369
370// An AlgorithmSigner is a Signer that also supports specifying an algorithm to
371// use for signing.
372//
373// An AlgorithmSigner can't advertise the algorithms it supports, unless it also
374// implements MultiAlgorithmSigner, so it should be prepared to be invoked with
375// every algorithm supported by the public key format.
376type AlgorithmSigner interface {
377 Signer
378
379 // SignWithAlgorithm is like Signer.Sign, but allows specifying a desired
380 // signing algorithm. Callers may pass an empty string for the algorithm in
381 // which case the AlgorithmSigner will use a default algorithm. This default
382 // doesn't currently control any behavior in this package.
383 SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error)
384}
385
386// MultiAlgorithmSigner is an AlgorithmSigner that also reports the algorithms
387// supported by that signer.
388type MultiAlgorithmSigner interface {
389 AlgorithmSigner
390
391 // Algorithms returns the available algorithms in preference order. The list
392 // must not be empty, and it must not include certificate types.
393 Algorithms() []string
394}
395
396// NewSignerWithAlgorithms returns a signer restricted to the specified
397// algorithms. The algorithms must be set in preference order. The list must not
398// be empty, and it must not include certificate types. An error is returned if
399// the specified algorithms are incompatible with the public key type.
400func NewSignerWithAlgorithms(signer AlgorithmSigner, algorithms []string) (MultiAlgorithmSigner, error) {
401 if len(algorithms) == 0 {
402 return nil, errors.New("ssh: please specify at least one valid signing algorithm")
403 }
404 var signerAlgos []string
405 supportedAlgos := algorithmsForKeyFormat(underlyingAlgo(signer.PublicKey().Type()))
406 if s, ok := signer.(*multiAlgorithmSigner); ok {
407 signerAlgos = s.Algorithms()
408 } else {
409 signerAlgos = supportedAlgos
410 }
411
412 for _, algo := range algorithms {
413 if !slices.Contains(supportedAlgos, algo) {
414 return nil, fmt.Errorf("ssh: algorithm %q is not supported for key type %q",
415 algo, signer.PublicKey().Type())
416 }
417 if !slices.Contains(signerAlgos, algo) {
418 return nil, fmt.Errorf("ssh: algorithm %q is restricted for the provided signer", algo)
419 }
420 }
421 return &multiAlgorithmSigner{
422 AlgorithmSigner: signer,
423 supportedAlgorithms: algorithms,
424 }, nil
425}
426
427type multiAlgorithmSigner struct {
428 AlgorithmSigner
429 supportedAlgorithms []string
430}
431
432func (s *multiAlgorithmSigner) Algorithms() []string {
433 return s.supportedAlgorithms
434}
435
436func (s *multiAlgorithmSigner) isAlgorithmSupported(algorithm string) bool {
437 if algorithm == "" {
438 algorithm = underlyingAlgo(s.PublicKey().Type())
439 }
440 for _, algo := range s.supportedAlgorithms {
441 if algorithm == algo {
442 return true
443 }
444 }
445 return false
446}
447
448func (s *multiAlgorithmSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
449 if !s.isAlgorithmSupported(algorithm) {
450 return nil, fmt.Errorf("ssh: algorithm %q is not supported: %v", algorithm, s.supportedAlgorithms)
451 }
452 return s.AlgorithmSigner.SignWithAlgorithm(rand, data, algorithm)
453}
454
455type rsaPublicKey rsa.PublicKey
456
457func (r *rsaPublicKey) Type() string {
458 return "ssh-rsa"
459}
460
461// parseRSA parses an RSA key according to RFC 4253, section 6.6.
462func parseRSA(in []byte) (out PublicKey, rest []byte, err error) {
463 var w struct {
464 E *big.Int
465 N *big.Int
466 Rest []byte `ssh:"rest"`
467 }
468 if err := Unmarshal(in, &w); err != nil {
469 return nil, nil, err
470 }
471
472 if w.E.BitLen() > 24 {
473 return nil, nil, errors.New("ssh: exponent too large")
474 }
475 e := w.E.Int64()
476 if e < 3 || e&1 == 0 {
477 return nil, nil, errors.New("ssh: incorrect exponent")
478 }
479
480 var key rsa.PublicKey
481 key.E = int(e)
482 key.N = w.N
483 return (*rsaPublicKey)(&key), w.Rest, nil
484}
485
486func (r *rsaPublicKey) Marshal() []byte {
487 e := new(big.Int).SetInt64(int64(r.E))
488 // RSA publickey struct layout should match the struct used by
489 // parseRSACert in the x/crypto/ssh/agent package.
490 wirekey := struct {
491 Name string
492 E *big.Int
493 N *big.Int
494 }{
495 KeyAlgoRSA,
496 e,
497 r.N,
498 }
499 return Marshal(&wirekey)
500}
501
502func (r *rsaPublicKey) Verify(data []byte, sig *Signature) error {
503 supportedAlgos := algorithmsForKeyFormat(r.Type())
504 if !slices.Contains(supportedAlgos, sig.Format) {
505 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, r.Type())
506 }
507 hash, err := hashFunc(sig.Format)
508 if err != nil {
509 return err
510 }
511 h := hash.New()
512 h.Write(data)
513 digest := h.Sum(nil)
514
515 // Signatures in PKCS1v15 must match the key's modulus in
516 // length. However with SSH, some signers provide RSA
517 // signatures which are missing the MSB 0's of the bignum
518 // represented. With ssh-rsa signatures, this is encouraged by
519 // the spec (even though e.g. OpenSSH will give the full
520 // length unconditionally). With rsa-sha2-* signatures, the
521 // verifier is allowed to support these, even though they are
522 // out of spec. See RFC 4253 Section 6.6 for ssh-rsa and RFC
523 // 8332 Section 3 for rsa-sha2-* details.
524 //
525 // In practice:
526 // * OpenSSH always allows "short" signatures:
527 // https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L526
528 // but always generates padded signatures:
529 // https://github.com/openssh/openssh-portable/blob/V_9_8_P1/ssh-rsa.c#L439
530 //
531 // * PuTTY versions 0.81 and earlier will generate short
532 // signatures for all RSA signature variants. Note that
533 // PuTTY is embedded in other software, such as WinSCP and
534 // FileZilla. At the time of writing, a patch has been
535 // applied to PuTTY to generate padded signatures for
536 // rsa-sha2-*, but not yet released:
537 // https://git.tartarus.org/?p=simon/putty.git;a=commitdiff;h=a5bcf3d384e1bf15a51a6923c3724cbbee022d8e
538 //
539 // * SSH.NET versions 2024.0.0 and earlier will generate short
540 // signatures for all RSA signature variants, fixed in 2024.1.0:
541 // https://github.com/sshnet/SSH.NET/releases/tag/2024.1.0
542 //
543 // As a result, we pad these up to the key size by inserting
544 // leading 0's.
545 //
546 // Note that support for short signatures with rsa-sha2-* may
547 // be removed in the future due to such signatures not being
548 // allowed by the spec.
549 blob := sig.Blob
550 keySize := (*rsa.PublicKey)(r).Size()
551 if len(blob) < keySize {
552 padded := make([]byte, keySize)
553 copy(padded[keySize-len(blob):], blob)
554 blob = padded
555 }
556 return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), hash, digest, blob)
557}
558
559func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey {
560 return (*rsa.PublicKey)(r)
561}
562
563type dsaPublicKey dsa.PublicKey
564
565func (k *dsaPublicKey) Type() string {
566 return "ssh-dss"
567}
568
569func checkDSAParams(param *dsa.Parameters) error {
570 // SSH specifies FIPS 186-2, which only provided a single size
571 // (1024 bits) DSA key. FIPS 186-3 allows for larger key
572 // sizes, which would confuse SSH.
573 if l := param.P.BitLen(); l != 1024 {
574 return fmt.Errorf("ssh: unsupported DSA key size %d", l)
575 }
576
577 return nil
578}
579
580// parseDSA parses an DSA key according to RFC 4253, section 6.6.
581func parseDSA(in []byte) (out PublicKey, rest []byte, err error) {
582 var w struct {
583 P, Q, G, Y *big.Int
584 Rest []byte `ssh:"rest"`
585 }
586 if err := Unmarshal(in, &w); err != nil {
587 return nil, nil, err
588 }
589
590 param := dsa.Parameters{
591 P: w.P,
592 Q: w.Q,
593 G: w.G,
594 }
595 if err := checkDSAParams(¶m); err != nil {
596 return nil, nil, err
597 }
598
599 key := &dsaPublicKey{
600 Parameters: param,
601 Y: w.Y,
602 }
603 return key, w.Rest, nil
604}
605
606func (k *dsaPublicKey) Marshal() []byte {
607 // DSA publickey struct layout should match the struct used by
608 // parseDSACert in the x/crypto/ssh/agent package.
609 w := struct {
610 Name string
611 P, Q, G, Y *big.Int
612 }{
613 k.Type(),
614 k.P,
615 k.Q,
616 k.G,
617 k.Y,
618 }
619
620 return Marshal(&w)
621}
622
623func (k *dsaPublicKey) Verify(data []byte, sig *Signature) error {
624 if sig.Format != k.Type() {
625 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
626 }
627 hash, err := hashFunc(sig.Format)
628 if err != nil {
629 return err
630 }
631 h := hash.New()
632 h.Write(data)
633 digest := h.Sum(nil)
634
635 // Per RFC 4253, section 6.6,
636 // The value for 'dss_signature_blob' is encoded as a string containing
637 // r, followed by s (which are 160-bit integers, without lengths or
638 // padding, unsigned, and in network byte order).
639 // For DSS purposes, sig.Blob should be exactly 40 bytes in length.
640 if len(sig.Blob) != 40 {
641 return errors.New("ssh: DSA signature parse error")
642 }
643 r := new(big.Int).SetBytes(sig.Blob[:20])
644 s := new(big.Int).SetBytes(sig.Blob[20:])
645 if dsa.Verify((*dsa.PublicKey)(k), digest, r, s) {
646 return nil
647 }
648 return errors.New("ssh: signature did not verify")
649}
650
651func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey {
652 return (*dsa.PublicKey)(k)
653}
654
655type dsaPrivateKey struct {
656 *dsa.PrivateKey
657}
658
659func (k *dsaPrivateKey) PublicKey() PublicKey {
660 return (*dsaPublicKey)(&k.PrivateKey.PublicKey)
661}
662
663func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) {
664 return k.SignWithAlgorithm(rand, data, k.PublicKey().Type())
665}
666
667func (k *dsaPrivateKey) Algorithms() []string {
668 return []string{k.PublicKey().Type()}
669}
670
671func (k *dsaPrivateKey) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
672 if algorithm != "" && algorithm != k.PublicKey().Type() {
673 return nil, fmt.Errorf("ssh: unsupported signature algorithm %s", algorithm)
674 }
675
676 hash, err := hashFunc(k.PublicKey().Type())
677 if err != nil {
678 return nil, err
679 }
680 h := hash.New()
681 h.Write(data)
682 digest := h.Sum(nil)
683 r, s, err := dsa.Sign(rand, k.PrivateKey, digest)
684 if err != nil {
685 return nil, err
686 }
687
688 sig := make([]byte, 40)
689 rb := r.Bytes()
690 sb := s.Bytes()
691
692 copy(sig[20-len(rb):20], rb)
693 copy(sig[40-len(sb):], sb)
694
695 return &Signature{
696 Format: k.PublicKey().Type(),
697 Blob: sig,
698 }, nil
699}
700
701type ecdsaPublicKey ecdsa.PublicKey
702
703func (k *ecdsaPublicKey) Type() string {
704 return "ecdsa-sha2-" + k.nistID()
705}
706
707func (k *ecdsaPublicKey) nistID() string {
708 switch k.Params().BitSize {
709 case 256:
710 return "nistp256"
711 case 384:
712 return "nistp384"
713 case 521:
714 return "nistp521"
715 }
716 panic("ssh: unsupported ecdsa key size")
717}
718
719type ed25519PublicKey ed25519.PublicKey
720
721func (k ed25519PublicKey) Type() string {
722 return KeyAlgoED25519
723}
724
725func parseED25519(in []byte) (out PublicKey, rest []byte, err error) {
726 var w struct {
727 KeyBytes []byte
728 Rest []byte `ssh:"rest"`
729 }
730
731 if err := Unmarshal(in, &w); err != nil {
732 return nil, nil, err
733 }
734
735 if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
736 return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
737 }
738
739 return ed25519PublicKey(w.KeyBytes), w.Rest, nil
740}
741
742func (k ed25519PublicKey) Marshal() []byte {
743 w := struct {
744 Name string
745 KeyBytes []byte
746 }{
747 KeyAlgoED25519,
748 []byte(k),
749 }
750 return Marshal(&w)
751}
752
753func (k ed25519PublicKey) Verify(b []byte, sig *Signature) error {
754 if sig.Format != k.Type() {
755 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
756 }
757 if l := len(k); l != ed25519.PublicKeySize {
758 return fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
759 }
760
761 if ok := ed25519.Verify(ed25519.PublicKey(k), b, sig.Blob); !ok {
762 return errors.New("ssh: signature did not verify")
763 }
764
765 return nil
766}
767
768func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey {
769 return ed25519.PublicKey(k)
770}
771
772func supportedEllipticCurve(curve elliptic.Curve) bool {
773 return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521()
774}
775
776// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1.
777func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) {
778 var w struct {
779 Curve string
780 KeyBytes []byte
781 Rest []byte `ssh:"rest"`
782 }
783
784 if err := Unmarshal(in, &w); err != nil {
785 return nil, nil, err
786 }
787
788 key := new(ecdsa.PublicKey)
789
790 switch w.Curve {
791 case "nistp256":
792 key.Curve = elliptic.P256()
793 case "nistp384":
794 key.Curve = elliptic.P384()
795 case "nistp521":
796 key.Curve = elliptic.P521()
797 default:
798 return nil, nil, errors.New("ssh: unsupported curve")
799 }
800
801 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
802 if key.X == nil || key.Y == nil {
803 return nil, nil, errors.New("ssh: invalid curve point")
804 }
805 return (*ecdsaPublicKey)(key), w.Rest, nil
806}
807
808func (k *ecdsaPublicKey) Marshal() []byte {
809 // See RFC 5656, section 3.1.
810 keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
811 // ECDSA publickey struct layout should match the struct used by
812 // parseECDSACert in the x/crypto/ssh/agent package.
813 w := struct {
814 Name string
815 ID string
816 Key []byte
817 }{
818 k.Type(),
819 k.nistID(),
820 keyBytes,
821 }
822
823 return Marshal(&w)
824}
825
826func (k *ecdsaPublicKey) Verify(data []byte, sig *Signature) error {
827 if sig.Format != k.Type() {
828 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
829 }
830 hash, err := hashFunc(sig.Format)
831 if err != nil {
832 return err
833 }
834 h := hash.New()
835 h.Write(data)
836 digest := h.Sum(nil)
837
838 // Per RFC 5656, section 3.1.2,
839 // The ecdsa_signature_blob value has the following specific encoding:
840 // mpint r
841 // mpint s
842 var ecSig struct {
843 R *big.Int
844 S *big.Int
845 }
846
847 if err := Unmarshal(sig.Blob, &ecSig); err != nil {
848 return err
849 }
850
851 if ecdsa.Verify((*ecdsa.PublicKey)(k), digest, ecSig.R, ecSig.S) {
852 return nil
853 }
854 return errors.New("ssh: signature did not verify")
855}
856
857func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey {
858 return (*ecdsa.PublicKey)(k)
859}
860
861// skFields holds the additional fields present in U2F/FIDO2 signatures.
862// See openssh/PROTOCOL.u2f 'SSH U2F Signatures' for details.
863type skFields struct {
864 // Flags contains U2F/FIDO2 flags such as 'user present'
865 Flags byte
866 // Counter is a monotonic signature counter which can be
867 // used to detect concurrent use of a private key, should
868 // it be extracted from hardware.
869 Counter uint32
870}
871
872type skECDSAPublicKey struct {
873 // application is a URL-like string, typically "ssh:" for SSH.
874 // see openssh/PROTOCOL.u2f for details.
875 application string
876 ecdsa.PublicKey
877}
878
879func (k *skECDSAPublicKey) Type() string {
880 return KeyAlgoSKECDSA256
881}
882
883func (k *skECDSAPublicKey) nistID() string {
884 return "nistp256"
885}
886
887func parseSKECDSA(in []byte) (out PublicKey, rest []byte, err error) {
888 var w struct {
889 Curve string
890 KeyBytes []byte
891 Application string
892 Rest []byte `ssh:"rest"`
893 }
894
895 if err := Unmarshal(in, &w); err != nil {
896 return nil, nil, err
897 }
898
899 key := new(skECDSAPublicKey)
900 key.application = w.Application
901
902 if w.Curve != "nistp256" {
903 return nil, nil, errors.New("ssh: unsupported curve")
904 }
905 key.Curve = elliptic.P256()
906
907 key.X, key.Y = elliptic.Unmarshal(key.Curve, w.KeyBytes)
908 if key.X == nil || key.Y == nil {
909 return nil, nil, errors.New("ssh: invalid curve point")
910 }
911
912 return key, w.Rest, nil
913}
914
915func (k *skECDSAPublicKey) Marshal() []byte {
916 // See RFC 5656, section 3.1.
917 keyBytes := elliptic.Marshal(k.Curve, k.X, k.Y)
918 w := struct {
919 Name string
920 ID string
921 Key []byte
922 Application string
923 }{
924 k.Type(),
925 k.nistID(),
926 keyBytes,
927 k.application,
928 }
929
930 return Marshal(&w)
931}
932
933func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
934 if sig.Format != k.Type() {
935 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
936 }
937 hash, err := hashFunc(sig.Format)
938 if err != nil {
939 return err
940 }
941 h := hash.New()
942 h.Write([]byte(k.application))
943 appDigest := h.Sum(nil)
944
945 h.Reset()
946 h.Write(data)
947 dataDigest := h.Sum(nil)
948
949 var ecSig struct {
950 R *big.Int
951 S *big.Int
952 }
953 if err := Unmarshal(sig.Blob, &ecSig); err != nil {
954 return err
955 }
956
957 var skf skFields
958 if err := Unmarshal(sig.Rest, &skf); err != nil {
959 return err
960 }
961
962 blob := struct {
963 ApplicationDigest []byte `ssh:"rest"`
964 Flags byte
965 Counter uint32
966 MessageDigest []byte `ssh:"rest"`
967 }{
968 appDigest,
969 skf.Flags,
970 skf.Counter,
971 dataDigest,
972 }
973
974 original := Marshal(blob)
975
976 h.Reset()
977 h.Write(original)
978 digest := h.Sum(nil)
979
980 if ecdsa.Verify((*ecdsa.PublicKey)(&k.PublicKey), digest, ecSig.R, ecSig.S) {
981 return nil
982 }
983 return errors.New("ssh: signature did not verify")
984}
985
986func (k *skECDSAPublicKey) CryptoPublicKey() crypto.PublicKey {
987 return &k.PublicKey
988}
989
990type skEd25519PublicKey struct {
991 // application is a URL-like string, typically "ssh:" for SSH.
992 // see openssh/PROTOCOL.u2f for details.
993 application string
994 ed25519.PublicKey
995}
996
997func (k *skEd25519PublicKey) Type() string {
998 return KeyAlgoSKED25519
999}
1000
1001func parseSKEd25519(in []byte) (out PublicKey, rest []byte, err error) {
1002 var w struct {
1003 KeyBytes []byte
1004 Application string
1005 Rest []byte `ssh:"rest"`
1006 }
1007
1008 if err := Unmarshal(in, &w); err != nil {
1009 return nil, nil, err
1010 }
1011
1012 if l := len(w.KeyBytes); l != ed25519.PublicKeySize {
1013 return nil, nil, fmt.Errorf("invalid size %d for Ed25519 public key", l)
1014 }
1015
1016 key := new(skEd25519PublicKey)
1017 key.application = w.Application
1018 key.PublicKey = ed25519.PublicKey(w.KeyBytes)
1019
1020 return key, w.Rest, nil
1021}
1022
1023func (k *skEd25519PublicKey) Marshal() []byte {
1024 w := struct {
1025 Name string
1026 KeyBytes []byte
1027 Application string
1028 }{
1029 KeyAlgoSKED25519,
1030 []byte(k.PublicKey),
1031 k.application,
1032 }
1033 return Marshal(&w)
1034}
1035
1036func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
1037 if sig.Format != k.Type() {
1038 return fmt.Errorf("ssh: signature type %s for key type %s", sig.Format, k.Type())
1039 }
1040 if l := len(k.PublicKey); l != ed25519.PublicKeySize {
1041 return fmt.Errorf("invalid size %d for Ed25519 public key", l)
1042 }
1043
1044 hash, err := hashFunc(sig.Format)
1045 if err != nil {
1046 return err
1047 }
1048 h := hash.New()
1049 h.Write([]byte(k.application))
1050 appDigest := h.Sum(nil)
1051
1052 h.Reset()
1053 h.Write(data)
1054 dataDigest := h.Sum(nil)
1055
1056 var edSig struct {
1057 Signature []byte `ssh:"rest"`
1058 }
1059
1060 if err := Unmarshal(sig.Blob, &edSig); err != nil {
1061 return err
1062 }
1063
1064 var skf skFields
1065 if err := Unmarshal(sig.Rest, &skf); err != nil {
1066 return err
1067 }
1068
1069 blob := struct {
1070 ApplicationDigest []byte `ssh:"rest"`
1071 Flags byte
1072 Counter uint32
1073 MessageDigest []byte `ssh:"rest"`
1074 }{
1075 appDigest,
1076 skf.Flags,
1077 skf.Counter,
1078 dataDigest,
1079 }
1080
1081 original := Marshal(blob)
1082
1083 if ok := ed25519.Verify(k.PublicKey, original, edSig.Signature); !ok {
1084 return errors.New("ssh: signature did not verify")
1085 }
1086
1087 return nil
1088}
1089
1090func (k *skEd25519PublicKey) CryptoPublicKey() crypto.PublicKey {
1091 return k.PublicKey
1092}
1093
1094// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
1095// *ecdsa.PrivateKey or any other crypto.Signer and returns a
1096// corresponding Signer instance. ECDSA keys must use P-256, P-384 or
1097// P-521. DSA keys must use parameter size L1024N160.
1098func NewSignerFromKey(key interface{}) (Signer, error) {
1099 switch key := key.(type) {
1100 case crypto.Signer:
1101 return NewSignerFromSigner(key)
1102 case *dsa.PrivateKey:
1103 return newDSAPrivateKey(key)
1104 default:
1105 return nil, fmt.Errorf("ssh: unsupported key type %T", key)
1106 }
1107}
1108
1109func newDSAPrivateKey(key *dsa.PrivateKey) (Signer, error) {
1110 if err := checkDSAParams(&key.PublicKey.Parameters); err != nil {
1111 return nil, err
1112 }
1113
1114 return &dsaPrivateKey{key}, nil
1115}
1116
1117type wrappedSigner struct {
1118 signer crypto.Signer
1119 pubKey PublicKey
1120}
1121
1122// NewSignerFromSigner takes any crypto.Signer implementation and
1123// returns a corresponding Signer interface. This can be used, for
1124// example, with keys kept in hardware modules.
1125func NewSignerFromSigner(signer crypto.Signer) (Signer, error) {
1126 pubKey, err := NewPublicKey(signer.Public())
1127 if err != nil {
1128 return nil, err
1129 }
1130
1131 return &wrappedSigner{signer, pubKey}, nil
1132}
1133
1134func (s *wrappedSigner) PublicKey() PublicKey {
1135 return s.pubKey
1136}
1137
1138func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) {
1139 return s.SignWithAlgorithm(rand, data, s.pubKey.Type())
1140}
1141
1142func (s *wrappedSigner) Algorithms() []string {
1143 return algorithmsForKeyFormat(s.pubKey.Type())
1144}
1145
1146func (s *wrappedSigner) SignWithAlgorithm(rand io.Reader, data []byte, algorithm string) (*Signature, error) {
1147 if algorithm == "" {
1148 algorithm = s.pubKey.Type()
1149 }
1150
1151 if !slices.Contains(s.Algorithms(), algorithm) {
1152 return nil, fmt.Errorf("ssh: unsupported signature algorithm %q for key format %q", algorithm, s.pubKey.Type())
1153 }
1154
1155 hashFunc, err := hashFunc(algorithm)
1156 if err != nil {
1157 return nil, err
1158 }
1159 var digest []byte
1160 if hashFunc != 0 {
1161 h := hashFunc.New()
1162 h.Write(data)
1163 digest = h.Sum(nil)
1164 } else {
1165 digest = data
1166 }
1167
1168 signature, err := s.signer.Sign(rand, digest, hashFunc)
1169 if err != nil {
1170 return nil, err
1171 }
1172
1173 // crypto.Signer.Sign is expected to return an ASN.1-encoded signature
1174 // for ECDSA and DSA, but that's not the encoding expected by SSH, so
1175 // re-encode.
1176 switch s.pubKey.(type) {
1177 case *ecdsaPublicKey, *dsaPublicKey:
1178 type asn1Signature struct {
1179 R, S *big.Int
1180 }
1181 asn1Sig := new(asn1Signature)
1182 _, err := asn1.Unmarshal(signature, asn1Sig)
1183 if err != nil {
1184 return nil, err
1185 }
1186
1187 switch s.pubKey.(type) {
1188 case *ecdsaPublicKey:
1189 signature = Marshal(asn1Sig)
1190
1191 case *dsaPublicKey:
1192 signature = make([]byte, 40)
1193 r := asn1Sig.R.Bytes()
1194 s := asn1Sig.S.Bytes()
1195 copy(signature[20-len(r):20], r)
1196 copy(signature[40-len(s):40], s)
1197 }
1198 }
1199
1200 return &Signature{
1201 Format: algorithm,
1202 Blob: signature,
1203 }, nil
1204}
1205
1206// NewPublicKey takes an *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
1207// or ed25519.PublicKey returns a corresponding PublicKey instance.
1208// ECDSA keys must use P-256, P-384 or P-521.
1209func NewPublicKey(key interface{}) (PublicKey, error) {
1210 switch key := key.(type) {
1211 case *rsa.PublicKey:
1212 return (*rsaPublicKey)(key), nil
1213 case *ecdsa.PublicKey:
1214 if !supportedEllipticCurve(key.Curve) {
1215 return nil, errors.New("ssh: only P-256, P-384 and P-521 EC keys are supported")
1216 }
1217 return (*ecdsaPublicKey)(key), nil
1218 case *dsa.PublicKey:
1219 return (*dsaPublicKey)(key), nil
1220 case ed25519.PublicKey:
1221 if l := len(key); l != ed25519.PublicKeySize {
1222 return nil, fmt.Errorf("ssh: invalid size %d for Ed25519 public key", l)
1223 }
1224 return ed25519PublicKey(key), nil
1225 default:
1226 return nil, fmt.Errorf("ssh: unsupported key type %T", key)
1227 }
1228}
1229
1230// ParsePrivateKey returns a Signer from a PEM encoded private key. It supports
1231// the same keys as ParseRawPrivateKey. If the private key is encrypted, it
1232// will return a PassphraseMissingError.
1233func ParsePrivateKey(pemBytes []byte) (Signer, error) {
1234 key, err := ParseRawPrivateKey(pemBytes)
1235 if err != nil {
1236 return nil, err
1237 }
1238
1239 return NewSignerFromKey(key)
1240}
1241
1242// ParsePrivateKeyWithPassphrase returns a Signer from a PEM encoded private
1243// key and passphrase. It supports the same keys as
1244// ParseRawPrivateKeyWithPassphrase.
1245func ParsePrivateKeyWithPassphrase(pemBytes, passphrase []byte) (Signer, error) {
1246 key, err := ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase)
1247 if err != nil {
1248 return nil, err
1249 }
1250
1251 return NewSignerFromKey(key)
1252}
1253
1254// encryptedBlock tells whether a private key is
1255// encrypted by examining its Proc-Type header
1256// for a mention of ENCRYPTED
1257// according to RFC 1421 Section 4.6.1.1.
1258func encryptedBlock(block *pem.Block) bool {
1259 return strings.Contains(block.Headers["Proc-Type"], "ENCRYPTED")
1260}
1261
1262// A PassphraseMissingError indicates that parsing this private key requires a
1263// passphrase. Use ParsePrivateKeyWithPassphrase.
1264type PassphraseMissingError struct {
1265 // PublicKey will be set if the private key format includes an unencrypted
1266 // public key along with the encrypted private key.
1267 PublicKey PublicKey
1268}
1269
1270func (*PassphraseMissingError) Error() string {
1271 return "ssh: this private key is passphrase protected"
1272}
1273
1274// ParseRawPrivateKey returns a private key from a PEM encoded private key. It supports
1275// RSA, DSA, ECDSA, and Ed25519 private keys in PKCS#1, PKCS#8, OpenSSL, and OpenSSH
1276// formats. If the private key is encrypted, it will return a PassphraseMissingError.
1277func ParseRawPrivateKey(pemBytes []byte) (interface{}, error) {
1278 block, _ := pem.Decode(pemBytes)
1279 if block == nil {
1280 return nil, errors.New("ssh: no key found")
1281 }
1282
1283 if encryptedBlock(block) {
1284 return nil, &PassphraseMissingError{}
1285 }
1286
1287 switch block.Type {
1288 case "RSA PRIVATE KEY":
1289 return x509.ParsePKCS1PrivateKey(block.Bytes)
1290 // RFC5208 - https://tools.ietf.org/html/rfc5208
1291 case "PRIVATE KEY":
1292 return x509.ParsePKCS8PrivateKey(block.Bytes)
1293 case "EC PRIVATE KEY":
1294 return x509.ParseECPrivateKey(block.Bytes)
1295 case "DSA PRIVATE KEY":
1296 return ParseDSAPrivateKey(block.Bytes)
1297 case "OPENSSH PRIVATE KEY":
1298 return parseOpenSSHPrivateKey(block.Bytes, unencryptedOpenSSHKey)
1299 default:
1300 return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type)
1301 }
1302}
1303
1304// ParseRawPrivateKeyWithPassphrase returns a private key decrypted with
1305// passphrase from a PEM encoded private key. If the passphrase is wrong, it
1306// will return x509.IncorrectPasswordError.
1307func ParseRawPrivateKeyWithPassphrase(pemBytes, passphrase []byte) (interface{}, error) {
1308 block, _ := pem.Decode(pemBytes)
1309 if block == nil {
1310 return nil, errors.New("ssh: no key found")
1311 }
1312
1313 if block.Type == "OPENSSH PRIVATE KEY" {
1314 return parseOpenSSHPrivateKey(block.Bytes, passphraseProtectedOpenSSHKey(passphrase))
1315 }
1316
1317 if !encryptedBlock(block) || !x509.IsEncryptedPEMBlock(block) {
1318 return nil, errors.New("ssh: not an encrypted key")
1319 }
1320
1321 buf, err := x509.DecryptPEMBlock(block, passphrase)
1322 if err != nil {
1323 if err == x509.IncorrectPasswordError {
1324 return nil, err
1325 }
1326 return nil, fmt.Errorf("ssh: cannot decode encrypted private keys: %v", err)
1327 }
1328
1329 var result interface{}
1330
1331 switch block.Type {
1332 case "RSA PRIVATE KEY":
1333 result, err = x509.ParsePKCS1PrivateKey(buf)
1334 case "EC PRIVATE KEY":
1335 result, err = x509.ParseECPrivateKey(buf)
1336 case "DSA PRIVATE KEY":
1337 result, err = ParseDSAPrivateKey(buf)
1338 default:
1339 err = fmt.Errorf("ssh: unsupported key type %q", block.Type)
1340 }
1341 // Because of deficiencies in the format, DecryptPEMBlock does not always
1342 // detect an incorrect password. In these cases decrypted DER bytes is
1343 // random noise. If the parsing of the key returns an asn1.StructuralError
1344 // we return x509.IncorrectPasswordError.
1345 if _, ok := err.(asn1.StructuralError); ok {
1346 return nil, x509.IncorrectPasswordError
1347 }
1348
1349 return result, err
1350}
1351
1352// ParseDSAPrivateKey returns a DSA private key from its ASN.1 DER encoding, as
1353// specified by the OpenSSL DSA man page.
1354func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
1355 var k struct {
1356 Version int
1357 P *big.Int
1358 Q *big.Int
1359 G *big.Int
1360 Pub *big.Int
1361 Priv *big.Int
1362 }
1363 rest, err := asn1.Unmarshal(der, &k)
1364 if err != nil {
1365 return nil, errors.New("ssh: failed to parse DSA key: " + err.Error())
1366 }
1367 if len(rest) > 0 {
1368 return nil, errors.New("ssh: garbage after DSA key")
1369 }
1370
1371 return &dsa.PrivateKey{
1372 PublicKey: dsa.PublicKey{
1373 Parameters: dsa.Parameters{
1374 P: k.P,
1375 Q: k.Q,
1376 G: k.G,
1377 },
1378 Y: k.Pub,
1379 },
1380 X: k.Priv,
1381 }, nil
1382}
1383
1384func unencryptedOpenSSHKey(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
1385 if kdfName != "none" || cipherName != "none" {
1386 return nil, &PassphraseMissingError{}
1387 }
1388 if kdfOpts != "" {
1389 return nil, errors.New("ssh: invalid openssh private key")
1390 }
1391 return privKeyBlock, nil
1392}
1393
1394func passphraseProtectedOpenSSHKey(passphrase []byte) openSSHDecryptFunc {
1395 return func(cipherName, kdfName, kdfOpts string, privKeyBlock []byte) ([]byte, error) {
1396 if kdfName == "none" || cipherName == "none" {
1397 return nil, errors.New("ssh: key is not password protected")
1398 }
1399 if kdfName != "bcrypt" {
1400 return nil, fmt.Errorf("ssh: unknown KDF %q, only supports %q", kdfName, "bcrypt")
1401 }
1402
1403 var opts struct {
1404 Salt string
1405 Rounds uint32
1406 }
1407 if err := Unmarshal([]byte(kdfOpts), &opts); err != nil {
1408 return nil, err
1409 }
1410
1411 k, err := bcrypt_pbkdf.Key(passphrase, []byte(opts.Salt), int(opts.Rounds), 32+16)
1412 if err != nil {
1413 return nil, err
1414 }
1415 key, iv := k[:32], k[32:]
1416
1417 c, err := aes.NewCipher(key)
1418 if err != nil {
1419 return nil, err
1420 }
1421 switch cipherName {
1422 case "aes256-ctr":
1423 ctr := cipher.NewCTR(c, iv)
1424 ctr.XORKeyStream(privKeyBlock, privKeyBlock)
1425 case "aes256-cbc":
1426 if len(privKeyBlock)%c.BlockSize() != 0 {
1427 return nil, fmt.Errorf("ssh: invalid encrypted private key length, not a multiple of the block size")
1428 }
1429 cbc := cipher.NewCBCDecrypter(c, iv)
1430 cbc.CryptBlocks(privKeyBlock, privKeyBlock)
1431 default:
1432 return nil, fmt.Errorf("ssh: unknown cipher %q, only supports %q or %q", cipherName, "aes256-ctr", "aes256-cbc")
1433 }
1434
1435 return privKeyBlock, nil
1436 }
1437}
1438
1439func unencryptedOpenSSHMarshaler(privKeyBlock []byte) ([]byte, string, string, string, error) {
1440 key := generateOpenSSHPadding(privKeyBlock, 8)
1441 return key, "none", "none", "", nil
1442}
1443
1444func passphraseProtectedOpenSSHMarshaler(passphrase []byte) openSSHEncryptFunc {
1445 return func(privKeyBlock []byte) ([]byte, string, string, string, error) {
1446 salt := make([]byte, 16)
1447 if _, err := rand.Read(salt); err != nil {
1448 return nil, "", "", "", err
1449 }
1450
1451 opts := struct {
1452 Salt []byte
1453 Rounds uint32
1454 }{salt, 16}
1455
1456 // Derive key to encrypt the private key block.
1457 k, err := bcrypt_pbkdf.Key(passphrase, salt, int(opts.Rounds), 32+aes.BlockSize)
1458 if err != nil {
1459 return nil, "", "", "", err
1460 }
1461
1462 // Add padding matching the block size of AES.
1463 keyBlock := generateOpenSSHPadding(privKeyBlock, aes.BlockSize)
1464
1465 // Encrypt the private key using the derived secret.
1466
1467 dst := make([]byte, len(keyBlock))
1468 key, iv := k[:32], k[32:]
1469 block, err := aes.NewCipher(key)
1470 if err != nil {
1471 return nil, "", "", "", err
1472 }
1473
1474 stream := cipher.NewCTR(block, iv)
1475 stream.XORKeyStream(dst, keyBlock)
1476
1477 return dst, "aes256-ctr", "bcrypt", string(Marshal(opts)), nil
1478 }
1479}
1480
1481const privateKeyAuthMagic = "openssh-key-v1\x00"
1482
1483type openSSHDecryptFunc func(CipherName, KdfName, KdfOpts string, PrivKeyBlock []byte) ([]byte, error)
1484type openSSHEncryptFunc func(PrivKeyBlock []byte) (ProtectedKeyBlock []byte, cipherName, kdfName, kdfOptions string, err error)
1485
1486type openSSHEncryptedPrivateKey struct {
1487 CipherName string
1488 KdfName string
1489 KdfOpts string
1490 NumKeys uint32
1491 PubKey []byte
1492 PrivKeyBlock []byte
1493 Rest []byte `ssh:"rest"`
1494}
1495
1496type openSSHPrivateKey struct {
1497 Check1 uint32
1498 Check2 uint32
1499 Keytype string
1500 Rest []byte `ssh:"rest"`
1501}
1502
1503type openSSHRSAPrivateKey struct {
1504 N *big.Int
1505 E *big.Int
1506 D *big.Int
1507 Iqmp *big.Int
1508 P *big.Int
1509 Q *big.Int
1510 Comment string
1511 Pad []byte `ssh:"rest"`
1512}
1513
1514type openSSHEd25519PrivateKey struct {
1515 Pub []byte
1516 Priv []byte
1517 Comment string
1518 Pad []byte `ssh:"rest"`
1519}
1520
1521type openSSHECDSAPrivateKey struct {
1522 Curve string
1523 Pub []byte
1524 D *big.Int
1525 Comment string
1526 Pad []byte `ssh:"rest"`
1527}
1528
1529// parseOpenSSHPrivateKey parses an OpenSSH private key, using the decrypt
1530// function to unwrap the encrypted portion. unencryptedOpenSSHKey can be used
1531// as the decrypt function to parse an unencrypted private key. See
1532// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key.
1533func parseOpenSSHPrivateKey(key []byte, decrypt openSSHDecryptFunc) (crypto.PrivateKey, error) {
1534 if len(key) < len(privateKeyAuthMagic) || string(key[:len(privateKeyAuthMagic)]) != privateKeyAuthMagic {
1535 return nil, errors.New("ssh: invalid openssh private key format")
1536 }
1537 remaining := key[len(privateKeyAuthMagic):]
1538
1539 var w openSSHEncryptedPrivateKey
1540 if err := Unmarshal(remaining, &w); err != nil {
1541 return nil, err
1542 }
1543 if w.NumKeys != 1 {
1544 // We only support single key files, and so does OpenSSH.
1545 // https://github.com/openssh/openssh-portable/blob/4103a3ec7/sshkey.c#L4171
1546 return nil, errors.New("ssh: multi-key files are not supported")
1547 }
1548
1549 privKeyBlock, err := decrypt(w.CipherName, w.KdfName, w.KdfOpts, w.PrivKeyBlock)
1550 if err != nil {
1551 if err, ok := err.(*PassphraseMissingError); ok {
1552 pub, errPub := ParsePublicKey(w.PubKey)
1553 if errPub != nil {
1554 return nil, fmt.Errorf("ssh: failed to parse embedded public key: %v", errPub)
1555 }
1556 err.PublicKey = pub
1557 }
1558 return nil, err
1559 }
1560
1561 var pk1 openSSHPrivateKey
1562 if err := Unmarshal(privKeyBlock, &pk1); err != nil || pk1.Check1 != pk1.Check2 {
1563 if w.CipherName != "none" {
1564 return nil, x509.IncorrectPasswordError
1565 }
1566 return nil, errors.New("ssh: malformed OpenSSH key")
1567 }
1568
1569 switch pk1.Keytype {
1570 case KeyAlgoRSA:
1571 var key openSSHRSAPrivateKey
1572 if err := Unmarshal(pk1.Rest, &key); err != nil {
1573 return nil, err
1574 }
1575
1576 if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
1577 return nil, err
1578 }
1579
1580 pk := &rsa.PrivateKey{
1581 PublicKey: rsa.PublicKey{
1582 N: key.N,
1583 E: int(key.E.Int64()),
1584 },
1585 D: key.D,
1586 Primes: []*big.Int{key.P, key.Q},
1587 }
1588
1589 if err := pk.Validate(); err != nil {
1590 return nil, err
1591 }
1592
1593 pk.Precompute()
1594
1595 return pk, nil
1596 case KeyAlgoED25519:
1597 var key openSSHEd25519PrivateKey
1598 if err := Unmarshal(pk1.Rest, &key); err != nil {
1599 return nil, err
1600 }
1601
1602 if len(key.Priv) != ed25519.PrivateKeySize {
1603 return nil, errors.New("ssh: private key unexpected length")
1604 }
1605
1606 if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
1607 return nil, err
1608 }
1609
1610 pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
1611 copy(pk, key.Priv)
1612 return &pk, nil
1613 case KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521:
1614 var key openSSHECDSAPrivateKey
1615 if err := Unmarshal(pk1.Rest, &key); err != nil {
1616 return nil, err
1617 }
1618
1619 if err := checkOpenSSHKeyPadding(key.Pad); err != nil {
1620 return nil, err
1621 }
1622
1623 var curve elliptic.Curve
1624 switch key.Curve {
1625 case "nistp256":
1626 curve = elliptic.P256()
1627 case "nistp384":
1628 curve = elliptic.P384()
1629 case "nistp521":
1630 curve = elliptic.P521()
1631 default:
1632 return nil, errors.New("ssh: unhandled elliptic curve: " + key.Curve)
1633 }
1634
1635 X, Y := elliptic.Unmarshal(curve, key.Pub)
1636 if X == nil || Y == nil {
1637 return nil, errors.New("ssh: failed to unmarshal public key")
1638 }
1639
1640 if key.D.Cmp(curve.Params().N) >= 0 {
1641 return nil, errors.New("ssh: scalar is out of range")
1642 }
1643
1644 x, y := curve.ScalarBaseMult(key.D.Bytes())
1645 if x.Cmp(X) != 0 || y.Cmp(Y) != 0 {
1646 return nil, errors.New("ssh: public key does not match private key")
1647 }
1648
1649 return &ecdsa.PrivateKey{
1650 PublicKey: ecdsa.PublicKey{
1651 Curve: curve,
1652 X: X,
1653 Y: Y,
1654 },
1655 D: key.D,
1656 }, nil
1657 default:
1658 return nil, errors.New("ssh: unhandled key type")
1659 }
1660}
1661
1662func marshalOpenSSHPrivateKey(key crypto.PrivateKey, comment string, encrypt openSSHEncryptFunc) (*pem.Block, error) {
1663 var w openSSHEncryptedPrivateKey
1664 var pk1 openSSHPrivateKey
1665
1666 // Random check bytes.
1667 var check uint32
1668 if err := binary.Read(rand.Reader, binary.BigEndian, &check); err != nil {
1669 return nil, err
1670 }
1671
1672 pk1.Check1 = check
1673 pk1.Check2 = check
1674 w.NumKeys = 1
1675
1676 // Use a []byte directly on ed25519 keys.
1677 if k, ok := key.(*ed25519.PrivateKey); ok {
1678 key = *k
1679 }
1680
1681 switch k := key.(type) {
1682 case *rsa.PrivateKey:
1683 E := new(big.Int).SetInt64(int64(k.PublicKey.E))
1684 // Marshal public key:
1685 // E and N are in reversed order in the public and private key.
1686 pubKey := struct {
1687 KeyType string
1688 E *big.Int
1689 N *big.Int
1690 }{
1691 KeyAlgoRSA,
1692 E, k.PublicKey.N,
1693 }
1694 w.PubKey = Marshal(pubKey)
1695
1696 // Marshal private key.
1697 key := openSSHRSAPrivateKey{
1698 N: k.PublicKey.N,
1699 E: E,
1700 D: k.D,
1701 Iqmp: k.Precomputed.Qinv,
1702 P: k.Primes[0],
1703 Q: k.Primes[1],
1704 Comment: comment,
1705 }
1706 pk1.Keytype = KeyAlgoRSA
1707 pk1.Rest = Marshal(key)
1708 case ed25519.PrivateKey:
1709 pub := make([]byte, ed25519.PublicKeySize)
1710 priv := make([]byte, ed25519.PrivateKeySize)
1711 copy(pub, k[32:])
1712 copy(priv, k)
1713
1714 // Marshal public key.
1715 pubKey := struct {
1716 KeyType string
1717 Pub []byte
1718 }{
1719 KeyAlgoED25519, pub,
1720 }
1721 w.PubKey = Marshal(pubKey)
1722
1723 // Marshal private key.
1724 key := openSSHEd25519PrivateKey{
1725 Pub: pub,
1726 Priv: priv,
1727 Comment: comment,
1728 }
1729 pk1.Keytype = KeyAlgoED25519
1730 pk1.Rest = Marshal(key)
1731 case *ecdsa.PrivateKey:
1732 var curve, keyType string
1733 switch name := k.Curve.Params().Name; name {
1734 case "P-256":
1735 curve = "nistp256"
1736 keyType = KeyAlgoECDSA256
1737 case "P-384":
1738 curve = "nistp384"
1739 keyType = KeyAlgoECDSA384
1740 case "P-521":
1741 curve = "nistp521"
1742 keyType = KeyAlgoECDSA521
1743 default:
1744 return nil, errors.New("ssh: unhandled elliptic curve " + name)
1745 }
1746
1747 pub := elliptic.Marshal(k.Curve, k.PublicKey.X, k.PublicKey.Y)
1748
1749 // Marshal public key.
1750 pubKey := struct {
1751 KeyType string
1752 Curve string
1753 Pub []byte
1754 }{
1755 keyType, curve, pub,
1756 }
1757 w.PubKey = Marshal(pubKey)
1758
1759 // Marshal private key.
1760 key := openSSHECDSAPrivateKey{
1761 Curve: curve,
1762 Pub: pub,
1763 D: k.D,
1764 Comment: comment,
1765 }
1766 pk1.Keytype = keyType
1767 pk1.Rest = Marshal(key)
1768 default:
1769 return nil, fmt.Errorf("ssh: unsupported key type %T", k)
1770 }
1771
1772 var err error
1773 // Add padding and encrypt the key if necessary.
1774 w.PrivKeyBlock, w.CipherName, w.KdfName, w.KdfOpts, err = encrypt(Marshal(pk1))
1775 if err != nil {
1776 return nil, err
1777 }
1778
1779 b := Marshal(w)
1780 block := &pem.Block{
1781 Type: "OPENSSH PRIVATE KEY",
1782 Bytes: append([]byte(privateKeyAuthMagic), b...),
1783 }
1784 return block, nil
1785}
1786
1787func checkOpenSSHKeyPadding(pad []byte) error {
1788 for i, b := range pad {
1789 if int(b) != i+1 {
1790 return errors.New("ssh: padding not as expected")
1791 }
1792 }
1793 return nil
1794}
1795
1796func generateOpenSSHPadding(block []byte, blockSize int) []byte {
1797 for i, l := 0, len(block); (l+i)%blockSize != 0; i++ {
1798 block = append(block, byte(i+1))
1799 }
1800 return block
1801}
1802
1803// FingerprintLegacyMD5 returns the user presentation of the key's
1804// fingerprint as described by RFC 4716 section 4.
1805func FingerprintLegacyMD5(pubKey PublicKey) string {
1806 md5sum := md5.Sum(pubKey.Marshal())
1807 hexarray := make([]string, len(md5sum))
1808 for i, c := range md5sum {
1809 hexarray[i] = hex.EncodeToString([]byte{c})
1810 }
1811 return strings.Join(hexarray, ":")
1812}
1813
1814// FingerprintSHA256 returns the user presentation of the key's
1815// fingerprint as unpadded base64 encoded sha256 hash.
1816// This format was introduced from OpenSSH 6.8.
1817// https://www.openssh.com/txt/release-6.8
1818// https://tools.ietf.org/html/rfc4648#section-3.2 (unpadded base64 encoding)
1819func FingerprintSHA256(pubKey PublicKey) string {
1820 sha256sum := sha256.Sum256(pubKey.Marshal())
1821 hash := base64.RawStdEncoding.EncodeToString(sha256sum[:])
1822 return "SHA256:" + hash
1823}