forked from jmhodges/certificatetransparency
-
Notifications
You must be signed in to change notification settings - Fork 4
/
handler.go
143 lines (122 loc) · 4.33 KB
/
handler.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package gossip
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
"time"
ct "github.com/google/certificate-transparency/go"
)
var defaultNumPollinationsToReturn = flag.Int("default_num_pollinations_to_return", 10,
"Number of randomly selected STH pollination entries to return for sth-pollination requests.")
type clock interface {
Now() time.Time
}
type realClock struct{}
func (realClock) Now() time.Time {
return time.Now()
}
// SignatureVerifierMap is a map of SignatureVerifier by LogID
type SignatureVerifierMap map[ct.SHA256Hash]ct.SignatureVerifier
// Handler for the gossip HTTP requests.
type Handler struct {
storage *Storage
verifiers SignatureVerifierMap
clock clock
}
func writeWrongMethodResponse(rw *http.ResponseWriter, allowed string) {
(*rw).Header().Add("Allow", allowed)
(*rw).WriteHeader(http.StatusMethodNotAllowed)
}
func writeErrorResponse(rw *http.ResponseWriter, status int, body string) {
(*rw).WriteHeader(status)
(*rw).Write([]byte(body))
}
// HandleSCTFeedback handles requests POSTed to .../sct-feedback.
// It attempts to store the provided SCT Feedback
func (h *Handler) HandleSCTFeedback(rw http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
writeWrongMethodResponse(&rw, "POST")
return
}
decoder := json.NewDecoder(req.Body)
var feedback SCTFeedback
if err := decoder.Decode(&feedback); err != nil {
writeErrorResponse(&rw, http.StatusBadRequest, fmt.Sprintf("Invalid SCT Feedback received: %v", err))
return
}
// TODO(alcutter): 5.1.1 Validate leaf chains up to a trusted root
// TODO(alcutter): 5.1.1/2 Verify each SCT is valid and from a known log, discard those which aren't
// TODO(alcutter): 5.1.1/3 Discard leaves for domains other than ours.
if err := h.storage.AddSCTFeedback(feedback); err != nil {
writeErrorResponse(&rw, http.StatusInternalServerError, fmt.Sprintf("Unable to store feedback: %v", err))
return
}
rw.WriteHeader(http.StatusOK)
}
// HandleSTHPollination handles requests POSTed to .../sth-pollination.
// It attempts to store the provided pollination info, and returns a random set of
// pollination data from the last 14 days (i.e. "fresh" by the definition of the gossip RFC.)
func (h *Handler) HandleSTHPollination(rw http.ResponseWriter, req *http.Request) {
if req.Method != "POST" {
writeWrongMethodResponse(&rw, "POST")
return
}
decoder := json.NewDecoder(req.Body)
var p STHPollination
if err := decoder.Decode(&p); err != nil {
writeErrorResponse(&rw, http.StatusBadRequest, fmt.Sprintf("Invalid STH Pollination received: %v", err))
return
}
sthToKeep := make([]ct.SignedTreeHead, 0, len(p.STHs))
for _, sth := range p.STHs {
v, found := h.verifiers[sth.LogID]
if !found {
log.Printf("Pollination entry for unknown logID: %s", sth.LogID.Base64String())
continue
}
if err := v.VerifySTHSignature(sth); err != nil {
log.Printf("Failed to verify STH, dropping: %v", err)
continue
}
sthToKeep = append(sthToKeep, sth)
}
p.STHs = sthToKeep
err := h.storage.AddSTHPollination(p)
if err != nil {
writeErrorResponse(&rw, http.StatusInternalServerError, fmt.Sprintf("Couldn't store pollination: %v", err))
return
}
freshTime := h.clock.Now().AddDate(0, 0, -14)
rp, err := h.storage.GetRandomSTHPollination(freshTime, *defaultNumPollinationsToReturn)
if err != nil {
writeErrorResponse(&rw, http.StatusInternalServerError, fmt.Sprintf("Couldn't fetch pollination to return: %v", err))
return
}
json := json.NewEncoder(rw)
if err := json.Encode(*rp); err != nil {
writeErrorResponse(&rw, http.StatusInternalServerError, fmt.Sprintf("Couldn't encode pollination to return: %v", err))
return
}
}
// NewHandler creates a new Handler object, taking a pointer a Storage object to
// use for storing and retrieving feedback and pollination data, and a
// SignatureVerifierMap for verifying signatures from known logs.
func NewHandler(s *Storage, v SignatureVerifierMap) Handler {
return Handler{
storage: s,
verifiers: v,
clock: realClock{},
}
}
// NewHandler creates a new Handler object, taking a pointer a Storage object to
// use for storing and retrieving feedback and pollination data, and a
// SignatureVerifierMap for verifying signatures from known logs.
func newHandlerWithClock(s *Storage, v SignatureVerifierMap, c clock) Handler {
return Handler{
storage: s,
verifiers: v,
clock: c,
}
}