diff options
Diffstat (limited to 'pkg/server')
-rw-r--r-- | pkg/server/handler.go | 32 | ||||
-rw-r--r-- | pkg/server/messages.go | 23 | ||||
-rw-r--r-- | pkg/server/nodes.go | 53 | ||||
-rw-r--r-- | pkg/server/server.go | 133 |
4 files changed, 0 insertions, 241 deletions
diff --git a/pkg/server/handler.go b/pkg/server/handler.go deleted file mode 100644 index 6d17af7..0000000 --- a/pkg/server/handler.go +++ /dev/null @@ -1,32 +0,0 @@ -package server - -import ( - "fmt" - "net/http" -) - -// handler implements the http.Handler interface -type handler struct { - method string - endpoint string - callback func(w http.ResponseWriter, r *http.Request) (int, string) -} - -func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("Cache-Control", "no-cache") - if r.Method != h.method { - http.Error(w, "Invalid HTTP method, expected "+h.method, http.StatusMethodNotAllowed) - return - } - code, text := h.callback(w, r) - if code != http.StatusOK { - http.Error(w, text, code) - return - } - fmt.Fprintf(w, fmt.Sprintf("%s\n", text)) -} - -func (h handler) register(mux *http.ServeMux) { - mux.Handle("/"+h.endpoint, h) -} diff --git a/pkg/server/messages.go b/pkg/server/messages.go deleted file mode 100644 index a6ea243..0000000 --- a/pkg/server/messages.go +++ /dev/null @@ -1,23 +0,0 @@ -package server - -import ( - "fmt" - "time" -) - -type MessageNodeSubmission struct { - SerialNumber string - NotBefore time.Time - DomainNames []string - PEMChain []byte -} - -type ErrorUnauthorizedDomainName struct { - PEMChain []byte - Node Node - Err error -} - -func (e ErrorUnauthorizedDomainName) Error() string { - return fmt.Sprintf("%v", e.Err) -} diff --git a/pkg/server/nodes.go b/pkg/server/nodes.go deleted file mode 100644 index 164c06f..0000000 --- a/pkg/server/nodes.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - "crypto/x509" - "fmt" - "net/http" -) - -// Node is an identified system that can request certificates -type Node struct { - Name string `json:"name"` // Artbirary node name for authentication - Secret string `json:"secret"` // Arbitrary node secret for authentication - Domains []string `json:"issues"` // Exact-match domain names that are allowed -} - -func (node *Node) authenticate(r *http.Request) error { - user, password, ok := r.BasicAuth() - if !ok { - return fmt.Errorf("no http basic auth credentials") - } - if user != node.Name || password != node.Secret { - return fmt.Errorf("invalid http basic auth credentials") - } - return nil -} - -func (node *Node) check(crt x509.Certificate) error { - for _, san := range crt.DNSNames { - ok := false - for _, domain := range node.Domains { - if domain == san { - ok = true - break - } - } - if !ok { - return fmt.Errorf("%s: not authorized to issue certificates for %s", node.Name, san) - } - } - return nil -} - -// Nodes is a list of nodes that can request certificates -type Nodes []Node - -func (nodes *Nodes) authenticate(r *http.Request) (Node, error) { - for _, node := range (*nodes)[:] { - if err := node.authenticate(r); err == nil { - return node, nil - } - } - return Node{}, fmt.Errorf("no valid HTTP basic auth credentials") -} diff --git a/pkg/server/server.go b/pkg/server/server.go deleted file mode 100644 index 06eb258..0000000 --- a/pkg/server/server.go +++ /dev/null @@ -1,133 +0,0 @@ -package server - -import ( - "context" - "fmt" - "io" - "net" - "net/http" - "time" - - "rgdd.se/silent-ct/internal/x509util" -) - -const ( - EndpointAddChain = "add-chain" - EndpointGetStatus = "get-status" - - DefaultNetwork = "tcp" - DefaultAddress = "localhost:2009" - DefaultConfigFile = "/home/rgdd/.config/silent-ct/config.json" // FIXME -) - -type Config struct { - Network string // tcp or unix - Address string // hostname[:port] or path to a unix socket - Nodes Nodes // Which nodes are trusted to issue what certificates -} - -type Server struct { - Config - - eventCh chan MessageNodeSubmission - errorCh chan error -} - -func New(cfg Config) (Server, error) { - if cfg.Network == "" { - cfg.Network = DefaultNetwork - } - if cfg.Address == "" { - cfg.Network = DefaultAddress - } - return Server{Config: cfg}, nil -} - -func (srv *Server) Run(ctx context.Context, submitCh chan MessageNodeSubmission, errorCh chan error) error { - srv.eventCh = submitCh - srv.errorCh = errorCh - mux := http.NewServeMux() - for _, handler := range srv.handlers() { - handler.register(mux) - } - - listener, err := net.Listen(srv.Network, srv.Address) - if err != nil { - return fmt.Errorf("listen: %v", err) - } - defer listener.Close() - - s := http.Server{Handler: mux} - exitCh := make(chan error, 1) - defer close(exitCh) - go func() { - exitCh <- s.Serve(listener) - }() - - select { - case err := <-exitCh: - if err != nil && err != http.ErrServerClosed { - return fmt.Errorf("serve: %v", err) - } - case <-ctx.Done(): - tctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - if err := s.Shutdown(tctx); err != nil { - return fmt.Errorf("shutdown: %v", err) - } - } - return nil -} - -func (srv *Server) handlers() []handler { - return []handler{ - handler{ - method: http.MethodGet, - endpoint: EndpointGetStatus, - callback: func(w http.ResponseWriter, r *http.Request) (int, string) { return srv.getStatus(w, r) }, - }, - handler{ - method: http.MethodPost, - endpoint: EndpointAddChain, - callback: func(w http.ResponseWriter, r *http.Request) (int, string) { return srv.addChain(w, r) }, - }, - } -} - -func (srv *Server) getStatus(w http.ResponseWriter, r *http.Request) (int, string) { - return http.StatusOK, "OK" -} - -func (srv *Server) addChain(w http.ResponseWriter, r *http.Request) (int, string) { - node, err := srv.Nodes.authenticate(r) - if err != nil { - return http.StatusForbidden, "Invalid HTTP Basic Auth credentials" - } - - b, err := io.ReadAll(r.Body) - if err != nil { - return http.StatusBadRequest, "Read HTTP POST body failed" - } - defer r.Body.Close() - - chain, err := x509util.ParseChain(b) - if err != nil { - return http.StatusBadRequest, "Malformed HTTP POST body" - } - if err := node.check(chain[0]); err != nil { - srv.errorCh <- ErrorUnauthorizedDomainName{ - PEMChain: b, - Node: node, - Err: err, - } - } else { - srv.eventCh <- MessageNodeSubmission{ - SerialNumber: chain[0].SerialNumber.String(), - NotBefore: chain[0].NotBefore, - DomainNames: chain[0].DNSNames, - PEMChain: b, - } - } - - return http.StatusOK, "OK" -} |