Skip to content

Commit

Permalink
/certs/[profile]/cacert.pem
Browse files Browse the repository at this point in the history
  • Loading branch information
yzp0n committed Dec 27, 2019
1 parent 1e02b0b commit ae0ac65
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 14 deletions.
100 changes: 100 additions & 0 deletions cli/serve/certshandler/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package certshandler

import (
"crypto/x509"
"errors"
"fmt"
"net/http"
"net/url"
"strings"

"github.com/IPA-CyberLab/kmgm/cli"
"github.com/IPA-CyberLab/kmgm/httperr"
"github.com/IPA-CyberLab/kmgm/pemparser"
"github.com/IPA-CyberLab/kmgm/storage/issuedb"
)

type Handler struct {
env *cli.Environment
}

func New(env *cli.Environment) http.Handler {
return &Handler{env}
}

func serveCertificate(w http.ResponseWriter, cert *x509.Certificate, filename string) error {
w.Header().Set("X-Content-Type-Options", "nosniff")
w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.QueryEscape(filename))
w.Header().Set("Content-Type", "application/x-pem-file")
certPem := pemparser.MarshalCertificateDer(cert.Raw)
if _, err := w.Write(certPem); err != nil {
return fmt.Errorf("Failed to output PEM: %w", err)
}
return nil
}

func (h *Handler) serveHTTPIfPossible(w http.ResponseWriter, r *http.Request) error {
if r.Method != "GET" {
return httperr.ErrorWithStatusCode{
StatusCode: http.StatusBadRequest,
Err: errors.New("Unsupported method")}
}

env := h.env.Clone()
slog := env.Logger.Sugar()

var queryStr string

args := strings.Split(strings.TrimPrefix(r.URL.Path, "/"), "/")
switch len(args) {
case 1:
queryStr = args[0]
case 2:
env.ProfileName = args[0]
queryStr = args[1]
default:
return httperr.ErrorWithStatusCode{
StatusCode: http.StatusNotFound,
Err: errors.New("bad path")}
}
queryStr = strings.TrimSuffix(queryStr, ".pem")

slog.Debugf("certshandler GET profile: %s, queryStr: %s", env.ProfileName, queryStr)

profile, err := env.Profile()
if err != nil {
return err
}

switch queryStr {
case "":
w.Header().Set("Content-Type", "text/plain")
w.Write([]byte("/issue/[profileName]/[query].pem\n"))
return nil
case "cacert":
cacert, err := profile.ReadCACertificate()
if err != nil {
return fmt.Errorf("Failed to query cacert: %w", err)
}

return serveCertificate(w, cacert, "cacert.pem")
}

db, err := issuedb.New(env.Randr, profile.IssueDBPath())
if err != nil {
return err
}

db.Query(123)

return nil
}

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
slog := h.env.Logger.Sugar()

if err := h.serveHTTPIfPossible(w, r); err != nil {
slog.Warnw("Failed to process request", "err", err)
http.Error(w, fmt.Sprintf("Failed to process request: %v", err), httperr.StatusCodeFromError(err))
}
}
21 changes: 11 additions & 10 deletions cli/serve/issuehandler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/IPA-CyberLab/kmgm/cli"
"github.com/IPA-CyberLab/kmgm/cli/issue"
"github.com/IPA-CyberLab/kmgm/dname"
"github.com/IPA-CyberLab/kmgm/httperr"
"github.com/IPA-CyberLab/kmgm/keyusage"
"github.com/IPA-CyberLab/kmgm/pemparser"
"github.com/IPA-CyberLab/kmgm/san"
Expand Down Expand Up @@ -128,7 +129,7 @@ func (h *Handler) serveHTTPIfPossible(w http.ResponseWriter, r *http.Request) er
// FIXME[P3]: allow Authorization header
token := q.Get("token")
if token != h.token {
return ErrorWithStatusCode{http.StatusUnauthorized, errors.New("Invalid token.")}
return httperr.ErrorWithStatusCode{http.StatusUnauthorized, errors.New("Invalid token.")}
}

profile, err := h.env.Storage.Profile(storage.DefaultProfileName)
Expand All @@ -150,13 +151,13 @@ func (h *Handler) serveHTTPIfPossible(w http.ResponseWriter, r *http.Request) er
if s := q.Get("ktype"); s != "" {
ktype, err = wcrypto.KeyTypeFromString(s)
if err != nil {
return ErrorWithStatusCode{http.StatusBadRequest, err}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, err}
}
}

