add snap support (#189)

* embed keygen

* add snap

* add generate log
This commit is contained in:
Boshi Lian 2023-08-11 06:25:58 -07:00 • committed by GitHub
parent 0b0bbc4bf9
commit f5b9f7233f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 177 additions and 11 deletions

View file

@ -44,11 +44,33 @@ func newDaemon(ctx *cli.Context) (*daemon, error) {
config.AddHostKey(private)
} else {
privateKeyFiles, err := filepath.Glob(ctx.String("server-key"))
keyfile := ctx.String("server-key")
privateKeyFiles, err := filepath.Glob(keyfile)
if err != nil {
return nil, err
}
generate := false
switch ctx.String("server-key-generate-mode") {
case "notexist":
generate = len(privateKeyFiles) == 0
case "always":
generate = true
case "disable":
default:
return nil, fmt.Errorf("unknown server-key-generate-mode %v", ctx.String("server-key-generate-mode"))
}
if generate {
log.Infof("generating host key %v", keyfile)
if err := generateSshKey(keyfile); err != nil {
return nil, err
}
privateKeyFiles = []string{keyfile}
}
if len(privateKeyFiles) == 0 {
return nil, fmt.Errorf("no server key found")
}

112
cmd/sshpiperd/key.go Normal file
View file

@ -0,0 +1,112 @@
package main
import (
"crypto/ed25519"
crand "crypto/rand"
"encoding/pem"
"math/rand"
"os"
"golang.org/x/crypto/ssh"
)
func generateSshKey(keyfile string) error {
_, privateKey, err := ed25519.GenerateKey(crand.Reader)
if err != nil {
return err
}
privateKeyPEM := &pem.Block{
Type: "OPENSSH PRIVATE KEY",
Bytes: marshalED25519PrivateKey(privateKey),
}
privateKeyBytes := pem.EncodeToMemory(privateKeyPEM)
return os.WriteFile(keyfile, privateKeyBytes, 0600)
}
// copy from https://github.com/mikesmitty/edkey/blob/master/edkey.go
/*
Writes ed25519 private keys into the new OpenSSH private key format.
I have no idea why this isn't implemented anywhere yet, you can do seemingly
everything except write it to disk in the OpenSSH private key format.
*/
func marshalED25519PrivateKey(key ed25519.PrivateKey) []byte {
// Add our key header (followed by a null byte)
magic := append([]byte("openssh-key-v1"), 0)
var w struct {
CipherName string
KdfName string
KdfOpts string
NumKeys uint32
PubKey []byte
PrivKeyBlock []byte
}
// Fill out the private key fields
pk1 := struct {
Check1 uint32
Check2 uint32
Keytype string
Pub []byte
Priv []byte
Comment string
Pad []byte `ssh:"rest"`
}{}
// Set our check ints
ci := rand.Uint32()
pk1.Check1 = ci
pk1.Check2 = ci
// Set our key type
pk1.Keytype = ssh.KeyAlgoED25519
// Add the pubkey to the optionally-encrypted block
pk, ok := key.Public().(ed25519.PublicKey)
if !ok {
//fmt.Fprintln(os.Stderr, "ed25519.PublicKey type assertion failed on an ed25519 public key. This should never ever happen.")
return nil
}
pubKey := []byte(pk)
pk1.Pub = pubKey
// Add our private key
pk1.Priv = []byte(key)
// Might be useful to put something in here at some point
pk1.Comment = ""
// Add some padding to match the encryption block size within PrivKeyBlock (without Pad field)
// 8 doesn't match the documentation, but that's what ssh-keygen uses for unencrypted keys. *shrug*
bs := 8
blockLen := len(ssh.Marshal(pk1))
padLen := (bs - (blockLen % bs)) % bs
pk1.Pad = make([]byte, padLen)
// Padding is a sequence of bytes like: 1, 2, 3...
for i := 0; i < padLen; i++ {
pk1.Pad[i] = byte(i + 1)
}
// Generate the pubkey prefix "\0\0\0\nssh-ed25519\0\0\0 "
prefix := []byte{0x0, 0x0, 0x0, 0x0b}
prefix = append(prefix, []byte(ssh.KeyAlgoED25519)...)
prefix = append(prefix, []byte{0x0, 0x0, 0x0, 0x20}...)
// Only going to support unencrypted keys for now
w.CipherName = "none"
w.KdfName = "none"
w.KdfOpts = ""
w.NumKeys = 1
w.PubKey = append(prefix, pubKey...)
w.PrivKeyBlock = ssh.Marshal(pk1)
magic = append(magic, ssh.Marshal(w)...)
return magic
}

View file

@ -99,9 +99,15 @@ func main() {
},
&cli.StringFlag{
Name: "server-key-data",
Usage: "server key in base64 format, server-key will be ignored if set",
Usage: "server key in base64 format, server-key, server-key-generate-mode will be ignored if set",
EnvVars: []string{"SSHPIPERD_SERVER_KEY_DATA"},
},
&cli.StringFlag{
Name: "server-key-generate-mode",
Usage: "server key generate mode, one of: disable, notexist, always. generated key will be written to `server-key` if notexist or always",
Value: "disable",
EnvVars: []string{"SSHPIPERD_SERVER_KEY_GENERATE_MODE"},
},
&cli.DurationFlag{
Name: "login-grace-time",
Value: 30 * time.Second,