-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #44 from keybase/david/revert-ed25519-everywhere
Revert ed25519 everywhere
- Loading branch information
Showing
6 changed files
with
62 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,83 @@ | ||
package sshutils | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
"strings" | ||
|
||
"github.com/ScaleFT/sshkeys" | ||
"github.com/keybase/bot-sshca/src/shared" | ||
"golang.org/x/crypto/ed25519" | ||
"golang.org/x/crypto/ssh" | ||
|
||
"github.com/keybase/bot-sshca/src/shared" | ||
) | ||
|
||
// Generate a new SSH key. Places the private key at filename and the public key at filename.pub. | ||
// We use ed25519 keys since they may be more secure (and are smaller). The go crypto ssh library | ||
// does not support marshalling ed25519 keys so we use ScaleFT/sshkeys to marshal them to the | ||
// correct on disk format for SSH | ||
// Generate a new SSH key and store the private key at filename and the public key at filename.pub | ||
// If the ssh-keygen binary exists, generates an ed25519 ssh key using ssh-keygen. Otherwise, | ||
// generates an ecdsa key using go's crypto library. Note that we use ecdsa rather than ed25519 | ||
// in this case since go's crypto library does not support marshalling ed25519 keys into the format | ||
// expected by openssh. github.com/ScaleFT/sshkeys claims to support this but does not reliably | ||
// work with all versions of ssh. | ||
func generateNewSSHKey(filename string) error { | ||
// Generate the key | ||
pub, private, err := ed25519.GenerateKey(rand.Reader) | ||
if sshKeygenBinaryExists() { | ||
return generateNewSSHKeyEd25519(filename) | ||
} | ||
|
||
return generateNewSSHKeyEcdsa(filename) | ||
} | ||
|
||
// Returns true iff the ssh-keygen binary exists and is in the user's path | ||
func sshKeygenBinaryExists() bool { | ||
_, err := exec.LookPath("ssh-keygen") | ||
return err == nil | ||
} | ||
|
||
// Generate an ed25519 ssh key via ssh-keygen. Stores the private key at filename and the public key at filename.pub | ||
func generateNewSSHKeyEd25519(filename string) error { | ||
cmd := exec.Command("ssh-keygen", "-t", "ed25519", "-f", filename, "-m", "PEM", "-N", "") | ||
bytes, err := cmd.CombinedOutput() | ||
if err != nil { | ||
return fmt.Errorf("failed to generate ed25519 key: %v", err) | ||
return fmt.Errorf("ssh-keygen failed: %s (%v)", strings.TrimSpace(string(bytes)), err) | ||
} | ||
return nil | ||
} | ||
|
||
// Write the private key | ||
bytes, err := sshkeys.Marshal(private, &sshkeys.MarshalOptions{Format: sshkeys.FormatOpenSSHv1}) | ||
// Generate an ecdsa ssh key in pure go code. Stores the private key at filename and the public key at filename.pub | ||
// Note that if you are editing this code, be careful to ensure you test it manually since the integration tests | ||
// run in an environment with ssh-keygen and thus do not call this function. This function is manually used on windows. | ||
func generateNewSSHKeyEcdsa(filename string) error { | ||
// ssh-keygen -t ecdsa uses P256 by default | ||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal ed25519 key: %v", err) | ||
return err | ||
} | ||
err = ioutil.WriteFile(filename, bytes, 0600) | ||
|
||
// 0600 are the correct permissions for an ssh private key | ||
privateKeyFile, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) | ||
if err != nil { | ||
return fmt.Errorf("failed to write ssh private key to %s: %v", filename, err) | ||
return err | ||
} | ||
defer privateKeyFile.Close() | ||
|
||
// Write the public key | ||
publicKey, err := ssh.NewPublicKey(pub) | ||
bytes, err := x509.MarshalECPrivateKey(privateKey) | ||
if err != nil { | ||
return fmt.Errorf("failed to create public key from ed25519 key: %v", err) | ||
return err | ||
} | ||
bytes = ssh.MarshalAuthorizedKey(publicKey) | ||
err = ioutil.WriteFile(shared.KeyPathToPubKey(filename), bytes, 0600) | ||
|
||
privateKeyPEM := &pem.Block{Type: "EC PRIVATE KEY", Bytes: bytes} | ||
err = pem.Encode(privateKeyFile, privateKeyPEM) | ||
if err != nil { | ||
return fmt.Errorf("failed to write ssh public key to %s: %v", shared.KeyPathToPubKey(filename), err) | ||
return err | ||
} | ||
|
||
return nil | ||
pub, err := ssh.NewPublicKey(&privateKey.PublicKey) | ||
if err != nil { | ||
return err | ||
} | ||
return ioutil.WriteFile(shared.KeyPathToPubKey(filename), ssh.MarshalAuthorizedKey(pub), 0600) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters