Skip to content
Closed
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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ script:
- go test -coverprofile=vrf.coverprofile ./crypto/vrf
- go test -coverprofile=merkletree.coverprofile ./merkletree
- go test -coverprofile=utils.coverprofile ./utils
- go test -coverprofile=keyserver.coverprofile ./keyserver
- $HOME/gopath/bin/gover
- $HOME/gopath/bin/goveralls -coverprofile=gover.coverprofile -service travis-ci

Expand Down
2 changes: 2 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
This license applies to all parts of the CONIKS Golang library and reference implementation except the following:
- The ed25519 subpackage, located in crypto/ed25519
This subpackage is copyrighted by the Go Authors.
- The mkkey.go ultility, located in utils/keygen/mkkey.go
This source code is copyrighted by the Dename Authors.
- Coname utility functions, located in utils/coname.go
- The vrf subpackage, located in crypto/vrf
- The kv subpackage, located in storage/kv
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ The packages in this library implement the various components of the CONIKS syst
- ``client``: Client-side protocol cgo hooks
- ``crypto``: Cryptographic algorithms and operations
- ``merkletree``: Merkle prefix tree and related data structures
- ``utils``: Utility functions
- ``keyserver``: Key server reference implementation
- ``utils``: Utility functions
- ``protocol``: CONIKS protocols implementation/library
- ``storage``: DB hooks for storage backend (currently the library supports key-value db only)

## Disclaimer
Expand Down
30 changes: 30 additions & 0 deletions keyserver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# CONIKS Server implementation in Golang

## Usage
Generate new config file with proper format
```
go run keyserver/coniksserver/main.go -genconfig
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 suppose at some point we'll encourage people to,

go install github.com/coniks-sys/coniks-go/keyserver/coniksserver
coniksserver -h

```

Generate new key pair for VRF and signing
```
go run utils/keygen/mkkey.go -vrf -signing
Copy link
Copy Markdown
Member

@arlolra arlolra Aug 12, 2016

Choose a reason for hiding this comment

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

Think I'd prefer to use this as,

go run keyserver/coniksserver/main.go -genkey signing,vrf

```

Generate a private key for secure connection (TLS)
```
openssl ecparam -genkey -name prime256v1 -out server.key
```

Generation of self-signed(x509) public key (PEM-encodings `.pem`) based on the private (`.key`)
```
openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650
```

Run the server
```
go run keyserver/coniksserver/main.go
```

## 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.
73 changes: 73 additions & 0 deletions keyserver/coniksserver/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package main

import (
"bytes"
"flag"
"os"
"os/signal"

"github.com/BurntSushi/toml"
"github.com/coniks-sys/coniks-go/keyserver"
"github.com/coniks-sys/coniks-go/utils"
)

const ConfigFile = "config.toml"
Copy link
Copy Markdown
Member

@arlolra arlolra Aug 12, 2016

Choose a reason for hiding this comment

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

We probably want to put,

config.toml
sign.pub
sign.priv
vrf.pub
vrf.priv

in the .gitignore file.

const PoliciesFile = "policies.toml"
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.

