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 // }