-
Notifications
You must be signed in to change notification settings - Fork 26
Implement reference key server #71
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| # CONIKS Server implementation in Golang | ||
|
|
||
| ## Usage | ||
| ``` | ||
| ⇒ go install github.com/coniks-sys/coniks-go/keyserver/coniksserver | ||
| ⇒ coniksserver -h | ||
| _______ _______ __ _ ___ ___ _ _______ | ||
| | || || | | || || | | || | | ||
| | || _ || |_| || || |_| || _____| | ||
| | || | | || || || _|| |_____ | ||
| | _|| |_| || _ || || |_ |_____ | | ||
| | |_ | || | | || || _ | _____| | | ||
| |_______||_______||_| |__||___||___| |_||_______| | ||
|
|
||
| Usage: | ||
| coniksserver [command] | ||
|
|
||
| Available Commands: | ||
| init Create a configuration file and generate all keys | ||
| run Run a CONIKS server instance | ||
|
|
||
| Flags: | ||
| -h, --help help for coniksserver | ||
|
|
||
| Use "coniksserver [command] --help" for more information about a command. | ||
| ``` | ||
|
|
||
| Run the server | ||
| ``` | ||
| ⇒ mkdir coniks; cd coniks | ||
| ⇒ coniksserver init -c # creates all files including a self-signed ssl keys/cert | ||
| ⇒ coniksserver run -p # run & write down the process ID into coniks.pid | ||
| ``` | ||
|
|
||
| You can reload the server's policies while it's running by editing the `config.toml` file | ||
| and possibly replace `vrf.priv` with a new key, then run | ||
| ``` | ||
| ⇒ kill -USR2 `cat coniks.pid` | ||
| ``` | ||
|
|
||
| ## Disclaimer | ||
| Please keep in mind that this CONIKS server implementation is under active development. The repository may contain experimental features that aren't fully tested. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "io/ioutil" | ||
| "log" | ||
| "os" | ||
| "path" | ||
| "strconv" | ||
|
|
||
| "github.com/BurntSushi/toml" | ||
| "github.com/coniks-sys/coniks-go/crypto/sign" | ||
| "github.com/coniks-sys/coniks-go/crypto/vrf" | ||
| "github.com/coniks-sys/coniks-go/keyserver" | ||
| "github.com/coniks-sys/coniks-go/keyserver/testutil" | ||
| "github.com/coniks-sys/coniks-go/utils" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| // initCmd represents the init command | ||
| var initCmd = &cobra.Command{ | ||
| Use: "init", | ||
| Short: "Create a configuration file and generate all keys", | ||
| Long: `Create a configuration file and generate all keys for signing and VRF`, | ||
| Run: func(cmd *cobra.Command, args []string) { | ||
| dir := cmd.Flag("dir").Value.String() | ||
| mkConfig(dir) | ||
| mkSigningKey(dir) | ||
| mkVrfKey(dir) | ||
|
|
||
| cert, err := strconv.ParseBool(cmd.Flag("cert").Value.String()) | ||
| if err == nil && cert { | ||
| testutil.CreateTLSCert(dir) | ||
| } | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| RootCmd.AddCommand(initCmd) | ||
| initCmd.Flags().StringP("dir", "d", ".", "Location of directory for storing generated files") | ||
| initCmd.Flags().BoolP("cert", "c", false, "Generate self-signed ssl keys/cert with sane defaults") | ||
| } | ||
|
|
||
| func mkConfig(dir string) { | ||
| file := path.Join(dir, "config.toml") | ||
| var conf = keyserver.ServerConfig{ | ||
| DatabasePath: "coniks.db", | ||
| LoadedHistoryLength: 1000000, | ||
| TLS: &keyserver.TLSConnection{ | ||
| LocalAddress: "127.0.0.1:3001", | ||
| PublicAddress: "0.0.0.0:3000", | ||
| TLSCertPath: "server.pem", | ||
| TLSKeyPath: "server.key", | ||
| }, | ||
| Policies: &keyserver.ServerPolicies{ | ||
| EpochDeadline: 60, | ||
| VRFKeyPath: "vrf.priv", | ||
| SignKeyPath: "sign.priv", | ||
| }, | ||
| } | ||
|
|
||
| var confBuf bytes.Buffer | ||
|
|
||
| e := toml.NewEncoder(&confBuf) | ||
| err := e.Encode(conf) | ||
| if err != nil { | ||
| log.Println(err) | ||
| return | ||
| } | ||
| util.WriteFile(file, confBuf) | ||
| } | ||
|
|
||
| func mkSigningKey(dir string) { | ||
| file := path.Join(dir, "sign.priv") | ||
| if _, err := os.Stat(file); err == nil { | ||
| log.Printf("%s already exists\n", file) | ||
| return | ||
| } | ||
| sk, err := sign.GenerateKey(nil) | ||
| if err != nil { | ||
| log.Print(err) | ||
| return | ||
| } | ||
| if err := ioutil.WriteFile(file, sk[:], 0600); err != nil { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we think file mode 0600 will be enough to protect the keys?
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I should clarify that I'm not opposed to this for now, but I do wonder if it'll be sufficient on the long run.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not so sure but the permission of private keys in
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably, but I'm not sure about the specifics. We should maybe just ensure the key is only required for reading at process launch, and then can be safely removed from its location. |
||
| log.Print(err) | ||
| return | ||
| } | ||
| } | ||
|
|
||
| func mkVrfKey(dir string) { | ||
| file := path.Join(dir, "vrf.priv") | ||
| if _, err := os.Stat(file); err == nil { | ||
| log.Printf("%s already exists\n", file) | ||
| return | ||
| } | ||
| sk, err := vrf.GenerateKey(nil) | ||
| if err != nil { | ||
| log.Print(err) | ||
| return | ||
| } | ||
| if err := ioutil.WriteFile(file, sk[:], 0600); err != nil { | ||
| log.Print(err) | ||
| return | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "os" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| // RootCmd represents the base command when called without any subcommands | ||
| var RootCmd = &cobra.Command{ | ||
| Use: "coniksserver", | ||
| Short: "CONIKS reference implementation in Go", | ||
| Long: ` | ||
| ________ _______ __ _ ___ ___ _ _______ | ||
| | || || | | || || | | || | | ||
| | || _ || |_| || || |_| || _____| | ||
| | || | | || || || _|| |_____ | ||
| | _|| |_| || _ || || |_ |_____ | | ||
| | |_ | || | | || || _ | _____| | | ||
| |_______||_______||_| |__||___||___| |_||_______| | ||
| `, | ||
| } | ||
|
|
||
| // Execute adds all child commands to the root command sets flags appropriately. | ||
| // This is called by main.main(). It only needs to happen once to the rootCmd. | ||
| func Execute() { | ||
| if err := RootCmd.Execute(); err != nil { | ||
| fmt.Println(err) | ||
| os.Exit(-1) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package cmd | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "log" | ||
| "os" | ||
| "os/signal" | ||
| "path" | ||
| "strconv" | ||
|
|
||
| "github.com/coniks-sys/coniks-go/keyserver" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| // runCmd represents the run command | ||
| var runCmd = &cobra.Command{ | ||
| Use: "run", | ||
| Short: "Run a CONIKS server instance", | ||
| Long: `Run a CONIKS server instance | ||
|
|
||
| This will look for config files with default names (config.toml) | ||
| in the current directory if not specified differently. | ||
| `, | ||
| Run: func(cmd *cobra.Command, args []string) { | ||
| config := cmd.Flag("config").Value.String() | ||
| pid, _ := strconv.ParseBool(cmd.Flag("pid").Value.String()) | ||
| // ignore the error here since it is handled by the flag parser. | ||
| if pid { | ||
| writePID() | ||
| } | ||
| run(config) | ||
| }, | ||
| } | ||
|
|
||
| func init() { | ||
| RootCmd.AddCommand(runCmd) | ||
| runCmd.Flags().StringP("config", "c", "config.toml", "Path to server configuration file") | ||
| runCmd.Flags().BoolP("pid", "p", false, "Write down the process id to coniks.pid in the current working directory") | ||
| } | ||
|
|
||
| func run(confPath string) { | ||
| conf, err := keyserver.LoadServerConfig(confPath) | ||
| if err != nil { | ||
| log.Fatal(err) | ||
| } | ||
| serv := keyserver.NewConiksServer(conf) | ||
|
|
||
| // run the server until receiving an interrupt signal | ||
| serv.Run(conf.TLS) | ||
| ch := make(chan os.Signal, 1) | ||
| signal.Notify(ch, os.Interrupt) | ||
| <-ch | ||
| serv.Shutdown() | ||
| } | ||
|
|
||
| func writePID() { | ||
| pidf, err := os.OpenFile(path.Join(".", "coniks.pid"), os.O_CREATE|os.O_WRONLY, 0666) | ||
| if err != nil { | ||
| log.Printf("Cannot create coniks.pid: %v", err) | ||
| return | ||
| } | ||
| if _, err := fmt.Fprint(pidf, os.Getpid()); err != nil { | ||
| log.Printf("Cannot write to pid file: %v", err) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package main | ||
|
|
||
| import "github.com/coniks-sys/coniks-go/keyserver/coniksserver/cmd" | ||
|
|
||
| func main() { | ||
| cmd.Execute() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| // Defines methods/functions to encode/decode messages between client and server. | ||
| // Currently this module supports JSON marshal/unmarshal only. | ||
| // Protobuf would be supported in the feature. | ||
|
|
||
| package keyserver | ||
|
|
||
| import ( | ||
| "encoding/json" | ||
|
|
||
| . "github.com/coniks-sys/coniks-go/protocol" | ||
| ) | ||
|
|
||
| func MarshalResponse(response Response) ([]byte, error) { | ||
| return json.Marshal(response) | ||
| } | ||
|
|
||
| func UnmarshalRequest(msg []byte) (*Request, error) { | ||
| var content json.RawMessage | ||
| req := Request{ | ||
| Request: &content, | ||
| } | ||
| if err := json.Unmarshal(msg, &req); err != nil { | ||
| return nil, err | ||
| } | ||
| switch req.Type { | ||
| case RegistrationType: | ||
| var request RegistrationRequest | ||
| if err := json.Unmarshal(content, &request); err != nil { | ||
| return nil, err | ||
| } | ||
| req.Request = &request | ||
| } | ||
| return &req, nil | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If
CreateTLSCertwon't be used only in tests anymore we should move it fromtestutilinto a generalutilpackage.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I was also thinking about it. But
CreateTLSCertshould be used for development environment only (i.e.,go testand local deployment), so I'm not sure moving it intoutilmakes sense.