Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,13 @@ _testmain.go
*.prof

# vscode
.vscode
.vscode

# CONIKS server
config.toml
sign.priv
vrf.priv
server.key
server.pem
coniks.db/
coniks.pid
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ script:
- go test -coverprofile=merkletree.coverprofile ./merkletree
- go test -coverprofile=utils.coverprofile ./utils
- go test -coverprofile=protocol.coverprofile ./protocol
- go test -coverprofile=keyserver.coverprofile ./keyserver

after_success:
- gover
Expand Down
42 changes: 42 additions & 0 deletions keyserver/README.md
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.
105 changes: 105 additions & 0 deletions keyserver/coniksserver/cmd/init.go
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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If CreateTLSCert won't be used only in tests anymore we should move it from testutil into a general util package.

Copy link
Copy Markdown
Member Author

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 CreateTLSCert should be used for development environment only (i.e., go test and local deployment), so I'm not sure moving it into util makes sense.

}
},
}

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure but the permission of private keys in .ssh is also 600. @arlolra : Will we have some better secure key management in production stage?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The 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
}
}
32 changes: 32 additions & 0 deletions keyserver/coniksserver/cmd/root.go
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)
}
}
65 changes: 65 additions & 0 deletions keyserver/coniksserver/cmd/run.go
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)
}
}
7 changes: 7 additions & 0 deletions keyserver/coniksserver/coniksserver.go
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()
}
34 changes: 34 additions & 0 deletions keyserver/encoding.go
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
}
Loading