commonName := q.Get("cn")
if commonName == "" {
return ErrorWithStatusCode{http.StatusBadRequest, errors.New("param \"cn\" is not specified.")}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, errors.New("param \"cn\" is not specified.")}
}
subject.CommonName = commonName

Expand All @@ -167,34 +168,34 @@ func (h *Handler) serveHTTPIfPossible(w http.ResponseWriter, r *http.Request) er

for _, e := range q["san"] {
if err := ns.Add(e); err != nil {
return ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse subjectAltName entry %q: %w", e, err)}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse subjectAltName entry %q: %w", e, err)}
}
}

if _, set := q["san_remoteip"]; set {
raddrWithPort := r.RemoteAddr
raddr, _, err := net.SplitHostPort(raddrWithPort)
if err != nil {
return ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse remoteip %q: %w", raddrWithPort, err)}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse remoteip %q: %w", raddrWithPort, err)}
}
if err := ns.Add(raddr); err != nil {
return ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to add remoteip %q as subjectAltName: %w", raddr, err)}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to add remoteip %q as subjectAltName: %w", raddr, err)}
}
}

days := uint(860)
if s, set := q["days"]; set {
n, err := strconv.ParseUint(s[0], 10, 32)
if err != nil {
return ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse days %q: %w", s[0], err)}
return httperr.ErrorWithStatusCode{http.StatusBadRequest, fmt.Errorf("Failed to parse days %q: %w", s[0], err)}
}
days = uint(n)
}

h.mu.Lock()
defer h.mu.Unlock()
if h.allowedCountLeft <= 0 {
return ErrorWithStatusCode{http.StatusTooManyRequests, errors.New("/issue was invoked for more than its allowed count.")}
return httperr.ErrorWithStatusCode{http.StatusTooManyRequests, errors.New("/issue was invoked for more than its allowed count.")}
}
h.allowedCountLeft -= 1

Expand Down Expand Up @@ -238,7 +239,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
slog := h.env.Logger.Sugar()

if err := h.serveHTTPIfPossible(w, r); err != nil {
slog.Errorw("Failed to process request", "err", err)
http.Error(w, fmt.Sprintf("Failed to process request: %v", err), StatusCodeFromError(err))
slog.Warnw("Failed to process request", "err", err)
http.Error(w, fmt.Sprintf("Failed to process request: %v", err), httperr.StatusCodeFromError(err))
}
}
2 changes: 2 additions & 0 deletions cli/serve/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/IPA-CyberLab/kmgm/cli"
"github.com/IPA-CyberLab/kmgm/cli/serve/authprofile"
"github.com/IPA-CyberLab/kmgm/cli/serve/certificateservice"
"github.com/IPA-CyberLab/kmgm/cli/serve/certshandler"
"github.com/IPA-CyberLab/kmgm/cli/serve/httpzaplog"
"github.com/IPA-CyberLab/kmgm/cli/serve/issuehandler"
"github.com/IPA-CyberLab/kmgm/pb"
Expand Down Expand Up @@ -203,6 +204,7 @@ func StartServer(env *cli.Environment, cfg *Config) (*Server, error) {
slog.Infof("HTTP issue endpoint enabled for %d times.", cfg.IssueHttp)
slog.Infof(" On clients, exec: %s", curlcmd)
}
mux.Handle("/certs/", http.StripPrefix("/certs/", certshandler.New(env)))

httpHandler := httpzaplog.Handler{
Upstream: mux,
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/manifoldco/promptui v0.6.0
github.com/prometheus/client_golang v1.3.0
github.com/urfave/cli/v2 v2.0.0
github.com/urfave/cli/v2 v2.1.1
go.uber.org/multierr v1.4.0
go.uber.org/zap v1.13.0
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tsenart/deadcode v0.0.0-20160724212837-210d2dc333e9/go.mod h1:q+QjxYvZ+fpjMXqs+XEriussHjSYqeXVnAdSV1tkMYk=
github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
github.com/urfave/cli/v2 v2.0.0 h1:+HU9SCbu8GnEUFtIBfuUNXN39ofWViIEJIp6SURMpCg=
github.com/urfave/cli/v2 v2.0.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
Expand Down
2 changes: 1 addition & 1 deletion cli/serve/issuehandler/error.go → httperr/error.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package issuehandler
package httperr

type ErrorWithStatusCode struct {
StatusCode int
Expand Down

0 comments on commit ae0ac65

Please sign in to comment.