Skip to content

Commit 1f97734

Browse files
authored
[witness] witness and feeder derive logID themselves (google#858)
1 parent 5f60211 commit 1f97734

File tree

7 files changed

+47
-27
lines changed

7 files changed

+47
-27
lines changed

internal/witness/api/http.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
// Package api provides the API endpoints for the witness.
1616
package api
1717

18+
import (
19+
"crypto/sha256"
20+
"encoding/base64"
21+
"fmt"
22+
)
23+
1824
const (
1925
// HTTPGetSTH is the path of the URL to get an STH. The
2026
// placeholder is for the logID (an alphanumeric string).
@@ -34,3 +40,13 @@ type UpdateRequest struct {
3440
STH []byte
3541
Proof [][]byte
3642
}
43+
44+
// LogIDFromPubKey builds the logID given the base64-encoded public key.
45+
func LogIDFromPubKey(pk string) (string, error) {
46+
der, err := base64.StdEncoding.DecodeString(pk)
47+
if err != nil {
48+
return "", fmt.Errorf("failed to decode public key: %v", err)
49+
}
50+
sha := sha256.Sum256(der)
51+
return base64.StdEncoding.EncodeToString(sha[:]), nil
52+
}

internal/witness/client/http/witness_client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func (w Witness) SigVerifier() ct.SignatureVerifier {
4646

4747
// GetLatestSTH returns a recent STH from the witness for the specified log ID.
4848
func (w Witness) GetLatestSTH(ctx context.Context, logID string) ([]byte, error) {
49-
u, err := w.URL.Parse(fmt.Sprintf(wit_api.HTTPGetSTH, logID))
49+
u, err := w.URL.Parse(fmt.Sprintf(wit_api.HTTPGetSTH, url.QueryEscape(logID)))
5050
if err != nil {
5151
return nil, fmt.Errorf("failed to parse URL: %v", err)
5252
}
@@ -78,7 +78,7 @@ func (w Witness) Update(ctx context.Context, logID string, sth []byte, proof [][
7878
if err != nil {
7979
return nil, fmt.Errorf("failed to marshal update request: %v", err)
8080
}
81-
u, err := w.URL.Parse(fmt.Sprintf(wit_api.HTTPUpdate, logID))
81+
u, err := w.URL.Parse(fmt.Sprintf(wit_api.HTTPUpdate, url.QueryEscape(logID)))
8282
if err != nil {
8383
return nil, fmt.Errorf("failed to parse URL: %v", err)
8484
}

internal/witness/cmd/feeder/main.go

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,27 @@ package main
1717

1818
import (
1919
"context"
20+
"encoding/base64"
2021
"encoding/json"
22+
"encoding/pem"
2123
"errors"
2224
"flag"
2325
"fmt"
24-
"io/ioutil"
2526
"net/http"
2627
"net/url"
2728
"time"
2829

2930
"github.com/golang/glog"
3031
ct "github.com/google/certificate-transparency-go"
3132
"github.com/google/certificate-transparency-go/client"
32-
"github.com/google/certificate-transparency-go/jsonclient"
33+
wa "github.com/google/certificate-transparency-go/internal/witness/api"
3334
wh "github.com/google/certificate-transparency-go/internal/witness/client/http"
35+
"github.com/google/certificate-transparency-go/jsonclient"
3436
)
3537

3638
var (
3739
logURL = flag.String("log_url", "", "The endpoint of the log HTTP API")
38-
logPK = flag.String("log_pk", "", "A file containing the PEM-encoded log public key")
39-
logID = flag.String("log_id", "", "The log ID")
40+
logPK = flag.String("log_pk", "", "The base64-encoded log public key")
4041
witness = flag.String("witness_url", "", "The endpoint of the witness HTTP API")
4142
interval = flag.Duration("poll", 10*time.Second, "How quickly to poll the log to get updates")
4243
)
@@ -56,11 +57,7 @@ func main() {
5657
glog.Exit("--log_pk must not be empty")
5758
}
5859
var w wh.Witness
59-
pemPK, err := ioutil.ReadFile(*logPK)
60-
if err != nil {
61-
glog.Exitf("Failed to read public key from file: %v", err)
62-
}
63-
pk, _, _, err := ct.PublicKeyFromPEM(pemPK)
60+
pk, err := ct.PublicKeyFromB64(*logPK)
6461
if err != nil {
6562
glog.Exitf("Failed to create public key: %v", err)
6663
}
@@ -77,22 +74,29 @@ func main() {
7774
}
7875
}
7976
// Now set up the log client.
80-
// TODO(smeiklej): This should be optional as it can be
81-
// deterministically derived from the public key.
82-
if *logID == "" {
83-
glog.Exit("--log_id must not be empty")
77+
logID, err := wa.LogIDFromPubKey(*logPK)
78+
if err != nil {
79+
glog.Exitf("Failed to create log id: %v", err)
8480
}
8581
if *logURL == "" {
8682
glog.Exit("--log_url must not be empty")
8783
}
84+
der, err := base64.StdEncoding.DecodeString(*logPK)
85+
if err != nil {
86+
glog.Exitf("Failed to decode public key: %v", err)
87+
}
88+
pemPK := pem.EncodeToMemory(&pem.Block{
89+
Type: "PUBLIC KEY",
90+
Bytes: der,
91+
})
8892
opts := jsonclient.Options{PublicKey: string(pemPK)}
8993
c, err := client.New(*logURL, http.DefaultClient, opts)
9094
if err != nil {
9195
glog.Exitf("Failed to create JSON client: %v", err)
9296
}
9397
// Create the feeder with no initial witness STH.
9498
feeder := feeder{
95-
logID: *logID,
99+
logID: logID,
96100
c: c,
97101
w: w,
98102
}

internal/witness/cmd/feeder/test.key

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
Logs:
22
- Description: Google 'Argon2021' log
3-
LogID: 9lyUL9F3MCIUVBgIMJRWjuNNExkzv98MLyALzE7xZOM
43
PubKey: MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAETeBmZOrzZKo4xYktx9gI2chEce3cw/tbr5xkoQlmhB18aKfsxD+MnILgGNl0FOm0eYGilFVi85wLRIOhK8lxKw==

internal/witness/cmd/witness/impl/witness.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424

2525
"github.com/golang/glog"
2626
ct "github.com/google/certificate-transparency-go"
27+
"github.com/google/certificate-transparency-go/internal/witness/api"
2728
ih "github.com/google/certificate-transparency-go/internal/witness/cmd/witness/internal/http"
2829
"github.com/google/certificate-transparency-go/internal/witness/cmd/witness/internal/witness"
2930
"github.com/gorilla/mux"
@@ -35,11 +36,8 @@ type LogConfig struct {
3536
Logs []LogInfo `yaml:"Logs"`
3637
}
3738

38-
// LogInfo contains the configuration options for a log: its identifier and public key.
39+
// LogInfo contains the configuration options for a log, which is just its public key.
3940
type LogInfo struct {
40-
// TODO(smeiklej): For CT the LogID is deterministically derived from
41-
// PubKey so we don't need to specify it separately.
42-
LogID string `yaml:"LogID"`
4341
PubKey string `yaml:"PubKey"`
4442
}
4543

@@ -59,6 +57,7 @@ type ServerOpts struct {
5957
func buildLogMap(config LogConfig) (map[string]ct.SignatureVerifier, error) {
6058
logMap := make(map[string]ct.SignatureVerifier)
6159
for _, log := range config.Logs {
60+
// Use the PubKey string to first create the verifier.
6261
pk, err := ct.PublicKeyFromB64(log.PubKey)
6362
if err != nil {
6463
return nil, fmt.Errorf("failed to create public key: %v", err)
@@ -67,7 +66,12 @@ func buildLogMap(config LogConfig) (map[string]ct.SignatureVerifier, error) {
6766
if err != nil {
6867
return nil, fmt.Errorf("failed to create signature verifier: %v", err)
6968
}
70-
logMap[log.LogID] = *logV
69+
// And then to create the (alphanumeric) logID.
70+
logID, err := api.LogIDFromPubKey(log.PubKey)
71+
if err != nil {
72+
return nil, fmt.Errorf("failed to create log id: %v", err)
73+
}
74+
logMap[logID] = *logV
7175
}
7276
return logMap, nil
7377
}

internal/witness/cmd/witness/internal/http/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func NewServer(witness *witness.Witness) *Server {
4141
}
4242

4343
// update handles requests to update STHs.
44-
// It expects a POSTed body containing a JSON-formatted api.UpdateRequest
44+
// It expects a PUT body containing a JSON-formatted api.UpdateRequest
4545
// statement and returns a JSON-formatted api.UpdateResponse statement.
4646
func (s *Server) update(w http.ResponseWriter, r *http.Request) {
4747
v := mux.Vars(r)
@@ -109,7 +109,7 @@ func (s *Server) getLogs(w http.ResponseWriter, r *http.Request) {
109109

110110
// RegisterHandlers registers HTTP handlers for witness endpoints.
111111
func (s *Server) RegisterHandlers(r *mux.Router) {
112-
logStr := "{logid:[a-zA-Z0-9-]+}"
112+
logStr := "{logid}"
113113
r.HandleFunc(fmt.Sprintf(api.HTTPGetSTH, logStr), s.getSTH).Methods("GET")
114114
r.HandleFunc(fmt.Sprintf(api.HTTPUpdate, logStr), s.update).Methods("PUT")
115115
r.HandleFunc(api.HTTPGetLogs, s.getLogs).Methods("GET")

0 commit comments

Comments
 (0)