Skip to content
Open
87 changes: 87 additions & 0 deletions application/auditor/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package auditor

import (
"github.com/coniks-sys/coniks-go/application"
"github.com/coniks-sys/coniks-go/crypto/sign"
"github.com/coniks-sys/coniks-go/protocol"
)

// directoryConfig contains the auditor's configuration needed to send a
// request to a CONIKS server: the path to the server's signing public-key
// file and the actual public-key parsed from that file; the path to
// the server's initial STR file and the actual STR parsed from that file;
// the server's address for receiving STR history requests.
type directoryConfig struct {
SignPubkeyPath string `toml:"sign_pubkey_path"`
SigningPubKey sign.PublicKey

InitSTRPath string `toml:"init_str_path"`
InitSTR *protocol.DirSTR

Address string `toml:"address"`
}

// Config maintains the auditor's configurations for all CONIKS
// directories it tracks.
type Config struct {
TrackedDirs []*directoryConfig
// TODO: Add server-side auditor config
}

var _ application.AppConfig = (*Config)(nil)

func newDirectoryConfig(signPubkeyPath, initSTRPath, serverAddr string) *directoryConfig {
var dconf = directoryConfig{
SignPubkeyPath: signPubkeyPath,
InitSTRPath: initSTRPath,
Address: serverAddr,
}

return &dconf
}

// NewConfig initializes a new auditor configuration with the given
// server signing public key path, registration address, and
// server address.
func NewConfig() *Config {
var conf = Config{
TrackedDirs: make([]*directoryConfig, 0),
}
return &conf
}

// AddDirectoryConfig adds the given CONIKS server settings to the
// auditor's configuration.
func (conf *Config) AddDirectoryConfig(signPubkeyPath, initSTRPath, serverAddr string) {
dconf := newDirectoryConfig(signPubkeyPath, initSTRPath, serverAddr)
conf.TrackedDirs = append(conf.TrackedDirs, dconf)
}

// Load initializes an auditor's configuration from the given file.
// For each directory in the configuration, it reads the signing public-key file
// and initial STR file, and parses the actual key and initial STR.
func (conf *Config) Load(file string) error {
tmp, err := application.LoadConfig(file)
if err != nil {
return err
}
conf = tmp.(*Config)

for _, dconf := range conf.TrackedDirs {
// load signing key
signPubKey, err := application.LoadSigningPubKey(dconf.SignPubkeyPath, file)
if err != nil {
return err
}
dconf.SigningPubKey = signPubKey

// load initial STR
initSTR, err := application.LoadInitSTR(dconf.InitSTRPath, file)
if err != nil {
return err
}
dconf.InitSTR = initSTR
}

return nil
}
9 changes: 9 additions & 0 deletions application/auditor/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
Package auditor implements the CONIKS auditor service
protocol.

Note: The auditor can current only be used in
interactive test mode with a server, and does not
accept auditing requests from CONIKS clients.
*/
package auditor
21 changes: 21 additions & 0 deletions application/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"io/ioutil"

"github.com/coniks-sys/coniks-go/crypto/sign"
"github.com/coniks-sys/coniks-go/protocol"
"github.com/coniks-sys/coniks-go/utils"
)

Expand Down Expand Up @@ -61,3 +62,23 @@ func LoadSigningPubKey(path, file string) (sign.PublicKey, error) {
}
return signPubKey, nil
}

// LoadIinitSTR loads an initial STR at the given path
// specified in the given config file.
// If there is any parsing error or the STR is malformed,
// LoadInitSTR() returns an error with a nil STR.
func LoadInitSTR(path, file string) (*protocol.DirSTR, error) {
initSTRPath := utils.ResolvePath(path, file)
initSTRBytes, err := ioutil.ReadFile(initSTRPath)
if err != nil {
return nil, fmt.Errorf("Cannot read init STR: %v", err)
}
initSTR := new(protocol.DirSTR)
if err := json.Unmarshal(initSTRBytes, &initSTR); err != nil {
return nil, fmt.Errorf("Cannot parse initial STR: %v", err)
}
if initSTR.Epoch != 0 {
return nil, fmt.Errorf("Initial STR epoch must be 0 (got %d)", initSTR.Epoch)
}
return initSTR, nil
}
32 changes: 31 additions & 1 deletion application/encoding.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"encoding/json"

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

