Vendor cfssl and cfssljson
This commit is contained in:
41
vendor/github.com/cloudflare/cfssl/api/BUILD
generated
vendored
Normal file
41
vendor/github.com/cloudflare/cfssl/api/BUILD
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["api.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api",
|
||||
importpath = "github.com/cloudflare/cfssl/api",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/bundle:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/certinfo:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/client:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/crl:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/gencrl:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/generator:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/info:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/initca:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/ocsp:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/revoke:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/scan:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/signhandler:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
231
vendor/github.com/cloudflare/cfssl/api/api.go
generated
vendored
Normal file
231
vendor/github.com/cloudflare/cfssl/api/api.go
generated
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
// Package api implements an HTTP-based API and server for CFSSL.
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// Handler is an interface providing a generic mechanism for handling HTTP requests.
|
||||
type Handler interface {
|
||||
Handle(w http.ResponseWriter, r *http.Request) error
|
||||
}
|
||||
|
||||
// HTTPHandler is a wrapper that encapsulates Handler interface as http.Handler.
|
||||
// HTTPHandler also enforces that the Handler only responds to requests with registered HTTP methods.
|
||||
type HTTPHandler struct {
|
||||
Handler // CFSSL handler
|
||||
Methods []string // The associated HTTP methods
|
||||
}
|
||||
|
||||
// HandlerFunc is similar to the http.HandlerFunc type; it serves as
|
||||
// an adapter allowing the use of ordinary functions as Handlers. If
|
||||
// f is a function with the appropriate signature, HandlerFunc(f) is a
|
||||
// Handler object that calls f.
|
||||
type HandlerFunc func(http.ResponseWriter, *http.Request) error
|
||||
|
||||
// Handle calls f(w, r)
|
||||
func (f HandlerFunc) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
return f(w, r)
|
||||
}
|
||||
|
||||
// HandleError is the centralised error handling and reporting.
|
||||
func HandleError(w http.ResponseWriter, err error) (code int) {
|
||||
if err == nil {
|
||||
return http.StatusOK
|
||||
}
|
||||
msg := err.Error()
|
||||
httpCode := http.StatusInternalServerError
|
||||
|
||||
// If it is recognized as HttpError emitted from cfssl,
|
||||
// we rewrite the status code accordingly. If it is a
|
||||
// cfssl error, set the http status to StatusBadRequest
|
||||
switch err := err.(type) {
|
||||
case *errors.HTTPError:
|
||||
httpCode = err.StatusCode
|
||||
code = err.StatusCode
|
||||
case *errors.Error:
|
||||
httpCode = http.StatusBadRequest
|
||||
code = err.ErrorCode
|
||||
msg = err.Message
|
||||
}
|
||||
|
||||
response := NewErrorResponse(msg, code)
|
||||
jsonMessage, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to marshal JSON: %v", err)
|
||||
} else {
|
||||
msg = string(jsonMessage)
|
||||
}
|
||||
http.Error(w, msg, httpCode)
|
||||
return code
|
||||
}
|
||||
|
||||
// ServeHTTP encapsulates the call to underlying Handler to handle the request
|
||||
// and return the response with proper HTTP status code
|
||||
func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
var err error
|
||||
var match bool
|
||||
// Throw 405 when requested with an unsupported verb.
|
||||
for _, m := range h.Methods {
|
||||
if m == r.Method {
|
||||
match = true
|
||||
}
|
||||
}
|
||||
if match {
|
||||
err = h.Handle(w, r)
|
||||
} else {
|
||||
err = errors.NewMethodNotAllowed(r.Method)
|
||||
}
|
||||
status := HandleError(w, err)
|
||||
log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status)
|
||||
}
|
||||
|
||||
// readRequestBlob takes a JSON-blob-encoded response body in the form
|
||||
// map[string]string and returns it, the list of keywords presented,
|
||||
// and any error that occurred.
|
||||
func readRequestBlob(r *http.Request) (map[string]string, error) {
|
||||
var blob map[string]string
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
err = json.Unmarshal(body, &blob)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blob, nil
|
||||
}
|
||||
|
||||
// ProcessRequestOneOf reads a JSON blob for the request and makes
|
||||
// sure it contains one of a set of keywords. For example, a request
|
||||
// might have the ('foo' && 'bar') keys, OR it might have the 'baz'
|
||||
// key. In either case, we want to accept the request; however, if
|
||||
// none of these sets shows up, the request is a bad request, and it
|
||||
// should be returned.
|
||||
func ProcessRequestOneOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
|
||||
blob, err := readRequestBlob(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
var matched []string
|
||||
for _, set := range keywordSets {
|
||||
if matchKeywords(blob, set) {
|
||||
if matched != nil {
|
||||
return nil, nil, errors.NewBadRequestString("mismatched parameters")
|
||||
}
|
||||
matched = set
|
||||
}
|
||||
}
|
||||
if matched == nil {
|
||||
return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
|
||||
}
|
||||
return blob, matched, nil
|
||||
}
|
||||
|
||||
// ProcessRequestFirstMatchOf reads a JSON blob for the request and returns
|
||||
// the first match of a set of keywords. For example, a request
|
||||
// might have one of the following combinations: (foo=1, bar=2), (foo=1), and (bar=2)
|
||||
// By giving a specific ordering of those combinations, we could decide how to accept
|
||||
// the request.
|
||||
func ProcessRequestFirstMatchOf(r *http.Request, keywordSets [][]string) (map[string]string, []string, error) {
|
||||
blob, err := readRequestBlob(r)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, set := range keywordSets {
|
||||
if matchKeywords(blob, set) {
|
||||
return blob, set, nil
|
||||
}
|
||||
}
|
||||
return nil, nil, errors.NewBadRequestString("no valid parameter sets found")
|
||||
}
|
||||
|
||||
func matchKeywords(blob map[string]string, keywords []string) bool {
|
||||
for _, keyword := range keywords {
|
||||
if _, ok := blob[keyword]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// ResponseMessage implements the standard for response errors and
|
||||
// messages. A message has a code and a string message.
|
||||
type ResponseMessage struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Response implements the CloudFlare standard for API
|
||||
// responses.
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
Result interface{} `json:"result"`
|
||||
Errors []ResponseMessage `json:"errors"`
|
||||
Messages []ResponseMessage `json:"messages"`
|
||||
}
|
||||
|
||||
// NewSuccessResponse is a shortcut for creating new successul API
|
||||
// responses.
|
||||
func NewSuccessResponse(result interface{}) Response {
|
||||
return Response{
|
||||
Success: true,
|
||||
Result: result,
|
||||
Errors: []ResponseMessage{},
|
||||
Messages: []ResponseMessage{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewSuccessResponseWithMessage is a shortcut for creating new successul API
|
||||
// responses that includes a message.
|
||||
func NewSuccessResponseWithMessage(result interface{}, message string, code int) Response {
|
||||
return Response{
|
||||
Success: true,
|
||||
Result: result,
|
||||
Errors: []ResponseMessage{},
|
||||
Messages: []ResponseMessage{{code, message}},
|
||||
}
|
||||
}
|
||||
|
||||
// NewErrorResponse is a shortcut for creating an error response for a
|
||||
// single error.
|
||||
func NewErrorResponse(message string, code int) Response {
|
||||
return Response{
|
||||
Success: false,
|
||||
Result: nil,
|
||||
Errors: []ResponseMessage{{code, message}},
|
||||
Messages: []ResponseMessage{},
|
||||
}
|
||||
}
|
||||
|
||||
// SendResponse builds a response from the result, sets the JSON
|
||||
// header, and writes to the http.ResponseWriter.
|
||||
func SendResponse(w http.ResponseWriter, result interface{}) error {
|
||||
response := NewSuccessResponse(result)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
err := enc.Encode(response)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendResponseWithMessage builds a response from the result and the
|
||||
// provided message, sets the JSON header, and writes to the
|
||||
// http.ResponseWriter.
|
||||
func SendResponseWithMessage(w http.ResponseWriter, result interface{}, message string, code int) error {
|
||||
response := NewSuccessResponseWithMessage(result, message, code)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
err := enc.Encode(response)
|
||||
return err
|
||||
}
|
29
vendor/github.com/cloudflare/cfssl/api/bundle/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/api/bundle/BUILD
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["bundle.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/bundle",
|
||||
importpath = "github.com/cloudflare/cfssl/api/bundle",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
91
vendor/github.com/cloudflare/cfssl/api/bundle/bundle.go
generated
vendored
Normal file
91
vendor/github.com/cloudflare/cfssl/api/bundle/bundle.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
// Package bundle implements the HTTP handler for the bundle command.
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// Handler accepts requests for either remote or uploaded
|
||||
// certificates to be bundled, and returns a certificate bundle (or
|
||||
// error).
|
||||
type Handler struct {
|
||||
bundler *bundler.Bundler
|
||||
}
|
||||
|
||||
// NewHandler creates a new bundler that uses the root bundle and
|
||||
// intermediate bundle in the trust chain.
|
||||
func NewHandler(caBundleFile, intBundleFile string) (http.Handler, error) {
|
||||
var err error
|
||||
|
||||
b := new(Handler)
|
||||
if b.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Info("bundler API ready")
|
||||
return api.HTTPHandler{Handler: b, Methods: []string{"POST"}}, nil
|
||||
}
|
||||
|
||||
// Handle implements an http.Handler interface for the bundle handler.
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
blob, matched, err := api.ProcessRequestFirstMatchOf(r,
|
||||
[][]string{
|
||||
{"certificate"},
|
||||
{"domain"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Warningf("invalid request: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
flavor := blob["flavor"]
|
||||
bf := bundler.Ubiquitous
|
||||
if flavor != "" {
|
||||
bf = bundler.BundleFlavor(flavor)
|
||||
}
|
||||
log.Infof("request for flavor %v", bf)
|
||||
|
||||
var result *bundler.Bundle
|
||||
switch matched[0] {
|
||||
case "domain":
|
||||
bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf)
|
||||
if err != nil {
|
||||
log.Warningf("couldn't bundle from remote: %v", err)
|
||||
return err
|
||||
}
|
||||
result = bundle
|
||||
case "certificate":
|
||||
bundle, err := h.bundler.BundleFromPEMorDER([]byte(blob["certificate"]), []byte(blob["private_key"]), bf, "")
|
||||
if err != nil {
|
||||
log.Warning("bad PEM certifcate or private key")
|
||||
return err
|
||||
}
|
||||
|
||||
serverName := blob["domain"]
|
||||
ip := blob["ip"]
|
||||
|
||||
if serverName != "" {
|
||||
err := bundle.Cert.VerifyHostname(serverName)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ip != "" {
|
||||
err := bundle.Cert.VerifyHostname(ip)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
result = bundle
|
||||
}
|
||||
log.Info("wrote response")
|
||||
return api.SendResponse(w, result)
|
||||
}
|
28
vendor/github.com/cloudflare/cfssl/api/certinfo/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/api/certinfo/BUILD
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["certinfo.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/certinfo",
|
||||
importpath = "github.com/cloudflare/cfssl/api/certinfo",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certinfo:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
50
vendor/github.com/cloudflare/cfssl/api/certinfo/certinfo.go
generated
vendored
Normal file
50
vendor/github.com/cloudflare/cfssl/api/certinfo/certinfo.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Package certinfo implements the HTTP handler for the certinfo command.
|
||||
package certinfo
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/certinfo"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// Handler accepts requests for either remote or uploaded
|
||||
// certificates to be bundled, and returns a certificate bundle (or
|
||||
// error).
|
||||
type Handler struct{}
|
||||
|
||||
// NewHandler creates a new bundler that uses the root bundle and
|
||||
// intermediate bundle in the trust chain.
|
||||
func NewHandler() http.Handler {
|
||||
return api.HTTPHandler{Handler: new(Handler), Methods: []string{"POST"}}
|
||||
}
|
||||
|
||||
// Handle implements an http.Handler interface for the bundle handler.
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) (err error) {
|
||||
blob, matched, err := api.ProcessRequestFirstMatchOf(r,
|
||||
[][]string{
|
||||
{"certificate"},
|
||||
{"domain"},
|
||||
})
|
||||
if err != nil {
|
||||
log.Warningf("invalid request: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var cert *certinfo.Certificate
|
||||
switch matched[0] {
|
||||
case "domain":
|
||||
if cert, err = certinfo.ParseCertificateDomain(blob["domain"]); err != nil {
|
||||
log.Warningf("couldn't parse remote certificate: %v", err)
|
||||
return err
|
||||
}
|
||||
case "certificate":
|
||||
if cert, err = certinfo.ParseCertificatePEM([]byte(blob["certificate"])); err != nil {
|
||||
log.Warningf("bad PEM certifcate: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return api.SendResponse(w, cert)
|
||||
}
|
34
vendor/github.com/cloudflare/cfssl/api/client/BUILD
generated
vendored
Normal file
34
vendor/github.com/cloudflare/cfssl/api/client/BUILD
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"api.go",
|
||||
"client.go",
|
||||
"group.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/client",
|
||||
importpath = "github.com/cloudflare/cfssl/api/client",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/auth:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
6
vendor/github.com/cloudflare/cfssl/api/client/api.go
generated
vendored
Normal file
6
vendor/github.com/cloudflare/cfssl/api/client/api.go
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
package client
|
||||
|
||||
// SignResult is the result of signing a CSR.
|
||||
type SignResult struct {
|
||||
Certificate []byte `json:"certificate"`
|
||||
}
|
356
vendor/github.com/cloudflare/cfssl/api/client/client.go
generated
vendored
Normal file
356
vendor/github.com/cloudflare/cfssl/api/client/client.go
generated
vendored
Normal file
@@ -0,0 +1,356 @@
|
||||
// Package client implements a Go client for CFSSL API commands.
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
stderr "errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/auth"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/info"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// A server points to a single remote CFSSL instance.
|
||||
type server struct {
|
||||
URL string
|
||||
TLSConfig *tls.Config
|
||||
reqModifier func(*http.Request, []byte)
|
||||
RequestTimeout time.Duration
|
||||
proxy func(*http.Request) (*url.URL, error)
|
||||
}
|
||||
|
||||
// A Remote points to at least one (but possibly multiple) remote
|
||||
// CFSSL instances. It must be able to perform a authenticated and
|
||||
// unauthenticated certificate signing requests, return information
|
||||
// about the CA on the other end, and return a list of the hosts that
|
||||
// are used by the remote.
|
||||
type Remote interface {
|
||||
AuthSign(req, id []byte, provider auth.Provider) ([]byte, error)
|
||||
Sign(jsonData []byte) ([]byte, error)
|
||||
Info(jsonData []byte) (*info.Resp, error)
|
||||
Hosts() []string
|
||||
SetReqModifier(func(*http.Request, []byte))
|
||||
SetRequestTimeout(d time.Duration)
|
||||
SetProxy(func(*http.Request) (*url.URL, error))
|
||||
}
|
||||
|
||||
// NewServer sets up a new server target. The address should be of
|
||||
// The format [protocol:]name[:port] of the remote CFSSL instance.
|
||||
// If no protocol is given http is default. If no port
|
||||
// is specified, the CFSSL default port (8888) is used. If the name is
|
||||
// a comma-separated list of hosts, an ordered group will be returned.
|
||||
func NewServer(addr string) Remote {
|
||||
return NewServerTLS(addr, nil)
|
||||
}
|
||||
|
||||
// NewServerTLS is the TLS version of NewServer
|
||||
func NewServerTLS(addr string, tlsConfig *tls.Config) Remote {
|
||||
addrs := strings.Split(addr, ",")
|
||||
|
||||
var remote Remote
|
||||
|
||||
if len(addrs) > 1 {
|
||||
remote, _ = NewGroup(addrs, tlsConfig, StrategyOrderedList)
|
||||
} else {
|
||||
u, err := normalizeURL(addrs[0])
|
||||
if err != nil {
|
||||
log.Errorf("bad url: %v", err)
|
||||
return nil
|
||||
}
|
||||
srv := newServer(u, tlsConfig)
|
||||
if srv != nil {
|
||||
remote = srv
|
||||
}
|
||||
}
|
||||
return remote
|
||||
}
|
||||
|
||||
func (srv *server) Hosts() []string {
|
||||
return []string{srv.URL}
|
||||
}
|
||||
|
||||
func (srv *server) SetReqModifier(mod func(*http.Request, []byte)) {
|
||||
srv.reqModifier = mod
|
||||
}
|
||||
|
||||
func (srv *server) SetRequestTimeout(timeout time.Duration) {
|
||||
srv.RequestTimeout = timeout
|
||||
}
|
||||
|
||||
func (srv *server) SetProxy(proxy func(*http.Request) (*url.URL, error)) {
|
||||
srv.proxy = proxy
|
||||
}
|
||||
|
||||
func newServer(u *url.URL, tlsConfig *tls.Config) *server {
|
||||
URL := u.String()
|
||||
return &server{
|
||||
URL: URL,
|
||||
TLSConfig: tlsConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (srv *server) getURL(endpoint string) string {
|
||||
return fmt.Sprintf("%s/api/v1/cfssl/%s", srv.URL, endpoint)
|
||||
}
|
||||
|
||||
func (srv *server) createTransport() (transport *http.Transport) {
|
||||
transport = new(http.Transport)
|
||||
// Setup HTTPS client
|
||||
tlsConfig := srv.TLSConfig
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
transport.TLSClientConfig = tlsConfig
|
||||
// Setup Proxy
|
||||
transport.Proxy = srv.proxy
|
||||
return transport
|
||||
}
|
||||
|
||||
// post connects to the remote server and returns a Response struct
|
||||
func (srv *server) post(url string, jsonData []byte) (*api.Response, error) {
|
||||
var resp *http.Response
|
||||
var err error
|
||||
client := &http.Client{}
|
||||
if srv.TLSConfig != nil {
|
||||
client.Transport = srv.createTransport()
|
||||
}
|
||||
if srv.RequestTimeout != 0 {
|
||||
client.Timeout = srv.RequestTimeout
|
||||
}
|
||||
req, err := http.NewRequest("POST", url, bytes.NewReader(jsonData))
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed POST to %s: %v", url, err)
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err)
|
||||
}
|
||||
req.Close = true
|
||||
req.Header.Set("content-type", "application/json")
|
||||
if srv.reqModifier != nil {
|
||||
srv.reqModifier(req, jsonData)
|
||||
}
|
||||
resp, err = client.Do(req)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("failed POST to %s: %v", url, err)
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err)
|
||||
}
|
||||
defer req.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.IOError, err)
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
log.Errorf("http error with %s", url)
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New(string(body)))
|
||||
}
|
||||
|
||||
var response api.Response
|
||||
err = json.Unmarshal(body, &response)
|
||||
if err != nil {
|
||||
log.Debug("Unable to parse response body:", string(body))
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
|
||||
}
|
||||
|
||||
if !response.Success || response.Result == nil {
|
||||
if len(response.Errors) > 0 {
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message))
|
||||
}
|
||||
return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed)
|
||||
}
|
||||
|
||||
return &response, nil
|
||||
}
|
||||
|
||||
// AuthSign fills out an authenticated signing request to the server,
|
||||
// receiving a certificate or error in response.
|
||||
// It takes the serialized JSON request to send, remote address and
|
||||
// authentication provider.
|
||||
func (srv *server) AuthSign(req, id []byte, provider auth.Provider) ([]byte, error) {
|
||||
return srv.authReq(req, id, provider, "sign")
|
||||
}
|
||||
|
||||
// AuthInfo fills out an authenticated info request to the server,
|
||||
// receiving a certificate or error in response.
|
||||
// It takes the serialized JSON request to send, remote address and
|
||||
// authentication provider.
|
||||
func (srv *server) AuthInfo(req, id []byte, provider auth.Provider) ([]byte, error) {
|
||||
return srv.authReq(req, id, provider, "info")
|
||||
}
|
||||
|
||||
// authReq is the common logic for AuthSign and AuthInfo -- perform the given
|
||||
// request, and return the resultant certificate.
|
||||
// The target is either 'sign' or 'info'.
|
||||
func (srv *server) authReq(req, ID []byte, provider auth.Provider, target string) ([]byte, error) {
|
||||
url := srv.getURL("auth" + target)
|
||||
|
||||
token, err := provider.Token(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.AuthenticationFailure, err)
|
||||
}
|
||||
|
||||
aReq := &auth.AuthenticatedRequest{
|
||||
Timestamp: time.Now().Unix(),
|
||||
RemoteAddress: ID,
|
||||
Token: token,
|
||||
Request: req,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(aReq)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
|
||||
}
|
||||
|
||||
response, err := srv.post(url, jsonData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result, ok := response.Result.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, errors.New(errors.APIClientError, errors.JSONError)
|
||||
}
|
||||
|
||||
cert, ok := result["certificate"].(string)
|
||||
if !ok {
|
||||
return nil, errors.New(errors.APIClientError, errors.JSONError)
|
||||
}
|
||||
|
||||
return []byte(cert), nil
|
||||
}
|
||||
|
||||
// Sign sends a signature request to the remote CFSSL server,
|
||||
// receiving a signed certificate or an error in response.
|
||||
// It takes the serialized JSON request to send.
|
||||
func (srv *server) Sign(jsonData []byte) ([]byte, error) {
|
||||
return srv.request(jsonData, "sign")
|
||||
}
|
||||
|
||||
// Info sends an info request to the remote CFSSL server, receiving a
|
||||
// response or an error in response.
|
||||
// It takes the serialized JSON request to send.
|
||||
func (srv *server) Info(jsonData []byte) (*info.Resp, error) {
|
||||
res, err := srv.getResultMap(jsonData, "info")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info := new(info.Resp)
|
||||
|
||||
if val, ok := res["certificate"]; ok {
|
||||
info.Certificate = val.(string)
|
||||
}
|
||||
var usages []interface{}
|
||||
if val, ok := res["usages"]; ok && val != nil {
|
||||
usages = val.([]interface{})
|
||||
}
|
||||
if val, ok := res["expiry"]; ok && val != nil {
|
||||
info.ExpiryString = val.(string)
|
||||
}
|
||||
|
||||
info.Usage = make([]string, len(usages))
|
||||
for i, s := range usages {
|
||||
info.Usage[i] = s.(string)
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
|
||||
func (srv *server) getResultMap(jsonData []byte, target string) (result map[string]interface{}, err error) {
|
||||
url := srv.getURL(target)
|
||||
response, err := srv.post(url, jsonData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
result, ok := response.Result.(map[string]interface{})
|
||||
if !ok {
|
||||
err = errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response is formatted improperly"))
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// request performs the common logic for Sign and Info, performing the actual
|
||||
// request and returning the resultant certificate.
|
||||
func (srv *server) request(jsonData []byte, target string) ([]byte, error) {
|
||||
result, err := srv.getResultMap(jsonData, target)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cert := result["certificate"].(string)
|
||||
if cert != "" {
|
||||
return []byte(cert), nil
|
||||
}
|
||||
|
||||
return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response doesn't contain certificate."))
|
||||
}
|
||||
|
||||
// AuthRemote acts as a Remote with a default Provider for AuthSign.
|
||||
type AuthRemote struct {
|
||||
Remote
|
||||
provider auth.Provider
|
||||
}
|
||||
|
||||
// NewAuthServer sets up a new auth server target with an addr
|
||||
// in the same format at NewServer and a default authentication provider to
|
||||
// use for Sign requests.
|
||||
func NewAuthServer(addr string, tlsConfig *tls.Config, provider auth.Provider) *AuthRemote {
|
||||
return &AuthRemote{
|
||||
Remote: NewServerTLS(addr, tlsConfig),
|
||||
provider: provider,
|
||||
}
|
||||
}
|
||||
|
||||
// Sign is overloaded to perform an AuthSign request using the default auth provider.
|
||||
func (ar *AuthRemote) Sign(req []byte) ([]byte, error) {
|
||||
return ar.AuthSign(req, nil, ar.provider)
|
||||
}
|
||||
|
||||
// nomalizeURL checks for http/https protocol, appends "http" as default protocol if not defiend in url
|
||||
func normalizeURL(addr string) (*url.URL, error) {
|
||||
addr = strings.TrimSpace(addr)
|
||||
|
||||
u, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if u.Opaque != "" {
|
||||
u.Host = net.JoinHostPort(u.Scheme, u.Opaque)
|
||||
u.Opaque = ""
|
||||
} else if u.Path != "" && !strings.Contains(u.Path, ":") {
|
||||
u.Host = net.JoinHostPort(u.Path, "8888")
|
||||
u.Path = ""
|
||||
} else if u.Scheme == "" {
|
||||
u.Host = u.Path
|
||||
u.Path = ""
|
||||
}
|
||||
|
||||
if u.Scheme != "https" {
|
||||
u.Scheme = "http"
|
||||
}
|
||||
|
||||
_, port, err := net.SplitHostPort(u.Host)
|
||||
if err != nil {
|
||||
_, port, err = net.SplitHostPort(u.Host + ":8888")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if port != "" {
|
||||
_, err = strconv.Atoi(port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return u, nil
|
||||
}
|
132
vendor/github.com/cloudflare/cfssl/api/client/group.go
generated
vendored
Normal file
132
vendor/github.com/cloudflare/cfssl/api/client/group.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/auth"
|
||||
"github.com/cloudflare/cfssl/info"
|
||||
)
|
||||
|
||||
// Strategy is the means by which the server to use as a remote should
|
||||
// be selected.
|
||||
type Strategy int
|
||||
|
||||
const (
|
||||
// StrategyInvalid indicates any strategy that is unsupported
|
||||
// or returned when no strategy is applicable.
|
||||
StrategyInvalid = iota
|
||||
|
||||
// StrategyOrderedList is a sequential list of servers: if the
|
||||
// first server cannot be reached, the next is used. The
|
||||
// client will proceed in this manner until the list of
|
||||
// servers is exhausted, and then an error is returned.
|
||||
StrategyOrderedList
|
||||
)
|
||||
|
||||
var strategyStrings = map[string]Strategy{
|
||||
"ordered_list": StrategyOrderedList,
|
||||
}
|
||||
|
||||
// StrategyFromString takes a string describing a
|
||||
func StrategyFromString(s string) Strategy {
|
||||
s = strings.TrimSpace(strings.ToLower(s))
|
||||
strategy, ok := strategyStrings[s]
|
||||
if !ok {
|
||||
return StrategyInvalid
|
||||
}
|
||||
return strategy
|
||||
}
|
||||
|
||||
// NewGroup will use the collection of remotes specified with the
|
||||
// given strategy.
|
||||
func NewGroup(remotes []string, tlsConfig *tls.Config, strategy Strategy) (Remote, error) {
|
||||
var servers = make([]*server, len(remotes))
|
||||
for i := range remotes {
|
||||
u, err := normalizeURL(remotes[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
servers[i] = newServer(u, tlsConfig)
|
||||
}
|
||||
|
||||
switch strategy {
|
||||
case StrategyOrderedList:
|
||||
return newOrdererdListGroup(servers)
|
||||
default:
|
||||
return nil, errors.New("unrecognised strategy")
|
||||
}
|
||||
}
|
||||
|
||||
type orderedListGroup struct {
|
||||
remotes []*server
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) Hosts() []string {
|
||||
var hosts = make([]string, 0, len(g.remotes))
|
||||
for _, srv := range g.remotes {
|
||||
srvHosts := srv.Hosts()
|
||||
hosts = append(hosts, srvHosts[0])
|
||||
}
|
||||
return hosts
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) SetRequestTimeout(timeout time.Duration) {
|
||||
for _, srv := range g.remotes {
|
||||
srv.SetRequestTimeout(timeout)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) SetProxy(proxy func(*http.Request) (*url.URL, error)) {
|
||||
for _, srv := range g.remotes {
|
||||
srv.SetProxy(proxy)
|
||||
}
|
||||
}
|
||||
|
||||
func newOrdererdListGroup(remotes []*server) (Remote, error) {
|
||||
return &orderedListGroup{
|
||||
remotes: remotes,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) AuthSign(req, id []byte, provider auth.Provider) (resp []byte, err error) {
|
||||
for i := range g.remotes {
|
||||
resp, err = g.remotes[i].AuthSign(req, id, provider)
|
||||
if err == nil {
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) Sign(jsonData []byte) (resp []byte, err error) {
|
||||
for i := range g.remotes {
|
||||
resp, err = g.remotes[i].Sign(jsonData)
|
||||
if err == nil {
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (g *orderedListGroup) Info(jsonData []byte) (resp *info.Resp, err error) {
|
||||
for i := range g.remotes {
|
||||
resp, err = g.remotes[i].Info(jsonData)
|
||||
if err == nil {
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// SetReqModifier does nothing because there is no request modifier for group
|
||||
func (g *orderedListGroup) SetReqModifier(mod func(*http.Request, []byte)) {
|
||||
// noop
|
||||
}
|
31
vendor/github.com/cloudflare/cfssl/api/crl/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/api/crl/BUILD
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["crl.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/crl",
|
||||
importpath = "github.com/cloudflare/cfssl/api/crl",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/crl:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
93
vendor/github.com/cloudflare/cfssl/api/crl/crl.go
generated
vendored
Normal file
93
vendor/github.com/cloudflare/cfssl/api/crl/crl.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Package crl implements the HTTP handler for the crl command.
|
||||
package crl
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/certdb"
|
||||
"github.com/cloudflare/cfssl/crl"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// A Handler accepts requests with a serial number parameter
|
||||
// and revokes
|
||||
type Handler struct {
|
||||
dbAccessor certdb.Accessor
|
||||
ca *x509.Certificate
|
||||
key crypto.Signer
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles a revoke request.
|
||||
func NewHandler(dbAccessor certdb.Accessor, caPath string, caKeyPath string) (http.Handler, error) {
|
||||
ca, err := helpers.ReadBytes(caPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
caKey, err := helpers.ReadBytes(caKeyPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err)
|
||||
}
|
||||
|
||||
// Parse the PEM encoded certificate
|
||||
issuerCert, err := helpers.ParseCertificatePEM(ca)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
|
||||
password := []byte(strPassword)
|
||||
if strPassword == "" {
|
||||
password = nil
|
||||
}
|
||||
|
||||
// Parse the key given
|
||||
key, err := helpers.ParsePrivateKeyPEMWithPassword(caKey, password)
|
||||
if err != nil {
|
||||
log.Debug("malformed private key %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
dbAccessor: dbAccessor,
|
||||
ca: issuerCert,
|
||||
key: key,
|
||||
},
|
||||
Methods: []string{"GET"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handle responds to revocation requests. It attempts to revoke
|
||||
// a certificate with a given serial number
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
var newExpiryTime = 7 * helpers.OneDay
|
||||
|
||||
certs, err := h.dbAccessor.GetRevokedAndUnexpiredCertificates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
queryExpiryTime := r.URL.Query().Get("expiry")
|
||||
if queryExpiryTime != "" {
|
||||
log.Infof("requested expiry time of %s", queryExpiryTime)
|
||||
newExpiryTime, err = time.ParseDuration(queryExpiryTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
result, err := crl.NewCRLFromDB(certs, h.ca, h.key, newExpiryTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return api.SendResponse(w, result)
|
||||
}
|
29
vendor/github.com/cloudflare/cfssl/api/gencrl/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/api/gencrl/BUILD
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["gencrl.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/gencrl",
|
||||
importpath = "github.com/cloudflare/cfssl/api/gencrl",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
102
vendor/github.com/cloudflare/cfssl/api/gencrl/gencrl.go
generated
vendored
Normal file
102
vendor/github.com/cloudflare/cfssl/api/gencrl/gencrl.go
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// Package gencrl implements the HTTP handler for the gencrl commands.
|
||||
package gencrl
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/json"
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// This type is meant to be unmarshalled from JSON
|
||||
type jsonCRLRequest struct {
|
||||
Certificate string `json:"certificate"`
|
||||
SerialNumber []string `json:"serialNumber"`
|
||||
PrivateKey string `json:"issuingKey"`
|
||||
ExpiryTime string `json:"expireTime"`
|
||||
}
|
||||
|
||||
// Handle responds to requests for crl generation. It creates this crl
|
||||
// based off of the given certificate, serial numbers, and private key
|
||||
func gencrlHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
var revokedCerts []pkix.RevokedCertificate
|
||||
var oneWeek = time.Duration(604800) * time.Second
|
||||
var newExpiryTime = time.Now()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
req := &jsonCRLRequest{}
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
|
||||
if req.ExpiryTime != "" {
|
||||
expiryTime := strings.TrimSpace(req.ExpiryTime)
|
||||
expiryInt, err := strconv.ParseInt(expiryTime, 0, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newExpiryTime = time.Now().Add((time.Duration(expiryInt) * time.Second))
|
||||
}
|
||||
|
||||
if req.ExpiryTime == "" {
|
||||
newExpiryTime = time.Now().Add(oneWeek)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate))
|
||||
if err != nil {
|
||||
log.Error("error from ParseCertificatePEM", err)
|
||||
return errors.NewBadRequestString("malformed certificate")
|
||||
}
|
||||
|
||||
for _, value := range req.SerialNumber {
|
||||
tempBigInt := new(big.Int)
|
||||
tempBigInt.SetString(value, 10)
|
||||
tempCert := pkix.RevokedCertificate{
|
||||
SerialNumber: tempBigInt,
|
||||
RevocationTime: time.Now(),
|
||||
}
|
||||
revokedCerts = append(revokedCerts, tempCert)
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM([]byte(req.PrivateKey))
|
||||
if err != nil {
|
||||
log.Debug("malformed private key %v", err)
|
||||
return errors.NewBadRequestString("malformed Private Key")
|
||||
}
|
||||
|
||||
result, err := cert.CreateCRL(rand.Reader, key, revokedCerts, time.Now(), newExpiryTime)
|
||||
if err != nil {
|
||||
log.Debug("unable to create CRL: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return api.SendResponse(w, result)
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles a crl generation request.
|
||||
func NewHandler() http.Handler {
|
||||
return api.HTTPHandler{
|
||||
Handler: api.HandlerFunc(gencrlHandler),
|
||||
Methods: []string{"POST"},
|
||||
}
|
||||
}
|
33
vendor/github.com/cloudflare/cfssl/api/generator/BUILD
generated
vendored
Normal file
33
vendor/github.com/cloudflare/cfssl/api/generator/BUILD
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["generator.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/generator",
|
||||
importpath = "github.com/cloudflare/cfssl/api/generator",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/config:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/signer/universal:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
319
vendor/github.com/cloudflare/cfssl/api/generator/generator.go
generated
vendored
Normal file
319
vendor/github.com/cloudflare/cfssl/api/generator/generator.go
generated
vendored
Normal file
@@ -0,0 +1,319 @@
|
||||
// Package generator implements the HTTP handlers for certificate generation.
|
||||
package generator
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/signer/universal"
|
||||
)
|
||||
|
||||
const (
|
||||
// CSRNoHostMessage is used to alert the user to a certificate lacking a hosts field.
|
||||
CSRNoHostMessage = `This certificate lacks a "hosts" field. This makes it unsuitable for
|
||||
websites. For more information see the Baseline Requirements for the Issuance and Management
|
||||
of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser Forum (https://cabforum.org);
|
||||
specifically, section 10.2.3 ("Information Requirements").`
|
||||
// NoBundlerMessage is used to alert the user that the server does not have a bundler initialized.
|
||||
NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.`
|
||||
)
|
||||
|
||||
// Sum contains digests for a certificate or certificate request.
|
||||
type Sum struct {
|
||||
MD5 string `json:"md5"`
|
||||
SHA1 string `json:"sha-1"`
|
||||
}
|
||||
|
||||
// Validator is a type of function that contains the logic for validating
|
||||
// a certificate request.
|
||||
type Validator func(*csr.CertificateRequest) error
|
||||
|
||||
// A CertRequest stores a PEM-encoded private key and corresponding
|
||||
// CSR; this is returned from the CSR generation endpoint.
|
||||
type CertRequest struct {
|
||||
Key string `json:"private_key"`
|
||||
CSR string `json:"certificate_request"`
|
||||
Sums map[string]Sum `json:"sums"`
|
||||
}
|
||||
|
||||
// A Handler accepts JSON-encoded certificate requests and
|
||||
// returns a new private key and certificate request.
|
||||
type Handler struct {
|
||||
generator *csr.Generator
|
||||
}
|
||||
|
||||
// NewHandler builds a new Handler from the
|
||||
// validation function provided.
|
||||
func NewHandler(validator Validator) (http.Handler, error) {
|
||||
log.Info("setting up key / CSR generator")
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
generator: &csr.Generator{Validator: validator},
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func computeSum(in []byte) (sum Sum, err error) {
|
||||
var data []byte
|
||||
p, _ := pem.Decode(in)
|
||||
if p == nil {
|
||||
err = errors.NewBadRequestString("not a CSR or certificate")
|
||||
return
|
||||
}
|
||||
|
||||
switch p.Type {
|
||||
case "CERTIFICATE REQUEST":
|
||||
var req *x509.CertificateRequest
|
||||
req, err = x509.ParseCertificateRequest(p.Bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = req.Raw
|
||||
case "CERTIFICATE":
|
||||
var cert *x509.Certificate
|
||||
cert, err = x509.ParseCertificate(p.Bytes)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
data = cert.Raw
|
||||
default:
|
||||
err = errors.NewBadRequestString("not a CSR or certificate")
|
||||
return
|
||||
}
|
||||
|
||||
md5Sum := md5.Sum(data)
|
||||
sha1Sum := sha1.Sum(data)
|
||||
sum.MD5 = fmt.Sprintf("%X", md5Sum[:])
|
||||
sum.SHA1 = fmt.Sprintf("%X", sha1Sum[:])
|
||||
return
|
||||
}
|
||||
|
||||
// Handle responds to requests for the CA to generate a new private
|
||||
// key and certificate request on behalf of the client. The format for
|
||||
// these requests is documented in the API documentation.
|
||||
func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("request for CSR")
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Warningf("failed to read request body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
req := new(csr.CertificateRequest)
|
||||
req.KeyRequest = csr.NewBasicKeyRequest()
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to unmarshal request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
if req.CA != nil {
|
||||
log.Warningf("request received with CA section")
|
||||
return errors.NewBadRequestString("ca section only permitted in initca")
|
||||
}
|
||||
|
||||
csr, key, err := g.generator.ProcessRequest(req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to process CSR: %v", err)
|
||||
// The validator returns a *cfssl/errors.HttpError
|
||||
return err
|
||||
}
|
||||
|
||||
sum, err := computeSum(csr)
|
||||
if err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
// Both key and csr are returned PEM-encoded.
|
||||
response := api.NewSuccessResponse(&CertRequest{
|
||||
Key: string(key),
|
||||
CSR: string(csr),
|
||||
Sums: map[string]Sum{"certificate_request": sum},
|
||||
})
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
err = enc.Encode(response)
|
||||
return err
|
||||
}
|
||||
|
||||
// A CertGeneratorHandler accepts JSON-encoded certificate requests
|
||||
// and returns a new private key and signed certificate; it handles
|
||||
// sending the CSR to the server.
|
||||
type CertGeneratorHandler struct {
|
||||
generator *csr.Generator
|
||||
bundler *bundler.Bundler
|
||||
signer signer.Signer
|
||||
}
|
||||
|
||||
// NewCertGeneratorHandler builds a new handler for generating
|
||||
// certificates directly from certificate requests; the validator covers
|
||||
// the certificate request and the CA's key and certificate are used to
|
||||
// sign the generated request. If remote is not an empty string, the
|
||||
// handler will send signature requests to the CFSSL instance contained
|
||||
// in remote.
|
||||
func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) {
|
||||
var err error
|
||||
log.Info("setting up new generator / signer")
|
||||
cg := new(CertGeneratorHandler)
|
||||
|
||||
if policy == nil {
|
||||
policy = &config.Signing{
|
||||
Default: config.DefaultConfig(),
|
||||
Profiles: nil,
|
||||
}
|
||||
}
|
||||
|
||||
root := universal.Root{
|
||||
Config: map[string]string{
|
||||
"ca-file": caFile,
|
||||
"ca-key-file": caKeyFile,
|
||||
},
|
||||
}
|
||||
if cg.signer, err = universal.NewSigner(root, policy); err != nil {
|
||||
log.Errorf("setting up signer failed: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cg.generator = &csr.Generator{Validator: validator}
|
||||
|
||||
return api.HTTPHandler{Handler: cg, Methods: []string{"POST"}}, nil
|
||||
}
|
||||
|
||||
// NewCertGeneratorHandlerFromSigner returns a handler directly from
|
||||
// the signer and validation function.
|
||||
func NewCertGeneratorHandlerFromSigner(validator Validator, signer signer.Signer) http.Handler {
|
||||
return api.HTTPHandler{
|
||||
Handler: &CertGeneratorHandler{
|
||||
generator: &csr.Generator{Validator: validator},
|
||||
signer: signer,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}
|
||||
}
|
||||
|
||||
// SetBundler allows injecting an optional Bundler into the CertGeneratorHandler.
|
||||
func (cg *CertGeneratorHandler) SetBundler(caBundleFile, intBundleFile string) (err error) {
|
||||
cg.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
|
||||
return err
|
||||
}
|
||||
|
||||
type genSignRequest struct {
|
||||
Request *csr.CertificateRequest `json:"request"`
|
||||
Profile string `json:"profile"`
|
||||
Label string `json:"label"`
|
||||
Bundle bool `json:"bundle"`
|
||||
}
|
||||
|
||||
// Handle responds to requests for the CA to generate a new private
|
||||
// key and certificate on behalf of the client. The format for these
|
||||
// requests is documented in the API documentation.
|
||||
func (cg *CertGeneratorHandler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("request for CSR")
|
||||
|
||||
req := new(genSignRequest)
|
||||
req.Request = csr.New()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Warningf("failed to read request body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to unmarshal request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
if req.Request == nil {
|
||||
log.Warning("empty request received")
|
||||
return errors.NewBadRequestString("missing request section")
|
||||
}
|
||||
|
||||
if req.Request.CA != nil {
|
||||
log.Warningf("request received with CA section")
|
||||
return errors.NewBadRequestString("ca section only permitted in initca")
|
||||
}
|
||||
|
||||
csr, key, err := cg.generator.ProcessRequest(req.Request)
|
||||
if err != nil {
|
||||
log.Warningf("failed to process CSR: %v", err)
|
||||
// The validator returns a *cfssl/errors.HttpError
|
||||
return err
|
||||
}
|
||||
|
||||
signReq := signer.SignRequest{
|
||||
Request: string(csr),
|
||||
Profile: req.Profile,
|
||||
Label: req.Label,
|
||||
}
|
||||
|
||||
certBytes, err := cg.signer.Sign(signReq)
|
||||
if err != nil {
|
||||
log.Warningf("failed to sign request: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
reqSum, err := computeSum(csr)
|
||||
if err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
certSum, err := computeSum(certBytes)
|
||||
if err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"private_key": string(key),
|
||||
"certificate_request": string(csr),
|
||||
"certificate": string(certBytes),
|
||||
"sums": map[string]Sum{
|
||||
"certificate_request": reqSum,
|
||||
"certificate": certSum,
|
||||
},
|
||||
}
|
||||
|
||||
if req.Bundle {
|
||||
if cg.bundler == nil {
|
||||
return api.SendResponseWithMessage(w, result, NoBundlerMessage,
|
||||
errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
|
||||
}
|
||||
|
||||
bundle, err := cg.bundler.BundleFromPEMorDER(certBytes, nil, bundler.Optimal, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result["bundle"] = bundle
|
||||
}
|
||||
|
||||
if len(req.Request.Hosts) == 0 {
|
||||
return api.SendResponseWithMessage(w, result, CSRNoHostMessage,
|
||||
errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
|
||||
}
|
||||
|
||||
return api.SendResponse(w, result)
|
||||
}
|
||||
|
||||
// CSRValidate does nothing and will never return an error. It exists because NewHandler
|
||||
// requires a Validator as a parameter.
|
||||
func CSRValidate(req *csr.CertificateRequest) error {
|
||||
return nil
|
||||
}
|
30
vendor/github.com/cloudflare/cfssl/api/info/BUILD
generated
vendored
Normal file
30
vendor/github.com/cloudflare/cfssl/api/info/BUILD
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["info.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/info",
|
||||
importpath = "github.com/cloudflare/cfssl/api/info",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/info:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
121
vendor/github.com/cloudflare/cfssl/api/info/info.go
generated
vendored
Normal file
121
vendor/github.com/cloudflare/cfssl/api/info/info.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
// Package info implements the HTTP handler for the info command.
|
||||
package info
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/info"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
)
|
||||
|
||||
// Handler is a type that contains the root certificates for the CA,
|
||||
// and serves information on them for clients that need the certificates.
|
||||
type Handler struct {
|
||||
sign signer.Signer
|
||||
}
|
||||
|
||||
// NewHandler creates a new handler to serve information on the CA's
|
||||
// certificates, taking a signer to use.
|
||||
func NewHandler(s signer.Signer) (http.Handler, error) {
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
sign: s,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handle listens for incoming requests for CA information, and returns
|
||||
// a list containing information on each root certificate.
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
req := new(info.Req)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Warningf("failed to read request body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to unmarshal request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
resp, err := h.sign.Info(*req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
response := api.NewSuccessResponse(resp)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(response)
|
||||
}
|
||||
|
||||
// MultiHandler is a handler for providing the public certificates for
|
||||
// a multi-root certificate authority. It takes a mapping of label to
|
||||
// signer and a default label, and handles the standard information
|
||||
// request as defined in the client package.
|
||||
type MultiHandler struct {
|
||||
signers map[string]signer.Signer
|
||||
defaultLabel string
|
||||
}
|
||||
|
||||
// NewMultiHandler constructs a MultiHandler from a mapping of labels
|
||||
// to signers and the default label.
|
||||
func NewMultiHandler(signers map[string]signer.Signer, defaultLabel string) (http.Handler, error) {
|
||||
return &api.HTTPHandler{
|
||||
Handler: &MultiHandler{
|
||||
signers: signers,
|
||||
defaultLabel: defaultLabel,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Handle accepts client information requests, and uses the label to
|
||||
// look up the signer whose public certificate should be retrieved. If
|
||||
// the label is empty, the default label is used.
|
||||
func (h *MultiHandler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
req := new(info.Req)
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Warningf("failed to read request body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to unmarshal request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
log.Debug("checking label")
|
||||
if req.Label == "" {
|
||||
req.Label = h.defaultLabel
|
||||
}
|
||||
|
||||
if _, ok := h.signers[req.Label]; !ok {
|
||||
log.Warningf("request for invalid endpoint")
|
||||
return errors.NewBadRequestString("bad label")
|
||||
}
|
||||
|
||||
log.Debug("getting info")
|
||||
resp, err := h.signers[req.Label].Info(*req)
|
||||
if err != nil {
|
||||
log.Infof("error getting certificate: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
response := api.NewSuccessResponse(resp)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(response)
|
||||
}
|
30
vendor/github.com/cloudflare/cfssl/api/initca/BUILD
generated
vendored
Normal file
30
vendor/github.com/cloudflare/cfssl/api/initca/BUILD
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["initca.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/initca",
|
||||
importpath = "github.com/cloudflare/cfssl/api/initca",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/initca:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
61
vendor/github.com/cloudflare/cfssl/api/initca/initca.go
generated
vendored
Normal file
61
vendor/github.com/cloudflare/cfssl/api/initca/initca.go
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
// Package initca implements the HTTP handler for the CA initialization command
|
||||
package initca
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/initca"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// A NewCA contains a private key and certificate suitable for serving
|
||||
// as the root key for a new certificate authority.
|
||||
type NewCA struct {
|
||||
Key string `json:"private_key"`
|
||||
Cert string `json:"certificate"`
|
||||
}
|
||||
|
||||
// initialCAHandler is an HTTP handler that accepts a JSON blob in the
|
||||
// same format as the CSR endpoint; this blob should contain the
|
||||
// identity information for the CA's root key. This endpoint is not
|
||||
// suitable for creating intermediate certificates.
|
||||
func initialCAHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("setting up initial CA handler")
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Warningf("failed to read request body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
req := new(csr.CertificateRequest)
|
||||
req.KeyRequest = csr.NewBasicKeyRequest()
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to unmarshal request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
cert, _, key, err := initca.New(req)
|
||||
if err != nil {
|
||||
log.Warningf("failed to initialise new CA: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
response := api.NewSuccessResponse(&NewCA{string(key), string(cert)})
|
||||
|
||||
enc := json.NewEncoder(w)
|
||||
err = enc.Encode(response)
|
||||
return err
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles request to
|
||||
// initialize a CA.
|
||||
func NewHandler() http.Handler {
|
||||
return api.HTTPHandler{Handler: api.HandlerFunc(initialCAHandler), Methods: []string{"POST"}}
|
||||
}
|
30
vendor/github.com/cloudflare/cfssl/api/ocsp/BUILD
generated
vendored
Normal file
30
vendor/github.com/cloudflare/cfssl/api/ocsp/BUILD
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["ocspsign.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/ocsp",
|
||||
importpath = "github.com/cloudflare/cfssl/api/ocsp",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/ocsp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
113
vendor/github.com/cloudflare/cfssl/api/ocsp/ocspsign.go
generated
vendored
Normal file
113
vendor/github.com/cloudflare/cfssl/api/ocsp/ocspsign.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
// Package ocsp implements the HTTP handler for the ocsp commands.
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"net/http"
|
||||
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
)
|
||||
|
||||
// A Handler accepts requests with a certficate parameter
|
||||
// (which should be PEM-encoded) and returns a signed ocsp
|
||||
// response.
|
||||
type Handler struct {
|
||||
signer ocsp.Signer
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles a ocspsign request.
|
||||
func NewHandler(s ocsp.Signer) http.Handler {
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
signer: s,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}
|
||||
}
|
||||
|
||||
// This type is meant to be unmarshalled from JSON
|
||||
type jsonSignRequest struct {
|
||||
Certificate string `json:"certificate"`
|
||||
Status string `json:"status"`
|
||||
Reason int `json:"reason,omitempty"`
|
||||
RevokedAt string `json:"revoked_at,omitempty"`
|
||||
IssuerHash string `json:"issuer_hash,omitempty"`
|
||||
}
|
||||
|
||||
var nameToHash = map[string]crypto.Hash{
|
||||
"MD5": crypto.MD5,
|
||||
"SHA1": crypto.SHA1,
|
||||
"SHA256": crypto.SHA256,
|
||||
"SHA384": crypto.SHA384,
|
||||
"SHA512": crypto.SHA512,
|
||||
}
|
||||
|
||||
// Handle responds to requests for a ocsp signature. It creates and signs
|
||||
// a ocsp response for the provided certificate and status. If the status
|
||||
// is revoked then it also adds reason and revoked_at. The response is
|
||||
// base64 encoded.
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
// Default the status to good so it matches the cli
|
||||
req := &jsonSignRequest{
|
||||
Status: "good",
|
||||
}
|
||||
err = json.Unmarshal(body, req)
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Unable to parse sign request")
|
||||
}
|
||||
|
||||
cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate))
|
||||
if err != nil {
|
||||
log.Error("Error from ParseCertificatePEM", err)
|
||||
return errors.NewBadRequestString("Malformed certificate")
|
||||
}
|
||||
|
||||
signReq := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: req.Status,
|
||||
}
|
||||
// We need to convert the time from being a string to a time.Time
|
||||
if req.Status == "revoked" {
|
||||
signReq.Reason = req.Reason
|
||||
// "now" is accepted and the default on the cli so default that here
|
||||
if req.RevokedAt == "" || req.RevokedAt == "now" {
|
||||
signReq.RevokedAt = time.Now()
|
||||
} else {
|
||||
signReq.RevokedAt, err = time.Parse("2006-01-02", req.RevokedAt)
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Malformed revocation time")
|
||||
}
|
||||
}
|
||||
}
|
||||
if req.IssuerHash != "" {
|
||||
issuerHash, ok := nameToHash[req.IssuerHash]
|
||||
if !ok {
|
||||
return errors.NewBadRequestString("Unsupported hash algorithm in request")
|
||||
}
|
||||
signReq.IssuerHash = issuerHash
|
||||
}
|
||||
|
||||
resp, err := h.signer.Sign(signReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b64Resp := base64.StdEncoding.EncodeToString(resp)
|
||||
result := map[string]string{"ocspResponse": b64Resp}
|
||||
return api.SendResponse(w, result)
|
||||
}
|
31
vendor/github.com/cloudflare/cfssl/api/revoke/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/api/revoke/BUILD
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["revoke.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/revoke",
|
||||
importpath = "github.com/cloudflare/cfssl/api/revoke",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/ocsp:go_default_library",
|
||||
"//vendor/golang.org/x/crypto/ocsp:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
137
vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go
generated
vendored
Normal file
137
vendor/github.com/cloudflare/cfssl/api/revoke/revoke.go
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
// Package revoke implements the HTTP handler for the revoke command
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/certdb"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
|
||||
stdocsp "golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// A Handler accepts requests with a serial number parameter
|
||||
// and revokes
|
||||
type Handler struct {
|
||||
dbAccessor certdb.Accessor
|
||||
Signer ocsp.Signer
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles a revoke request.
|
||||
func NewHandler(dbAccessor certdb.Accessor) http.Handler {
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
dbAccessor: dbAccessor,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}
|
||||
}
|
||||
|
||||
// NewOCSPHandler returns a new http.Handler that handles a revoke
|
||||
// request and also generates an OCSP response
|
||||
func NewOCSPHandler(dbAccessor certdb.Accessor, signer ocsp.Signer) http.Handler {
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
dbAccessor: dbAccessor,
|
||||
Signer: signer,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}
|
||||
}
|
||||
|
||||
// This type is meant to be unmarshalled from JSON
|
||||
type jsonRevokeRequest struct {
|
||||
Serial string `json:"serial"`
|
||||
AKI string `json:"authority_key_id"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
// Handle responds to revocation requests. It attempts to revoke
|
||||
// a certificate with a given serial number
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
// Default the status to good so it matches the cli
|
||||
var req jsonRevokeRequest
|
||||
err = json.Unmarshal(body, &req)
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Unable to parse revocation request")
|
||||
}
|
||||
|
||||
if len(req.Serial) == 0 {
|
||||
return errors.NewBadRequestString("serial number is required but not provided")
|
||||
}
|
||||
|
||||
var reasonCode int
|
||||
reasonCode, err = ocsp.ReasonStringToCode(req.Reason)
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Invalid reason code")
|
||||
}
|
||||
|
||||
err = h.dbAccessor.RevokeCertificate(req.Serial, req.AKI, reasonCode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// If we were given a signer, try and generate an OCSP
|
||||
// response indicating revocation
|
||||
if h.Signer != nil {
|
||||
// TODO: should these errors be errors?
|
||||
// Grab the certificate from the database
|
||||
cr, err := h.dbAccessor.GetCertificate(req.Serial, req.AKI)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(cr) != 1 {
|
||||
return errors.NewBadRequestString("No unique certificate found")
|
||||
}
|
||||
|
||||
cert, err := helpers.ParseCertificatePEM([]byte(cr[0].PEM))
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Unable to parse certificates from PEM data")
|
||||
}
|
||||
|
||||
sr := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: "revoked",
|
||||
Reason: reasonCode,
|
||||
RevokedAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
ocspResponse, err := h.Signer.Sign(sr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// We parse the OCSP repsonse in order to get the next
|
||||
// update time/expiry time
|
||||
ocspParsed, err := stdocsp.ParseResponse(ocspResponse, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ocspRecord := certdb.OCSPRecord{
|
||||
Serial: req.Serial,
|
||||
AKI: req.AKI,
|
||||
Body: string(ocspResponse),
|
||||
Expiry: ocspParsed.NextUpdate,
|
||||
}
|
||||
|
||||
if err = h.dbAccessor.InsertOCSP(ocspRecord); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
result := map[string]string{}
|
||||
return api.SendResponse(w, result)
|
||||
}
|
29
vendor/github.com/cloudflare/cfssl/api/scan/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/api/scan/BUILD
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["scan.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/scan",
|
||||
importpath = "github.com/cloudflare/cfssl/api/scan",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/scan:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
76
vendor/github.com/cloudflare/cfssl/api/scan/scan.go
generated
vendored
Normal file
76
vendor/github.com/cloudflare/cfssl/api/scan/scan.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/scan"
|
||||
)
|
||||
|
||||
// scanHandler is an HTTP handler that accepts GET parameters for host (required)
|
||||
// family and scanner, and uses these to perform scans, returning a JSON blob result.
|
||||
func scanHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
log.Warningf("failed to parse body: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
family := r.Form.Get("family")
|
||||
scanner := r.Form.Get("scanner")
|
||||
ip := r.Form.Get("ip")
|
||||
timeoutStr := r.Form.Get("timeout")
|
||||
var timeout time.Duration
|
||||
var err error
|
||||
if timeoutStr != "" {
|
||||
if timeout, err = time.ParseDuration(timeoutStr); err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
if timeout < time.Second || timeout > 5*time.Minute {
|
||||
return errors.NewBadRequestString("invalid timeout given")
|
||||
}
|
||||
} else {
|
||||
timeout = time.Minute
|
||||
}
|
||||
|
||||
host := r.Form.Get("host")
|
||||
if host == "" {
|
||||
log.Warningf("no host given")
|
||||
return errors.NewBadRequestString("no host given")
|
||||
}
|
||||
|
||||
results, err := scan.Default.RunScans(host, ip, family, scanner, timeout)
|
||||
if err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
return json.NewEncoder(w).Encode(api.NewSuccessResponse(results))
|
||||
}
|
||||
|
||||
// NewHandler returns a new http.Handler that handles a scan request.
|
||||
func NewHandler(caBundleFile string) (http.Handler, error) {
|
||||
return api.HTTPHandler{
|
||||
Handler: api.HandlerFunc(scanHandler),
|
||||
Methods: []string{"GET"},
|
||||
}, scan.LoadRootCAs(caBundleFile)
|
||||
}
|
||||
|
||||
// scanInfoHandler is an HTTP handler that returns a JSON blob result describing
|
||||
// the possible families and scans to be run.
|
||||
func scanInfoHandler(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("setting up scaninfo handler")
|
||||
response := api.NewSuccessResponse(scan.Default)
|
||||
enc := json.NewEncoder(w)
|
||||
return enc.Encode(response)
|
||||
}
|
||||
|
||||
// NewInfoHandler returns a new http.Handler that handles a request for scan info.
|
||||
func NewInfoHandler() http.Handler {
|
||||
return api.HTTPHandler{
|
||||
Handler: api.HandlerFunc(scanInfoHandler),
|
||||
Methods: []string{"GET"},
|
||||
}
|
||||
}
|
31
vendor/github.com/cloudflare/cfssl/api/signhandler/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/api/signhandler/BUILD
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["signhandler.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/signhandler",
|
||||
importpath = "github.com/cloudflare/cfssl/api/signhandler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/auth:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
294
vendor/github.com/cloudflare/cfssl/api/signhandler/signhandler.go
generated
vendored
Normal file
294
vendor/github.com/cloudflare/cfssl/api/signhandler/signhandler.go
generated
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
// Package signhandler provides the handlers for signers.
|
||||
package signhandler
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/auth"
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
)
|
||||
|
||||
// NoBundlerMessage is used to alert the user that the server does not have a bundler initialized.
|
||||
const NoBundlerMessage = `This request requires a bundler, but one is not initialized for the API server.`
|
||||
|
||||
// A Handler accepts requests with a hostname and certficate
|
||||
// parameter (which should be PEM-encoded) and returns a new signed
|
||||
// certificate. It includes upstream servers indexed by their
|
||||
// profile name.
|
||||
type Handler struct {
|
||||
signer signer.Signer
|
||||
bundler *bundler.Bundler
|
||||
}
|
||||
|
||||
// NewHandlerFromSigner generates a new Handler directly from
|
||||
// an existing signer.
|
||||
func NewHandlerFromSigner(signer signer.Signer) (h *api.HTTPHandler, err error) {
|
||||
policy := signer.Policy()
|
||||
if policy == nil {
|
||||
err = errors.New(errors.PolicyError, errors.InvalidPolicy)
|
||||
return
|
||||
}
|
||||
|
||||
// Sign will only respond for profiles that have no auth provider.
|
||||
// So if all of the profiles require authentication, we return an error.
|
||||
haveUnauth := (policy.Default.Provider == nil)
|
||||
for _, profile := range policy.Profiles {
|
||||
haveUnauth = haveUnauth || (profile.Provider == nil)
|
||||
}
|
||||
|
||||
if !haveUnauth {
|
||||
err = errors.New(errors.PolicyError, errors.InvalidPolicy)
|
||||
return
|
||||
}
|
||||
|
||||
return &api.HTTPHandler{
|
||||
Handler: &Handler{
|
||||
signer: signer,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetBundler allows injecting an optional Bundler into the Handler.
|
||||
func (h *Handler) SetBundler(caBundleFile, intBundleFile string) (err error) {
|
||||
h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
|
||||
return err
|
||||
}
|
||||
|
||||
// This type is meant to be unmarshalled from JSON so that there can be a
|
||||
// hostname field in the API
|
||||
// TODO: Change the API such that the normal struct can be used.
|
||||
type jsonSignRequest struct {
|
||||
Hostname string `json:"hostname"`
|
||||
Hosts []string `json:"hosts"`
|
||||
Request string `json:"certificate_request"`
|
||||
Subject *signer.Subject `json:"subject,omitempty"`
|
||||
Profile string `json:"profile"`
|
||||
Label string `json:"label"`
|
||||
Serial *big.Int `json:"serial,omitempty"`
|
||||
Bundle bool `json:"bundle"`
|
||||
}
|
||||
|
||||
func jsonReqToTrue(js jsonSignRequest) signer.SignRequest {
|
||||
sub := new(signer.Subject)
|
||||
if js.Subject == nil {
|
||||
sub = nil
|
||||
} else {
|
||||
// make a copy
|
||||
*sub = *js.Subject
|
||||
}
|
||||
|
||||
if js.Hostname != "" {
|
||||
return signer.SignRequest{
|
||||
Hosts: signer.SplitHosts(js.Hostname),
|
||||
Subject: sub,
|
||||
Request: js.Request,
|
||||
Profile: js.Profile,
|
||||
Label: js.Label,
|
||||
Serial: js.Serial,
|
||||
}
|
||||
}
|
||||
|
||||
return signer.SignRequest{
|
||||
Hosts: js.Hosts,
|
||||
Subject: sub,
|
||||
Request: js.Request,
|
||||
Profile: js.Profile,
|
||||
Label: js.Label,
|
||||
Serial: js.Serial,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle responds to requests for the CA to sign the certificate request
|
||||
// present in the "certificate_request" parameter for the host named
|
||||
// in the "hostname" parameter. The certificate should be PEM-encoded. If
|
||||
// provided, subject information from the "subject" parameter will be used
|
||||
// in place of the subject information from the CSR.
|
||||
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("signature request received")
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
var req jsonSignRequest
|
||||
|
||||
err = json.Unmarshal(body, &req)
|
||||
if err != nil {
|
||||
return errors.NewBadRequestString("Unable to parse sign request")
|
||||
}
|
||||
|
||||
signReq := jsonReqToTrue(req)
|
||||
|
||||
if req.Request == "" {
|
||||
return errors.NewBadRequestString("missing parameter 'certificate_request'")
|
||||
}
|
||||
|
||||
var cert []byte
|
||||
profile, err := signer.Profile(h.signer, req.Profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if profile.Provider != nil {
|
||||
log.Error("profile requires authentication")
|
||||
return errors.NewBadRequestString("authentication required")
|
||||
}
|
||||
|
||||
cert, err = h.signer.Sign(signReq)
|
||||
if err != nil {
|
||||
log.Warningf("failed to sign request: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
result := map[string]interface{}{"certificate": string(cert)}
|
||||
if req.Bundle {
|
||||
if h.bundler == nil {
|
||||
return api.SendResponseWithMessage(w, result, NoBundlerMessage,
|
||||
errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
|
||||
}
|
||||
|
||||
bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result["bundle"] = bundle
|
||||
}
|
||||
log.Info("wrote response")
|
||||
return api.SendResponse(w, result)
|
||||
}
|
||||
|
||||
// An AuthHandler verifies and signs incoming signature requests.
|
||||
type AuthHandler struct {
|
||||
signer signer.Signer
|
||||
bundler *bundler.Bundler
|
||||
}
|
||||
|
||||
// NewAuthHandlerFromSigner creates a new AuthHandler from the signer
|
||||
// that is passed in.
|
||||
func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) {
|
||||
policy := signer.Policy()
|
||||
if policy == nil {
|
||||
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
|
||||
}
|
||||
|
||||
if policy.Default == nil && policy.Profiles == nil {
|
||||
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
|
||||
}
|
||||
|
||||
// AuthSign will not respond for profiles that have no auth provider.
|
||||
// So if there are no profiles with auth providers in this policy,
|
||||
// we return an error.
|
||||
haveAuth := (policy.Default.Provider != nil)
|
||||
for _, profile := range policy.Profiles {
|
||||
if haveAuth {
|
||||
break
|
||||
}
|
||||
haveAuth = (profile.Provider != nil)
|
||||
}
|
||||
|
||||
if !haveAuth {
|
||||
return nil, errors.New(errors.PolicyError, errors.InvalidPolicy)
|
||||
}
|
||||
|
||||
return &api.HTTPHandler{
|
||||
Handler: &AuthHandler{
|
||||
signer: signer,
|
||||
},
|
||||
Methods: []string{"POST"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// SetBundler allows injecting an optional Bundler into the Handler.
|
||||
func (h *AuthHandler) SetBundler(caBundleFile, intBundleFile string) (err error) {
|
||||
h.bundler, err = bundler.NewBundler(caBundleFile, intBundleFile)
|
||||
return err
|
||||
}
|
||||
|
||||
// Handle receives the incoming request, validates it, and processes it.
|
||||
func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error {
|
||||
log.Info("signature request received")
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
log.Errorf("failed to read response body: %v", err)
|
||||
return err
|
||||
}
|
||||
r.Body.Close()
|
||||
|
||||
var aReq auth.AuthenticatedRequest
|
||||
err = json.Unmarshal(body, &aReq)
|
||||
if err != nil {
|
||||
log.Errorf("failed to unmarshal authenticated request: %v", err)
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
|
||||
var req jsonSignRequest
|
||||
err = json.Unmarshal(aReq.Request, &req)
|
||||
if err != nil {
|
||||
log.Errorf("failed to unmarshal request from authenticated request: %v", err)
|
||||
return errors.NewBadRequestString("Unable to parse authenticated sign request")
|
||||
}
|
||||
|
||||
// Sanity checks to ensure that we have a valid policy. This
|
||||
// should have been checked in NewAuthHandler.
|
||||
policy := h.signer.Policy()
|
||||
if policy == nil {
|
||||
log.Critical("signer was initialised without a signing policy")
|
||||
return errors.NewBadRequestString("invalid policy")
|
||||
}
|
||||
|
||||
profile, err := signer.Profile(h.signer, req.Profile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if profile.Provider == nil {
|
||||
log.Error("profile has no authentication provider")
|
||||
return errors.NewBadRequestString("no authentication provider")
|
||||
}
|
||||
|
||||
if !profile.Provider.Verify(&aReq) {
|
||||
log.Warning("received authenticated request with invalid token")
|
||||
return errors.NewBadRequestString("invalid token")
|
||||
}
|
||||
|
||||
signReq := jsonReqToTrue(req)
|
||||
|
||||
if signReq.Request == "" {
|
||||
return errors.NewBadRequestString("missing parameter 'certificate_request'")
|
||||
}
|
||||
|
||||
cert, err := h.signer.Sign(signReq)
|
||||
if err != nil {
|
||||
log.Errorf("signature failed: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
result := map[string]interface{}{"certificate": string(cert)}
|
||||
if req.Bundle {
|
||||
if h.bundler == nil {
|
||||
return api.SendResponseWithMessage(w, result, NoBundlerMessage,
|
||||
errors.New(errors.PolicyError, errors.InvalidRequest).ErrorCode)
|
||||
}
|
||||
|
||||
bundle, err := h.bundler.BundleFromPEMorDER(cert, nil, bundler.Optimal, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result["bundle"] = bundle
|
||||
}
|
||||
log.Info("wrote response")
|
||||
return api.SendResponse(w, result)
|
||||
}
|
Reference in New Issue
Block a user