File: handler.go

package info (click to toggle)
golang-github-google-certificate-transparency 0.0~git20160709.0.0f6e3d1~ds1-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster
  • size: 5,676 kB
  • sloc: cpp: 35,278; python: 11,838; java: 1,911; sh: 1,885; makefile: 950; xml: 520; ansic: 225
file content (143 lines) | stat: -rw-r--r-- 4,435 bytes parent folder | download
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,
	}
}