Index: ssh/keys.go |
=================================================================== |
--- a/ssh/keys.go |
+++ b/ssh/keys.go |
@@ -7,6 +7,8 @@ |
import ( |
"bytes" |
"crypto/dsa" |
+ "crypto/ecdsa" |
+ "crypto/elliptic" |
"crypto/rsa" |
"encoding/base64" |
"math/big" |
@@ -29,11 +31,13 @@ |
} |
switch string(algo) { |
- case hostAlgoRSA: |
+ case keyAlgoRSA: |
return parseRSA(in) |
- case hostAlgoDSA: |
+ case keyAlgoDSA: |
return parseDSA(in) |
- case hostAlgoRSACertV01, hostAlgoDSACertV01: |
+ case keyAlgoECDSA256, keyAlgoECDSA384, keyAlgoECDSA521: |
+ return parseECDSA(in) |
+ case certAlgoRSAv01, certAlgoDSAv01, certAlgoECDSA256v01, certAlgoECDSA384v01, certAlgoECDSA521v01: |
return parseOpenSSHCertV01(in, string(algo)) |
} |
panic("ssh: unknown public key type") |
@@ -86,15 +90,49 @@ |
return key, in, ok |
} |
+// parseECDSA parses an ECDSA key according to RFC 5656, section 3.1. |
+func parseECDSA(in []byte) (out *ecdsa.PublicKey, rest []byte, ok bool) { |
+ var identifier []byte |
+ if identifier, in, ok = parseString(in); !ok { |
+ return |
+ } |
+ |
+ key := new(ecdsa.PublicKey) |
+ |
+ switch string(identifier) { |
+ case "nistp256": |
+ key.Curve = elliptic.P256() |
+ case "nistp384": |
+ key.Curve = elliptic.P384() |
+ case "nistp521": |
+ key.Curve = elliptic.P521() |
+ default: |
+ ok = false |
+ return |
+ } |
+ |
+ var keyBytes []byte |
+ if keyBytes, in, ok = parseString(in); !ok { |
+ return |
+ } |
+ |
+ key.X, key.Y = elliptic.Unmarshal(key.Curve, keyBytes) |
+ if key.X == nil || key.Y == nil { |
+ ok = false |
+ return |
+ } |
+ return key, in, ok |
dfc
2012/12/13 11:16:03
/s/return.*/return/
jmpittman
2012/12/13 18:38:49
Just return will only return out, rest, and ok whi
|
+} |
+ |
// marshalPrivRSA serializes an RSA private key according to RFC 4253, section 6.6. |
func marshalPrivRSA(priv *rsa.PrivateKey) []byte { |
e := new(big.Int).SetInt64(int64(priv.E)) |
- length := stringLength(len(hostAlgoRSA)) |
+ length := stringLength(len(keyAlgoRSA)) |
length += intLength(e) |
length += intLength(priv.N) |
ret := make([]byte, length) |
- r := marshalString(ret, []byte(hostAlgoRSA)) |
+ r := marshalString(ret, []byte(keyAlgoRSA)) |
r = marshalInt(r, e) |
r = marshalInt(r, priv.N) |
@@ -125,11 +163,35 @@ |
r := marshalInt(ret, key.P) |
r = marshalInt(r, key.Q) |
r = marshalInt(r, key.G) |
- marshalInt(r, key.Y) |
+ r = marshalInt(r, key.Y) |
return ret |
} |
+// marshalPubECDSA serializes an ECDSA public key according to RFC 5656, section 3.1. |
+func marshalPubECDSA(key *ecdsa.PublicKey) []byte { |
+ var identifier []byte |
+ switch key.Params().BitSize { |
+ case 256: |
+ identifier = []byte("nistp256") |
+ case 384: |
+ identifier = []byte("nistp384") |
+ case 521: |
+ identifier = []byte("nistp521") |
+ default: |
+ panic("ssh: unsupported ecdsa key size") |
+ } |
+ keyBytes := elliptic.Marshal(key.Curve, key.X, key.Y) |
+ |
+ length := stringLength(len(identifier)) |
+ length += stringLength(len(keyBytes)) |
+ |
+ ret := make([]byte, length) |
+ r := marshalString(ret, identifier) |
+ r = marshalString(r, keyBytes) |
+ return ret |
+} |
+ |
// parseAuthorizedKey parses a public key in OpenSSH authorized_keys format |
// (see sshd(8) manual page) once the options and key type fields have been |
// removed. |
@@ -196,8 +258,8 @@ |
// We don't support these keys. |
in = rest |
continue |
- case hostAlgoRSACertV01, hostAlgoDSACertV01, |
- hostAlgoECDSA256CertV01, hostAlgoECDSA384CertV01, hostAlgoECDSA521CertV01: |
+ case certAlgoRSAv01, certAlgoDSAv01, |
+ certAlgoECDSA256v01, certAlgoECDSA384v01, certAlgoECDSA521v01: |
// We don't support these certificates. |
in = rest |
continue |
@@ -270,15 +332,37 @@ |
b := &bytes.Buffer{} |
switch keyType := key.(type) { |
case *rsa.PublicKey: |
- b.WriteString(hostAlgoRSA) |
+ b.WriteString(keyAlgoRSA) |
case *dsa.PublicKey: |
- b.WriteString(hostAlgoDSA) |
+ b.WriteString(keyAlgoDSA) |
+ case *ecdsa.PublicKey: |
+ switch keyType.Params().BitSize { |
+ case 256: |
+ b.WriteString(keyAlgoECDSA256) |
+ case 384: |
+ b.WriteString(keyAlgoECDSA384) |
+ case 521: |
+ b.WriteString(keyAlgoECDSA521) |
+ default: |
+ panic("unexpected key type") |
dfc
2012/12/13 11:16:03
there are a lot of panics that all do the same thi
jmpittman
2012/12/13 18:38:49
Yeah, I agree. It does seem a bit excessive consid
|
+ } |
case *OpenSSHCertV01: |
switch keyType.Key.(type) { |
case *rsa.PublicKey: |
- b.WriteString(hostAlgoRSACertV01) |
+ b.WriteString(certAlgoRSAv01) |
case *dsa.PublicKey: |
- b.WriteString(hostAlgoDSACertV01) |
+ b.WriteString(certAlgoDSAv01) |
+ case *ecdsa.PublicKey: |
+ switch keyType.Key.(*ecdsa.PublicKey).Params().BitSize { |
+ case 256: |
+ b.WriteString(certAlgoECDSA256v01) |
+ case 384: |
+ b.WriteString(certAlgoECDSA384v01) |
+ case 521: |
+ b.WriteString(certAlgoECDSA521v01) |
+ default: |
+ panic("unexpected key type") |
+ } |
default: |
panic("unexpected key type") |
} |