|
|
@@ -824,7 +824,7 @@ func ParseDSAPrivateKey(der []byte) (*dsa.PrivateKey, error) {
|
|
|
|
|
|
// Implemented based on the documentation at
|
|
|
// https://github.com/openssh/openssh-portable/blob/master/PROTOCOL.key
|
|
|
-func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
|
|
|
+func parseOpenSSHPrivateKey(key []byte) (crypto.PrivateKey, error) {
|
|
|
magic := append([]byte("openssh-key-v1"), 0)
|
|
|
if !bytes.Equal(magic, key[0:len(magic)]) {
|
|
|
return nil, errors.New("ssh: invalid openssh private key format")
|
|
|
@@ -844,14 +844,15 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ if w.KdfName != "none" || w.CipherName != "none" {
|
|
|
+ return nil, errors.New("ssh: cannot decode encrypted private keys")
|
|
|
+ }
|
|
|
+
|
|
|
pk1 := struct {
|
|
|
Check1 uint32
|
|
|
Check2 uint32
|
|
|
Keytype string
|
|
|
- Pub []byte
|
|
|
- Priv []byte
|
|
|
- Comment string
|
|
|
- Pad []byte `ssh:"rest"`
|
|
|
+ Rest []byte `ssh:"rest"`
|
|
|
}{}
|
|
|
|
|
|
if err := Unmarshal(w.PrivKeyBlock, &pk1); err != nil {
|
|
|
@@ -862,24 +863,75 @@ func parseOpenSSHPrivateKey(key []byte) (*ed25519.PrivateKey, error) {
|
|
|
return nil, errors.New("ssh: checkint mismatch")
|
|
|
}
|
|
|
|
|
|
- // we only handle ed25519 keys currently
|
|
|
- if pk1.Keytype != KeyAlgoED25519 {
|
|
|
- return nil, errors.New("ssh: unhandled key type")
|
|
|
- }
|
|
|
+ // we only handle ed25519 and rsa keys currently
|
|
|
+ switch pk1.Keytype {
|
|
|
+ case KeyAlgoRSA:
|
|
|
+ // https://github.com/openssh/openssh-portable/blob/master/sshkey.c#L2760-L2773
|
|
|
+ key := struct {
|
|
|
+ N *big.Int
|
|
|
+ E *big.Int
|
|
|
+ D *big.Int
|
|
|
+ Iqmp *big.Int
|
|
|
+ P *big.Int
|
|
|
+ Q *big.Int
|
|
|
+ Comment string
|
|
|
+ Pad []byte `ssh:"rest"`
|
|
|
+ }{}
|
|
|
+
|
|
|
+ if err := Unmarshal(pk1.Rest, &key); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
|
|
|
- for i, b := range pk1.Pad {
|
|
|
- if int(b) != i+1 {
|
|
|
- return nil, errors.New("ssh: padding not as expected")
|
|
|
+ for i, b := range key.Pad {
|
|
|
+ if int(b) != i+1 {
|
|
|
+ return nil, errors.New("ssh: padding not as expected")
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if len(pk1.Priv) != ed25519.PrivateKeySize {
|
|
|
- return nil, errors.New("ssh: private key unexpected length")
|
|
|
- }
|
|
|
+ pk := &rsa.PrivateKey{
|
|
|
+ PublicKey: rsa.PublicKey{
|
|
|
+ N: key.N,
|
|
|
+ E: int(key.E.Int64()),
|
|
|
+ },
|
|
|
+ D: key.D,
|
|
|
+ Primes: []*big.Int{key.P, key.Q},
|
|
|
+ }
|
|
|
|
|
|
- pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
|
|
|
- copy(pk, pk1.Priv)
|
|
|
- return &pk, nil
|
|
|
+ if err := pk.Validate(); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ pk.Precompute()
|
|
|
+
|
|
|
+ return pk, nil
|
|
|
+ case KeyAlgoED25519:
|
|
|
+ key := struct {
|
|
|
+ Pub []byte
|
|
|
+ Priv []byte
|
|
|
+ Comment string
|
|
|
+ Pad []byte `ssh:"rest"`
|
|
|
+ }{}
|
|
|
+
|
|
|
+ if err := Unmarshal(pk1.Rest, &key); err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(key.Priv) != ed25519.PrivateKeySize {
|
|
|
+ return nil, errors.New("ssh: private key unexpected length")
|
|
|
+ }
|
|
|
+
|
|
|
+ for i, b := range key.Pad {
|
|
|
+ if int(b) != i+1 {
|
|
|
+ return nil, errors.New("ssh: padding not as expected")
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ pk := ed25519.PrivateKey(make([]byte, ed25519.PrivateKeySize))
|
|
|
+ copy(pk, key.Priv)
|
|
|
+ return &pk, nil
|
|
|
+ default:
|
|
|
+ return nil, errors.New("ssh: unhandled key type")
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// FingerprintLegacyMD5 returns the user presentation of the key's
|