forked from google/certificate-transparency-go
-
Notifications
You must be signed in to change notification settings - Fork 0
/
handler.go
157 lines (135 loc) · 4.93 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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
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,
}
}