Why a separate policy file?

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 and @masomel have had a discussion over this (b5907c7#commitcomment-18595647). She pointed out for me that policy file was redundant. I probably should remove this policies.toml. Thank you!


func main() {
genConfigPtr := flag.Bool("genconfig", false, "Generate server config")
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 there was only one config file, we could pass in a path for where to generate it,

flag.Bool("genconfig", "config.toml", "Generate server config")

and get rid of the globals (ConfigFile, PoliciesFile).

configPathPtr := flag.String("config", "config.toml", "path to config file")
flag.Parse()

if *genConfigPtr {
mkConfig()
return
}

// set up a CONIKS server from config file
conf := keyserver.LoadServerConfig(*configPathPtr)
serv := keyserver.NewConiksServer(conf)

// run the server until receiving an interrupt signal
serv.RunWithConfig(conf)
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.

Passing in the conf again seems unnecessary.

ch := make(chan os.Signal, 1)
signal.Notify(ch, os.Interrupt)
<-ch
serv.Shutdown()
}

func mkConfig() {
var conf = keyserver.ServerConfig{
SigningKeyPath: "ed25519.secret",
DatabasePath: "coniks.db",
RegistrationAddress: "127.0.0.1:3001",
Address: "0.0.0.0:3000",
PoliciesPath: "policies.toml",
LoadedHistoryLength: 1000000,
RegistrationCapacity: 100000,
}
conf.TLS.TLSCertPath = "server.pem"
conf.TLS.TLSKeyPath = "server.key"

var policies = keyserver.ServerPolicies{
EpochDeadline: 60,
VRFKeyPath: "vrf.secret",
}

var confBuf bytes.Buffer
var policiesBuf bytes.Buffer

e := toml.NewEncoder(&confBuf)
err := e.Encode(conf)
if err != nil {
panic(err)
}
util.WriteFile(ConfigFile, confBuf)

e = toml.NewEncoder(&policiesBuf)
err = e.Encode(policies)
if err != nil {
panic(err)
}
util.WriteFile(PoliciesFile, policiesBuf)
}
49 changes: 49 additions & 0 deletions keyserver/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package keyserver

import (
. "github.com/coniks-sys/coniks-go/protocol"
"github.com/coniks-sys/coniks-go/utils"
)

func (server *ConiksServer) handleRegistrationMessage(reg *RegistrationRequest) (Response, error) {
if len(reg.Username) == 0 || len(reg.Key) == 0 {
return NewErrorResponse(ErrorMalformedClientMessage),
ErrorMalformedClientMessage.Error()
}

server.Lock()

ap, tb, errCode := server.directory.Register(reg.Username, []byte(reg.Key))
if errCode != Success {
server.Unlock()
return NewErrorResponse(errCode),
errCode.Error()
}
server.Unlock()

// store the user policies into DB
err := server.StoreUserPoliciesToKV(&ConiksUserPolicies{
AllowUnsignedKeychange: reg.AllowUnsignedKeychange,
AllowPublicLookup: reg.AllowPublicLookup,
})
if err != nil {
return NewErrorResponse(ErrorInternalServer),
err
}

return &RegistrationResponse{
Type: RegistrationType,
STR: server.directory.LatestSTR(),
AP: ap,
TB: tb,
}, nil
}

func (server *ConiksServer) StoreUserPoliciesToKV(up *ConiksUserPolicies) error {
buf := make([]byte, 0, 1)
buf = append(util.ToBytes([]bool{up.AllowUnsignedKeychange, up.AllowPublicLookup}))
if err := server.db.Put([]byte(up.Username), buf); err != nil {
return err
}
return nil
}
146 changes: 146 additions & 0 deletions keyserver/listener.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package keyserver

import (
"encoding/json"
"io"
"log"
"net"
"time"

. "github.com/coniks-sys/coniks-go/protocol"
)

func (server *ConiksServer) listenForRequests(ln net.Listener, handler func(msg []byte) ([]byte, error)) {
defer server.waitStop.Done()
defer ln.Close()
go func() {
<-server.stop
ln.Close()
}()

for {
conn, err := ln.Accept()
if err != nil {
select {
case <-server.stop:
return
default:
log.Printf("accept client: %s", err)
continue
}
}
server.waitStop.Add(1)
go server.acceptClient(conn, handler)
}
}

func (server *ConiksServer) acceptClient(conn net.Conn, handler func(msg []byte) ([]byte, error)) {
defer conn.Close()
defer server.waitStop.Done()
closed := make(chan struct{})
defer close(closed)
go func() {
select {
case <-server.stop:
conn.Close()
case <-closed:
}
}()

conn.SetDeadline(time.Now().Add(5 * time.Second))

// handle request
buf := make([]byte, 4096)
for {
n, err := conn.Read(buf)
if err != nil {
select {
case <-server.stop:
return
default:
if err != io.EOF {
log.Printf("client read %v: %v", conn.RemoteAddr(), err)
}
return
}
}

res, err := handler(buf[:n])
if err != nil {
log.Printf("client handle %v: %v", conn.RemoteAddr(), err)
}

n, err = conn.Write([]byte(res))
if err != nil {
select {
case <-server.stop:
return
default:
log.Printf("client write %v: %v", conn.RemoteAddr(), err)
return
}
}
}
}

func malformedClientMsg() []byte {
res, err := MarshalErrorResponse(ErrorMalformedClientMessage)
if err != nil {
panic(err)
}
return res
}

// handleClientMessage returns a byte slice of marshaled response
// and an error for server logging
func (server *ConiksServer) handleClientMessage(msg []byte) ([]byte, error) {
// get request message
req, _, err := UnmarshalRequest(msg)
if err != nil {
return malformedClientMsg(), err
}

// handle request
switch req.Type {
default:
log.Printf("unknown message type: %q", req.Type)
return malformedClientMsg(), ErrorMalformedClientMessage.Error()
}
}

func (server *ConiksServer) handleBotMessage(msg []byte) ([]byte, error) {
var response Response
var err error

// get request message
req, content, err := UnmarshalRequest(msg)
if err != nil {
return malformedClientMsg(), err
}

// handle request
switch req.Type {
case RegistrationType:
var reg RegistrationRequest
if err = json.Unmarshal(content, &reg); err != nil {
return malformedClientMsg(), err
}
response, err = server.handleRegistrationMessage(&reg)
if err == nil {
res, e := MarshalRegistrationResponse(response.(*RegistrationResponse))
if e != nil {
panic(e)
}
return res, nil
}
res, e := MarshalErrorResponse(response.(*ErrorResponse).Error)
if e != nil {
panic(e)
}
return res, nil

default:
log.Printf("unknown message type: %q", req.Type)
return malformedClientMsg(), ErrorMalformedClientMessage.Error()
}
}
38 changes: 38 additions & 0 deletions keyserver/policy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package keyserver

import (
"io/ioutil"
"log"

"github.com/BurntSushi/toml"
"github.com/coniks-sys/coniks-go/crypto/vrf"
"github.com/coniks-sys/coniks-go/merkletree"
)

type ServerPolicies struct {
EpochDeadline merkletree.TimeStamp `toml:"epoch_deadline"`
VRFKeyPath string `toml:"vrf_key_path"`
}

func readPolicies(path string) (*ServerPolicies, *vrf.PrivateKey, error) {
var p ServerPolicies
if _, err := toml.DecodeFile(path, &p); err != nil {
log.Fatalf("Failed to load config: %v", err)
return nil, nil, err
}

// load vrf key
skBytes, err := ioutil.ReadFile(p.VRFKeyPath)
if err != nil {
log.Fatalf("Cannot read VRF key: %v", err)
return nil, nil, nil
}
if len(skBytes) != vrf.PrivateKeySize {
log.Fatalf("Signing key must be 64 bytes (got %d)", len(skBytes))
return nil, nil, nil
}

vrfKey := new(vrf.PrivateKey)
copy(vrfKey[:], skBytes)
return &p, vrfKey, nil
}
Loading