// MarshalRequest returns a JSON encoding of the client's request.
Expand Down Expand Up @@ -39,6 +40,8 @@ func UnmarshalRequest(msg []byte) (*protocol.Request, error) {
request = new(protocol.KeyLookupInEpochRequest)
case protocol.MonitoringType:
request = new(protocol.MonitoringRequest)
case protocol.STRType:
request = new(protocol.STRHistoryRequest)
}
if err := json.Unmarshal(content, &request); err != nil {
return nil, err
Expand Down Expand Up @@ -91,7 +94,7 @@ func UnmarshalResponse(t int, msg []byte) *protocol.Response {
Error: res.Error,
DirectoryResponse: response,
}
case protocol.STRType:
case protocol.AuditType, protocol.STRType:
response := new(protocol.STRHistoryRange)
if err := json.Unmarshal(res.DirectoryResponse, &response); err != nil {
return &protocol.Response{
Expand All @@ -114,3 +117,30 @@ func malformedClientMsg(err error) *protocol.Response {
}
return protocol.NewErrorResponse(protocol.ErrMalformedMessage)
}

// CreateSTRRequestMsg returns a JSON encoding of
// a protocol.STRHistoryRequest for the given (start, end) epoch
// range.
func CreateSTRRequestMsg(start, end uint64) ([]byte, error) {
return json.Marshal(&protocol.Request{
Type: protocol.STRType,
Request: &protocol.STRHistoryRequest{
StartEpoch: start,
EndEpoch: end,
},
})
}

// MarshalSTRToFile serializes the given STR to the given path.
func MarshalSTRToFile(str *protocol.DirSTR, path string) error {
strBytes, err := json.Marshal(str)
if err != nil {
return err
}

if err := utils.WriteFile(path, strBytes, 0600); err != nil {
return err
}

return nil
}
34 changes: 30 additions & 4 deletions application/encoding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,41 @@ func TestUnmarshalErrorResponse(t *testing.T) {
}
}

func TestUnmarshalSampleMessage(t *testing.T) {
func TestUnmarshalMalformedSTRHistoryRange(t *testing.T) {
errResponse := protocol.NewErrorResponse(protocol.ReqNameNotFound)
msg, err := json.Marshal(errResponse)
if err != nil {
t.Fatal(err)
}
res := UnmarshalResponse(protocol.STRType, msg)
if res.Error != protocol.ErrMalformedMessage {
t.Error("Expect error", protocol.ErrMalformedMessage,
"got", res.Error)
}
}

func TestUnmarshalSampleClientMessage(t *testing.T) {
d := directory.NewTestDirectory(t)
res := d.Register(&protocol.RegistrationRequest{
Username: "alice",
Key: []byte("key")})
msg, _ := MarshalResponse(res)
response := UnmarshalResponse(protocol.RegistrationType, []byte(msg))
str := response.DirectoryResponse.(*protocol.DirectoryProof).STR[0]
if !bytes.Equal(d.LatestSTR().Serialize(), str.Serialize()) {
t.Error("Cannot unmarshal Associated Data properly")
}
}

func TestUnmarshalSampleAuditorMessage(t *testing.T) {
d := directory.NewTestDirectory(t)
res := d.GetSTRHistory(&protocol.STRHistoryRequest{
StartEpoch: 0,
EndEpoch: 0})
StartEpoch: uint64(0),
EndEpoch: uint64(1)})
msg, _ := MarshalResponse(res)
response := UnmarshalResponse(protocol.STRType, []byte(msg))
str := response.DirectoryResponse.(*protocol.STRHistoryRange).STR[0]
if !bytes.Equal(d.LatestSTR().Serialize(), str.Serialize()) {
t.Error("Cannot unmarshal Associate Data properly")
t.Error("Cannot unmarshal Associated Data properly")
}
}
2 changes: 2 additions & 0 deletions application/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type Config struct {
LoadedHistoryLength uint64 `toml:"loaded_history_length"`
// Policies contains the server's CONIKS policies configuration.
Policies *Policies `toml:"policies"`
// Path to store the initial STR
InitSTRPath string `toml:"init_str_path"`
// Addresses contains the server's connections configuration.
Addresses []*Address `toml:"addresses"`
// The server's epoch interval for updating the directory
Expand Down
6 changes: 6 additions & 0 deletions application/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/coniks-sys/coniks-go/application"
"github.com/coniks-sys/coniks-go/protocol"
"github.com/coniks-sys/coniks-go/protocol/directory"
"github.com/coniks-sys/coniks-go/utils"
)

