diff options
Diffstat (limited to 'vendor/golang.org/x/crypto/ssh/keys.go')
-rw-r--r-- | vendor/golang.org/x/crypto/ssh/keys.go | 905 |
1 files changed, 905 insertions, 0 deletions
diff --git a/vendor/golang.org/x/crypto/ssh/keys.go b/vendor/golang.org/x/crypto/ssh/keys.go new file mode 100644 index 0000000..f38de98 --- /dev/null +++ b/vendor/golang.org/x/crypto/ssh/keys.go | |||
@@ -0,0 +1,905 @@ | |||
1 | // Copyright 2012 The Go Authors. All rights reserved. | ||
2 | // Use of this source code is governed by a BSD-style | ||
3 | // license that can be found in the LICENSE file. | ||
4 | |||
5 | package ssh | ||
6 | |||
7 | import ( | ||
8 | "bytes" | ||
9 | "crypto" | ||
10 | "crypto/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. | ||
32 | const ( | ||
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. | ||
43 | func 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. | ||
66 | func 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. | ||
104 | func 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. | ||
164 | func 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. | ||
246 | func 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. | ||
262 | func 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. | ||
274 | type 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. | ||
280 | Marshal() []byte | ||
281 | |||
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 | ||
285 | } | ||
286 | |||
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 | ||
291 | } | ||
292 | |||
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 | ||
297 | |||
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) | ||
301 | } | ||
302 | |||
303 | type rsaPublicKey rsa.PublicKey | ||
304 | |||
305 | func (r *rsaPublicKey) Type() string { | ||
306 | return "ssh-rsa" | ||
307 | } | ||
308 | |||
309 | // parseRSA parses an RSA key according to RFC 4253, section 6.6. | ||
310 | func parseRSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
311 | var w struct { | ||
312 | E *big.Int | ||
313 | N *big.Int | ||
314 | Rest []byte `ssh:"rest"` | ||
315 | } | ||
316 | if err := Unmarshal(in, &w); err != nil { | ||
317 | return nil, nil, err | ||
318 | } | ||
319 | |||
320 | if w.E.BitLen() > 24 { | ||
321 | return nil, nil, errors.New("ssh: exponent too large") | ||
322 | } | ||
323 | e := w.E.Int64() | ||
324 | if e < 3 || e&1 == 0 { | ||
325 | return nil, nil, errors.New("ssh: incorrect exponent") | ||
326 | } | ||
327 | |||
328 | var key rsa.PublicKey | ||
329 | key.E = int(e) | ||
330 | key.N = w.N | ||
331 | return (*rsaPublicKey)(&key), w.Rest, nil | ||
332 | } | ||
333 | |||
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. | ||
338 | wirekey := struct { | ||
339 | Name string | ||
340 | E *big.Int | ||
341 | N *big.Int | ||
342 | }{ | ||
343 | KeyAlgoRSA, | ||
344 | e, | ||
345 | r.N, | ||
346 | } | ||
347 | return Marshal(&wirekey) | ||
348 | } | ||
349 | |||
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()) | ||
353 | } | ||
354 | h := crypto.SHA1.New() | ||
355 | h.Write(data) | ||
356 | digest := h.Sum(nil) | ||
357 | return rsa.VerifyPKCS1v15((*rsa.PublicKey)(r), crypto.SHA1, digest, sig.Blob) | ||
358 | } | ||
359 | |||
360 | func (r *rsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
361 | return (*rsa.PublicKey)(r) | ||
362 | } | ||
363 | |||
364 | type dsaPublicKey dsa.PublicKey | ||
365 | |||
366 | func (r *dsaPublicKey) Type() string { | ||
367 | return "ssh-dss" | ||
368 | } | ||
369 | |||
370 | // parseDSA parses an DSA key according to RFC 4253, section 6.6. | ||
371 | func parseDSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
372 | var w struct { | ||
373 | P, Q, G, Y *big.Int | ||
374 | Rest []byte `ssh:"rest"` | ||
375 | } | ||
376 | if err := Unmarshal(in, &w); err != nil { | ||
377 | return nil, nil, err | ||
378 | } | ||
379 | |||
380 | key := &dsaPublicKey{ | ||
381 | Parameters: dsa.Parameters{ | ||
382 | P: w.P, | ||
383 | Q: w.Q, | ||
384 | G: w.G, | ||
385 | }, | ||
386 | Y: w.Y, | ||
387 | } | ||
388 | return key, w.Rest, nil | ||
389 | } | ||
390 | |||
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. | ||
394 | w := struct { | ||
395 | Name string | ||
396 | P, Q, G, Y *big.Int | ||
397 | }{ | ||
398 | k.Type(), | ||
399 | k.P, | ||
400 | k.Q, | ||
401 | k.G, | ||
402 | k.Y, | ||
403 | } | ||
404 | |||
405 | return Marshal(&w) | ||
406 | } | ||
407 | |||
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()) | ||
411 | } | ||
412 | h := crypto.SHA1.New() | ||
413 | h.Write(data) | ||
414 | digest := h.Sum(nil) | ||
415 | |||
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") | ||
423 | } | ||
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) { | ||
427 | return nil | ||
428 | } | ||
429 | return errors.New("ssh: signature did not verify") | ||
430 | } | ||
431 | |||
432 | func (k *dsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
433 | return (*dsa.PublicKey)(k) | ||
434 | } | ||
435 | |||
436 | type dsaPrivateKey struct { | ||
437 | *dsa.PrivateKey | ||
438 | } | ||
439 | |||
440 | func (k *dsaPrivateKey) PublicKey() PublicKey { | ||
441 | return (*dsaPublicKey)(&k.PrivateKey.PublicKey) | ||
442 | } | ||
443 | |||
444 | func (k *dsaPrivateKey) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||
445 | h := crypto.SHA1.New() | ||
446 | h.Write(data) | ||
447 | digest := h.Sum(nil) | ||
448 | r, s, err := dsa.Sign(rand, k.PrivateKey, digest) | ||
449 | if err != nil { | ||
450 | return nil, err | ||
451 | } | ||
452 | |||
453 | sig := make([]byte, 40) | ||
454 | rb := r.Bytes() | ||
455 | sb := s.Bytes() | ||
456 | |||
457 | copy(sig[20-len(rb):20], rb) | ||
458 | copy(sig[40-len(sb):], sb) | ||
459 | |||
460 | return &Signature{ | ||
461 | Format: k.PublicKey().Type(), | ||
462 | Blob: sig, | ||
463 | }, nil | ||
464 | } | ||
465 | |||
466 | type ecdsaPublicKey ecdsa.PublicKey | ||
467 | |||
468 | func (key *ecdsaPublicKey) Type() string { | ||
469 | return "ecdsa-sha2-" + key.nistID() | ||
470 | } | ||
471 | |||
472 | func (key *ecdsaPublicKey) nistID() string { | ||
473 | switch key.Params().BitSize { | ||
474 | case 256: | ||
475 | return "nistp256" | ||
476 | case 384: | ||
477 | return "nistp384" | ||
478 | case 521: | ||
479 | return "nistp521" | ||
480 | } | ||
481 | panic("ssh: unsupported ecdsa key size") | ||
482 | } | ||
483 | |||
484 | type ed25519PublicKey ed25519.PublicKey | ||
485 | |||
486 | func (key ed25519PublicKey) Type() string { | ||
487 | return KeyAlgoED25519 | ||
488 | } | ||
489 | |||
490 | func parseED25519(in []byte) (out PublicKey, rest []byte, err error) { | ||
491 | var w struct { | ||
492 | KeyBytes []byte | ||
493 | Rest []byte `ssh:"rest"` | ||
494 | } | ||
495 | |||
496 | if err := Unmarshal(in, &w); err != nil { | ||
497 | return nil, nil, err | ||
498 | } | ||
499 | |||
500 | key := ed25519.PublicKey(w.KeyBytes) | ||
501 | |||
502 | return (ed25519PublicKey)(key), w.Rest, nil | ||
503 | } | ||
504 | |||
505 | func (key ed25519PublicKey) Marshal() []byte { | ||
506 | w := struct { | ||
507 | Name string | ||
508 | KeyBytes []byte | ||
509 | }{ | ||
510 | KeyAlgoED25519, | ||
511 | []byte(key), | ||
512 | } | ||
513 | return Marshal(&w) | ||
514 | } | ||
515 | |||
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()) | ||
519 | } | ||
520 | |||
521 | edKey := (ed25519.PublicKey)(key) | ||
522 | if ok := ed25519.Verify(edKey, b, sig.Blob); !ok { | ||
523 | return errors.New("ssh: signature did not verify") | ||
524 | } | ||
525 | |||
526 | return nil | ||
527 | } | ||
528 | |||
529 | func (k ed25519PublicKey) CryptoPublicKey() crypto.PublicKey { | ||
530 | return ed25519.PublicKey(k) | ||
531 | } | ||
532 | |||
533 | func supportedEllipticCurve(curve elliptic.Curve) bool { | ||
534 | return curve == elliptic.P256() || curve == elliptic.P384() || curve == elliptic.P521() | ||
535 | } | ||
536 | |||
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 | ||
541 | switch { | ||
542 | case bitSize <= 256: | ||
543 | return crypto.SHA256 | ||
544 | case bitSize <= 384: | ||
545 | return crypto.SHA384 | ||
546 | } | ||
547 | return crypto.SHA512 | ||
548 | } | ||
549 | |||
550 | // parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. | ||
551 | func parseECDSA(in []byte) (out PublicKey, rest []byte, err error) { | ||
552 | var w struct { | ||
553 | Curve string | ||
554 | KeyBytes []byte | ||
555 | Rest []byte `ssh:"rest"` | ||
556 | } | ||
557 | |||
558 | if err := Unmarshal(in, &w); err != nil { | ||
559 | return nil, nil, err | ||
560 | } | ||
561 | |||
562 | key := new(ecdsa.PublicKey) | ||
563 | |||
564 | switch w.Curve { | ||
565 | case "nistp256": | ||
566 | key.Curve = elliptic.P256() | ||
567 | case "nistp384": | ||
568 | key.Curve = elliptic.P384() | ||
569 | case "nistp521": | ||
570 | key.Curve = elliptic.P521() | ||
571 | default: | ||
572 | return nil, nil, errors.New("ssh: unsupported curve") | ||
573 | } | ||
574 | |||
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") | ||
578 | } | ||
579 | return (*ecdsaPublicKey)(key), w.Rest, nil | ||
580 | } | ||
581 | |||
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. | ||
587 | w := struct { | ||
588 | Name string | ||
589 | ID string | ||
590 | Key []byte | ||
591 | }{ | ||
592 | key.Type(), | ||
593 | key.nistID(), | ||
594 | keyBytes, | ||
595 | } | ||
596 | |||
597 | return Marshal(&w) | ||
598 | } | ||
599 | |||
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()) | ||
603 | } | ||
604 | |||
605 | h := ecHash(key.Curve).New() | ||
606 | h.Write(data) | ||
607 | digest := h.Sum(nil) | ||
608 | |||
609 | // Per RFC 5656, section 3.1.2, | ||
610 | // The ecdsa_signature_blob value has the following specific encoding: | ||
611 | // mpint r | ||
612 | // mpint s | ||
613 | var ecSig struct { | ||
614 | R *big.Int | ||
615 | S *big.Int | ||
616 | } | ||
617 | |||
618 | if err := Unmarshal(sig.Blob, &ecSig); err != nil { | ||
619 | return err | ||
620 | } | ||
621 | |||
622 | if ecdsa.Verify((*ecdsa.PublicKey)(key), digest, ecSig.R, ecSig.S) { | ||
623 | return nil | ||
624 | } | ||
625 | return errors.New("ssh: signature did not verify") | ||
626 | } | ||
627 | |||
628 | func (k *ecdsaPublicKey) CryptoPublicKey() crypto.PublicKey { | ||
629 | return (*ecdsa.PublicKey)(k) | ||
630 | } | ||
631 | |||
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) { | ||
637 | case crypto.Signer: | ||
638 | return NewSignerFromSigner(key) | ||
639 | case *dsa.PrivateKey: | ||
640 | return &dsaPrivateKey{key}, nil | ||
641 | default: | ||
642 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
643 | } | ||
644 | } | ||
645 | |||
646 | type wrappedSigner struct { | ||
647 | signer crypto.Signer | ||
648 | pubKey PublicKey | ||
649 | } | ||
650 | |||
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()) | ||
656 | if err != nil { | ||
657 | return nil, err | ||
658 | } | ||
659 | |||
660 | return &wrappedSigner{signer, pubKey}, nil | ||
661 | } | ||
662 | |||
663 | func (s *wrappedSigner) PublicKey() PublicKey { | ||
664 | return s.pubKey | ||
665 | } | ||
666 | |||
667 | func (s *wrappedSigner) Sign(rand io.Reader, data []byte) (*Signature, error) { | ||
668 | var hashFunc crypto.Hash | ||
669 | |||
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: | ||
676 | default: | ||
677 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
678 | } | ||
679 | |||
680 | var digest []byte | ||
681 | if hashFunc != 0 { | ||
682 | h := hashFunc.New() | ||
683 | h.Write(data) | ||
684 | digest = h.Sum(nil) | ||
685 | } else { | ||
686 | digest = data | ||
687 | } | ||
688 | |||
689 | signature, err := s.signer.Sign(rand, digest, hashFunc) | ||
690 | if err != nil { | ||
691 | return nil, err | ||
692 | } | ||
693 | |||
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 | ||
696 | // re-encode. | ||
697 | switch s.pubKey.(type) { | ||
698 | case *ecdsaPublicKey, *dsaPublicKey: | ||
699 | type asn1Signature struct { | ||
700 | R, S *big.Int | ||
701 | } | ||
702 | asn1Sig := new(asn1Signature) | ||
703 | _, err := asn1.Unmarshal(signature, asn1Sig) | ||
704 | if err != nil { | ||
705 | return nil, err | ||
706 | } | ||
707 | |||
708 | switch s.pubKey.(type) { | ||
709 | case *ecdsaPublicKey: | ||
710 | signature = Marshal(asn1Sig) | ||
711 | |||
712 | case *dsaPublicKey: | ||
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) | ||
718 | } | ||
719 | } | ||
720 | |||
721 | return &Signature{ | ||
722 | Format: s.pubKey.Type(), | ||
723 | Blob: signature, | ||
724 | }, nil | ||
725 | } | ||
726 | |||
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) { | ||
732 | case *rsa.PublicKey: | ||
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.") | ||
737 | } | ||
738 | return (*ecdsaPublicKey)(key), nil | ||
739 | case *dsa.PublicKey: | ||
740 | return (*dsaPublicKey)(key), nil | ||
741 | case ed25519.PublicKey: | ||
742 | return (ed25519PublicKey)(key), nil | ||
743 | default: | ||
744 | return nil, fmt.Errorf("ssh: unsupported key type %T", key) | ||
745 | } | ||
746 | } | ||
747 | |||
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) | ||
752 | if err != nil { | ||
753 | return nil, err | ||
754 | } | ||
755 | |||
756 | return NewSignerFromKey(key) | ||
757 | } | ||
758 | |||
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") | ||
765 | } | ||
766 | |||
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) | ||
771 | if block == nil { | ||
772 | return nil, errors.New("ssh: no key found") | ||
773 | } | ||
774 | |||
775 | if encryptedBlock(block) { | ||
776 | return nil, errors.New("ssh: cannot decode encrypted private keys") | ||
777 | } | ||
778 | |||
779 | switch block.Type { | ||
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) | ||
788 | default: | ||
789 | return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) | ||
790 | } | ||
791 | } | ||
792 | |||
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) { | ||
796 | var k struct { | ||
797 | Version int | ||
798 | P *big.Int | ||
799 | Q *big.Int | ||
800 | G *big.Int | ||
801 | Pub *big.Int | ||
802 | Priv *big.Int | ||
803 | } | ||
804 | rest, err := asn1.Unmarshal(der, &k) | ||
805 | if err != nil { | ||
806 | return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) | ||
807 | } | ||
808 | if len(rest) > 0 { | ||
809 | return nil, errors.New("ssh: garbage after DSA key") | ||
810 | } | ||
811 | |||
812 | return &dsa.PrivateKey{ | ||
813 | PublicKey: dsa.PublicKey{ | ||
814 | Parameters: dsa.Parameters{ | ||
815 | P: k.P, | ||
816 | Q: k.Q, | ||
817 | G: k.G, | ||
818 | }, | ||
819 | Y: k.Pub, | ||
820 | }, | ||
821 | X: k.Priv, | ||
822 | }, nil | ||
823 | } | ||
824 | |||
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") | ||
831 | } | ||
832 | remaining := key[len(magic):] | ||
833 | |||
834 | var w struct { | ||
835 | CipherName string | ||
836 | KdfName string | ||
837 | KdfOpts string | ||
838 | NumKeys uint32 | ||
839 | PubKey []byte | ||
840 | PrivKeyBlock []byte | ||
841 | } | ||
842 | |||
843 | if err := Unmarshal(remaining, &w); err != nil { | ||
844 | return nil, err | ||
845 | } | ||
846 | |||
847 | pk1 := struct { | ||
848 | Check1 uint32 | ||
849 | Check2 uint32 | ||
850 | Keytype string | ||
851 | Pub []byte | ||
852 | Priv []byte | ||
853 | Comment string | ||
854 | Pad []byte `ssh:"rest"` | ||
855 | }{} | ||
856 | |||
857 | if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil { | ||
858 | return nil, err | ||
859 | } | ||
860 | |||
861 | if pk1.Check1 != pk1.Check2 { | ||
862 | return nil, errors.New("ssh: checkint mismatch") | ||
863 | } | ||
864 | |||
865 | // we only handle ed25519 keys currently | ||
866 | if pk1.Keytype != KeyAlgoED25519 { | ||
867 | return nil, errors.New("ssh: unhandled key type") | ||
868 | } | ||
869 | |||
870 | for i, b := range pk1.Pad { | ||
871 | if int(b) != i+1 { | ||
872 | return nil, errors.New("ssh: padding not as expected") | ||
873 | } | ||
874 | } | ||
875 | |||
876 | if len(pk1.Priv) != ed25519.PrivateKeySize { | ||
877 | return nil, errors.New("ssh: private key unexpected length") | ||
878 | } | ||
879 | |||
880 | pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize)) | ||
881 | copy(pk, pk1.Priv) | ||
882 | return &pk, nil | ||
883 | } | ||
884 | |||
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}) | ||
892 | } | ||
893 | return strings.Join(hexarray, ":") | ||
894 | } | ||
895 | |||
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 | ||
905 | } | ||