aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--database.go75
-rw-r--r--main.go46
-rw-r--r--monitor/database.go13
-rw-r--r--own.go155
4 files changed, 12 insertions, 277 deletions
diff --git a/database.go b/database.go
deleted file mode 100644
index 87dfb4c..0000000
--- a/database.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package main
-
-import (
- "bytes"
- "io/ioutil"
- "log"
- "net/http"
- "sync"
- "time"
-
- "git.sr.ht/~benburwell/gosumdbaudit/sumdb"
-)
-
-type database struct {
- host string
- key string
- pollInterval time.Duration
-
- hc http.Client
-
- config map[string][]byte
- configMu sync.RWMutex
-}
-
-func (d *database) ReadRemote(path string) ([]byte, error) {
- log.Printf("read remote: %s", path)
- resp, err := d.hc.Get("https://" + d.host + path)
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- return ioutil.ReadAll(resp.Body)
-}
-
-func (d *database) ReadConfig(file string) ([]byte, error) {
- log.Printf("read config: %s", file)
- if file == "key" {
- return []byte(d.key), nil
- }
- d.configMu.RLock()
- defer d.configMu.RUnlock()
- if d.config == nil {
- d.config = make(map[string][]byte)
- // d.config["sum.golang.org/latest"] = []byte(`go.sum database tree
- // 163038
- // S1dhskM/kuUJUOCz3InBRhl0vFiHxr0INft+24ClisI=
-
- // — sum.golang.org Az3gruAGD/ybzwcCUArmKpzAZNmEOu3Yahr9WIKA2SFAK3G2xzo39uHS70mylR3nsT9t3ZpVQW89RT6Tg1+1nIf7bgI=
- // `)
- }
- c, ok := d.config[file]
- if !ok {
- return nil, nil
- }
- return c, nil
-}
-
-func (d *database) WriteConfig(file string, old, new []byte) error {
- log.Printf("write config: %s", file)
- d.configMu.Lock()
- defer d.configMu.Unlock()
- if val, ok := d.config[file]; ok && !bytes.Equal(val, old) {
- return sumdb.ErrWriteConflict
- }
- d.config[file] = new
- return nil
-}
-
-func (d *database) Log(msg string) {
- log.Printf(msg)
-}
-
-func (d *database) SecurityError(msg string) {
- log.Printf("!!! SECURITY ERROR !!!\n%s", msg)
-}
diff --git a/main.go b/main.go
index f60372f..b63f8fb 100644
--- a/main.go
+++ b/main.go
@@ -14,51 +14,7 @@ func main() {
Key: "sum.golang.org+033de0ae+Ac4zctda0e5eza+HJyk9SxEdh+s3Ux18htTTAD8OuAn8",
})
- if err := mon.Watch(10 * time.Second); err != nil {
+ if err := mon.Watch(1 * time.Minute); err != nil {
log.Printf("AUDIT FAILED: %v", err)
}
}
-
-// func monitor(db *database) error {
-// log.Printf("starting monitor for %s", db.host)
-
-// client := sumdb.NewClient(db)
-
-// tree, err := client.FetchLatest()
-// if err != nil {
-// return err
-// }
-// log.Printf("got latest: N=%d, Hash=%s", tree.N, tree.Hash)
-
-// if err := client.FetchTreeProof(tree); err != nil {
-// return err
-// }
-
-// // fetch all entries in the tree according to the STH
-// // entries := client.Entries(nil, latest)
-
-// // confirm the tree made from the entries produces the same hash as the STH
-// // IF NOT: the server has signed invalid data
-
-// // prev := latest
-// for {
-// // await a new STH
-// // prev = latest
-// time.Sleep(db.pollInterval)
-// log.Printf("checking %s for new STH...", db.host)
-// // awaitNewSTH()
-
-// // latest, err := client.Latest()
-// // if err != nil {
-// // return err
-// // }
-
-// // fetch all NEW entries between prev and latest
-// // if unavailable for an extended period, this should be viewed as misbehavior
-// // entries := client.Entries(prev, latest)
-
-// // fetch a consistency proof for the new STH with the previous STH
-// // verify consistency proof
-// // verify the new entries generate the corresponding elements in the consistency proof
-// }
-// }
diff --git a/monitor/database.go b/monitor/database.go
index 7a0ead1..1c2a913 100644
--- a/monitor/database.go
+++ b/monitor/database.go
@@ -10,14 +10,23 @@ import (
"golang.org/x/mod/sumdb/tlog"
)
+const userAgent = "gosumdbaudit/1.0 (+https://bnbl.io/gosumdbaudit)"
+
type Database struct {
URL string
Key string
+
+ c http.Client
}
func (db *Database) readRemote(path string) ([]byte, error) {
log.Printf("GET %s", path)
- resp, err := http.Get("https://" + db.URL + path)
+ req, err := http.NewRequest(http.MethodGet, "https://"+db.URL+path, nil)
+ if err != nil {
+ return nil, err
+ }
+ req.Header.Set("user-agent", userAgent)
+ resp, err := db.c.Do(req)
if err != nil {
return nil, err
}
@@ -30,7 +39,7 @@ func (db *Database) readRemote(path string) ([]byte, error) {
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
- return nil, fmt.Errorf("get %s: %v", err)
+ return nil, fmt.Errorf("get %s: %v", path, err)
}
return body, nil
}
diff --git a/own.go b/own.go
deleted file mode 100644
index ae3e457..0000000
--- a/own.go
+++ /dev/null
@@ -1,155 +0,0 @@
-package main
-
-// func audit(d *db) error {
-// log.Printf("starting audit of %s...", d.host)
-// size, hash, err := d.getLatest()
-// if err != nil {
-// return err
-// }
-// log.Printf("db size %d", size)
-// log.Printf("db hash %s", hash)
-// return nil
-// }
-
-// type db struct {
-// host string
-// key string
-// pollInterval time.Duration
-// }
-
-// // httpGet makes a GET request to the specified path of the database and
-// // returns a byte slice of the response body.
-// func (d *db) httpGet(path string) ([]byte, error) {
-// client := &http.Client{}
-// resp, err := client.Get("https://" + d.host + path)
-// if err != nil {
-// return nil, err
-// }
-// defer resp.Body.Close()
-// var body bytes.Buffer
-// if _, err := io.Copy(&body, resp.Body); err != nil {
-// return nil, fmt.Errorf("could not read response body: %w", err)
-// }
-// return body.Bytes(), nil
-// }
-
-// // verifyNote takes a signed byte slice, verifies the signature against the
-// // db's public key. If successful, the note content is returned, otherwise, an
-// // error.
-// func (d *db) verifyNote(b []byte) (string, error) {
-// verifier, err := note.NewVerifier(d.key)
-// if err != nil {
-// return "", err
-// }
-// verifiers := note.VerifierList(verifier)
-// msg, err := note.Open(b, verifiers)
-// if err != nil {
-// return "", err
-// }
-// return msg.Text, nil
-// }
-
-// // bootstrapMonitor fetches and verifies the current tree starting from the
-// // first log entry, and returns the current verified size and hash.
-// func (d *db) bootstrapMonitor() (int, string, error) {
-// log.Printf("bootstrapping monitor")
-// log.Printf("TODO: implement fully")
-// log.Printf("verified until size 163038")
-// return 163038, "S1dhskM/kuUJUOCz3InBRhl0vFiHxr0INft+24ClisI=", nil
-
-// // TODO: implement
-
-// // 1. Fetch the current STH (section 4.3)
-// // 2. Verify the STH signature
-// // size, hash, err := d.getLatest()
-// // if err != nil {
-// // return err
-// // }
-
-// // 3. Fetch all entries in the tree corresponding to the STH (section 4.6)
-
-// // 4. Confirm that the tree made from the fetched entries produces the same
-// // hash as that in the STH.
-// }
-
-// // monitor monitors the db to ensure it behaves correctly, using the algorithm
-// // for CT logs specified in RFC 6952 section 3.5.
-// func (d *db) monitor() error {
-// log.Printf("starting monitor")
-// size, hash, err := d.bootstrapMonitor()
-// if err != nil {
-// return err
-// }
-// log.Printf("successfully verified merkle tree proof until size %d and hash %s", size, hash)
-
-// // 5. Fetch the current STH (section 4.3). Repeat until the STH changes.
-// // 6. Verify the STH signature.
-// log.Printf("waiting for a tree size greater than %d", size)
-// newSize, newHash, err := d.awaitNewSTH(size)
-// if err != nil {
-// return err
-// }
-// log.Printf("got new STH with size %d and hash %s", newSize, newHash)
-
-// // 7. Fetch all the new entries in the tree corresponding to the STH (section
-// // 4.6). If they remain unavailable for an extended period, then this should
-// // be viewed as misbehavior on the part of the log.
-
-// // 8. Fetch a consistency proof for the new STH with the previous STH
-// // (section 4.4).
-
-// // 9. Verify the consistency proof.
-
-// // 10. Verify that the new entries generate the corresponding elements in the
-// // consistency proof.
-
-// // 11. Go to step 5.
-
-// return nil
-// }
-
-// // awaitNewSTH periodically checks and verifies the current STH. If the latest
-// // tree size differs from the previous size, the new verified size and hash are
-// // returned.
-// func (d *db) awaitNewSTH(prevSize int) (int, string, error) {
-// for {
-// log.Printf("sleeping...")
-// time.Sleep(d.pollInterval)
-// log.Printf("checking latest tree size")
-// size, hash, err := d.getLatest()
-// if err != nil {
-// return 0, "", err
-// }
-// if size < prevSize {
-// return 0, "", fmt.Errorf("misbehaving log: latest log contains %d entries but previously reported %d", size, prevSize)
-// }
-// if size != prevSize {
-// log.Printf("found a new STH (size=%d)", size)
-// return size, hash, nil
-// }
-// log.Printf("tree sizes match")
-// }
-// }
-
-// // getLatest fetches and verifies the latest signed tree head hash and database
-// // size.
-// func (d *db) getLatest() (int, string, error) {
-// body, err := d.httpGet("/latest")
-// if err != nil {
-// return 0, "", fmt.Errorf("could not fetch latest: %w", err)
-// }
-// msg, err := d.verifyNote(body)
-// if err != nil {
-// return 0, "", fmt.Errorf("could not verify note: %w", err)
-// }
-// parts := strings.Split(msg, "\n")
-// if len(parts) != 4 {
-// return 0, "", fmt.Errorf("could not parse latest: expected %d lines but got %d", 4, len(parts))
-// }
-// size, err := strconv.Atoi(parts[1])
-// if err != nil {
-// return 0, "", fmt.Errorf("could not parse tree size: %w", err)
-// }
-// hash := parts[2]
-// return size, hash, nil
-// }