// An Address describes a server's connection.
Expand Down Expand Up @@ -64,6 +65,11 @@ func NewConiksServer(conf *Config) *ConiksServer {
epochTimer: application.NewEpochTimer(conf.EpochDeadline),
}

// save the initial STR to be used for initializing auditors
initSTRPath := utils.ResolvePath(conf.InitSTRPath,
conf.ConfigFilePath)
application.MarshalSTRToFile(server.dir.LatestSTR(), initSTRPath)

return server
}

Expand Down
87 changes: 87 additions & 0 deletions cli/coniksauditor/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# CONIKS Auditor implementation in Golang
__Do not use your real public key or private key with this test auditor.__

## Usage

**Note:** This auditor CLI currently only implements the CONIKS key
directory-to-auditor protocol (i.e. the auditor only retrieves and verifies
STRs from the server, it does _not_ accept auditing requests from clients).
To test the implementation, the auditor can be run with an interactive REPL.

##### Install the test auditor
```
⇒ go install github.com/coniks-sys/coniks-go/coniksauditor/cli
⇒ coniksauditor -h
________ _______ __ _ ___ ___ _ _______
| || || | | || || | | || |
| || _ || |_| || || |_| || _____|
| || | | || || || _|| |_____
| _|| |_| || _ || || |_ |_____ |
| |_ | || | | || || _ | _____| |
|_______||_______||_| |__||___||___| |_||_______|

Usage:
coniksauditor [command]

Available Commands:
init Creates a config file for the auditor.
test Run the interactive test auditor.

Use "coniksauditor [command] --help" for more information about a command.
```

### Configure the auditor

- Make sure you have at least one running CONIKS directory for your
auditor to track. For information on setting up a CONIKS directory,
see our [CONIKS server setup guide](https://github.com/coniks-sys/coniks-go/blob/master/coniksserver/README.md).

- Generate the configuration file:
```
⇒ mkdir coniks-auditor; cd coniks-auditor
⇒ coniksauditor init
```
- Ensure the auditor has the directory's *test* public signing key.
- Edit the configuration file as needed:
- Replace the `sign_pubkey_path` with the location of the directory's public signing key.
- Replace the `init_str_path` with the location of the directory's initial signed tree root.
- Replace the `address` with the directory's public CONIKS address (for lookups, monitoring etc).
_Note: The auditor is capable of verifying multiple key directories, but
we currently only configure the test auditor with a single directory for simplcity._

### Run the test auditor

```
⇒ coniksauditor test # this will open a REPL
```

##### Update the auditor with the latest STR history from the given directory
```
> update [dir]
# The auditor should display something like this if the request is successful
[+] Valid! The auditor is up-to-date on the STR history of [dir]
```

This command updates the auditor's STR log for the directory upon a
successful audit.

##### Retrieve and verify a specific STR history range
```
> getrange [dir] [start] [end]
# The auditor should display something like this if the request is successful
[+] Success! The requested STR history range for [dir] is valid
```

This command only performs an audit on the requested STR history range.
It does not update the auditor's STR log for the directory.

##### Other commands

Use `help` for more information.

Use `exit` to close the REPL and exit the client.

## Disclaimer
Please keep in mind that this CONIKS auditor is under active development.
The repository may contain experimental features that aren't fully tested.
We recommend using a [tagged release](https://github.com/coniks-sys/coniks-go/releases).
12 changes: 12 additions & 0 deletions cli/coniksauditor/coniksauditor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Executable CONIKS auditor. See README for
// usage instructions.
package main

import (
"github.com/coniks-sys/coniks-go/cli"
"github.com/coniks-sys/coniks-go/cli/coniksauditor/internal/cmd"
)

func main() {
cli.Execute(cmd.RootCmd)
}
Loading