diff options
| author | Han-Wen Nienhuys <hanwen@google.com> | 2013-09-26 11:17:52 -0400 |
|---|---|---|
| committer | Adam Langley <agl@golang.org> | 2013-09-26 11:17:52 -0400 |
| commit | 4e0581245c387292aaa4f50016fbf2c32ed9b954 (patch) | |
| tree | fea957691f2a0a51efe8f158e47e611bc7a1200c /ssh | |
| parent | 73e99326fb280d3bfd0c28ed55d0a989bf70f8d8 (diff) | |
| download | go-x-crypto-4e0581245c387292aaa4f50016fbf2c32ed9b954.tar.xz | |
go.crypto/ssh: parse DSA private keys too.
R=golang-dev, agl
CC=golang-dev
https://golang.org/cl/13966043
Diffstat (limited to 'ssh')
| -rw-r--r-- | ssh/keys.go | 47 | ||||
| -rw-r--r-- | ssh/keys_test.go | 31 |
2 files changed, 73 insertions, 5 deletions
diff --git a/ssh/keys.go b/ssh/keys.go index 9738694..0c6c6b3 100644 --- a/ssh/keys.go +++ b/ssh/keys.go @@ -12,6 +12,7 @@ import ( "crypto/elliptic" "crypto/rsa" "crypto/x509" + "encoding/asn1" "encoding/base64" "encoding/pem" "errors" @@ -557,8 +558,8 @@ func NewPublicKey(k interface{}) (PublicKey, error) { return sshKey, nil } -// ParsePublicKey parses a PEM encoded private key. Currently, only -// PKCS#1, RSA and ECDSA private keys are supported. +// ParsePublicKey parses a PEM encoded private key. It supports +// PKCS#1, RSA, DSA and ECDSA private keys. func ParsePrivateKey(pemBytes []byte) (Signer, error) { block, _ := pem.Decode(pemBytes) if block == nil { @@ -579,12 +580,48 @@ func ParsePrivateKey(pemBytes []byte) (Signer, error) { return nil, err } rawkey = ec - - // TODO(hanwen): find doc for format and implement PEM parsing - // for DSA keys. + case "DSA PRIVATE KEY": + ec, err := parseDSAPrivate(block.Bytes) + if err != nil { + return nil, err + } + rawkey = ec default: return nil, fmt.Errorf("ssh: unsupported key type %q", block.Type) } return NewSignerFromKey(rawkey) } + +// parseDSAPrivate parses a DSA key in ASN.1 DER encoding, as +// documented in the OpenSSL DSA manpage. +// TODO(hanwen): move this in to crypto/x509 after the Go 1.2 freeze. +func parseDSAPrivate(p []byte) (*dsa.PrivateKey, error) { + k := struct { + Version int + P *big.Int + Q *big.Int + G *big.Int + Priv *big.Int + Pub *big.Int + }{} + rest, err := asn1.Unmarshal(p, &k) + if err != nil { + return nil, errors.New("ssh: failed to parse DSA key: " + err.Error()) + } + if len(rest) > 0 { + return nil, errors.New("ssh: garbage after DSA key") + } + + return &dsa.PrivateKey{ + PublicKey: dsa.PublicKey{ + Parameters: dsa.Parameters{ + P: k.P, + Q: k.Q, + G: k.G, + }, + Y: k.Priv, + }, + X: k.Pub, + }, nil +} diff --git a/ssh/keys_test.go b/ssh/keys_test.go index fb3f21e..595fb29 100644 --- a/ssh/keys_test.go +++ b/ssh/keys_test.go @@ -132,6 +132,37 @@ AwEHoUQDQgAEi9Hdw6KvZcWxfg2IDhA7UkpDtzzt6ZqJXSsFdLd+Kx4S3Sx4cVO+ } } +// ssh-keygen -t dsa -f /tmp/idsa.pem +var dsaPEM = `-----BEGIN DSA PRIVATE KEY----- +MIIBuwIBAAKBgQD6PDSEyXiI9jfNs97WuM46MSDCYlOqWw80ajN16AohtBncs1YB +lHk//dQOvCYOsYaE+gNix2jtoRjwXhDsc25/IqQbU1ahb7mB8/rsaILRGIbA5WH3 +EgFtJmXFovDz3if6F6TzvhFpHgJRmLYVR8cqsezL3hEZOvvs2iH7MorkxwIVAJHD +nD82+lxh2fb4PMsIiaXudAsBAoGAQRf7Q/iaPRn43ZquUhd6WwvirqUj+tkIu6eV +2nZWYmXLlqFQKEy4Tejl7Wkyzr2OSYvbXLzo7TNxLKoWor6ips0phYPPMyXld14r +juhT24CrhOzuLMhDduMDi032wDIZG4Y+K7ElU8Oufn8Sj5Wge8r6ANmmVgmFfynr +FhdYCngCgYEA3ucGJ93/Mx4q4eKRDxcWD3QzWyqpbRVRRV1Vmih9Ha/qC994nJFz +DQIdjxDIT2Rk2AGzMqFEB68Zc3O+Wcsmz5eWWzEwFxaTwOGWTyDqsDRLm3fD+QYj +nOwuxb0Kce+gWI8voWcqC9cyRm09jGzu2Ab3Bhtpg8JJ8L7gS3MRZK4CFEx4UAfY +Fmsr0W6fHB9nhS4/UXM8 +-----END DSA PRIVATE KEY-----` + +func TestParseDSA(t *testing.T) { + s, err := ParsePrivateKey([]byte(dsaPEM)) + if err != nil { + t.Fatalf("ParsePrivateKey returned error: %s", err) + } + + data := []byte("sign me") + sig, err := s.Sign(rand.Reader, data) + if err != nil { + t.Fatalf("dsa.Sign: %v", err) + } + + if !s.PublicKey().Verify(data, sig) { + t.Error("Verify failed.") + } +} + func init() { raw, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) ecdsaKey, _ = NewSignerFromKey(raw) |
