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)
|
||||
}
|
33
vendor/github.com/cloudflare/cfssl/bundler/BUILD
generated
vendored
Normal file
33
vendor/github.com/cloudflare/cfssl/bundler/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 = [
|
||||
"bundle.go",
|
||||
"bundler.go",
|
||||
"doc.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/bundler",
|
||||
importpath = "github.com/cloudflare/cfssl/bundler",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//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/ubiquity: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"],
|
||||
)
|
186
vendor/github.com/cloudflare/cfssl/bundler/bundle.go
generated
vendored
Normal file
186
vendor/github.com/cloudflare/cfssl/bundler/bundle.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/json"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
)
|
||||
|
||||
// A Bundle contains a certificate and its trust chain. It is intended
|
||||
// to store the most widely applicable chain, with shortness an
|
||||
// explicit goal.
|
||||
type Bundle struct {
|
||||
Chain []*x509.Certificate
|
||||
Cert *x509.Certificate
|
||||
Root *x509.Certificate
|
||||
Key interface{}
|
||||
Issuer *pkix.Name
|
||||
Subject *pkix.Name
|
||||
Expires time.Time
|
||||
LeafExpires time.Time
|
||||
Hostnames []string
|
||||
Status *BundleStatus
|
||||
}
|
||||
|
||||
// BundleStatus is designated for various status reporting.
|
||||
type BundleStatus struct {
|
||||
// A flag on whether a new bundle is generated
|
||||
IsRebundled bool `json:"rebundled"`
|
||||
// A list of SKIs of expiring certificates
|
||||
ExpiringSKIs []string `json:"expiring_SKIs"`
|
||||
// A list of untrusted root store names
|
||||
Untrusted []string `json:"untrusted_root_stores"`
|
||||
// A list of human readable warning messages based on the bundle status.
|
||||
Messages []string `json:"messages"`
|
||||
// A status code consists of binary flags
|
||||
Code int `json:"code"`
|
||||
}
|
||||
|
||||
type chain []*x509.Certificate
|
||||
|
||||
func (c chain) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, cert := range c {
|
||||
buf.Write(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw}))
|
||||
}
|
||||
ret := bytes.TrimSpace(buf.Bytes())
|
||||
return json.Marshal(string(ret))
|
||||
}
|
||||
|
||||
// PemBlockToString turns a pem.Block into the string encoded form.
|
||||
func PemBlockToString(block *pem.Block) string {
|
||||
if block.Bytes == nil || block.Type == "" {
|
||||
return ""
|
||||
}
|
||||
return string(bytes.TrimSpace(pem.EncodeToMemory(block)))
|
||||
}
|
||||
|
||||
var typeToName = map[int]string{
|
||||
3: "CommonName",
|
||||
5: "SerialNumber",
|
||||
6: "Country",
|
||||
7: "Locality",
|
||||
8: "Province",
|
||||
9: "StreetAddress",
|
||||
10: "Organization",
|
||||
11: "OrganizationalUnit",
|
||||
17: "PostalCode",
|
||||
}
|
||||
|
||||
type names []pkix.AttributeTypeAndValue
|
||||
|
||||
func (n names) MarshalJSON() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
for _, name := range n {
|
||||
buf.WriteString(fmt.Sprintf("/%s=%s", typeToName[name.Type[3]], name.Value))
|
||||
}
|
||||
return json.Marshal(buf.String())
|
||||
}
|
||||
|
||||
// MarshalJSON serialises the bundle to JSON. The resulting JSON
|
||||
// structure contains the bundle (as a sequence of PEM-encoded
|
||||
// certificates), the certificate, the private key, the size of they
|
||||
// key, the issuer(s), the subject name(s), the expiration, the
|
||||
// hostname(s), the OCSP server, and the signature on the certificate.
|
||||
func (b *Bundle) MarshalJSON() ([]byte, error) {
|
||||
if b == nil || b.Cert == nil {
|
||||
return nil, errors.New("no certificate in bundle")
|
||||
}
|
||||
var keyBytes, rootBytes []byte
|
||||
var keyLength int
|
||||
var keyType, keyString string
|
||||
keyLength = helpers.KeyLength(b.Cert.PublicKey)
|
||||
switch b.Cert.PublicKeyAlgorithm {
|
||||
case x509.ECDSA:
|
||||
keyType = fmt.Sprintf("%d-bit ECDSA", keyLength)
|
||||
case x509.RSA:
|
||||
keyType = fmt.Sprintf("%d-bit RSA", keyLength)
|
||||
case x509.DSA:
|
||||
keyType = "DSA"
|
||||
default:
|
||||
keyType = "Unknown"
|
||||
}
|
||||
|
||||
switch key := b.Key.(type) {
|
||||
case *rsa.PrivateKey:
|
||||
keyBytes = x509.MarshalPKCS1PrivateKey(key)
|
||||
keyString = PemBlockToString(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: keyBytes})
|
||||
case *ecdsa.PrivateKey:
|
||||
keyBytes, _ = x509.MarshalECPrivateKey(key)
|
||||
keyString = PemBlockToString(&pem.Block{Type: "EC PRIVATE KEY", Bytes: keyBytes})
|
||||
case fmt.Stringer:
|
||||
keyString = key.String()
|
||||
}
|
||||
|
||||
if len(b.Hostnames) == 0 {
|
||||
b.buildHostnames()
|
||||
}
|
||||
var ocspSupport = false
|
||||
if b.Cert.OCSPServer != nil {
|
||||
ocspSupport = true
|
||||
}
|
||||
var crlSupport = false
|
||||
if b.Cert.CRLDistributionPoints != nil {
|
||||
crlSupport = true
|
||||
}
|
||||
if b.Root != nil {
|
||||
rootBytes = b.Root.Raw
|
||||
}
|
||||
|
||||
return json.Marshal(map[string]interface{}{
|
||||
"bundle": chain(b.Chain),
|
||||
"root": PemBlockToString(&pem.Block{Type: "CERTIFICATE", Bytes: rootBytes}),
|
||||
"crt": PemBlockToString(&pem.Block{Type: "CERTIFICATE", Bytes: b.Cert.Raw}),
|
||||
"key": keyString,
|
||||
"key_type": keyType,
|
||||
"key_size": keyLength,
|
||||
"issuer": names(b.Issuer.Names),
|
||||
"subject": names(b.Subject.Names),
|
||||
"expires": b.Expires,
|
||||
"leaf_expires": b.LeafExpires,
|
||||
"hostnames": b.Hostnames,
|
||||
"ocsp_support": ocspSupport,
|
||||
"crl_support": crlSupport,
|
||||
"ocsp": b.Cert.OCSPServer,
|
||||
"signature": helpers.SignatureString(b.Cert.SignatureAlgorithm),
|
||||
"status": b.Status,
|
||||
})
|
||||
}
|
||||
|
||||
// buildHostnames sets bundle.Hostnames by the x509 cert's subject CN and DNS names
|
||||
// Since the subject CN may overlap with one of the DNS names, it needs to handle
|
||||
// the duplication by a set.
|
||||
func (b *Bundle) buildHostnames() {
|
||||
if b.Cert == nil {
|
||||
return
|
||||
}
|
||||
// hset keeps a set of unique hostnames.
|
||||
hset := make(map[string]bool)
|
||||
// insert CN into hset
|
||||
if b.Cert.Subject.CommonName != "" {
|
||||
hset[b.Cert.Subject.CommonName] = true
|
||||
}
|
||||
// insert all DNS names into hset
|
||||
for _, h := range b.Cert.DNSNames {
|
||||
hset[h] = true
|
||||
}
|
||||
|
||||
// convert hset to an array of hostnames
|
||||
b.Hostnames = make([]string, len(hset))
|
||||
i := 0
|
||||
for h := range hset {
|
||||
b.Hostnames[i] = h
|
||||
i++
|
||||
}
|
||||
}
|
843
vendor/github.com/cloudflare/cfssl/bundler/bundler.go
generated
vendored
Normal file
843
vendor/github.com/cloudflare/cfssl/bundler/bundler.go
generated
vendored
Normal file
@@ -0,0 +1,843 @@
|
||||
// Package bundler implements certificate bundling functionality for
|
||||
// CFSSL.
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rsa"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
goerr "errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ubiquity"
|
||||
)
|
||||
|
||||
// IntermediateStash contains the path to the directory where
|
||||
// downloaded intermediates should be saved.
|
||||
// When unspecified, downloaded intermediates are not saved.
|
||||
var IntermediateStash string
|
||||
|
||||
// BundleFlavor is named optimization strategy on certificate chain selection when bundling.
|
||||
type BundleFlavor string
|
||||
|
||||
const (
|
||||
// Optimal means the shortest chain with newest intermediates and
|
||||
// the most advanced crypto.
|
||||
Optimal BundleFlavor = "optimal"
|
||||
|
||||
// Ubiquitous is aimed to provide the chain which is accepted
|
||||
// by the most platforms.
|
||||
Ubiquitous BundleFlavor = "ubiquitous"
|
||||
|
||||
// Force means the bundler only verfiies the input as a valid bundle, not optimization is done.
|
||||
Force BundleFlavor = "force"
|
||||
)
|
||||
|
||||
const (
|
||||
sha2Warning = "The bundle contains certificates signed with advanced hash functions such as SHA2, which are problematic for certain operating systems, e.g. Windows XP SP2."
|
||||
ecdsaWarning = "The bundle contains ECDSA signatures, which are problematic for certain operating systems, e.g. Windows XP, Android 2.2 and Android 2.3."
|
||||
expiringWarningStub = "The bundle is expiring within 30 days."
|
||||
untrustedWarningStub = "The bundle may not be trusted by the following platform(s):"
|
||||
ubiquityWarning = "Unable to measure bundle ubiquity: No platform metadata present."
|
||||
)
|
||||
|
||||
// A Bundler contains the certificate pools for producing certificate
|
||||
// bundles. It contains any intermediates and root certificates that
|
||||
// should be used.
|
||||
type Bundler struct {
|
||||
RootPool *x509.CertPool
|
||||
IntermediatePool *x509.CertPool
|
||||
KnownIssuers map[string]bool
|
||||
opts options
|
||||
}
|
||||
|
||||
type options struct {
|
||||
keyUsages []x509.ExtKeyUsage
|
||||
}
|
||||
|
||||
var defaultOptions = options{
|
||||
keyUsages: []x509.ExtKeyUsage{
|
||||
x509.ExtKeyUsageAny,
|
||||
},
|
||||
}
|
||||
|
||||
// An Option sets options such as allowed key usages, etc.
|
||||
type Option func(*options)
|
||||
|
||||
// WithKeyUsages lets you set which Extended Key Usage values are acceptable. By
|
||||
// default x509.ExtKeyUsageAny will be used.
|
||||
func WithKeyUsages(usages ...x509.ExtKeyUsage) Option {
|
||||
return func(o *options) {
|
||||
o.keyUsages = usages
|
||||
}
|
||||
}
|
||||
|
||||
// NewBundler creates a new Bundler from the files passed in; these
|
||||
// files should contain a list of valid root certificates and a list
|
||||
// of valid intermediate certificates, respectively.
|
||||
func NewBundler(caBundleFile, intBundleFile string, opt ...Option) (*Bundler, error) {
|
||||
var caBundle, intBundle []byte
|
||||
var err error
|
||||
|
||||
if caBundleFile != "" {
|
||||
log.Debug("Loading CA bundle: ", caBundleFile)
|
||||
caBundle, err = ioutil.ReadFile(caBundleFile)
|
||||
if err != nil {
|
||||
log.Errorf("root bundle failed to load: %v", err)
|
||||
return nil, errors.Wrap(errors.RootError, errors.ReadFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
if intBundleFile != "" {
|
||||
log.Debug("Loading Intermediate bundle: ", intBundleFile)
|
||||
intBundle, err = ioutil.ReadFile(intBundleFile)
|
||||
if err != nil {
|
||||
log.Errorf("intermediate bundle failed to load: %v", err)
|
||||
return nil, errors.Wrap(errors.IntermediatesError, errors.ReadFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
if IntermediateStash != "" {
|
||||
if _, err = os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
|
||||
log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
|
||||
err = os.MkdirAll(IntermediateStash, 0755)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create intermediate stash directory %s: %v",
|
||||
IntermediateStash, err)
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("intermediate stash directory %s created", IntermediateStash)
|
||||
}
|
||||
}
|
||||
|
||||
return NewBundlerFromPEM(caBundle, intBundle, opt...)
|
||||
|
||||
}
|
||||
|
||||
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and
|
||||
// intermediate certificates.
|
||||
// If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle.
|
||||
func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte, opt ...Option) (*Bundler, error) {
|
||||
opts := defaultOptions
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
log.Debug("parsing root certificates from PEM")
|
||||
roots, err := helpers.ParseCertificatesPEM(caBundlePEM)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse root bundle: %v", err)
|
||||
return nil, errors.New(errors.RootError, errors.ParseFailed)
|
||||
}
|
||||
|
||||
log.Debug("parse intermediate certificates from PEM")
|
||||
intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse intermediate bundle: %v", err)
|
||||
return nil, errors.New(errors.IntermediatesError, errors.ParseFailed)
|
||||
}
|
||||
|
||||
b := &Bundler{
|
||||
KnownIssuers: map[string]bool{},
|
||||
IntermediatePool: x509.NewCertPool(),
|
||||
opts: opts,
|
||||
}
|
||||
|
||||
log.Debug("building certificate pools")
|
||||
|
||||
// RootPool will be nil if caBundlePEM is nil, also
|
||||
// that translates to caBundleFile is "".
|
||||
// Systems root store will be used.
|
||||
if caBundlePEM != nil {
|
||||
b.RootPool = x509.NewCertPool()
|
||||
}
|
||||
|
||||
for _, c := range roots {
|
||||
b.RootPool.AddCert(c)
|
||||
b.KnownIssuers[string(c.Signature)] = true
|
||||
}
|
||||
|
||||
for _, c := range intermediates {
|
||||
b.IntermediatePool.AddCert(c)
|
||||
b.KnownIssuers[string(c.Signature)] = true
|
||||
}
|
||||
|
||||
log.Debug("bundler set up")
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// VerifyOptions generates an x509 VerifyOptions structure that can be
|
||||
// used for verifying certificates.
|
||||
func (b *Bundler) VerifyOptions() x509.VerifyOptions {
|
||||
return x509.VerifyOptions{
|
||||
Roots: b.RootPool,
|
||||
Intermediates: b.IntermediatePool,
|
||||
KeyUsages: b.opts.keyUsages,
|
||||
}
|
||||
}
|
||||
|
||||
// BundleFromFile takes a set of files containing the PEM-encoded leaf certificate
|
||||
// (optionally along with some intermediate certs), the PEM-encoded private key
|
||||
// and returns the bundle built from that key and the certificate(s).
|
||||
func (b *Bundler) BundleFromFile(bundleFile, keyFile string, flavor BundleFlavor, password string) (*Bundle, error) {
|
||||
log.Debug("Loading Certificate: ", bundleFile)
|
||||
certsRaw, err := ioutil.ReadFile(bundleFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CertificateError, errors.ReadFailed, err)
|
||||
}
|
||||
|
||||
var keyPEM []byte
|
||||
// Load private key PEM only if a file is given
|
||||
if keyFile != "" {
|
||||
log.Debug("Loading private key: ", keyFile)
|
||||
keyPEM, err = ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
log.Debugf("failed to read private key: ", err)
|
||||
return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err)
|
||||
}
|
||||
if len(keyPEM) == 0 {
|
||||
log.Debug("key is empty")
|
||||
return nil, errors.Wrap(errors.PrivateKeyError, errors.DecodeFailed, err)
|
||||
}
|
||||
}
|
||||
|
||||
return b.BundleFromPEMorDER(certsRaw, keyPEM, flavor, password)
|
||||
}
|
||||
|
||||
// BundleFromPEMorDER builds a certificate bundle from the set of byte
|
||||
// slices containing the PEM or DER-encoded certificate(s), private key.
|
||||
func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) {
|
||||
log.Debug("bundling from PEM files")
|
||||
var key crypto.Signer
|
||||
var err error
|
||||
if len(keyPEM) != 0 {
|
||||
key, err = helpers.ParsePrivateKeyPEM(keyPEM)
|
||||
if err != nil {
|
||||
log.Debugf("failed to parse private key: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
certs, err := helpers.ParseCertificatesPEM(certsRaw)
|
||||
if err != nil {
|
||||
// If PEM doesn't work try DER
|
||||
var keyDER crypto.Signer
|
||||
var errDER error
|
||||
certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password)
|
||||
// Only use DER key if no key read from file
|
||||
if key == nil && keyDER != nil {
|
||||
key = keyDER
|
||||
}
|
||||
if errDER != nil {
|
||||
log.Debugf("failed to parse certificates: %v", err)
|
||||
// If neither parser works pass along PEM error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
if len(certs) == 0 {
|
||||
log.Debugf("no certificates found")
|
||||
return nil, errors.New(errors.CertificateError, errors.DecodeFailed)
|
||||
}
|
||||
|
||||
log.Debugf("bundle ready")
|
||||
return b.Bundle(certs, key, flavor)
|
||||
}
|
||||
|
||||
// BundleFromRemote fetches the certificate served by the server at
|
||||
// serverName (or ip, if the ip argument is not the empty string). It
|
||||
// is expected that the method will be able to make a connection at
|
||||
// port 443. The certificate used by the server in this connection is
|
||||
// used to build the bundle, which will necessarily be keyless.
|
||||
func (b *Bundler) BundleFromRemote(serverName, ip string, flavor BundleFlavor) (*Bundle, error) {
|
||||
config := &tls.Config{
|
||||
RootCAs: b.RootPool,
|
||||
ServerName: serverName,
|
||||
}
|
||||
|
||||
// Dial by IP if present
|
||||
var dialName string
|
||||
if ip != "" {
|
||||
dialName = ip + ":443"
|
||||
} else {
|
||||
dialName = serverName + ":443"
|
||||
}
|
||||
|
||||
log.Debugf("bundling from remote %s", dialName)
|
||||
|
||||
dialer := &net.Dialer{Timeout: time.Duration(5) * time.Second}
|
||||
conn, err := tls.DialWithDialer(dialer, "tcp", dialName, config)
|
||||
var dialError string
|
||||
// If there's an error in tls.Dial, try again with
|
||||
// InsecureSkipVerify to fetch the remote bundle to (re-)bundle
|
||||
// with. If the bundle is indeed not usable (expired, mismatched
|
||||
// hostnames, etc.), report the error. Otherwise, create a
|
||||
// working bundle and insert the tls error in the bundle.Status.
|
||||
if err != nil {
|
||||
log.Debugf("dial failed: %v", err)
|
||||
// record the error msg
|
||||
dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err)
|
||||
// dial again with InsecureSkipVerify
|
||||
log.Debugf("try again with InsecureSkipVerify.")
|
||||
config.InsecureSkipVerify = true
|
||||
conn, err = tls.DialWithDialer(dialer, "tcp", dialName, config)
|
||||
if err != nil {
|
||||
log.Debugf("dial with InsecureSkipVerify failed: %v", err)
|
||||
return nil, errors.Wrap(errors.DialError, errors.Unknown, err)
|
||||
}
|
||||
}
|
||||
|
||||
connState := conn.ConnectionState()
|
||||
|
||||
certs := connState.PeerCertificates
|
||||
|
||||
err = conn.VerifyHostname(serverName)
|
||||
if err != nil {
|
||||
log.Debugf("failed to verify hostname: %v", err)
|
||||
return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
|
||||
// Bundle with remote certs. Inject the initial dial error, if any, to the status reporting.
|
||||
bundle, err := b.Bundle(certs, nil, flavor)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if dialError != "" {
|
||||
bundle.Status.Messages = append(bundle.Status.Messages, dialError)
|
||||
}
|
||||
return bundle, err
|
||||
}
|
||||
|
||||
type fetchedIntermediate struct {
|
||||
Cert *x509.Certificate
|
||||
Name string
|
||||
}
|
||||
|
||||
// fetchRemoteCertificate retrieves a single URL pointing to a certificate
|
||||
// and attempts to first parse it as a DER-encoded certificate; if
|
||||
// this fails, it attempts to decode it as a PEM-encoded certificate.
|
||||
func fetchRemoteCertificate(certURL string) (fi *fetchedIntermediate, err error) {
|
||||
log.Debugf("fetching remote certificate: %s", certURL)
|
||||
var resp *http.Response
|
||||
resp, err = http.Get(certURL)
|
||||
if err != nil {
|
||||
log.Debugf("failed HTTP get: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
var certData []byte
|
||||
certData, err = ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Debugf("failed to read response body: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Debugf("attempting to parse certificate as DER")
|
||||
crt, err := x509.ParseCertificate(certData)
|
||||
if err != nil {
|
||||
log.Debugf("attempting to parse certificate as PEM")
|
||||
crt, err = helpers.ParseCertificatePEM(certData)
|
||||
if err != nil {
|
||||
log.Debugf("failed to parse certificate: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Debugf("certificate fetch succeeds")
|
||||
fi = &fetchedIntermediate{Cert: crt, Name: constructCertFileName(crt)}
|
||||
return
|
||||
}
|
||||
|
||||
func reverse(certs []*x509.Certificate) []*x509.Certificate {
|
||||
n := len(certs)
|
||||
if n == 0 {
|
||||
return certs
|
||||
}
|
||||
rcerts := []*x509.Certificate{}
|
||||
for i := n - 1; i >= 0; i-- {
|
||||
rcerts = append(rcerts, certs[i])
|
||||
}
|
||||
return rcerts
|
||||
}
|
||||
|
||||
// Check if the certs form a partial cert chain: every cert verifies
|
||||
// the signature of the one in front of it.
|
||||
func partialVerify(certs []*x509.Certificate) bool {
|
||||
n := len(certs)
|
||||
if n == 0 {
|
||||
return false
|
||||
}
|
||||
for i := 0; i < n-1; i++ {
|
||||
if certs[i].CheckSignatureFrom(certs[i+1]) != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func isSelfSigned(cert *x509.Certificate) bool {
|
||||
return cert.CheckSignatureFrom(cert) == nil
|
||||
}
|
||||
|
||||
func isChainRootNode(cert *x509.Certificate) bool {
|
||||
if isSelfSigned(cert) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool {
|
||||
// This process will verify if the root of the (partial) chain is in our root pool,
|
||||
// and will fail otherwise.
|
||||
log.Debugf("verifying chain")
|
||||
for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] {
|
||||
cert := vchain[0]
|
||||
// If this is a certificate in one of the pools, skip it.
|
||||
if b.KnownIssuers[string(cert.Cert.Signature)] {
|
||||
log.Debugf("certificate is known")
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := cert.Cert.Verify(b.VerifyOptions())
|
||||
if err != nil {
|
||||
log.Debugf("certificate failed verification: %v", err)
|
||||
return false
|
||||
} else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) {
|
||||
// The first certificate in the chain is a root; it shouldn't be stored.
|
||||
log.Debug("looking at root certificate, will not store")
|
||||
continue
|
||||
}
|
||||
|
||||
// leaf cert has an empty name, don't store leaf cert.
|
||||
if cert.Name == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debug("add certificate to intermediate pool:", cert.Name)
|
||||
b.IntermediatePool.AddCert(cert.Cert)
|
||||
b.KnownIssuers[string(cert.Cert.Signature)] = true
|
||||
|
||||
if IntermediateStash != "" {
|
||||
fileName := filepath.Join(IntermediateStash, cert.Name)
|
||||
|
||||
var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw}
|
||||
|
||||
log.Debugf("write intermediate to stash directory: %s", fileName)
|
||||
// If the write fails, verification should not fail.
|
||||
err = ioutil.WriteFile(fileName, pem.EncodeToMemory(&block), 0644)
|
||||
if err != nil {
|
||||
log.Errorf("failed to write new intermediate: %v", err)
|
||||
} else {
|
||||
log.Info("stashed new intermediate ", cert.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// constructCertFileName returns a uniquely identifying file name for a certificate
|
||||
func constructCertFileName(cert *x509.Certificate) string {
|
||||
// construct the filename as the CN with no period and space
|
||||
name := strings.Replace(cert.Subject.CommonName, ".", "", -1)
|
||||
name = strings.Replace(name, " ", "", -1)
|
||||
|
||||
// add SKI and serial number as extra identifier
|
||||
name += fmt.Sprintf("_%x", cert.SubjectKeyId)
|
||||
name += fmt.Sprintf("_%x", cert.SerialNumber.Bytes())
|
||||
|
||||
name += ".crt"
|
||||
return name
|
||||
}
|
||||
|
||||
// fetchIntermediates goes through each of the URLs in the AIA "Issuing
|
||||
// CA" extensions and fetches those certificates. If those
|
||||
// certificates are not present in either the root pool or
|
||||
// intermediate pool, the certificate is saved to file and added to
|
||||
// the list of intermediates to be used for verification. This will
|
||||
// not add any new certificates to the root pool; if the ultimate
|
||||
// issuer is not trusted, fetching the certicate here will not change
|
||||
// that.
|
||||
func (b *Bundler) fetchIntermediates(certs []*x509.Certificate) (err error) {
|
||||
if IntermediateStash != "" {
|
||||
log.Debugf("searching intermediates")
|
||||
if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
|
||||
log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
|
||||
err = os.MkdirAll(IntermediateStash, 0755)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err)
|
||||
return err
|
||||
}
|
||||
log.Infof("intermediate stash directory %s created", IntermediateStash)
|
||||
}
|
||||
}
|
||||
// stores URLs and certificate signatures that have been seen
|
||||
seen := map[string]bool{}
|
||||
var foundChains int
|
||||
|
||||
// Construct a verify chain as a reversed partial bundle,
|
||||
// such that the certs are ordered by promxity to the root CAs.
|
||||
var chain []*fetchedIntermediate
|
||||
for i, cert := range certs {
|
||||
var name string
|
||||
|
||||
// Only construct filenames for non-leaf intermediate certs
|
||||
// so they will be saved to disk if necessary.
|
||||
// Leaf cert gets a empty name and will be skipped.
|
||||
if i > 0 {
|
||||
name = constructCertFileName(cert)
|
||||
}
|
||||
|
||||
chain = append([]*fetchedIntermediate{{cert, name}}, chain...)
|
||||
seen[string(cert.Signature)] = true
|
||||
}
|
||||
|
||||
// Verify the chain and store valid intermediates in the chain.
|
||||
// If it doesn't verify, fetch the intermediates and extend the chain
|
||||
// in a DFS manner and verify each time we hit a root.
|
||||
for {
|
||||
if len(chain) == 0 {
|
||||
log.Debugf("search complete")
|
||||
if foundChains == 0 {
|
||||
return x509.UnknownAuthorityError{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
current := chain[0]
|
||||
var advanced bool
|
||||
if b.verifyChain(chain) {
|
||||
foundChains++
|
||||
}
|
||||
log.Debugf("walk AIA issuers")
|
||||
for _, url := range current.Cert.IssuingCertificateURL {
|
||||
if seen[url] {
|
||||
log.Debugf("url %s has been seen", url)
|
||||
continue
|
||||
}
|
||||
crt, err := fetchRemoteCertificate(url)
|
||||
if err != nil {
|
||||
continue
|
||||
} else if seen[string(crt.Cert.Signature)] {
|
||||
log.Debugf("fetched certificate is known")
|
||||
continue
|
||||
}
|
||||
seen[url] = true
|
||||
seen[string(crt.Cert.Signature)] = true
|
||||
chain = append([]*fetchedIntermediate{crt}, chain...)
|
||||
advanced = true
|
||||
break
|
||||
}
|
||||
|
||||
if !advanced {
|
||||
log.Debugf("didn't advance, stepping back")
|
||||
chain = chain[1:]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Bundle takes an X509 certificate (already in the
|
||||
// Certificate structure), a private key as crypto.Signer in one of the appropriate
|
||||
// formats (i.e. *rsa.PrivateKey or *ecdsa.PrivateKey, or even a opaque key), using them to
|
||||
// build a certificate bundle.
|
||||
func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer, flavor BundleFlavor) (*Bundle, error) {
|
||||
log.Infof("bundling certificate for %+v", certs[0].Subject)
|
||||
if len(certs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Detect reverse ordering of the cert chain.
|
||||
if len(certs) > 1 && !partialVerify(certs) {
|
||||
rcerts := reverse(certs)
|
||||
if partialVerify(rcerts) {
|
||||
certs = rcerts
|
||||
}
|
||||
}
|
||||
|
||||
var ok bool
|
||||
cert := certs[0]
|
||||
if key != nil {
|
||||
switch {
|
||||
case cert.PublicKeyAlgorithm == x509.RSA:
|
||||
|
||||
var rsaPublicKey *rsa.PublicKey
|
||||
if rsaPublicKey, ok = key.Public().(*rsa.PublicKey); !ok {
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
|
||||
}
|
||||
if cert.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
|
||||
}
|
||||
case cert.PublicKeyAlgorithm == x509.ECDSA:
|
||||
var ecdsaPublicKey *ecdsa.PublicKey
|
||||
if ecdsaPublicKey, ok = key.Public().(*ecdsa.PublicKey); !ok {
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
|
||||
}
|
||||
if cert.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
|
||||
}
|
||||
default:
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
|
||||
}
|
||||
} else {
|
||||
switch {
|
||||
case cert.PublicKeyAlgorithm == x509.RSA:
|
||||
case cert.PublicKeyAlgorithm == x509.ECDSA:
|
||||
default:
|
||||
return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
|
||||
}
|
||||
}
|
||||
|
||||
bundle := new(Bundle)
|
||||
bundle.Cert = cert
|
||||
bundle.Key = key
|
||||
bundle.Issuer = &cert.Issuer
|
||||
bundle.Subject = &cert.Subject
|
||||
|
||||
bundle.buildHostnames()
|
||||
|
||||
if flavor == Force {
|
||||
// force bundle checks the certificates
|
||||
// forms a verification chain.
|
||||
if !partialVerify(certs) {
|
||||
return nil,
|
||||
errors.Wrap(errors.CertificateError, errors.VerifyFailed,
|
||||
goerr.New("Unable to verify the certificate chain"))
|
||||
}
|
||||
bundle.Chain = certs
|
||||
} else {
|
||||
// disallow self-signed cert
|
||||
if cert.CheckSignatureFrom(cert) == nil {
|
||||
return nil, errors.New(errors.CertificateError, errors.SelfSigned)
|
||||
}
|
||||
|
||||
chains, err := cert.Verify(b.VerifyOptions())
|
||||
if err != nil {
|
||||
log.Debugf("verification failed: %v", err)
|
||||
// If the error was an unknown authority, try to fetch
|
||||
// the intermediate specified in the AIA and add it to
|
||||
// the intermediates bundle.
|
||||
if _, ok := err.(x509.UnknownAuthorityError); !ok {
|
||||
return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
|
||||
log.Debugf("searching for intermediates via AIA issuer")
|
||||
searchErr := b.fetchIntermediates(certs)
|
||||
if searchErr != nil {
|
||||
log.Debugf("search failed: %v", searchErr)
|
||||
return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
|
||||
log.Debugf("verifying new chain")
|
||||
chains, err = cert.Verify(b.VerifyOptions())
|
||||
if err != nil {
|
||||
log.Debugf("failed to verify chain: %v", err)
|
||||
return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
|
||||
}
|
||||
log.Debugf("verify ok")
|
||||
}
|
||||
var matchingChains [][]*x509.Certificate
|
||||
switch flavor {
|
||||
case Optimal:
|
||||
matchingChains = optimalChains(chains)
|
||||
case Ubiquitous:
|
||||
if len(ubiquity.Platforms) == 0 {
|
||||
log.Warning("No metadata, Ubiquitous falls back to Optimal.")
|
||||
}
|
||||
matchingChains = ubiquitousChains(chains)
|
||||
default:
|
||||
matchingChains = ubiquitousChains(chains)
|
||||
}
|
||||
|
||||
bundle.Chain = matchingChains[0]
|
||||
}
|
||||
|
||||
statusCode := int(errors.Success)
|
||||
var messages []string
|
||||
// Check if bundle is expiring.
|
||||
expiringCerts := checkExpiringCerts(bundle.Chain)
|
||||
if len(expiringCerts) > 0 {
|
||||
statusCode |= errors.BundleExpiringBit
|
||||
messages = append(messages, expirationWarning(expiringCerts))
|
||||
}
|
||||
// Check if bundle contains SHA2 certs.
|
||||
if ubiquity.ChainHashUbiquity(bundle.Chain) <= ubiquity.SHA2Ubiquity {
|
||||
statusCode |= errors.BundleNotUbiquitousBit
|
||||
messages = append(messages, sha2Warning)
|
||||
}
|
||||
// Check if bundle contains ECDSA signatures.
|
||||
if ubiquity.ChainKeyAlgoUbiquity(bundle.Chain) <= ubiquity.ECDSA256Ubiquity {
|
||||
statusCode |= errors.BundleNotUbiquitousBit
|
||||
messages = append(messages, ecdsaWarning)
|
||||
}
|
||||
|
||||
// when forcing a bundle, bundle ubiquity doesn't matter
|
||||
// also we don't retrieve the anchoring root of the bundle
|
||||
var untrusted []string
|
||||
if flavor != Force {
|
||||
// Add root store presence info
|
||||
root := bundle.Chain[len(bundle.Chain)-1]
|
||||
bundle.Root = root
|
||||
log.Infof("the anchoring root is %v", root.Subject)
|
||||
// Check if there is any platform that doesn't trust the chain.
|
||||
// Also, an warning will be generated if ubiquity.Platforms is nil,
|
||||
untrusted = ubiquity.UntrustedPlatforms(root)
|
||||
untrustedMsg := untrustedPlatformsWarning(untrusted)
|
||||
if len(untrustedMsg) > 0 {
|
||||
log.Debug("Populate untrusted platform warning.")
|
||||
statusCode |= errors.BundleNotUbiquitousBit
|
||||
messages = append(messages, untrustedMsg)
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is any platform that rejects the chain because of SHA1 deprecation.
|
||||
sha1Msgs := ubiquity.SHA1DeprecationMessages(bundle.Chain)
|
||||
if len(sha1Msgs) > 0 {
|
||||
log.Debug("Populate SHA1 deprecation warning.")
|
||||
statusCode |= errors.BundleNotUbiquitousBit
|
||||
messages = append(messages, sha1Msgs...)
|
||||
}
|
||||
|
||||
bundle.Status = &BundleStatus{ExpiringSKIs: getSKIs(bundle.Chain, expiringCerts), Code: statusCode, Messages: messages, Untrusted: untrusted}
|
||||
|
||||
// attempt to not to include the root certificate for optimization
|
||||
if flavor != Force {
|
||||
// Include at least one intermediate if the leaf has enabled OCSP and is not CA.
|
||||
if bundle.Cert.OCSPServer != nil && !bundle.Cert.IsCA && len(bundle.Chain) <= 2 {
|
||||
// No op. Return one intermediate if there is one.
|
||||
} else {
|
||||
// do not include the root.
|
||||
bundle.Chain = bundle.Chain[:len(bundle.Chain)-1]
|
||||
}
|
||||
}
|
||||
|
||||
bundle.Status.IsRebundled = diff(bundle.Chain, certs)
|
||||
bundle.Expires = helpers.ExpiryTime(bundle.Chain)
|
||||
bundle.LeafExpires = bundle.Chain[0].NotAfter
|
||||
|
||||
log.Debugf("bundle complete")
|
||||
return bundle, nil
|
||||
}
|
||||
|
||||
// checkExpiringCerts returns indices of certs that are expiring within 30 days.
|
||||
func checkExpiringCerts(chain []*x509.Certificate) (expiringIntermediates []int) {
|
||||
now := time.Now()
|
||||
for i, cert := range chain {
|
||||
if cert.NotAfter.Sub(now).Hours() < 720 {
|
||||
expiringIntermediates = append(expiringIntermediates, i)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// getSKIs returns a list of cert subject key id in the bundle chain with matched indices.
|
||||
func getSKIs(chain []*x509.Certificate, indices []int) (skis []string) {
|
||||
for _, index := range indices {
|
||||
ski := fmt.Sprintf("%X", chain[index].SubjectKeyId)
|
||||
skis = append(skis, ski)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// expirationWarning generates a warning message with expiring certs.
|
||||
func expirationWarning(expiringIntermediates []int) (ret string) {
|
||||
if len(expiringIntermediates) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ret = expiringWarningStub
|
||||
if len(expiringIntermediates) > 1 {
|
||||
ret = ret + "The expiring certs are"
|
||||
} else {
|
||||
ret = ret + "The expiring cert is"
|
||||
}
|
||||
for _, index := range expiringIntermediates {
|
||||
ret = ret + " #" + strconv.Itoa(index+1)
|
||||
}
|
||||
ret = ret + " in the chain."
|
||||
return
|
||||
}
|
||||
|
||||
// untrustedPlatformsWarning generates a warning message with untrusted platform names.
|
||||
func untrustedPlatformsWarning(platforms []string) string {
|
||||
if len(ubiquity.Platforms) == 0 {
|
||||
return ubiquityWarning
|
||||
}
|
||||
|
||||
if len(platforms) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
msg := untrustedWarningStub
|
||||
for i, platform := range platforms {
|
||||
if i > 0 {
|
||||
msg += ","
|
||||
}
|
||||
msg += " " + platform
|
||||
}
|
||||
msg += "."
|
||||
return msg
|
||||
}
|
||||
|
||||
// Optimal chains are the shortest chains, with newest intermediates and most advanced crypto suite being the tie breaker.
|
||||
func optimalChains(chains [][]*x509.Certificate) [][]*x509.Certificate {
|
||||
// Find shortest chains
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainLength)
|
||||
// Find the chains with longest expiry.
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainExpiry)
|
||||
// Find the chains with more advanced crypto suite
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainCryptoSuite)
|
||||
|
||||
return chains
|
||||
}
|
||||
|
||||
// Ubiquitous chains are the chains with highest platform coverage and break ties with the optimal strategy.
|
||||
func ubiquitousChains(chains [][]*x509.Certificate) [][]*x509.Certificate {
|
||||
// Filter out chains with highest cross platform ubiquity.
|
||||
chains = ubiquity.Filter(chains, ubiquity.ComparePlatformUbiquity)
|
||||
// Prefer that all intermediates are SHA-2 certs if the leaf is a SHA-2 cert, in order to improve ubiquity.
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareSHA2Homogeneity)
|
||||
// Filter shortest chains
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainLength)
|
||||
// Filter chains with highest signature hash ubiquity.
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainHashUbiquity)
|
||||
// Filter chains with highest keyAlgo ubiquity.
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareChainKeyAlgoUbiquity)
|
||||
// Filter chains with intermediates that last longer.
|
||||
chains = ubiquity.Filter(chains, ubiquity.CompareExpiryUbiquity)
|
||||
// Use the optimal strategy as final tie breaker.
|
||||
return optimalChains(chains)
|
||||
}
|
||||
|
||||
// diff checkes if two input cert chains are not identical
|
||||
func diff(chain1, chain2 []*x509.Certificate) bool {
|
||||
// Check if bundled one is different from the input.
|
||||
diff := false
|
||||
if len(chain1) != len(chain2) {
|
||||
diff = true
|
||||
} else {
|
||||
for i := 0; i < len(chain1); i++ {
|
||||
cert1 := chain1[i]
|
||||
cert2 := chain2[i]
|
||||
// Use signature to differentiate.
|
||||
if !bytes.Equal(cert1.Signature, cert2.Signature) {
|
||||
diff = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return diff
|
||||
}
|
16
vendor/github.com/cloudflare/cfssl/bundler/doc.go
generated
vendored
Normal file
16
vendor/github.com/cloudflare/cfssl/bundler/doc.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Package bundler provides an API for creating certificate bundles,
|
||||
// which contain a trust chain of certificates. Generally, the bundles
|
||||
// will also include the private key (but this is not strictly
|
||||
// required). In this package, a bundle refers to a certificate with
|
||||
// full trust chain -- all certificates in the chain in one file or
|
||||
// buffer.
|
||||
//
|
||||
// The first step in creating a certificate bundle is to create a
|
||||
// Bundler. A Bundler must be created from a pre-existing certificate
|
||||
// authority bundle and an intermediate certificate bundle. Once the
|
||||
// Bundler is initialised, bundles may be created using a variety of
|
||||
// methods: from PEM- or DER-encoded files, directly from the relevant
|
||||
// Go structures, or by starting with the certificate from a remote
|
||||
// system. These functions return a Bundle value, which may be
|
||||
// serialised to JSON.
|
||||
package bundler
|
6
vendor/github.com/cloudflare/cfssl/certdb/BUILD
generated
vendored
6
vendor/github.com/cloudflare/cfssl/certdb/BUILD
generated
vendored
@@ -17,7 +17,11 @@ filegroup(
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
28
vendor/github.com/cloudflare/cfssl/certdb/dbconf/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/certdb/dbconf/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 = ["db_config.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/certdb/dbconf",
|
||||
importpath = "github.com/cloudflare/cfssl/certdb/dbconf",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log:go_default_library",
|
||||
"//vendor/github.com/jmoiron/sqlx: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"],
|
||||
)
|
57
vendor/github.com/cloudflare/cfssl/certdb/dbconf/db_config.go
generated
vendored
Normal file
57
vendor/github.com/cloudflare/cfssl/certdb/dbconf/db_config.go
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
package dbconf
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// DBConfig contains the database driver name and configuration to be passed to Open
|
||||
type DBConfig struct {
|
||||
DriverName string `json:"driver"`
|
||||
DataSourceName string `json:"data_source"`
|
||||
}
|
||||
|
||||
// LoadFile attempts to load the db configuration file stored at the path
|
||||
// and returns the configuration. On error, it returns nil.
|
||||
func LoadFile(path string) (cfg *DBConfig, err error) {
|
||||
log.Debugf("loading db configuration file from %s", path)
|
||||
if path == "" {
|
||||
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
|
||||
}
|
||||
|
||||
var body []byte
|
||||
body, err = ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
|
||||
}
|
||||
|
||||
cfg = &DBConfig{}
|
||||
err = json.Unmarshal(body, &cfg)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
|
||||
errors.New("failed to unmarshal configuration: "+err.Error()))
|
||||
}
|
||||
|
||||
if cfg.DataSourceName == "" || cfg.DriverName == "" {
|
||||
return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid db configuration"))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// DBFromConfig opens a sql.DB from settings in a db config file
|
||||
func DBFromConfig(path string) (db *sqlx.DB, err error) {
|
||||
var dbCfg *DBConfig
|
||||
dbCfg, err = LoadFile(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sqlx.Open(dbCfg.DriverName, dbCfg.DataSourceName)
|
||||
}
|
29
vendor/github.com/cloudflare/cfssl/certdb/sql/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/certdb/sql/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 = ["database_accessor.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/certdb/sql",
|
||||
importpath = "github.com/cloudflare/cfssl/certdb/sql",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/errors:go_default_library",
|
||||
"//vendor/github.com/jmoiron/sqlx:go_default_library",
|
||||
"//vendor/github.com/kisielk/sqlstruct: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"],
|
||||
)
|
352
vendor/github.com/cloudflare/cfssl/certdb/sql/database_accessor.go
generated
vendored
Normal file
352
vendor/github.com/cloudflare/cfssl/certdb/sql/database_accessor.go
generated
vendored
Normal file
@@ -0,0 +1,352 @@
|
||||
package sql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/kisielk/sqlstruct"
|
||||
)
|
||||
|
||||
// Match to sqlx
|
||||
func init() {
|
||||
sqlstruct.TagName = "db"
|
||||
}
|
||||
|
||||
const (
|
||||
insertSQL = `
|
||||
INSERT INTO certificates (serial_number, authority_key_identifier, ca_label, status, reason, expiry, revoked_at, pem)
|
||||
VALUES (:serial_number, :authority_key_identifier, :ca_label, :status, :reason, :expiry, :revoked_at, :pem);`
|
||||
|
||||
selectSQL = `
|
||||
SELECT %s FROM certificates
|
||||
WHERE (serial_number = ? AND authority_key_identifier = ?);`
|
||||
|
||||
selectAllUnexpiredSQL = `
|
||||
SELECT %s FROM certificates
|
||||
WHERE CURRENT_TIMESTAMP < expiry;`
|
||||
|
||||
selectAllRevokedAndUnexpiredWithLabelSQL = `
|
||||
SELECT %s FROM certificates
|
||||
WHERE CURRENT_TIMESTAMP < expiry AND status='revoked' AND ca_label= ?;`
|
||||
|
||||
selectAllRevokedAndUnexpiredSQL = `
|
||||
SELECT %s FROM certificates
|
||||
WHERE CURRENT_TIMESTAMP < expiry AND status='revoked';`
|
||||
|
||||
updateRevokeSQL = `
|
||||
UPDATE certificates
|
||||
SET status='revoked', revoked_at=CURRENT_TIMESTAMP, reason=:reason
|
||||
WHERE (serial_number = :serial_number AND authority_key_identifier = :authority_key_identifier);`
|
||||
|
||||
insertOCSPSQL = `
|
||||
INSERT INTO ocsp_responses (serial_number, authority_key_identifier, body, expiry)
|
||||
VALUES (:serial_number, :authority_key_identifier, :body, :expiry);`
|
||||
|
||||
updateOCSPSQL = `
|
||||
UPDATE ocsp_responses
|
||||
SET body = :body, expiry = :expiry
|
||||
WHERE (serial_number = :serial_number AND authority_key_identifier = :authority_key_identifier);`
|
||||
|
||||
selectAllUnexpiredOCSPSQL = `
|
||||
SELECT %s FROM ocsp_responses
|
||||
WHERE CURRENT_TIMESTAMP < expiry;`
|
||||
|
||||
selectOCSPSQL = `
|
||||
SELECT %s FROM ocsp_responses
|
||||
WHERE (serial_number = ? AND authority_key_identifier = ?);`
|
||||
)
|
||||
|
||||
// Accessor implements certdb.Accessor interface.
|
||||
type Accessor struct {
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func wrapSQLError(err error) error {
|
||||
if err != nil {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.Unknown, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Accessor) checkDB() error {
|
||||
if d.db == nil {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.Unknown,
|
||||
errors.New("unknown db object, please check SetDB method"))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewAccessor returns a new Accessor.
|
||||
func NewAccessor(db *sqlx.DB) *Accessor {
|
||||
return &Accessor{db: db}
|
||||
}
|
||||
|
||||
// SetDB changes the underlying sql.DB object Accessor is manipulating.
|
||||
func (d *Accessor) SetDB(db *sqlx.DB) {
|
||||
d.db = db
|
||||
return
|
||||
}
|
||||
|
||||
// InsertCertificate puts a certdb.CertificateRecord into db.
|
||||
func (d *Accessor) InsertCertificate(cr certdb.CertificateRecord) error {
|
||||
err := d.checkDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
res, err := d.db.NamedExec(insertSQL, &certdb.CertificateRecord{
|
||||
Serial: cr.Serial,
|
||||
AKI: cr.AKI,
|
||||
CALabel: cr.CALabel,
|
||||
Status: cr.Status,
|
||||
Reason: cr.Reason,
|
||||
Expiry: cr.Expiry.UTC(),
|
||||
RevokedAt: cr.RevokedAt.UTC(),
|
||||
PEM: cr.PEM,
|
||||
})
|
||||
if err != nil {
|
||||
return wrapSQLError(err)
|
||||
}
|
||||
|
||||
numRowsAffected, err := res.RowsAffected()
|
||||
|
||||
if numRowsAffected == 0 {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the certificate record"))
|
||||
}
|
||||
|
||||
if numRowsAffected != 1 {
|
||||
return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetCertificate gets a certdb.CertificateRecord indexed by serial.
|
||||
func (d *Accessor) GetCertificate(serial, aki string) (crs []certdb.CertificateRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectSQL), sqlstruct.Columns(certdb.CertificateRecord{})), serial, aki)
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return crs, nil
|
||||
}
|
||||
|
||||
// GetUnexpiredCertificates gets all unexpired certificate from db.
|
||||
func (d *Accessor) GetUnexpiredCertificates() (crs []certdb.CertificateRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllUnexpiredSQL), sqlstruct.Columns(certdb.CertificateRecord{})))
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return crs, nil
|
||||
}
|
||||
|
||||
// GetRevokedAndUnexpiredCertificates gets all revoked and unexpired certificate from db (for CRLs).
|
||||
func (d *Accessor) GetRevokedAndUnexpiredCertificates() (crs []certdb.CertificateRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllRevokedAndUnexpiredSQL), sqlstruct.Columns(certdb.CertificateRecord{})))
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return crs, nil
|
||||
}
|
||||
|
||||
// GetRevokedAndUnexpiredCertificatesByLabel gets all revoked and unexpired certificate from db (for CRLs) with specified ca_label.
|
||||
func (d *Accessor) GetRevokedAndUnexpiredCertificatesByLabel(label string) (crs []certdb.CertificateRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&crs, fmt.Sprintf(d.db.Rebind(selectAllRevokedAndUnexpiredWithLabelSQL), sqlstruct.Columns(certdb.CertificateRecord{})), label)
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return crs, nil
|
||||
}
|
||||
|
||||
// RevokeCertificate updates a certificate with a given serial number and marks it revoked.
|
||||
func (d *Accessor) RevokeCertificate(serial, aki string, reasonCode int) error {
|
||||
err := d.checkDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := d.db.NamedExec(updateRevokeSQL, &certdb.CertificateRecord{
|
||||
AKI: aki,
|
||||
Reason: reasonCode,
|
||||
Serial: serial,
|
||||
})
|
||||
if err != nil {
|
||||
return wrapSQLError(err)
|
||||
}
|
||||
|
||||
numRowsAffected, err := result.RowsAffected()
|
||||
|
||||
if numRowsAffected == 0 {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to revoke the certificate: certificate not found"))
|
||||
}
|
||||
|
||||
if numRowsAffected != 1 {
|
||||
return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// InsertOCSP puts a new certdb.OCSPRecord into the db.
|
||||
func (d *Accessor) InsertOCSP(rr certdb.OCSPRecord) error {
|
||||
err := d.checkDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := d.db.NamedExec(insertOCSPSQL, &certdb.OCSPRecord{
|
||||
AKI: rr.AKI,
|
||||
Body: rr.Body,
|
||||
Expiry: rr.Expiry.UTC(),
|
||||
Serial: rr.Serial,
|
||||
})
|
||||
if err != nil {
|
||||
return wrapSQLError(err)
|
||||
}
|
||||
|
||||
numRowsAffected, err := result.RowsAffected()
|
||||
|
||||
if numRowsAffected == 0 {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the OCSP record"))
|
||||
}
|
||||
|
||||
if numRowsAffected != 1 {
|
||||
return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// GetOCSP retrieves a certdb.OCSPRecord from db by serial.
|
||||
func (d *Accessor) GetOCSP(serial, aki string) (ors []certdb.OCSPRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&ors, fmt.Sprintf(d.db.Rebind(selectOCSPSQL), sqlstruct.Columns(certdb.OCSPRecord{})), serial, aki)
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return ors, nil
|
||||
}
|
||||
|
||||
// GetUnexpiredOCSPs retrieves all unexpired certdb.OCSPRecord from db.
|
||||
func (d *Accessor) GetUnexpiredOCSPs() (ors []certdb.OCSPRecord, err error) {
|
||||
err = d.checkDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = d.db.Select(&ors, fmt.Sprintf(d.db.Rebind(selectAllUnexpiredOCSPSQL), sqlstruct.Columns(certdb.OCSPRecord{})))
|
||||
if err != nil {
|
||||
return nil, wrapSQLError(err)
|
||||
}
|
||||
|
||||
return ors, nil
|
||||
}
|
||||
|
||||
// UpdateOCSP updates a ocsp response record with a given serial number.
|
||||
func (d *Accessor) UpdateOCSP(serial, aki, body string, expiry time.Time) error {
|
||||
err := d.checkDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := d.db.NamedExec(updateOCSPSQL, &certdb.OCSPRecord{
|
||||
AKI: aki,
|
||||
Body: body,
|
||||
Expiry: expiry.UTC(),
|
||||
Serial: serial,
|
||||
})
|
||||
if err != nil {
|
||||
return wrapSQLError(err)
|
||||
}
|
||||
|
||||
numRowsAffected, err := result.RowsAffected()
|
||||
|
||||
if numRowsAffected == 0 {
|
||||
return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to update the OCSP record"))
|
||||
}
|
||||
|
||||
if numRowsAffected != 1 {
|
||||
return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// UpsertOCSP update a ocsp response record with a given serial number,
|
||||
// or insert the record if it doesn't yet exist in the db
|
||||
// Implementation note:
|
||||
// We didn't implement 'upsert' with SQL statement and we lost race condition
|
||||
// prevention provided by underlying DBMS.
|
||||
// Reasoning:
|
||||
// 1. it's diffcult to support multiple DBMS backends in the same time, the
|
||||
// SQL syntax differs from one to another.
|
||||
// 2. we don't need a strict simultaneous consistency between OCSP and certificate
|
||||
// status. It's OK that a OCSP response still shows 'good' while the
|
||||
// corresponding certificate is being revoked seconds ago, as long as the OCSP
|
||||
// response catches up to be eventually consistent (within hours to days).
|
||||
// Write race condition between OCSP writers on OCSP table is not a problem,
|
||||
// since we don't have write race condition on Certificate table and OCSP
|
||||
// writers should periodically use Certificate table to update OCSP table
|
||||
// to catch up.
|
||||
func (d *Accessor) UpsertOCSP(serial, aki, body string, expiry time.Time) error {
|
||||
err := d.checkDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result, err := d.db.NamedExec(updateOCSPSQL, &certdb.OCSPRecord{
|
||||
AKI: aki,
|
||||
Body: body,
|
||||
Expiry: expiry.UTC(),
|
||||
Serial: serial,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return wrapSQLError(err)
|
||||
}
|
||||
|
||||
numRowsAffected, err := result.RowsAffected()
|
||||
|
||||
if numRowsAffected == 0 {
|
||||
return d.InsertOCSP(certdb.OCSPRecord{Serial: serial, AKI: aki, Body: body, Expiry: expiry})
|
||||
}
|
||||
|
||||
if numRowsAffected != 1 {
|
||||
return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
24
vendor/github.com/cloudflare/cfssl/certinfo/BUILD
generated
vendored
Normal file
24
vendor/github.com/cloudflare/cfssl/certinfo/BUILD
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
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/certinfo",
|
||||
importpath = "github.com/cloudflare/cfssl/certinfo",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/cloudflare/cfssl/helpers: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"],
|
||||
)
|
166
vendor/github.com/cloudflare/cfssl/certinfo/certinfo.go
generated
vendored
Normal file
166
vendor/github.com/cloudflare/cfssl/certinfo/certinfo.go
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
package certinfo
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
)
|
||||
|
||||
// Certificate represents a JSON description of an X.509 certificate.
|
||||
type Certificate struct {
|
||||
Subject Name `json:"subject,omitempty"`
|
||||
Issuer Name `json:"issuer,omitempty"`
|
||||
SerialNumber string `json:"serial_number,omitempty"`
|
||||
SANs []string `json:"sans,omitempty"`
|
||||
NotBefore time.Time `json:"not_before"`
|
||||
NotAfter time.Time `json:"not_after"`
|
||||
SignatureAlgorithm string `json:"sigalg"`
|
||||
AKI string `json:"authority_key_id"`
|
||||
SKI string `json:"subject_key_id"`
|
||||
RawPEM string `json:"pem"`
|
||||
}
|
||||
|
||||
// Name represents a JSON description of a PKIX Name
|
||||
type Name struct {
|
||||
CommonName string `json:"common_name,omitempty"`
|
||||
SerialNumber string `json:"serial_number,omitempty"`
|
||||
Country string `json:"country,omitempty"`
|
||||
Organization string `json:"organization,omitempty"`
|
||||
OrganizationalUnit string `json:"organizational_unit,omitempty"`
|
||||
Locality string `json:"locality,omitempty"`
|
||||
Province string `json:"province,omitempty"`
|
||||
StreetAddress string `json:"street_address,omitempty"`
|
||||
PostalCode string `json:"postal_code,omitempty"`
|
||||
Names []interface{} `json:"names,omitempty"`
|
||||
//ExtraNames []interface{} `json:"extra_names,omitempty"`
|
||||
}
|
||||
|
||||
// ParseName parses a new name from a *pkix.Name
|
||||
func ParseName(name pkix.Name) Name {
|
||||
n := Name{
|
||||
CommonName: name.CommonName,
|
||||
SerialNumber: name.SerialNumber,
|
||||
Country: strings.Join(name.Country, ","),
|
||||
Organization: strings.Join(name.Organization, ","),
|
||||
OrganizationalUnit: strings.Join(name.OrganizationalUnit, ","),
|
||||
Locality: strings.Join(name.Locality, ","),
|
||||
Province: strings.Join(name.Province, ","),
|
||||
StreetAddress: strings.Join(name.StreetAddress, ","),
|
||||
PostalCode: strings.Join(name.PostalCode, ","),
|
||||
}
|
||||
|
||||
for i := range name.Names {
|
||||
n.Names = append(n.Names, name.Names[i].Value)
|
||||
}
|
||||
|
||||
// ExtraNames aren't supported in Go 1.4
|
||||
// for i := range name.ExtraNames {
|
||||
// n.ExtraNames = append(n.ExtraNames, name.ExtraNames[i].Value)
|
||||
// }
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
func formatKeyID(id []byte) string {
|
||||
var s string
|
||||
|
||||
for i, c := range id {
|
||||
if i > 0 {
|
||||
s += ":"
|
||||
}
|
||||
s += fmt.Sprintf("%02X", c)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// ParseCertificate parses an x509 certificate.
|
||||
func ParseCertificate(cert *x509.Certificate) *Certificate {
|
||||
c := &Certificate{
|
||||
RawPEM: string(helpers.EncodeCertificatePEM(cert)),
|
||||
SignatureAlgorithm: helpers.SignatureString(cert.SignatureAlgorithm),
|
||||
NotBefore: cert.NotBefore,
|
||||
NotAfter: cert.NotAfter,
|
||||
Subject: ParseName(cert.Subject),
|
||||
Issuer: ParseName(cert.Issuer),
|
||||
SANs: cert.DNSNames,
|
||||
AKI: formatKeyID(cert.AuthorityKeyId),
|
||||
SKI: formatKeyID(cert.SubjectKeyId),
|
||||
SerialNumber: cert.SerialNumber.String(),
|
||||
}
|
||||
for _, ip := range cert.IPAddresses {
|
||||
c.SANs = append(c.SANs, ip.String())
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// ParseCertificateFile parses x509 certificate file.
|
||||
func ParseCertificateFile(certFile string) (*Certificate, error) {
|
||||
certPEM, err := ioutil.ReadFile(certFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseCertificatePEM(certPEM)
|
||||
}
|
||||
|
||||
// ParseCertificatePEM parses an x509 certificate PEM.
|
||||
func ParseCertificatePEM(certPEM []byte) (*Certificate, error) {
|
||||
cert, err := helpers.ParseCertificatePEM(certPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseCertificate(cert), nil
|
||||
}
|
||||
|
||||
// ParseCSRPEM uses the helper to parse an x509 CSR PEM.
|
||||
func ParseCSRPEM(csrPEM []byte) (*x509.CertificateRequest, error) {
|
||||
csrObject, err := helpers.ParseCSRPEM(csrPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return csrObject, nil
|
||||
}
|
||||
|
||||
// ParseCSRFile uses the helper to parse an x509 CSR PEM file.
|
||||
func ParseCSRFile(csrFile string) (*x509.CertificateRequest, error) {
|
||||
csrPEM, err := ioutil.ReadFile(csrFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ParseCSRPEM(csrPEM)
|
||||
}
|
||||
|
||||
// ParseCertificateDomain parses the certificate served by the given domain.
|
||||
func ParseCertificateDomain(domain string) (cert *Certificate, err error) {
|
||||
var host, port string
|
||||
if host, port, err = net.SplitHostPort(domain); err != nil {
|
||||
host = domain
|
||||
port = "443"
|
||||
}
|
||||
|
||||
var conn *tls.Conn
|
||||
conn, err = tls.DialWithDialer(&net.Dialer{Timeout: 10 * time.Second}, "tcp", net.JoinHostPort(host, port), &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if len(conn.ConnectionState().PeerCertificates) == 0 {
|
||||
return nil, errors.New("received no server certificates")
|
||||
}
|
||||
|
||||
cert = ParseCertificate(conn.ConnectionState().PeerCertificates[0])
|
||||
return
|
||||
}
|
53
vendor/github.com/cloudflare/cfssl/cli/BUILD
generated
vendored
Normal file
53
vendor/github.com/cloudflare/cfssl/cli/BUILD
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"cli.go",
|
||||
"config.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli",
|
||||
importpath = "github.com/cloudflare/cfssl/cli",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/config: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/signer/universal: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/cli/bundle:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/certinfo:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/crl:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencert:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencrl:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencsr:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/genkey:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/info:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspdump:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocsprefresh:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspserve:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspsign:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/printdefault:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/revoke:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/scan:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/selfsign:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/serve:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/sign:all-srcs",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/version:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
28
vendor/github.com/cloudflare/cfssl/cli/bundle/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/cli/bundle/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 = ["bundle.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/bundle",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/bundle",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/ubiquity: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"],
|
||||
)
|
88
vendor/github.com/cloudflare/cfssl/cli/bundle/bundle.go
generated
vendored
Normal file
88
vendor/github.com/cloudflare/cfssl/cli/bundle/bundle.go
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
// Package bundle implements the bundle command.
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/ubiquity"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl bundle'
|
||||
var bundlerUsageText = `cfssl bundle -- create a certificate bundle that contains the client cert
|
||||
|
||||
Usage of bundle:
|
||||
- Bundle local certificate files
|
||||
cfssl bundle -cert file [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file] [-key keyfile] [-flavor optimal|ubiquitous|force] [-password password]
|
||||
- Bundle certificate from remote server.
|
||||
cfssl bundle -domain domain_name [-ip ip_address] [-ca-bundle file] [-int-bundle file] [-int-dir dir] [-metadata file]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// flags used by 'cfssl bundle'
|
||||
var bundlerFlags = []string{"cert", "key", "ca-bundle", "int-bundle", "flavor", "int-dir", "metadata", "domain", "ip", "password"}
|
||||
|
||||
// bundlerMain is the main CLI of bundler functionality.
|
||||
func bundlerMain(args []string, c cli.Config) (err error) {
|
||||
bundler.IntermediateStash = c.IntDir
|
||||
ubiquity.LoadPlatforms(c.Metadata)
|
||||
flavor := bundler.BundleFlavor(c.Flavor)
|
||||
var b *bundler.Bundler
|
||||
// If it is a force bundle, don't require ca bundle and intermediate bundle
|
||||
// Otherwise, initialize a bundler with CA bundle and intermediate bundle.
|
||||
if flavor == bundler.Force {
|
||||
b = &bundler.Bundler{}
|
||||
} else {
|
||||
b, err = bundler.NewBundler(c.CABundleFile, c.IntBundleFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var bundle *bundler.Bundle
|
||||
if c.CertFile != "" {
|
||||
if c.CertFile == "-" {
|
||||
var certPEM, keyPEM []byte
|
||||
certPEM, err = cli.ReadStdin(c.CertFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if c.KeyFile != "" {
|
||||
keyPEM, err = cli.ReadStdin(c.KeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
bundle, err = b.BundleFromPEMorDER(certPEM, keyPEM, flavor, "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Bundle the client cert
|
||||
bundle, err = b.BundleFromFile(c.CertFile, c.KeyFile, flavor, c.Password)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if c.Domain != "" {
|
||||
bundle, err = b.BundleFromRemote(c.Domain, c.IP, flavor)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return errors.New("Must specify bundle target through -cert or -domain")
|
||||
}
|
||||
|
||||
marshaled, err := bundle.MarshalJSON()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s", marshaled)
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'bundle'
|
||||
var Command = &cli.Command{UsageText: bundlerUsageText, Flags: bundlerFlags, Main: bundlerMain}
|
27
vendor/github.com/cloudflare/cfssl/cli/certinfo/BUILD
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/cli/certinfo/BUILD
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
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/cli/certinfo",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/certinfo",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certinfo:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
89
vendor/github.com/cloudflare/cfssl/cli/certinfo/certinfo.go
generated
vendored
Normal file
89
vendor/github.com/cloudflare/cfssl/cli/certinfo/certinfo.go
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
// Package certinfo implements the certinfo command
|
||||
package certinfo
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cfssl/certinfo"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl certinfo'
|
||||
var dataUsageText = `cfssl certinfo -- output certinfo about the given cert
|
||||
|
||||
Usage of certinfo:
|
||||
- Data from local certificate files
|
||||
cfssl certinfo -cert file
|
||||
- Data from local CSR file
|
||||
cfssl certinfo -csr file
|
||||
- Data from certificate from remote server.
|
||||
cfssl certinfo -domain domain_name
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// flags used by 'cfssl certinfo'
|
||||
var certinfoFlags = []string{"cert", "csr", "domain"}
|
||||
|
||||
// certinfoMain is the main CLI of certinfo functionality
|
||||
func certinfoMain(args []string, c cli.Config) (err error) {
|
||||
var cert *certinfo.Certificate
|
||||
var csr *x509.CertificateRequest
|
||||
|
||||
if c.CertFile != "" {
|
||||
if c.CertFile == "-" {
|
||||
var certPEM []byte
|
||||
if certPEM, err = cli.ReadStdin(c.CertFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if cert, err = certinfo.ParseCertificatePEM(certPEM); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if cert, err = certinfo.ParseCertificateFile(c.CertFile); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if c.CSRFile != "" {
|
||||
if c.CSRFile == "-" {
|
||||
var csrPEM []byte
|
||||
if csrPEM, err = cli.ReadStdin(c.CSRFile); err != nil {
|
||||
return
|
||||
}
|
||||
if csr, err = certinfo.ParseCSRPEM(csrPEM); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if csr, err = certinfo.ParseCSRFile(c.CSRFile); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if c.Domain != "" {
|
||||
if cert, err = certinfo.ParseCertificateDomain(c.Domain); err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return errors.New("Must specify certinfo target through -cert, -csr, or -domain")
|
||||
}
|
||||
|
||||
var b []byte
|
||||
if cert != nil {
|
||||
b, err = json.MarshalIndent(cert, "", " ")
|
||||
} else if csr != nil {
|
||||
b, err = json.MarshalIndent(csr, "", " ")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(string(b))
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'certinfo'
|
||||
var Command = &cli.Command{UsageText: dataUsageText, Flags: certinfoFlags, Main: certinfoMain}
|
199
vendor/github.com/cloudflare/cfssl/cli/cli.go
generated
vendored
Normal file
199
vendor/github.com/cloudflare/cfssl/cli/cli.go
generated
vendored
Normal file
@@ -0,0 +1,199 @@
|
||||
// Package cli provides the template for adding new cfssl commands
|
||||
package cli
|
||||
|
||||
/*
|
||||
cfssl is the command line tool to issue/sign/bundle client certificate. It's
|
||||
also a tool to start a HTTP server to handle web requests for signing, bundling
|
||||
and verification.
|
||||
|
||||
Usage:
|
||||
cfssl command [-flags] arguments
|
||||
|
||||
The commands are defined in the cli subpackages and include
|
||||
|
||||
bundle create a certificate bundle
|
||||
sign signs a certificate signing request (CSR)
|
||||
serve starts a HTTP server handling sign and bundle requests
|
||||
version prints the current cfssl version
|
||||
genkey generates a key and an associated CSR
|
||||
gencert generates a key and a signed certificate
|
||||
gencsr generates a certificate request
|
||||
selfsign generates a self-signed certificate
|
||||
ocspsign signs an OCSP response
|
||||
|
||||
Use "cfssl [command] -help" to find out more about a command.
|
||||
*/
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
)
|
||||
|
||||
// Command holds the implementation details of a cfssl command.
|
||||
type Command struct {
|
||||
// The Usage Text
|
||||
UsageText string
|
||||
// Flags to look up in the global table
|
||||
Flags []string
|
||||
// Main runs the command, args are the arguments after flags
|
||||
Main func(args []string, c Config) error
|
||||
}
|
||||
|
||||
var cmdName string
|
||||
|
||||
// usage is the cfssl usage heading. It will be appended with names of defined commands in cmds
|
||||
// to form the final usage message of cfssl.
|
||||
const usage = `Usage:
|
||||
Available commands:
|
||||
`
|
||||
|
||||
// printDefaultValue is a helper function to print out a user friendly
|
||||
// usage message of a flag. It's useful since we want to write customized
|
||||
// usage message on selected subsets of the global flag set. It is
|
||||
// borrowed from standard library source code. Since flag value type is
|
||||
// not exported, default string flag values are printed without
|
||||
// quotes. The only exception is the empty string, which is printed as "".
|
||||
func printDefaultValue(f *flag.Flag) {
|
||||
format := " -%s=%s: %s\n"
|
||||
if f.DefValue == "" {
|
||||
format = " -%s=%q: %s\n"
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, format, f.Name, f.DefValue, f.Usage)
|
||||
}
|
||||
|
||||
// PopFirstArgument returns the first element and the rest of a string
|
||||
// slice and return error if failed to do so. It is a helper function
|
||||
// to parse non-flag arguments previously used in cfssl commands.
|
||||
func PopFirstArgument(args []string) (string, []string, error) {
|
||||
if len(args) < 1 {
|
||||
return "", nil, errors.New("not enough arguments are supplied --- please refer to the usage")
|
||||
}
|
||||
return args[0], args[1:], nil
|
||||
}
|
||||
|
||||
// Start is the entrance point of cfssl command line tools.
|
||||
func Start(cmds map[string]*Command) error {
|
||||
// cfsslFlagSet is the flag sets for cfssl.
|
||||
var cfsslFlagSet = flag.NewFlagSet("cfssl", flag.ExitOnError)
|
||||
var c Config
|
||||
|
||||
registerFlags(&c, cfsslFlagSet)
|
||||
// Initial parse of command line arguments. By convention, only -h/-help is supported.
|
||||
if flag.Usage == nil {
|
||||
flag.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, usage)
|
||||
for name := range cmds {
|
||||
fmt.Fprintf(os.Stderr, "\t%s\n", name)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "Top-level flags:\n")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
}
|
||||
|
||||
flag.Parse()
|
||||
|
||||
if flag.NArg() < 1 {
|
||||
fmt.Fprintf(os.Stderr, "No command is given.\n")
|
||||
flag.Usage()
|
||||
return errors.New("no command was given")
|
||||
}
|
||||
|
||||
// Clip out the command name and args for the command
|
||||
cmdName = flag.Arg(0)
|
||||
args := flag.Args()[1:]
|
||||
cmd, found := cmds[cmdName]
|
||||
if !found {
|
||||
fmt.Fprintf(os.Stderr, "Command %s is not defined.\n", cmdName)
|
||||
flag.Usage()
|
||||
return errors.New("undefined command")
|
||||
}
|
||||
// always have flag 'loglevel' for each command
|
||||
cmd.Flags = append(cmd.Flags, "loglevel")
|
||||
// The usage of each individual command is re-written to mention
|
||||
// flags defined and referenced only in that command.
|
||||
cfsslFlagSet.Usage = func() {
|
||||
fmt.Fprintf(os.Stderr, "\t%s", cmd.UsageText)
|
||||
for _, name := range cmd.Flags {
|
||||
if f := cfsslFlagSet.Lookup(name); f != nil {
|
||||
printDefaultValue(f)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all flags and take the rest as argument lists for the command
|
||||
cfsslFlagSet.Parse(args)
|
||||
args = cfsslFlagSet.Args()
|
||||
|
||||
var err error
|
||||
if c.ConfigFile != "" {
|
||||
c.CFG, err = config.LoadFile(c.ConfigFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to load config file: %v", err)
|
||||
return errors.New("failed to load config file")
|
||||
}
|
||||
}
|
||||
|
||||
if err := cmd.Main(args, c); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadStdin reads from stdin if the file is "-"
|
||||
func ReadStdin(filename string) ([]byte, error) {
|
||||
if filename == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
return ioutil.ReadFile(filename)
|
||||
}
|
||||
|
||||
// PrintCert outputs a cert, key and csr to stdout
|
||||
func PrintCert(key, csrBytes, cert []byte) {
|
||||
out := map[string]string{}
|
||||
if cert != nil {
|
||||
out["cert"] = string(cert)
|
||||
}
|
||||
|
||||
if key != nil {
|
||||
out["key"] = string(key)
|
||||
}
|
||||
|
||||
if csrBytes != nil {
|
||||
out["csr"] = string(csrBytes)
|
||||
}
|
||||
|
||||
jsonOut, err := json.Marshal(out)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s\n", jsonOut)
|
||||
}
|
||||
|
||||
// PrintOCSPResponse outputs an OCSP response to stdout
|
||||
// ocspResponse is base64 encoded
|
||||
func PrintOCSPResponse(resp []byte) {
|
||||
b64Resp := base64.StdEncoding.EncodeToString(resp)
|
||||
|
||||
out := map[string]string{"ocspResponse": b64Resp}
|
||||
jsonOut, err := json.Marshal(out)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Printf("%s\n", jsonOut)
|
||||
}
|
||||
|
||||
// PrintCRL outputs the CRL to stdout
|
||||
func PrintCRL(certList []byte) {
|
||||
b64Resp := base64.StdEncoding.EncodeToString(certList)
|
||||
|
||||
fmt.Printf("%s\n", b64Resp)
|
||||
}
|
143
vendor/github.com/cloudflare/cfssl/cli/config.go
generated
vendored
Normal file
143
vendor/github.com/cloudflare/cfssl/cli/config.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer/universal"
|
||||
)
|
||||
|
||||
// Config is a type to hold flag values used by cfssl commands.
|
||||
type Config struct {
|
||||
Hostname string
|
||||
CertFile string
|
||||
CSRFile string
|
||||
CAFile string
|
||||
CAKeyFile string
|
||||
TLSCertFile string
|
||||
TLSKeyFile string
|
||||
MutualTLSCAFile string
|
||||
MutualTLSCNRegex string
|
||||
TLSRemoteCAs string
|
||||
MutualTLSCertFile string
|
||||
MutualTLSKeyFile string
|
||||
KeyFile string
|
||||
IntermediatesFile string
|
||||
CABundleFile string
|
||||
IntBundleFile string
|
||||
Address string
|
||||
Port int
|
||||
Password string
|
||||
ConfigFile string
|
||||
CFG *config.Config
|
||||
Profile string
|
||||
IsCA bool
|
||||
RenewCA bool
|
||||
IntDir string
|
||||
Flavor string
|
||||
Metadata string
|
||||
Domain string
|
||||
IP string
|
||||
Remote string
|
||||
Label string
|
||||
AuthKey string
|
||||
ResponderFile string
|
||||
ResponderKeyFile string
|
||||
Status string
|
||||
Reason string
|
||||
RevokedAt string
|
||||
Interval time.Duration
|
||||
List bool
|
||||
Family string
|
||||
Timeout time.Duration
|
||||
Scanner string
|
||||
CSVFile string
|
||||
NumWorkers int
|
||||
MaxHosts int
|
||||
Responses string
|
||||
Path string
|
||||
CRL string
|
||||
Usage string
|
||||
PGPPrivate string
|
||||
PGPName string
|
||||
Serial string
|
||||
CNOverride string
|
||||
AKI string
|
||||
DBConfigFile string
|
||||
CRLExpiration time.Duration
|
||||
}
|
||||
|
||||
// registerFlags defines all cfssl command flags and associates their values with variables.
|
||||
func registerFlags(c *Config, f *flag.FlagSet) {
|
||||
f.StringVar(&c.Hostname, "hostname", "", "Hostname for the cert, could be a comma-separated hostname list")
|
||||
f.StringVar(&c.CertFile, "cert", "", "Client certificate that contains the public key")
|
||||
f.StringVar(&c.CSRFile, "csr", "", "Certificate signature request file for new public key")
|
||||
f.StringVar(&c.CAFile, "ca", "", "CA used to sign the new certificate -- accepts '[file:]fname' or 'env:varname'")
|
||||
f.StringVar(&c.CAKeyFile, "ca-key", "", "CA private key -- accepts '[file:]fname' or 'env:varname'")
|
||||
f.StringVar(&c.TLSCertFile, "tls-cert", "", "Other endpoint CA to set up TLS protocol")
|
||||
f.StringVar(&c.TLSKeyFile, "tls-key", "", "Other endpoint CA private key")
|
||||
f.StringVar(&c.MutualTLSCAFile, "mutual-tls-ca", "", "Mutual TLS - require clients be signed by this CA ")
|
||||
f.StringVar(&c.MutualTLSCNRegex, "mutual-tls-cn", "", "Mutual TLS - regex for whitelist of allowed client CNs")
|
||||
f.StringVar(&c.TLSRemoteCAs, "tls-remote-ca", "", "CAs to trust for remote TLS requests")
|
||||
f.StringVar(&c.MutualTLSCertFile, "mutual-tls-client-cert", "", "Mutual TLS - client certificate to call remote instance requiring client certs")
|
||||
f.StringVar(&c.MutualTLSKeyFile, "mutual-tls-client-key", "", "Mutual TLS - client key to call remote instance requiring client certs")
|
||||
f.StringVar(&c.KeyFile, "key", "", "private key for the certificate")
|
||||
f.StringVar(&c.IntermediatesFile, "intermediates", "", "intermediate certs")
|
||||
f.StringVar(&c.CABundleFile, "ca-bundle", "", "path to root certificate store")
|
||||
f.StringVar(&c.IntBundleFile, "int-bundle", "", "path to intermediate certificate store")
|
||||
f.StringVar(&c.Address, "address", "127.0.0.1", "Address to bind")
|
||||
f.IntVar(&c.Port, "port", 8888, "Port to bind")
|
||||
f.StringVar(&c.ConfigFile, "config", "", "path to configuration file")
|
||||
f.StringVar(&c.Profile, "profile", "", "signing profile to use")
|
||||
f.BoolVar(&c.IsCA, "initca", false, "initialise new CA")
|
||||
f.BoolVar(&c.RenewCA, "renewca", false, "re-generate a CA certificate from existing CA certificate/key")
|
||||
f.StringVar(&c.IntDir, "int-dir", "", "specify intermediates directory")
|
||||
f.StringVar(&c.Flavor, "flavor", "ubiquitous", "Bundle Flavor: ubiquitous, optimal and force.")
|
||||
f.StringVar(&c.Metadata, "metadata", "", "Metadata file for root certificate presence. The content of the file is a json dictionary (k,v): each key k is SHA-1 digest of a root certificate while value v is a list of key store filenames.")
|
||||
f.StringVar(&c.Domain, "domain", "", "remote server domain name")
|
||||
f.StringVar(&c.IP, "ip", "", "remote server ip")
|
||||
f.StringVar(&c.Remote, "remote", "", "remote CFSSL server")
|
||||
f.StringVar(&c.Label, "label", "", "key label to use in remote CFSSL server")
|
||||
f.StringVar(&c.AuthKey, "authkey", "", "key to authenticate requests to remote CFSSL server")
|
||||
f.StringVar(&c.ResponderFile, "responder", "", "Certificate for OCSP responder")
|
||||
f.StringVar(&c.ResponderKeyFile, "responder-key", "", "private key for OCSP responder certificate")
|
||||
f.StringVar(&c.Status, "status", "good", "Status of the certificate: good, revoked, unknown")
|
||||
f.StringVar(&c.Reason, "reason", "0", "Reason code for revocation")
|
||||
f.StringVar(&c.RevokedAt, "revoked-at", "now", "Date of revocation (YYYY-MM-DD)")
|
||||
f.DurationVar(&c.Interval, "interval", 4*helpers.OneDay, "Interval between OCSP updates (default: 96h)")
|
||||
f.BoolVar(&c.List, "list", false, "list possible scanners")
|
||||
f.StringVar(&c.Family, "family", "", "scanner family regular expression")
|
||||
f.StringVar(&c.Scanner, "scanner", "", "scanner regular expression")
|
||||
f.DurationVar(&c.Timeout, "timeout", 5*time.Minute, "duration (ns, us, ms, s, m, h) to scan each host before timing out")
|
||||
f.StringVar(&c.CSVFile, "csv", "", "file containing CSV of hosts")
|
||||
f.IntVar(&c.NumWorkers, "num-workers", 10, "number of workers to use for scan")
|
||||
f.IntVar(&c.MaxHosts, "max-hosts", 100, "maximum number of hosts to scan")
|
||||
f.StringVar(&c.Responses, "responses", "", "file to load OCSP responses from")
|
||||
f.StringVar(&c.Path, "path", "/", "Path on which the server will listen")
|
||||
f.StringVar(&c.CRL, "crl", "", "CRL URL Override")
|
||||
f.StringVar(&c.Password, "password", "0", "Password for accessing PKCS #12 data passed to bundler")
|
||||
f.StringVar(&c.Usage, "usage", "", "usage of private key")
|
||||
f.StringVar(&c.PGPPrivate, "pgp-private", "", "file to load a PGP Private key decryption")
|
||||
f.StringVar(&c.PGPName, "pgp-name", "", "PGP public key name, can be a comma-sepearted key name list")
|
||||
f.StringVar(&c.Serial, "serial", "", "certificate serial number")
|
||||
f.StringVar(&c.CNOverride, "cn", "", "certificate common name (CN)")
|
||||
f.StringVar(&c.AKI, "aki", "", "certificate issuer (authority) key identifier")
|
||||
f.StringVar(&c.DBConfigFile, "db-config", "", "certificate db configuration file")
|
||||
f.DurationVar(&c.CRLExpiration, "expiry", 7*helpers.OneDay, "time from now after which the CRL will expire (default: one week)")
|
||||
f.IntVar(&log.Level, "loglevel", log.LevelInfo, "Log level (0 = DEBUG, 5 = FATAL)")
|
||||
}
|
||||
|
||||
// RootFromConfig returns a universal signer Root structure that can
|
||||
// be used to produce a signer.
|
||||
func RootFromConfig(c *Config) universal.Root {
|
||||
return universal.Root{
|
||||
Config: map[string]string{
|
||||
"cert-file": c.CAFile,
|
||||
"key-file": c.CAKeyFile,
|
||||
},
|
||||
ForceRemote: c.Remote != "",
|
||||
}
|
||||
}
|
33
vendor/github.com/cloudflare/cfssl/cli/crl/BUILD
generated
vendored
Normal file
33
vendor/github.com/cloudflare/cfssl/cli/crl/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 = ["crl.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/crl",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/crl",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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",
|
||||
"//vendor/github.com/jmoiron/sqlx: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"],
|
||||
)
|
105
vendor/github.com/cloudflare/cfssl/cli/crl/crl.go
generated
vendored
Normal file
105
vendor/github.com/cloudflare/cfssl/cli/crl/crl.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
//Package crl implements the crl command
|
||||
package crl
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
certsql "github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/crl"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
var crlUsageText = `cfssl crl -- generate a new Certificate Revocation List from Database
|
||||
|
||||
Usage of crl:
|
||||
cfssl crl
|
||||
|
||||
Flags:
|
||||
`
|
||||
var crlFlags = []string{"db-config", "ca", "ca-key", "expiry"}
|
||||
|
||||
func generateCRL(c cli.Config) (crlBytes []byte, err error) {
|
||||
if c.CAFile == "" {
|
||||
log.Error("need CA certificate (provide one with -ca)")
|
||||
return
|
||||
}
|
||||
|
||||
if c.CAKeyFile == "" {
|
||||
log.Error("need CA key (provide one with -ca-key)")
|
||||
return
|
||||
}
|
||||
|
||||
var db *sqlx.DB
|
||||
if c.DBConfigFile != "" {
|
||||
db, err = dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
log.Error("no Database specified!")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dbAccessor := certsql.NewAccessor(db)
|
||||
|
||||
log.Debug("loading CA: ", c.CAFile)
|
||||
ca, err := helpers.ReadBytes(c.CAFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("loading CA key: ", c.CAKeyFile)
|
||||
cakey, err := helpers.ReadBytes(c.CAKeyFile)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.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
|
||||
}
|
||||
|
||||
certs, err := dbAccessor.GetRevokedAndUnexpiredCertificates()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req, err := crl.NewCRLFromDB(certs, issuerCert, key, c.CRLExpiration)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func crlMain(args []string, c cli.Config) (err error) {
|
||||
req, err := generateCRL(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cli.PrintCRL(req)
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'crl'
|
||||
var Command = &cli.Command{UsageText: crlUsageText, Flags: crlFlags, Main: crlMain}
|
33
vendor/github.com/cloudflare/cfssl/cli/gencert/BUILD
generated
vendored
Normal file
33
vendor/github.com/cloudflare/cfssl/cli/gencert/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 = ["gencert.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/gencert",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/gencert",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api/generator:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/genkey:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/sign:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/initca: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"],
|
||||
)
|
165
vendor/github.com/cloudflare/cfssl/cli/gencert/gencert.go
generated
vendored
Normal file
165
vendor/github.com/cloudflare/cfssl/cli/gencert/gencert.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
// Package gencert implements the gencert command.
|
||||
package gencert
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/cloudflare/cfssl/api/generator"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/cli/genkey"
|
||||
"github.com/cloudflare/cfssl/cli/sign"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/initca"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
)
|
||||
|
||||
var gencertUsageText = `cfssl gencert -- generate a new key and signed certificate
|
||||
|
||||
Usage of gencert:
|
||||
Generate a new key and cert from CSR:
|
||||
cfssl gencert -initca CSRJSON
|
||||
cfssl gencert -ca cert -ca-key key [-config config] [-profile profile] [-hostname hostname] CSRJSON
|
||||
cfssl gencert -remote remote_host [-config config] [-profile profile] [-label label] [-hostname hostname] CSRJSON
|
||||
|
||||
Re-generate a CA cert with the CA key and CSR:
|
||||
cfssl gencert -initca -ca-key key CSRJSON
|
||||
|
||||
Re-generate a CA cert with the CA key and certificate:
|
||||
cfssl gencert -renewca -ca cert -ca-key key
|
||||
|
||||
Arguments:
|
||||
CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var gencertFlags = []string{"initca", "remote", "ca", "ca-key", "config", "cn", "hostname", "profile", "label"}
|
||||
|
||||
func gencertMain(args []string, c cli.Config) error {
|
||||
if c.RenewCA {
|
||||
log.Infof("re-generate a CA certificate from CA cert and key")
|
||||
cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile)
|
||||
if err != nil {
|
||||
log.Errorf("%v\n", err)
|
||||
return err
|
||||
}
|
||||
cli.PrintCert(nil, nil, cert)
|
||||
return nil
|
||||
}
|
||||
|
||||
csrJSONFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
return errors.New("only one argument is accepted, please check with usage")
|
||||
}
|
||||
|
||||
csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req := csr.CertificateRequest{
|
||||
KeyRequest: csr.NewBasicKeyRequest(),
|
||||
}
|
||||
err = json.Unmarshal(csrJSONFileBytes, &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.CNOverride != "" {
|
||||
req.CN = c.CNOverride
|
||||
}
|
||||
switch {
|
||||
case c.IsCA:
|
||||
var key, csrPEM, cert []byte
|
||||
if c.CAKeyFile != "" {
|
||||
log.Infof("re-generate a CA certificate from CSR and CA key")
|
||||
cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile)
|
||||
if err != nil {
|
||||
log.Errorf("%v\n", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
log.Infof("generating a new CA key and certificate from CSR")
|
||||
cert, csrPEM, key, err = initca.New(&req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
cli.PrintCert(key, csrPEM, cert)
|
||||
|
||||
default:
|
||||
if req.CA != nil {
|
||||
err = errors.New("ca section only permitted in initca")
|
||||
return err
|
||||
}
|
||||
|
||||
if c.Hostname != "" {
|
||||
req.Hosts = signer.SplitHosts(c.Hostname)
|
||||
}
|
||||
// Remote can be forced on the command line or in the config
|
||||
if c.Remote == "" && c.CFG == nil {
|
||||
if c.CAFile == "" {
|
||||
log.Error("need a CA certificate (provide one with -ca)")
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.CAKeyFile == "" {
|
||||
log.Error("need a CA key (provide one with -ca-key)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
var key, csrBytes []byte
|
||||
g := &csr.Generator{Validator: genkey.Validator}
|
||||
csrBytes, key, err = g.ProcessRequest(&req)
|
||||
if err != nil {
|
||||
key = nil
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := sign.SignerFromConfig(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var cert []byte
|
||||
signReq := signer.SignRequest{
|
||||
Request: string(csrBytes),
|
||||
Hosts: signer.SplitHosts(c.Hostname),
|
||||
Profile: c.Profile,
|
||||
Label: c.Label,
|
||||
}
|
||||
|
||||
if c.CRL != "" {
|
||||
signReq.CRLOverride = c.CRL
|
||||
}
|
||||
cert, err = s.Sign(signReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// This follows 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"), states:
|
||||
//
|
||||
// "Applicant information MUST include, but not be limited to, at least one
|
||||
// Fully-Qualified Domain Name or IP address to be included in the Certificate’s
|
||||
// SubjectAltName extension."
|
||||
if len(signReq.Hosts) == 0 && len(req.Hosts) == 0 {
|
||||
log.Warning(generator.CSRNoHostMessage)
|
||||
}
|
||||
|
||||
cli.PrintCert(key, csrBytes, cert)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'gencert'
|
||||
var Command = &cli.Command{UsageText: gencertUsageText, Flags: gencertFlags, Main: gencertMain}
|
27
vendor/github.com/cloudflare/cfssl/cli/gencrl/BUILD
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/cli/gencrl/BUILD
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
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/cli/gencrl",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/gencrl",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/crl: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"],
|
||||
)
|
82
vendor/github.com/cloudflare/cfssl/cli/gencrl/gencrl.go
generated
vendored
Normal file
82
vendor/github.com/cloudflare/cfssl/cli/gencrl/gencrl.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
//Package gencrl implements the gencrl command
|
||||
package gencrl
|
||||
|
||||
import (
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/crl"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var gencrlUsageText = `cfssl gencrl -- generate a new Certificate Revocation List
|
||||
|
||||
Usage of gencrl:
|
||||
cfssl gencrl INPUTFILE CERT KEY TIME
|
||||
|
||||
Arguments:
|
||||
INPUTFILE: Text file with one serial number per line, use '-' for reading text from stdin
|
||||
CERT: The certificate that is signing this CRL, use '-' for reading text from stdin
|
||||
KEY: The private key of the certificate that is signing the CRL, use '-' for reading text from stdin
|
||||
TIME (OPTIONAL): The desired expiration from now, in seconds
|
||||
|
||||
Flags:
|
||||
`
|
||||
var gencrlFlags = []string{}
|
||||
|
||||
func gencrlMain(args []string, c cli.Config) (err error) {
|
||||
serialList, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
serialListBytes, err := cli.ReadStdin(serialList)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
certFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
certFileBytes, err := cli.ReadStdin(certFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keyFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
keyBytes, err := cli.ReadStdin(keyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Default value if no expiry time is given
|
||||
timeString := string("0")
|
||||
|
||||
if len(args) > 0 {
|
||||
timeArg, _, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
timeString = string(timeArg)
|
||||
|
||||
// This is used to get rid of newlines
|
||||
timeString = strings.TrimSpace(timeString)
|
||||
|
||||
}
|
||||
|
||||
req, err := crl.NewCRLFromFile(serialListBytes, certFileBytes, keyBytes, timeString)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cli.PrintCRL(req)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'gencrl'
|
||||
var Command = &cli.Command{UsageText: gencrlUsageText, Flags: gencrlFlags, Main: gencrlMain}
|
29
vendor/github.com/cloudflare/cfssl/cli/gencsr/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/cli/gencsr/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 = ["gencsr.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/gencsr",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/gencsr",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers: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"],
|
||||
)
|
99
vendor/github.com/cloudflare/cfssl/cli/gencsr/gencsr.go
generated
vendored
Normal file
99
vendor/github.com/cloudflare/cfssl/cli/gencsr/gencsr.go
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
// Package gencsr implements the gencsr command.
|
||||
package gencsr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
)
|
||||
|
||||
var gencsrUsageText = `cfssl gencsr -- generate a csr from a private key with existing CSR json specification or certificate
|
||||
|
||||
Usage of genkey:
|
||||
cfssl gencsr -key private_key_file [-host hostname_override] CSRJSON
|
||||
cfssl gencsr -key private_key_file [-host hostname_override] -cert certificate_file
|
||||
|
||||
Arguments:
|
||||
CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var gencsrFlags = []string{"key", "cert"}
|
||||
|
||||
func gencsrMain(args []string, c cli.Config) (err error) {
|
||||
if c.KeyFile == "" {
|
||||
return errors.New("private key file is required through '-key', please check with usage")
|
||||
}
|
||||
|
||||
keyBytes, err := helpers.ReadBytes(c.KeyFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// prepare a stub CertificateRequest
|
||||
req := &csr.CertificateRequest{
|
||||
KeyRequest: csr.NewBasicKeyRequest(),
|
||||
}
|
||||
|
||||
if c.CertFile != "" {
|
||||
if len(args) > 0 {
|
||||
return errors.New("no argument is accepted with '-cert', please check with usage")
|
||||
}
|
||||
|
||||
certBytes, err := helpers.ReadBytes(c.CertFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cert, err := helpers.ParseCertificatePEM(certBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req = csr.ExtractCertificateRequest(cert)
|
||||
} else {
|
||||
csrFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
return errors.New("only one argument is accepted, please check with usage")
|
||||
}
|
||||
|
||||
csrFileBytes, err := cli.ReadStdin(csrFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(csrFileBytes, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if c.Hostname != "" {
|
||||
req.Hosts = signer.SplitHosts(c.Hostname)
|
||||
}
|
||||
|
||||
csrBytes, err := csr.Generate(key, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cli.PrintCert(keyBytes, csrBytes, nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'gencsr'
|
||||
var Command = &cli.Command{UsageText: gencsrUsageText, Flags: gencsrFlags, Main: gencsrMain}
|
28
vendor/github.com/cloudflare/cfssl/cli/genkey/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/cli/genkey/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 = ["genkey.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/genkey",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/genkey",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/csr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/initca: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"],
|
||||
)
|
82
vendor/github.com/cloudflare/cfssl/cli/genkey/genkey.go
generated
vendored
Normal file
82
vendor/github.com/cloudflare/cfssl/cli/genkey/genkey.go
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
// Package genkey implements the genkey command.
|
||||
package genkey
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/initca"
|
||||
)
|
||||
|
||||
var genkeyUsageText = `cfssl genkey -- generate a new key and CSR
|
||||
|
||||
Usage of genkey:
|
||||
cfssl genkey CSRJSON
|
||||
|
||||
Arguments:
|
||||
CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var genkeyFlags = []string{"initca", "config"}
|
||||
|
||||
func genkeyMain(args []string, c cli.Config) (err error) {
|
||||
csrFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
return errors.New("only one argument is accepted, please check with usage")
|
||||
}
|
||||
|
||||
csrFileBytes, err := cli.ReadStdin(csrFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req := csr.CertificateRequest{
|
||||
KeyRequest: csr.NewBasicKeyRequest(),
|
||||
}
|
||||
err = json.Unmarshal(csrFileBytes, &req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if c.IsCA {
|
||||
var key, csrPEM, cert []byte
|
||||
cert, csrPEM, key, err = initca.New(&req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cli.PrintCert(key, csrPEM, cert)
|
||||
} else {
|
||||
if req.CA != nil {
|
||||
err = errors.New("ca section only permitted in initca")
|
||||
return
|
||||
}
|
||||
|
||||
var key, csrPEM []byte
|
||||
g := &csr.Generator{Validator: Validator}
|
||||
csrPEM, key, err = g.ProcessRequest(&req)
|
||||
if err != nil {
|
||||
key = nil
|
||||
return
|
||||
}
|
||||
|
||||
cli.PrintCert(key, csrPEM, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validator does nothing and will never return an error. It exists because creating a
|
||||
// csr.Generator requires a Validator.
|
||||
func Validator(req *csr.CertificateRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'genkey'
|
||||
var Command = &cli.Command{UsageText: genkeyUsageText, Flags: genkeyFlags, Main: genkeyMain}
|
31
vendor/github.com/cloudflare/cfssl/cli/info/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/cli/info/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 = ["info.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/info",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/info",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/api/client:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/sign: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/info: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"],
|
||||
)
|
110
vendor/github.com/cloudflare/cfssl/cli/info/info.go
generated
vendored
Normal file
110
vendor/github.com/cloudflare/cfssl/cli/info/info.go
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
// Package info implements the info command.
|
||||
package info
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cfssl/api/client"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/cli/sign"
|
||||
"github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/info"
|
||||
|
||||
goerr "errors"
|
||||
)
|
||||
|
||||
var infoUsageTxt = `cfssl info -- get info about a remote signer
|
||||
|
||||
Usage:
|
||||
|
||||
Get info about a remote signer:
|
||||
cfssl info -remote remote_host [-label label] [-profile profile] [-label label]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var infoFlags = []string{"remote", "label", "profile", "config"}
|
||||
|
||||
func getInfoFromRemote(c cli.Config) (resp *info.Resp, err error) {
|
||||
req := new(info.Req)
|
||||
req.Label = c.Label
|
||||
req.Profile = c.Profile
|
||||
|
||||
cert, err := helpers.LoadClientCertificate(c.MutualTLSCertFile, c.MutualTLSKeyFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
remoteCAs, err := helpers.LoadPEMCertPool(c.TLSRemoteCAs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
serv := client.NewServerTLS(c.Remote, helpers.CreateTLSConfig(remoteCAs, cert))
|
||||
reqJSON, _ := json.Marshal(req)
|
||||
resp, err = serv.Info(reqJSON)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
_, err = helpers.ParseCertificatePEM([]byte(resp.Certificate))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func getInfoFromConfig(c cli.Config) (resp *info.Resp, err error) {
|
||||
s, err := sign.SignerFromConfig(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req := new(info.Req)
|
||||
req.Label = c.Label
|
||||
req.Profile = c.Profile
|
||||
|
||||
resp, err = s.Info(*req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func infoMain(args []string, c cli.Config) (err error) {
|
||||
if len(args) > 0 {
|
||||
return goerr.New("argument is provided but not defined; please refer to the usage by flag -h.")
|
||||
}
|
||||
|
||||
var resp *info.Resp
|
||||
|
||||
if c.Remote != "" {
|
||||
resp, err = getInfoFromRemote(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else if c.CFG != nil {
|
||||
resp, err = getInfoFromConfig(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
return goerr.New("Either -remote or -config must be given. Refer to cfssl info -h for usage.")
|
||||
}
|
||||
|
||||
respJSON, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
return errors.NewBadRequest(err)
|
||||
}
|
||||
fmt.Print(string(respJSON))
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'info'
|
||||
var Command = &cli.Command{
|
||||
UsageText: infoUsageTxt,
|
||||
Flags: infoFlags,
|
||||
Main: infoMain,
|
||||
}
|
28
vendor/github.com/cloudflare/cfssl/cli/ocspdump/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/cli/ocspdump/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 = ["ocspdump.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/ocspdump",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/ocspdump",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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/cli/ocspdump/ocspdump.go
generated
vendored
Normal file
50
vendor/github.com/cloudflare/cfssl/cli/ocspdump/ocspdump.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
// Package ocspdump implements the ocspdump command.
|
||||
package ocspdump
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
"github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl ocspdump'
|
||||
var ocspdumpUsageText = `cfssl ocspdump -- generates a series of concatenated OCSP responses
|
||||
for use with ocspserve from all OCSP responses in the cert db
|
||||
|
||||
Usage of ocspdump:
|
||||
cfssl ocspdump -db-config db-config
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags of 'cfssl ocspdump'
|
||||
var ocspdumpFlags = []string{"db-config"}
|
||||
|
||||
// ocspdumpMain is the main CLI of OCSP dump functionality.
|
||||
func ocspdumpMain(args []string, c cli.Config) error {
|
||||
if c.DBConfigFile == "" {
|
||||
return errors.New("need DB config file (provide with -db-config)")
|
||||
}
|
||||
|
||||
db, err := dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbAccessor := sql.NewAccessor(db)
|
||||
records, err := dbAccessor.GetUnexpiredOCSPs()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, certRecord := range records {
|
||||
fmt.Printf("%s\n", base64.StdEncoding.EncodeToString([]byte(certRecord.Body)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'ocspdump'
|
||||
var Command = &cli.Command{UsageText: ocspdumpUsageText, Flags: ocspdumpFlags, Main: ocspdumpMain}
|
31
vendor/github.com/cloudflare/cfssl/cli/ocsprefresh/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/cli/ocsprefresh/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 = ["ocsprefresh.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/ocsprefresh",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/ocsprefresh",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
112
vendor/github.com/cloudflare/cfssl/cli/ocsprefresh/ocsprefresh.go
generated
vendored
Normal file
112
vendor/github.com/cloudflare/cfssl/cli/ocsprefresh/ocsprefresh.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Package ocsprefresh implements the ocsprefresh command.
|
||||
package ocsprefresh
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
"github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl ocsprefresh'
|
||||
var ocsprefreshUsageText = `cfssl ocsprefresh -- refreshes the ocsp_responses table
|
||||
with new OCSP responses for all known unexpired certificates
|
||||
|
||||
Usage of ocsprefresh:
|
||||
cfssl ocsprefresh -db-config db-config -ca cert -responder cert -responder-key key [-interval 96h]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags of 'cfssl ocsprefresh'
|
||||
var ocsprefreshFlags = []string{"ca", "responder", "responder-key", "db-config", "interval"}
|
||||
|
||||
// ocsprefreshMain is the main CLI of OCSP refresh functionality.
|
||||
func ocsprefreshMain(args []string, c cli.Config) error {
|
||||
if c.DBConfigFile == "" {
|
||||
return errors.New("need DB config file (provide with -db-config)")
|
||||
}
|
||||
|
||||
if c.ResponderFile == "" {
|
||||
return errors.New("need responder certificate (provide with -responder)")
|
||||
}
|
||||
|
||||
if c.ResponderKeyFile == "" {
|
||||
return errors.New("need responder key (provide with -responder-key)")
|
||||
}
|
||||
|
||||
if c.CAFile == "" {
|
||||
return errors.New("need CA certificate (provide with -ca)")
|
||||
}
|
||||
|
||||
s, err := SignerFromConfig(c)
|
||||
if err != nil {
|
||||
log.Critical("Unable to create OCSP signer: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
db, err := dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbAccessor := sql.NewAccessor(db)
|
||||
certs, err := dbAccessor.GetUnexpiredCertificates()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set an expiry timestamp for all certificates refreshed in this batch
|
||||
ocspExpiry := time.Now().Add(c.Interval)
|
||||
for _, certRecord := range certs {
|
||||
cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM))
|
||||
if err != nil {
|
||||
log.Critical("Unable to parse certificate: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
req := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: certRecord.Status,
|
||||
}
|
||||
|
||||
if certRecord.Status == "revoked" {
|
||||
req.Reason = int(certRecord.Reason)
|
||||
req.RevokedAt = certRecord.RevokedAt
|
||||
}
|
||||
|
||||
resp, err := s.Sign(req)
|
||||
if err != nil {
|
||||
log.Critical("Unable to sign OCSP response: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = dbAccessor.UpsertOCSP(cert.SerialNumber.String(), hex.EncodeToString(cert.AuthorityKeyId), string(resp), ocspExpiry)
|
||||
if err != nil {
|
||||
log.Critical("Unable to save OCSP response: ", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve
|
||||
func SignerFromConfig(c cli.Config) (ocsp.Signer, error) {
|
||||
//if this is called from serve then we need to use the specific responder key file
|
||||
//fallback to key for backwards-compatibility
|
||||
k := c.ResponderKeyFile
|
||||
if k == "" {
|
||||
k = c.KeyFile
|
||||
}
|
||||
return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval))
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'ocsprefresh'
|
||||
var Command = &cli.Command{UsageText: ocsprefreshUsageText, Flags: ocsprefreshFlags, Main: ocsprefreshMain}
|
28
vendor/github.com/cloudflare/cfssl/cli/ocspserve/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/cli/ocspserve/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 = ["ocspserve.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/ocspserve",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/ocspserve",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
62
vendor/github.com/cloudflare/cfssl/cli/ocspserve/ocspserve.go
generated
vendored
Normal file
62
vendor/github.com/cloudflare/cfssl/cli/ocspserve/ocspserve.go
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
// Package ocspserve implements the ocspserve function.
|
||||
package ocspserve
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl serve'
|
||||
var ocspServerUsageText = `cfssl ocspserve -- set up an HTTP server that handles OCSP requests from either a file or directly from a database (see RFC 5019)
|
||||
|
||||
Usage of ocspserve:
|
||||
cfssl ocspserve [-address address] [-port port] [-responses file] [-db-config db-config]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags used by 'cfssl serve'
|
||||
var ocspServerFlags = []string{"address", "port", "responses", "db-config"}
|
||||
|
||||
// ocspServerMain is the command line entry point to the OCSP responder.
|
||||
// It sets up a new HTTP server that responds to OCSP requests.
|
||||
func ocspServerMain(args []string, c cli.Config) error {
|
||||
var src ocsp.Source
|
||||
// serve doesn't support arguments.
|
||||
if len(args) > 0 {
|
||||
return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
|
||||
}
|
||||
|
||||
if c.Responses != "" {
|
||||
s, err := ocsp.NewSourceFromFile(c.Responses)
|
||||
if err != nil {
|
||||
return errors.New("unable to read response file")
|
||||
}
|
||||
src = s
|
||||
} else if c.DBConfigFile != "" {
|
||||
s, err := ocsp.NewSourceFromDB(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return errors.New("unable to read configuration file")
|
||||
}
|
||||
src = s
|
||||
} else {
|
||||
return errors.New(
|
||||
"no response file or db-config provided, please set the one of these using either -responses or -db-config flags",
|
||||
)
|
||||
}
|
||||
|
||||
log.Info("Registering OCSP responder handler")
|
||||
http.Handle(c.Path, ocsp.NewResponder(src))
|
||||
|
||||
addr := fmt.Sprintf("%s:%d", c.Address, c.Port)
|
||||
log.Info("Now listening on ", addr)
|
||||
return http.ListenAndServe(addr, nil)
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'ocspserve'
|
||||
var Command = &cli.Command{UsageText: ocspServerUsageText, Flags: ocspServerFlags, Main: ocspServerMain}
|
29
vendor/github.com/cloudflare/cfssl/cli/ocspsign/BUILD
generated
vendored
Normal file
29
vendor/github.com/cloudflare/cfssl/cli/ocspsign/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 = ["ocspsign.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/ocspsign",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/ocspsign",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
93
vendor/github.com/cloudflare/cfssl/cli/ocspsign/ocspsign.go
generated
vendored
Normal file
93
vendor/github.com/cloudflare/cfssl/cli/ocspsign/ocspsign.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// Package ocspsign implements the ocspsign command.
|
||||
package ocspsign
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl ocspsign'
|
||||
var ocspSignerUsageText = `cfssl ocspsign -- signs an OCSP response for a given CA, cert, and status.
|
||||
Returns a base64-encoded OCSP response.
|
||||
|
||||
Usage of ocspsign:
|
||||
cfssl ocspsign -ca cert -responder cert -responder-key key -cert cert [-status status] [-reason code] [-revoked-at YYYY-MM-DD] [-interval 96h]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags of 'cfssl ocspsign'
|
||||
var ocspSignerFlags = []string{"ca", "responder", "responder-key", "reason", "status", "revoked-at", "interval"}
|
||||
|
||||
// ocspSignerMain is the main CLI of OCSP signer functionality.
|
||||
func ocspSignerMain(args []string, c cli.Config) (err error) {
|
||||
// Read the cert to be revoked from file
|
||||
certBytes, err := ioutil.ReadFile(c.CertFile)
|
||||
if err != nil {
|
||||
log.Critical("Unable to read certificate: ", err)
|
||||
return
|
||||
}
|
||||
cert, err := helpers.ParseCertificatePEM(certBytes)
|
||||
if err != nil {
|
||||
log.Critical("Unable to parse certificate: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
req := ocsp.SignRequest{
|
||||
Certificate: cert,
|
||||
Status: c.Status,
|
||||
}
|
||||
|
||||
if c.Status == "revoked" {
|
||||
var reasonCode int
|
||||
reasonCode, err = ocsp.ReasonStringToCode(c.Reason)
|
||||
if err != nil {
|
||||
log.Critical("Invalid reason code: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
req.Reason = reasonCode
|
||||
req.RevokedAt = time.Now()
|
||||
if c.RevokedAt != "now" {
|
||||
req.RevokedAt, err = time.Parse("2006-01-02", c.RevokedAt)
|
||||
if err != nil {
|
||||
log.Critical("Malformed revocation time: ", c.RevokedAt)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s, err := SignerFromConfig(c)
|
||||
if err != nil {
|
||||
log.Critical("Unable to create OCSP signer: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
resp, err := s.Sign(req)
|
||||
if err != nil {
|
||||
log.Critical("Unable to sign OCSP response: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
cli.PrintOCSPResponse(resp)
|
||||
return
|
||||
}
|
||||
|
||||
// SignerFromConfig creates a signer from a cli.Config as a helper for cli and serve
|
||||
func SignerFromConfig(c cli.Config) (ocsp.Signer, error) {
|
||||
//if this is called from serve then we need to use the specific responder key file
|
||||
//fallback to key for backwards-compatibility
|
||||
k := c.ResponderKeyFile
|
||||
if k == "" {
|
||||
k = c.KeyFile
|
||||
}
|
||||
return ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, k, time.Duration(c.Interval))
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'ocspsign'
|
||||
var Command = &cli.Command{UsageText: ocspSignerUsageText, Flags: ocspSignerFlags, Main: ocspSignerMain}
|
27
vendor/github.com/cloudflare/cfssl/cli/printdefault/BUILD
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/cli/printdefault/BUILD
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"defaults.go",
|
||||
"printdefault.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/printdefault",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/printdefault",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
49
vendor/github.com/cloudflare/cfssl/cli/printdefault/defaults.go
generated
vendored
Normal file
49
vendor/github.com/cloudflare/cfssl/cli/printdefault/defaults.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package printdefaults
|
||||
|
||||
var defaults = map[string]string{
|
||||
"config": `{
|
||||
"signing": {
|
||||
"default": {
|
||||
"expiry": "168h"
|
||||
},
|
||||
"profiles": {
|
||||
"www": {
|
||||
"expiry": "8760h",
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"server auth"
|
||||
]
|
||||
},
|
||||
"client": {
|
||||
"expiry": "8760h",
|
||||
"usages": [
|
||||
"signing",
|
||||
"key encipherment",
|
||||
"client auth"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
"csr": `{
|
||||
"CN": "example.net",
|
||||
"hosts": [
|
||||
"example.net",
|
||||
"www.example.net"
|
||||
],
|
||||
"key": {
|
||||
"algo": "ecdsa",
|
||||
"size": 256
|
||||
},
|
||||
"names": [
|
||||
{
|
||||
"C": "US",
|
||||
"ST": "CA",
|
||||
"L": "San Francisco"
|
||||
}
|
||||
]
|
||||
}
|
||||
`,
|
||||
}
|
48
vendor/github.com/cloudflare/cfssl/cli/printdefault/printdefault.go
generated
vendored
Normal file
48
vendor/github.com/cloudflare/cfssl/cli/printdefault/printdefault.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package printdefaults
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
)
|
||||
|
||||
var printDefaultsUsage = `cfssl print-defaults -- print default configurations that can be used as a template
|
||||
|
||||
Usage of print-defaults:
|
||||
cfssl print-defaults TYPE
|
||||
|
||||
If "list" is used as the TYPE, the list of supported types will be printed.
|
||||
`
|
||||
|
||||
func printAvailable() {
|
||||
fmt.Println("Default configurations are available for:")
|
||||
for name := range defaults {
|
||||
fmt.Println("\t" + name)
|
||||
}
|
||||
}
|
||||
|
||||
func printDefaults(args []string, c cli.Config) (err error) {
|
||||
arg, _, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if arg == "list" {
|
||||
printAvailable()
|
||||
} else {
|
||||
if config, ok := defaults[arg]; !ok {
|
||||
printAvailable()
|
||||
} else {
|
||||
fmt.Println(config)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'print-defaults'
|
||||
var Command = &cli.Command{
|
||||
UsageText: printDefaultsUsage,
|
||||
Flags: []string{},
|
||||
Main: printDefaults,
|
||||
}
|
30
vendor/github.com/cloudflare/cfssl/cli/revoke/BUILD
generated
vendored
Normal file
30
vendor/github.com/cloudflare/cfssl/cli/revoke/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 = ["revoke.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/revoke",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/revoke",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
66
vendor/github.com/cloudflare/cfssl/cli/revoke/revoke.go
generated
vendored
Normal file
66
vendor/github.com/cloudflare/cfssl/cli/revoke/revoke.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
// Package revoke implements the revoke command.
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
"github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
)
|
||||
|
||||
var revokeUsageTxt = `cfssl revoke -- revoke a certificate in the certificate store
|
||||
|
||||
Usage:
|
||||
|
||||
Revoke a certificate:
|
||||
cfssl revoke -db-config config_file -serial serial -aki authority_key_id [-reason reason]
|
||||
|
||||
Reason can be an integer code or a string in ReasonFlags in RFC 5280
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var revokeFlags = []string{"serial", "reason"}
|
||||
|
||||
func revokeMain(args []string, c cli.Config) error {
|
||||
if len(args) > 0 {
|
||||
return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
|
||||
}
|
||||
|
||||
if len(c.Serial) == 0 {
|
||||
return errors.New("serial number is required but not provided")
|
||||
}
|
||||
|
||||
if len(c.AKI) == 0 {
|
||||
return errors.New("authority key id is required but not provided")
|
||||
}
|
||||
|
||||
if c.DBConfigFile == "" {
|
||||
return errors.New("need DB config file (provide with -db-config)")
|
||||
}
|
||||
|
||||
db, err := dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dbAccessor := sql.NewAccessor(db)
|
||||
|
||||
reasonCode, err := ocsp.ReasonStringToCode(c.Reason)
|
||||
if err != nil {
|
||||
log.Error("Invalid reason code: ", err)
|
||||
return err
|
||||
}
|
||||
|
||||
return dbAccessor.RevokeCertificate(c.Serial, c.AKI, reasonCode)
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'revoke'
|
||||
var Command = &cli.Command{
|
||||
UsageText: revokeUsageTxt,
|
||||
Flags: revokeFlags,
|
||||
Main: revokeMain,
|
||||
}
|
28
vendor/github.com/cloudflare/cfssl/cli/scan/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/cli/scan/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 = ["scan.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/scan",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/scan",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
123
vendor/github.com/cloudflare/cfssl/cli/scan/scan.go
generated
vendored
Normal file
123
vendor/github.com/cloudflare/cfssl/cli/scan/scan.go
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/scan"
|
||||
)
|
||||
|
||||
var scanUsageText = `cfssl scan -- scan a host for issues
|
||||
Usage of scan:
|
||||
cfssl scan [-family regexp] [-scanner regexp] [-timeout duration] [-ip IPAddr] [-num-workers num] [-max-hosts num] [-csv hosts.csv] HOST+
|
||||
cfssl scan -list
|
||||
|
||||
Arguments:
|
||||
HOST: Host(s) to scan (including port)
|
||||
Flags:
|
||||
`
|
||||
var scanFlags = []string{"list", "family", "scanner", "timeout", "ip", "ca-bundle", "num-workers", "csv", "max-hosts"}
|
||||
|
||||
func printJSON(v interface{}) {
|
||||
b, err := json.MarshalIndent(v, "", " ")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Printf("%s\n\n", b)
|
||||
}
|
||||
|
||||
type context struct {
|
||||
sync.WaitGroup
|
||||
c cli.Config
|
||||
hosts chan string
|
||||
}
|
||||
|
||||
func newContext(c cli.Config, numWorkers int) *context {
|
||||
ctx := &context{
|
||||
c: c,
|
||||
hosts: make(chan string, numWorkers),
|
||||
}
|
||||
ctx.Add(numWorkers)
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
go ctx.runWorker()
|
||||
}
|
||||
return ctx
|
||||
}
|
||||
|
||||
func (ctx *context) runWorker() {
|
||||
for host := range ctx.hosts {
|
||||
fmt.Printf("Scanning %s...\n", host)
|
||||
results, err := scan.Default.RunScans(host, ctx.c.IP, ctx.c.Family, ctx.c.Scanner, ctx.c.Timeout)
|
||||
fmt.Printf("=== %s ===\n", host)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
} else {
|
||||
printJSON(results)
|
||||
}
|
||||
}
|
||||
ctx.Done()
|
||||
}
|
||||
|
||||
func parseCSV(hosts []string, csvFile string, maxHosts int) ([]string, error) {
|
||||
f, err := os.Open(csvFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := csv.NewReader(f)
|
||||
for err == nil && len(hosts) < maxHosts {
|
||||
var record []string
|
||||
record, err = r.Read()
|
||||
hosts = append(hosts, record[len(record)-1])
|
||||
}
|
||||
if err == io.EOF {
|
||||
err = nil
|
||||
}
|
||||
|
||||
return hosts, err
|
||||
}
|
||||
|
||||
func scanMain(args []string, c cli.Config) (err error) {
|
||||
if c.List {
|
||||
printJSON(scan.Default)
|
||||
} else {
|
||||
if err = scan.LoadRootCAs(c.CABundleFile); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) >= c.MaxHosts {
|
||||
log.Warningf("Only scanning max-hosts=%d out of %d args given", c.MaxHosts, len(args))
|
||||
args = args[:c.MaxHosts]
|
||||
} else if c.CSVFile != "" {
|
||||
args, err = parseCSV(args, c.CSVFile, c.MaxHosts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx := newContext(c, c.NumWorkers)
|
||||
// Execute for each HOST argument given
|
||||
for len(args) > 0 {
|
||||
var host string
|
||||
host, args, err = cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
ctx.hosts <- host
|
||||
}
|
||||
close(ctx.hosts)
|
||||
ctx.Wait()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'scan'
|
||||
var Command = &cli.Command{UsageText: scanUsageText, Flags: scanFlags, Main: scanMain}
|
31
vendor/github.com/cloudflare/cfssl/cli/selfsign/BUILD
generated
vendored
Normal file
31
vendor/github.com/cloudflare/cfssl/cli/selfsign/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 = ["selfsign.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/selfsign",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/selfsign",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/genkey: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/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/selfsign: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"],
|
||||
)
|
120
vendor/github.com/cloudflare/cfssl/cli/selfsign/selfsign.go
generated
vendored
Normal file
120
vendor/github.com/cloudflare/cfssl/cli/selfsign/selfsign.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
// Package selfsign implements the selfsign command.
|
||||
package selfsign
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/cli/genkey"
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/selfsign"
|
||||
)
|
||||
|
||||
var selfSignUsageText = `cfssl selfsign -- generate a new self-signed key and signed certificate
|
||||
|
||||
Usage of gencert:
|
||||
cfssl selfsign HOSTNAME CSRJSON
|
||||
|
||||
WARNING: this should ONLY be used for testing. This should never be
|
||||
used in production.
|
||||
|
||||
WARNING: self-signed certificates are insecure; they do not provide
|
||||
the authentication required for secure systems. Use these at your own
|
||||
risk.
|
||||
|
||||
Arguments:
|
||||
HOSTNAME: Hostname for the cert
|
||||
CSRJSON: JSON file containing the request, use '-' for reading JSON from stdin
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
var selfSignFlags = []string{"config"}
|
||||
|
||||
func selfSignMain(args []string, c cli.Config) (err error) {
|
||||
if c.Hostname == "" && !c.IsCA {
|
||||
c.Hostname, args, err = cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
csrFile, args, err := cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(args) > 0 {
|
||||
return errors.New("too many arguments are provided, please check with usage")
|
||||
}
|
||||
|
||||
csrFileBytes, err := cli.ReadStdin(csrFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var req = csr.New()
|
||||
err = json.Unmarshal(csrFileBytes, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var key, csrPEM []byte
|
||||
g := &csr.Generator{Validator: genkey.Validator}
|
||||
csrPEM, key, err = g.ProcessRequest(req)
|
||||
if err != nil {
|
||||
key = nil
|
||||
return
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(key)
|
||||
if err != nil {
|
||||
key = nil
|
||||
return
|
||||
}
|
||||
|
||||
var profile *config.SigningProfile
|
||||
|
||||
// If there is a config, use its signing policy. Otherwise, leave policy == nil
|
||||
// and NewSigner will use DefaultConfig().
|
||||
if c.CFG != nil {
|
||||
if c.Profile != "" && c.CFG.Signing.Profiles != nil {
|
||||
profile = c.CFG.Signing.Profiles[c.Profile]
|
||||
}
|
||||
}
|
||||
|
||||
if profile == nil {
|
||||
profile = config.DefaultConfig()
|
||||
profile.Expiry = 2190 * time.Hour
|
||||
}
|
||||
|
||||
cert, err := selfsign.Sign(priv, csrPEM, profile)
|
||||
if err != nil {
|
||||
key = nil
|
||||
priv = nil
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(os.Stderr, `*** WARNING ***
|
||||
|
||||
Self-signed certificates are dangerous. Use this self-signed
|
||||
certificate at your own risk.
|
||||
|
||||
It is strongly recommended that these certificates NOT be used
|
||||
in production.
|
||||
|
||||
*** WARNING ***
|
||||
|
||||
`)
|
||||
cli.PrintCert(key, csrPEM, cert)
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'selfsign'
|
||||
var Command = &cli.Command{UsageText: selfSignUsageText, Flags: selfSignFlags, Main: selfSignMain}
|
50
vendor/github.com/cloudflare/cfssl/cli/serve/BUILD
generated
vendored
Normal file
50
vendor/github.com/cloudflare/cfssl/cli/serve/BUILD
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["serve.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/serve",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/serve",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/GeertJohan/go.rice:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/bundle:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/certinfo:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/crl:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/gencrl:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/generator:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/info:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/initca:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/ocsp:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/revoke:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/scan:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/api/signhandler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspsign:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/sign: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",
|
||||
"//vendor/github.com/cloudflare/cfssl/signer:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/ubiquity:go_default_library",
|
||||
"//vendor/github.com/jmoiron/sqlx: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"],
|
||||
)
|
13
vendor/github.com/cloudflare/cfssl/cli/serve/README.md
generated
vendored
Normal file
13
vendor/github.com/cloudflare/cfssl/cli/serve/README.md
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
## Compiling and serving static files using esc
|
||||
|
||||
```
|
||||
go install github.com/mjibson/esc
|
||||
|
||||
# Compile changes to static files
|
||||
cd $GOPATH/src/github.com/cloudflare/cfssl
|
||||
esc -pkg serve -prefix cli/serve/static cli/serve/static > cli/serve/static.go
|
||||
|
||||
# Build and run CFSSL
|
||||
go build ./cmd/cfssl/...
|
||||
./cfssl serve
|
||||
```
|
365
vendor/github.com/cloudflare/cfssl/cli/serve/serve.go
generated
vendored
Normal file
365
vendor/github.com/cloudflare/cfssl/cli/serve/serve.go
generated
vendored
Normal file
@@ -0,0 +1,365 @@
|
||||
// Package serve implements the serve command for CFSSL's API.
|
||||
package serve
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
rice "github.com/GeertJohan/go.rice"
|
||||
"github.com/cloudflare/cfssl/api"
|
||||
"github.com/cloudflare/cfssl/api/bundle"
|
||||
"github.com/cloudflare/cfssl/api/certinfo"
|
||||
"github.com/cloudflare/cfssl/api/crl"
|
||||
"github.com/cloudflare/cfssl/api/gencrl"
|
||||
"github.com/cloudflare/cfssl/api/generator"
|
||||
"github.com/cloudflare/cfssl/api/info"
|
||||
"github.com/cloudflare/cfssl/api/initca"
|
||||
apiocsp "github.com/cloudflare/cfssl/api/ocsp"
|
||||
"github.com/cloudflare/cfssl/api/revoke"
|
||||
"github.com/cloudflare/cfssl/api/scan"
|
||||
"github.com/cloudflare/cfssl/api/signhandler"
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
certsql "github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
ocspsign "github.com/cloudflare/cfssl/cli/ocspsign"
|
||||
"github.com/cloudflare/cfssl/cli/sign"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/ocsp"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/ubiquity"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl serve'
|
||||
var serverUsageText = `cfssl serve -- set up a HTTP server handles CF SSL requests
|
||||
|
||||
Usage of serve:
|
||||
cfssl serve [-address address] [-ca cert] [-ca-bundle bundle] \
|
||||
[-ca-key key] [-int-bundle bundle] [-int-dir dir] [-port port] \
|
||||
[-metadata file] [-remote remote_host] [-config config] \
|
||||
[-responder cert] [-responder-key key] [-tls-cert cert] [-tls-key key] \
|
||||
[-mutual-tls-ca ca] [-mutual-tls-cn regex] \
|
||||
[-tls-remote-ca ca] [-mutual-tls-client-cert cert] [-mutual-tls-client-key key] \
|
||||
[-db-config db-config]
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags used by 'cfssl serve'
|
||||
var serverFlags = []string{"address", "port", "ca", "ca-key", "ca-bundle", "int-bundle", "int-dir", "metadata",
|
||||
"remote", "config", "responder", "responder-key", "tls-key", "tls-cert", "mutual-tls-ca", "mutual-tls-cn",
|
||||
"tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config"}
|
||||
|
||||
var (
|
||||
conf cli.Config
|
||||
s signer.Signer
|
||||
ocspSigner ocsp.Signer
|
||||
db *sqlx.DB
|
||||
)
|
||||
|
||||
// V1APIPrefix is the prefix of all CFSSL V1 API Endpoints.
|
||||
var V1APIPrefix = "/api/v1/cfssl/"
|
||||
|
||||
// v1APIPath prepends the V1 API prefix to endpoints not beginning with "/"
|
||||
func v1APIPath(path string) string {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = V1APIPrefix + path
|
||||
}
|
||||
return (&url.URL{Path: path}).String()
|
||||
}
|
||||
|
||||
// httpBox implements http.FileSystem which allows the use of Box with a http.FileServer.
|
||||
// Atempting to Open an API endpoint will result in an error.
|
||||
type httpBox struct {
|
||||
*rice.Box
|
||||
redirects map[string]string
|
||||
}
|
||||
|
||||
func (hb *httpBox) findStaticBox() (err error) {
|
||||
hb.Box, err = rice.FindBox("static")
|
||||
return
|
||||
}
|
||||
|
||||
// Open returns a File for non-API enpoints using the http.File interface.
|
||||
func (hb *httpBox) Open(name string) (http.File, error) {
|
||||
if strings.HasPrefix(name, V1APIPrefix) {
|
||||
return nil, os.ErrNotExist
|
||||
}
|
||||
|
||||
if location, ok := hb.redirects[name]; ok {
|
||||
return hb.Box.Open(location)
|
||||
}
|
||||
|
||||
return hb.Box.Open(name)
|
||||
}
|
||||
|
||||
// staticBox is the box containing all static assets.
|
||||
var staticBox = &httpBox{
|
||||
redirects: map[string]string{
|
||||
"/scan": "/index.html",
|
||||
"/bundle": "/index.html",
|
||||
},
|
||||
}
|
||||
|
||||
var errBadSigner = errors.New("signer not initialized")
|
||||
var errNoCertDBConfigured = errors.New("cert db not configured (missing -db-config)")
|
||||
|
||||
var endpoints = map[string]func() (http.Handler, error){
|
||||
"sign": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
|
||||
h, err := signhandler.NewHandlerFromSigner(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if conf.CABundleFile != "" && conf.IntBundleFile != "" {
|
||||
sh := h.Handler.(*signhandler.Handler)
|
||||
if err := sh.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return h, nil
|
||||
},
|
||||
|
||||
"authsign": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
|
||||
h, err := signhandler.NewAuthHandlerFromSigner(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if conf.CABundleFile != "" && conf.IntBundleFile != "" {
|
||||
sh := h.(*api.HTTPHandler).Handler.(*signhandler.AuthHandler)
|
||||
if err := sh.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return h, nil
|
||||
},
|
||||
|
||||
"info": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
return info.NewHandler(s)
|
||||
},
|
||||
|
||||
"crl": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
|
||||
if db == nil {
|
||||
return nil, errNoCertDBConfigured
|
||||
}
|
||||
|
||||
return crl.NewHandler(certsql.NewAccessor(db), conf.CAFile, conf.CAKeyFile)
|
||||
},
|
||||
|
||||
"gencrl": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
return gencrl.NewHandler(), nil
|
||||
},
|
||||
|
||||
"newcert": func() (http.Handler, error) {
|
||||
if s == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
h := generator.NewCertGeneratorHandlerFromSigner(generator.CSRValidate, s)
|
||||
if conf.CABundleFile != "" && conf.IntBundleFile != "" {
|
||||
cg := h.(api.HTTPHandler).Handler.(*generator.CertGeneratorHandler)
|
||||
if err := cg.SetBundler(conf.CABundleFile, conf.IntBundleFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return h, nil
|
||||
},
|
||||
|
||||
"bundle": func() (http.Handler, error) {
|
||||
return bundle.NewHandler(conf.CABundleFile, conf.IntBundleFile)
|
||||
},
|
||||
|
||||
"newkey": func() (http.Handler, error) {
|
||||
return generator.NewHandler(generator.CSRValidate)
|
||||
},
|
||||
|
||||
"init_ca": func() (http.Handler, error) {
|
||||
return initca.NewHandler(), nil
|
||||
},
|
||||
|
||||
"scan": func() (http.Handler, error) {
|
||||
return scan.NewHandler(conf.CABundleFile)
|
||||
},
|
||||
|
||||
"scaninfo": func() (http.Handler, error) {
|
||||
return scan.NewInfoHandler(), nil
|
||||
},
|
||||
|
||||
"certinfo": func() (http.Handler, error) {
|
||||
return certinfo.NewHandler(), nil
|
||||
},
|
||||
|
||||
"ocspsign": func() (http.Handler, error) {
|
||||
if ocspSigner == nil {
|
||||
return nil, errBadSigner
|
||||
}
|
||||
return apiocsp.NewHandler(ocspSigner), nil
|
||||
},
|
||||
|
||||
"revoke": func() (http.Handler, error) {
|
||||
if db == nil {
|
||||
return nil, errNoCertDBConfigured
|
||||
}
|
||||
return revoke.NewHandler(certsql.NewAccessor(db)), nil
|
||||
},
|
||||
|
||||
"/": func() (http.Handler, error) {
|
||||
if err := staticBox.findStaticBox(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return http.FileServer(staticBox), nil
|
||||
},
|
||||
}
|
||||
|
||||
// registerHandlers instantiates various handlers and associate them to corresponding endpoints.
|
||||
func registerHandlers() {
|
||||
for path, getHandler := range endpoints {
|
||||
log.Debugf("getHandler for %s", path)
|
||||
if handler, err := getHandler(); err != nil {
|
||||
log.Warningf("endpoint '%s' is disabled: %v", path, err)
|
||||
} else {
|
||||
if path, handler, err = wrapHandler(path, handler, err); err != nil {
|
||||
log.Warningf("endpoint '%s' is disabled by wrapper: %v", path, err)
|
||||
} else {
|
||||
log.Infof("endpoint '%s' is enabled", path)
|
||||
http.Handle(path, handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Info("Handler set up complete.")
|
||||
}
|
||||
|
||||
// serverMain is the command line entry point to the API server. It sets up a
|
||||
// new HTTP server to handle sign, bundle, and validate requests.
|
||||
func serverMain(args []string, c cli.Config) error {
|
||||
conf = c
|
||||
// serve doesn't support arguments.
|
||||
if len(args) > 0 {
|
||||
return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
|
||||
}
|
||||
|
||||
bundler.IntermediateStash = conf.IntDir
|
||||
var err error
|
||||
|
||||
if err = ubiquity.LoadPlatforms(conf.Metadata); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if c.DBConfigFile != "" {
|
||||
db, err = dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("Initializing signer")
|
||||
|
||||
if s, err = sign.SignerFromConfigAndDB(c, db); err != nil {
|
||||
log.Warningf("couldn't initialize signer: %v", err)
|
||||
}
|
||||
|
||||
if ocspSigner, err = ocspsign.SignerFromConfig(c); err != nil {
|
||||
log.Warningf("couldn't initialize ocsp signer: %v", err)
|
||||
}
|
||||
|
||||
registerHandlers()
|
||||
|
||||
addr := net.JoinHostPort(conf.Address, strconv.Itoa(conf.Port))
|
||||
|
||||
if conf.TLSCertFile == "" || conf.TLSKeyFile == "" {
|
||||
log.Info("Now listening on ", addr)
|
||||
return http.ListenAndServe(addr, nil)
|
||||
}
|
||||
if conf.MutualTLSCAFile != "" {
|
||||
clientPool, err := helpers.LoadPEMCertPool(conf.MutualTLSCAFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load mutual TLS CA file: %s", err)
|
||||
}
|
||||
|
||||
server := http.Server{
|
||||
Addr: addr,
|
||||
TLSConfig: &tls.Config{
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
ClientCAs: clientPool,
|
||||
},
|
||||
}
|
||||
|
||||
if conf.MutualTLSCNRegex != "" {
|
||||
log.Debugf(`Requiring CN matches regex "%s" for client connections`, conf.MutualTLSCNRegex)
|
||||
re, err := regexp.Compile(conf.MutualTLSCNRegex)
|
||||
if err != nil {
|
||||
return fmt.Errorf("malformed CN regex: %s", err)
|
||||
}
|
||||
server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r != nil && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
|
||||
if re.MatchString(r.TLS.PeerCertificates[0].Subject.CommonName) {
|
||||
http.DefaultServeMux.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
log.Warningf(`Rejected client cert CN "%s" does not match regex %s`,
|
||||
r.TLS.PeerCertificates[0].Subject.CommonName, conf.MutualTLSCNRegex)
|
||||
}
|
||||
http.Error(w, "Invalid CN", http.StatusForbidden)
|
||||
})
|
||||
}
|
||||
log.Info("Now listening with mutual TLS on https://", addr)
|
||||
return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile)
|
||||
}
|
||||
log.Info("Now listening on https://", addr)
|
||||
return http.ListenAndServeTLS(addr, conf.TLSCertFile, conf.TLSKeyFile, nil)
|
||||
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'serve'
|
||||
var Command = &cli.Command{UsageText: serverUsageText, Flags: serverFlags, Main: serverMain}
|
||||
|
||||
var wrapHandler = defaultWrapHandler
|
||||
|
||||
// The default wrapper simply returns the normal handler and prefixes the path appropriately
|
||||
func defaultWrapHandler(path string, handler http.Handler, err error) (string, http.Handler, error) {
|
||||
return v1APIPath(path), handler, err
|
||||
}
|
||||
|
||||
// SetWrapHandler sets the wrap handler which is called for all endpoints
|
||||
// A custom wrap handler may be provided in order to add arbitrary server-side pre or post processing
|
||||
// of server-side HTTP handling of requests.
|
||||
func SetWrapHandler(wh func(path string, handler http.Handler, err error) (string, http.Handler, error)) {
|
||||
wrapHandler = wh
|
||||
}
|
||||
|
||||
// SetEndpoint can be used to add additional routes/endpoints to the HTTP server, or to override an existing route/endpoint
|
||||
func SetEndpoint(path string, getHandler func() (http.Handler, error)) {
|
||||
endpoints[path] = getHandler
|
||||
}
|
33
vendor/github.com/cloudflare/cfssl/cli/sign/BUILD
generated
vendored
Normal file
33
vendor/github.com/cloudflare/cfssl/cli/sign/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 = ["sign.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/sign",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/sign",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/config: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",
|
||||
"//vendor/github.com/jmoiron/sqlx: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"],
|
||||
)
|
181
vendor/github.com/cloudflare/cfssl/cli/sign/sign.go
generated
vendored
Normal file
181
vendor/github.com/cloudflare/cfssl/cli/sign/sign.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
// Package sign implements the sign command.
|
||||
package sign
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
certsql "github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/signer/universal"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// Usage text of 'cfssl sign'
|
||||
var signerUsageText = `cfssl sign -- signs a client cert with a host name by a given CA and CA key
|
||||
|
||||
Usage of sign:
|
||||
cfssl sign -ca cert -ca-key key [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-hostname hostname] [-db-config db-config] CSR [SUBJECT]
|
||||
cfssl sign -remote remote_host [mutual-tls-cert cert] [mutual-tls-key key] [-config config] [-profile profile] [-label label] [-hostname hostname] CSR [SUBJECT]
|
||||
|
||||
Arguments:
|
||||
CSR: PEM file for certificate request, use '-' for reading PEM from stdin.
|
||||
|
||||
Note: CSR can also be supplied via flag values; flag value will take precedence over the argument.
|
||||
|
||||
SUBJECT is an optional file containing subject information to use for the certificate instead of the subject information in the CSR.
|
||||
|
||||
Flags:
|
||||
`
|
||||
|
||||
// Flags of 'cfssl sign'
|
||||
var signerFlags = []string{"hostname", "csr", "ca", "ca-key", "config", "profile", "label", "remote",
|
||||
"mutual-tls-cert", "mutual-tls-key", "db-config"}
|
||||
|
||||
// SignerFromConfigAndDB takes the Config and creates the appropriate
|
||||
// signer.Signer object with a specified db
|
||||
func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) {
|
||||
// If there is a config, use its signing policy. Otherwise create a default policy.
|
||||
var policy *config.Signing
|
||||
if c.CFG != nil {
|
||||
policy = c.CFG.Signing
|
||||
} else {
|
||||
policy = &config.Signing{
|
||||
Profiles: map[string]*config.SigningProfile{},
|
||||
Default: config.DefaultConfig(),
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure the policy reflects the new remote
|
||||
if c.Remote != "" {
|
||||
err := policy.OverrideRemotes(c.Remote)
|
||||
if err != nil {
|
||||
log.Infof("Invalid remote %v, reverting to configuration default", c.Remote)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" {
|
||||
err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile)
|
||||
if err != nil {
|
||||
log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile)
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile)
|
||||
}
|
||||
|
||||
if c.TLSRemoteCAs != "" {
|
||||
err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs)
|
||||
if err != nil {
|
||||
log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs)
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs)
|
||||
}
|
||||
|
||||
s, err := universal.NewSigner(cli.RootFromConfig(&c), policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if db != nil {
|
||||
dbAccessor := certsql.NewAccessor(db)
|
||||
s.SetDBAccessor(dbAccessor)
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// SignerFromConfig takes the Config and creates the appropriate
|
||||
// signer.Signer object
|
||||
func SignerFromConfig(c cli.Config) (s signer.Signer, err error) {
|
||||
var db *sqlx.DB
|
||||
if c.DBConfigFile != "" {
|
||||
db, err = dbconf.DBFromConfig(c.DBConfigFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return SignerFromConfigAndDB(c, db)
|
||||
}
|
||||
|
||||
// signerMain is the main CLI of signer functionality.
|
||||
// [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs.
|
||||
func signerMain(args []string, c cli.Config) (err error) {
|
||||
if c.CSRFile == "" {
|
||||
c.CSRFile, args, err = cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var subjectData *signer.Subject
|
||||
if len(args) > 0 {
|
||||
var subjectFile string
|
||||
subjectFile, args, err = cli.PopFirstArgument(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(args) > 0 {
|
||||
return errors.New("too many arguments are provided, please check with usage")
|
||||
}
|
||||
|
||||
var subjectJSON []byte
|
||||
subjectJSON, err = ioutil.ReadFile(subjectFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
subjectData = new(signer.Subject)
|
||||
err = json.Unmarshal(subjectJSON, subjectData)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
csr, err := cli.ReadStdin(c.CSRFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Remote can be forced on the command line or in the config
|
||||
if c.Remote == "" && c.CFG == nil {
|
||||
if c.CAFile == "" {
|
||||
log.Error("need CA certificate (provide one with -ca)")
|
||||
return
|
||||
}
|
||||
|
||||
if c.CAKeyFile == "" {
|
||||
log.Error("need CA key (provide one with -ca-key)")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
s, err := SignerFromConfig(c)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
req := signer.SignRequest{
|
||||
Hosts: signer.SplitHosts(c.Hostname),
|
||||
Request: string(csr),
|
||||
Subject: subjectData,
|
||||
Profile: c.Profile,
|
||||
Label: c.Label,
|
||||
}
|
||||
cert, err := s.Sign(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cli.PrintCert(nil, csr, cert)
|
||||
return
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'sign'
|
||||
var Command = &cli.Command{UsageText: signerUsageText, Flags: signerFlags, Main: signerMain}
|
27
vendor/github.com/cloudflare/cfssl/cli/version/BUILD
generated
vendored
Normal file
27
vendor/github.com/cloudflare/cfssl/cli/version/BUILD
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"version.go",
|
||||
"version_dev.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cli/version",
|
||||
importpath = "github.com/cloudflare/cfssl/cli/version",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = ["//vendor/github.com/cloudflare/cfssl/cli: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"],
|
||||
)
|
42
vendor/github.com/cloudflare/cfssl/cli/version/version.go
generated
vendored
Normal file
42
vendor/github.com/cloudflare/cfssl/cli/version/version.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
// Package version implements the version command.
|
||||
package version
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
)
|
||||
|
||||
// Version stores the semantic versioning information for CFSSL.
|
||||
var version = struct {
|
||||
Major int
|
||||
Minor int
|
||||
Patch int
|
||||
Revision string
|
||||
}{1, 3, 0, "release"}
|
||||
|
||||
func versionString() string {
|
||||
return fmt.Sprintf("%d.%d.%d", version.Major, version.Minor, version.Patch)
|
||||
}
|
||||
|
||||
// Usage text for 'cfssl version'
|
||||
var versionUsageText = `cfssl version -- print out the version of CF SSL
|
||||
|
||||
Usage of version:
|
||||
cfssl version
|
||||
`
|
||||
|
||||
// FormatVersion returns the formatted version string.
|
||||
func FormatVersion() string {
|
||||
return fmt.Sprintf("Version: %s\nRevision: %s\nRuntime: %s\n", versionString(), version.Revision, runtime.Version())
|
||||
}
|
||||
|
||||
// The main functionality of 'cfssl version' is to print out the version info.
|
||||
func versionMain(args []string, c cli.Config) (err error) {
|
||||
fmt.Printf("%s", FormatVersion())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Command assembles the definition of Command 'version'
|
||||
var Command = &cli.Command{UsageText: versionUsageText, Flags: nil, Main: versionMain}
|
7
vendor/github.com/cloudflare/cfssl/cli/version/version_dev.go
generated
vendored
Normal file
7
vendor/github.com/cloudflare/cfssl/cli/version/version_dev.go
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// +build !release
|
||||
|
||||
package version
|
||||
|
||||
func init() {
|
||||
version.Revision = "dev"
|
||||
}
|
54
vendor/github.com/cloudflare/cfssl/cmd/cfssl/BUILD
generated
vendored
Normal file
54
vendor/github.com/cloudflare/cfssl/cmd/cfssl/BUILD
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["cfssl.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cmd/cfssl",
|
||||
importpath = "github.com/cloudflare/cfssl/cmd/cfssl",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/cli:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/bundle:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/certinfo:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/crl:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencert:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencrl:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/gencsr:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/genkey:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/info:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspdump:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocsprefresh:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspserve:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/ocspsign:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/printdefault:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/revoke:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/scan:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/selfsign:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/serve:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/sign:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/cli/version:go_default_library",
|
||||
"//vendor/github.com/go-sql-driver/mysql:go_default_library",
|
||||
"//vendor/github.com/lib/pq:go_default_library",
|
||||
"//vendor/github.com/mattn/go-sqlite3:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "cfssl",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
87
vendor/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go
generated
vendored
Normal file
87
vendor/github.com/cloudflare/cfssl/cmd/cfssl/cfssl.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
cfssl is the command line tool to issue/sign/bundle client certificate. It's
|
||||
also a tool to start a HTTP server to handle web requests for signing, bundling
|
||||
and verification.
|
||||
|
||||
Usage:
|
||||
cfssl command [-flags] arguments
|
||||
|
||||
The commands are
|
||||
|
||||
bundle create a certificate bundle
|
||||
sign signs a certificate signing request (CSR)
|
||||
serve starts a HTTP server handling sign and bundle requests
|
||||
version prints the current cfssl version
|
||||
genkey generates a key and an associated CSR
|
||||
gencert generates a key and a signed certificate
|
||||
gencsr generates a certificate request
|
||||
selfsign generates a self-signed certificate
|
||||
|
||||
Use "cfssl [command] -help" to find out more about a command.
|
||||
*/
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli"
|
||||
"github.com/cloudflare/cfssl/cli/bundle"
|
||||
"github.com/cloudflare/cfssl/cli/certinfo"
|
||||
"github.com/cloudflare/cfssl/cli/crl"
|
||||
"github.com/cloudflare/cfssl/cli/gencert"
|
||||
"github.com/cloudflare/cfssl/cli/gencrl"
|
||||
"github.com/cloudflare/cfssl/cli/gencsr"
|
||||
"github.com/cloudflare/cfssl/cli/genkey"
|
||||
"github.com/cloudflare/cfssl/cli/info"
|
||||
"github.com/cloudflare/cfssl/cli/ocspdump"
|
||||
"github.com/cloudflare/cfssl/cli/ocsprefresh"
|
||||
"github.com/cloudflare/cfssl/cli/ocspserve"
|
||||
"github.com/cloudflare/cfssl/cli/ocspsign"
|
||||
"github.com/cloudflare/cfssl/cli/printdefault"
|
||||
"github.com/cloudflare/cfssl/cli/revoke"
|
||||
"github.com/cloudflare/cfssl/cli/scan"
|
||||
"github.com/cloudflare/cfssl/cli/selfsign"
|
||||
"github.com/cloudflare/cfssl/cli/serve"
|
||||
"github.com/cloudflare/cfssl/cli/sign"
|
||||
"github.com/cloudflare/cfssl/cli/version"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql" // import to support MySQL
|
||||
_ "github.com/lib/pq" // import to support Postgres
|
||||
_ "github.com/mattn/go-sqlite3" // import to support SQLite3
|
||||
)
|
||||
|
||||
// main defines the cfssl usage and registers all defined commands and flags.
|
||||
func main() {
|
||||
// Add command names to cfssl usage
|
||||
flag.Usage = nil // this is set to nil for testabilty
|
||||
// Register commands.
|
||||
cmds := map[string]*cli.Command{
|
||||
"bundle": bundle.Command,
|
||||
"certinfo": certinfo.Command,
|
||||
"crl": crl.Command,
|
||||
"sign": sign.Command,
|
||||
"serve": serve.Command,
|
||||
"version": version.Command,
|
||||
"genkey": genkey.Command,
|
||||
"gencert": gencert.Command,
|
||||
"gencsr": gencsr.Command,
|
||||
"gencrl": gencrl.Command,
|
||||
"ocspdump": ocspdump.Command,
|
||||
"ocsprefresh": ocsprefresh.Command,
|
||||
"ocspsign": ocspsign.Command,
|
||||
"ocspserve": ocspserve.Command,
|
||||
"selfsign": selfsign.Command,
|
||||
"scan": scan.Command,
|
||||
"info": info.Command,
|
||||
"print-defaults": printdefaults.Command,
|
||||
"revoke": revoke.Command,
|
||||
}
|
||||
|
||||
// If the CLI returns an error, exit with an appropriate status
|
||||
// code.
|
||||
err := cli.Start(cmds)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
30
vendor/github.com/cloudflare/cfssl/cmd/cfssljson/BUILD
generated
vendored
Normal file
30
vendor/github.com/cloudflare/cfssl/cmd/cfssljson/BUILD
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["cfssljson.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/cmd/cfssljson",
|
||||
importpath = "github.com/cloudflare/cfssl/cmd/cfssljson",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = ["//vendor/github.com/cloudflare/cfssl/cli/version:go_default_library"],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "cfssljson",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
211
vendor/github.com/cloudflare/cfssl/cmd/cfssljson/cfssljson.go
generated
vendored
Normal file
211
vendor/github.com/cloudflare/cfssl/cmd/cfssljson/cfssljson.go
generated
vendored
Normal file
@@ -0,0 +1,211 @@
|
||||
// cfssljson splits out JSON with cert, csr, and key fields to separate
|
||||
// files.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/cloudflare/cfssl/cli/version"
|
||||
)
|
||||
|
||||
func readFile(filespec string) ([]byte, error) {
|
||||
if filespec == "-" {
|
||||
return ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
return ioutil.ReadFile(filespec)
|
||||
}
|
||||
|
||||
func writeFile(filespec, contents string, perms os.FileMode) {
|
||||
err := ioutil.WriteFile(filespec, []byte(contents), perms)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// ResponseMessage represents the format of a CFSSL output for an error or message
|
||||
type ResponseMessage struct {
|
||||
Code int `json:"int"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Response represents the format of a CFSSL output
|
||||
type Response struct {
|
||||
Success bool `json:"success"`
|
||||
Result map[string]interface{} `json:"result"`
|
||||
Errors []ResponseMessage `json:"errors"`
|
||||
Messages []ResponseMessage `json:"messages"`
|
||||
}
|
||||
|
||||
type outputFile struct {
|
||||
Filename string
|
||||
Contents string
|
||||
IsBinary bool
|
||||
Perms os.FileMode
|
||||
}
|
||||
|
||||
func main() {
|
||||
bare := flag.Bool("bare", false, "the response from CFSSL is not wrapped in the API standard response")
|
||||
inFile := flag.String("f", "-", "JSON input")
|
||||
output := flag.Bool("stdout", false, "output the response instead of saving to a file")
|
||||
printVersion := flag.Bool("version", false, "print version and exit")
|
||||
flag.Parse()
|
||||
|
||||
if *printVersion {
|
||||
fmt.Printf("%s", version.FormatVersion())
|
||||
return
|
||||
}
|
||||
|
||||
var baseName string
|
||||
if flag.NArg() == 0 {
|
||||
baseName = "cert"
|
||||
} else {
|
||||
baseName = flag.Arg(0)
|
||||
}
|
||||
|
||||
var input = map[string]interface{}{}
|
||||
var outs []outputFile
|
||||
var cert string
|
||||
var key string
|
||||
var csr string
|
||||
|
||||
fileData, err := readFile(*inFile)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to read input: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if *bare {
|
||||
err = json.Unmarshal(fileData, &input)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
} else {
|
||||
var response Response
|
||||
err = json.Unmarshal(fileData, &response)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to parse input: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if !response.Success {
|
||||
fmt.Fprintf(os.Stderr, "Request failed:\n")
|
||||
for _, msg := range response.Errors {
|
||||
fmt.Fprintf(os.Stderr, "\t%s\n", msg.Message)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
input = response.Result
|
||||
}
|
||||
|
||||
if contents, ok := input["cert"]; ok {
|
||||
cert = contents.(string)
|
||||
} else if contents, ok = input["certificate"]; ok {
|
||||
cert = contents.(string)
|
||||
}
|
||||
if cert != "" {
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + ".pem",
|
||||
Contents: cert,
|
||||
Perms: 0664,
|
||||
})
|
||||
}
|
||||
|
||||
if contents, ok := input["key"]; ok {
|
||||
key = contents.(string)
|
||||
} else if contents, ok = input["private_key"]; ok {
|
||||
key = contents.(string)
|
||||
}
|
||||
if key != "" {
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + "-key.pem",
|
||||
Contents: key,
|
||||
Perms: 0600,
|
||||
})
|
||||
}
|
||||
|
||||
if contents, ok := input["encrypted_key"]; ok {
|
||||
encKey := contents.(string)
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + "-key.enc",
|
||||
Contents: encKey,
|
||||
IsBinary: true,
|
||||
Perms: 0600,
|
||||
})
|
||||
}
|
||||
|
||||
if contents, ok := input["csr"]; ok {
|
||||
csr = contents.(string)
|
||||
} else if contents, ok = input["certificate_request"]; ok {
|
||||
csr = contents.(string)
|
||||
}
|
||||
if csr != "" {
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + ".csr",
|
||||
Contents: csr,
|
||||
Perms: 0644,
|
||||
})
|
||||
}
|
||||
|
||||
if result, ok := input["result"].(map[string]interface{}); ok {
|
||||
if bundle, ok := result["bundle"].(map[string]interface{}); ok {
|
||||
|
||||
// if we've gotten this deep then we're trying to parse out
|
||||
// a bundle, now we fail if we can't find the keys we need.
|
||||
|
||||
certificateBundle, ok := bundle["bundle"].(string)
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "inner bundle parsing failed!\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
rootCertificate, ok := bundle["root"].(string)
|
||||
if !ok {
|
||||
fmt.Fprintf(os.Stderr, "root parsing failed!\n")
|
||||
os.Exit(1)
|
||||
}
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + "-bundle.pem",
|
||||
Contents: certificateBundle + "\n" + rootCertificate,
|
||||
Perms: 0644,
|
||||
})
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + "-root.pem",
|
||||
Contents: rootCertificate,
|
||||
Perms: 0644,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if contents, ok := input["ocspResponse"]; ok {
|
||||
//ocspResponse is base64 encoded
|
||||
resp, err := base64.StdEncoding.DecodeString(contents.(string))
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to parse ocspResponse: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
outs = append(outs, outputFile{
|
||||
Filename: baseName + "-response.der",
|
||||
Contents: string(resp),
|
||||
IsBinary: true,
|
||||
Perms: 0644,
|
||||
})
|
||||
}
|
||||
|
||||
for _, e := range outs {
|
||||
if *output {
|
||||
if e.IsBinary {
|
||||
e.Contents = base64.StdEncoding.EncodeToString([]byte(e.Contents))
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, "%s\n", e.Contents)
|
||||
} else {
|
||||
writeFile(e.Filename, e.Contents, e.Perms)
|
||||
}
|
||||
}
|
||||
}
|
28
vendor/github.com/cloudflare/cfssl/crl/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/crl/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 = ["crl.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/crl",
|
||||
importpath = "github.com/cloudflare/cfssl/crl",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb: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"],
|
||||
)
|
108
vendor/github.com/cloudflare/cfssl/crl/crl.go
generated
vendored
Normal file
108
vendor/github.com/cloudflare/cfssl/crl/crl.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
// Package crl exposes Certificate Revocation List generation functionality
|
||||
package crl
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// NewCRLFromFile takes in a list of serial numbers, one per line, as well as the issuing certificate
|
||||
// of the CRL, and the private key. This function is then used to parse the list and generate a CRL
|
||||
func NewCRLFromFile(serialList, issuerFile, keyFile []byte, expiryTime string) ([]byte, error) {
|
||||
|
||||
var revokedCerts []pkix.RevokedCertificate
|
||||
var oneWeek = time.Duration(604800) * time.Second
|
||||
|
||||
expiryInt, err := strconv.ParseInt(expiryTime, 0, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newDurationFromInt := time.Duration(expiryInt) * time.Second
|
||||
newExpiryTime := time.Now().Add(newDurationFromInt)
|
||||
if expiryInt == 0 {
|
||||
newExpiryTime = time.Now().Add(oneWeek)
|
||||
}
|
||||
|
||||
// Parse the PEM encoded certificate
|
||||
issuerCert, err := helpers.ParseCertificatePEM(issuerFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Split input file by new lines
|
||||
individualCerts := strings.Split(string(serialList), "\n")
|
||||
|
||||
// For every new line, create a new revokedCertificate and add it to slice
|
||||
for _, value := range individualCerts {
|
||||
if len(strings.TrimSpace(value)) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
tempBigInt := new(big.Int)
|
||||
tempBigInt.SetString(value, 10)
|
||||
tempCert := pkix.RevokedCertificate{
|
||||
SerialNumber: tempBigInt,
|
||||
RevocationTime: time.Now(),
|
||||
}
|
||||
revokedCerts = append(revokedCerts, tempCert)
|
||||
}
|
||||
|
||||
strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
|
||||
password := []byte(strPassword)
|
||||
if strPassword == "" {
|
||||
password = nil
|
||||
}
|
||||
|
||||
// Parse the key given
|
||||
key, err := helpers.ParsePrivateKeyPEMWithPassword(keyFile, password)
|
||||
if err != nil {
|
||||
log.Debug("Malformed private key %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime)
|
||||
}
|
||||
|
||||
// NewCRLFromDB takes in a list of CertificateRecords, as well as the issuing certificate
|
||||
// of the CRL, and the private key. This function is then used to parse the records and generate a CRL
|
||||
func NewCRLFromDB(certs []certdb.CertificateRecord, issuerCert *x509.Certificate, key crypto.Signer, expiryTime time.Duration) ([]byte, error) {
|
||||
var revokedCerts []pkix.RevokedCertificate
|
||||
|
||||
newExpiryTime := time.Now().Add(expiryTime)
|
||||
|
||||
// For every record, create a new revokedCertificate and add it to slice
|
||||
for _, certRecord := range certs {
|
||||
serialInt := new(big.Int)
|
||||
serialInt.SetString(certRecord.Serial, 10)
|
||||
tempCert := pkix.RevokedCertificate{
|
||||
SerialNumber: serialInt,
|
||||
RevocationTime: certRecord.RevokedAt,
|
||||
}
|
||||
revokedCerts = append(revokedCerts, tempCert)
|
||||
}
|
||||
|
||||
return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime)
|
||||
}
|
||||
|
||||
// CreateGenericCRL is a helper function that takes in all of the information above, and then calls the createCRL
|
||||
// function. This outputs the bytes of the created CRL.
|
||||
func CreateGenericCRL(certList []pkix.RevokedCertificate, key crypto.Signer, issuingCert *x509.Certificate, expiryTime time.Time) ([]byte, error) {
|
||||
crlBytes, err := issuingCert.CreateCRL(rand.Reader, key, certList, time.Now(), expiryTime)
|
||||
if err != nil {
|
||||
log.Debug("error creating CRL: %s", err)
|
||||
}
|
||||
|
||||
return crlBytes, err
|
||||
|
||||
}
|
32
vendor/github.com/cloudflare/cfssl/initca/BUILD
generated
vendored
Normal file
32
vendor/github.com/cloudflare/cfssl/initca/BUILD
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
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/initca",
|
||||
importpath = "github.com/cloudflare/cfssl/initca",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//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/helpers: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/local: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"],
|
||||
)
|
249
vendor/github.com/cloudflare/cfssl/initca/initca.go
generated
vendored
Normal file
249
vendor/github.com/cloudflare/cfssl/initca/initca.go
generated
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
// Package initca contains code to initialise a certificate authority,
|
||||
// generating a new root key and certificate.
|
||||
package initca
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/config"
|
||||
"github.com/cloudflare/cfssl/csr"
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/cloudflare/cfssl/signer"
|
||||
"github.com/cloudflare/cfssl/signer/local"
|
||||
)
|
||||
|
||||
// validator contains the default validation logic for certificate
|
||||
// authority certificates. The only requirement here is that the
|
||||
// certificate have a non-empty subject field.
|
||||
func validator(req *csr.CertificateRequest) error {
|
||||
if req.CN != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(req.Names) == 0 {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
|
||||
}
|
||||
|
||||
for i := range req.Names {
|
||||
if csr.IsNameEmpty(req.Names[i]) {
|
||||
return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// New creates a new root certificate from the certificate request.
|
||||
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
|
||||
policy := CAPolicy()
|
||||
if req.CA != nil {
|
||||
if req.CA.Expiry != "" {
|
||||
policy.Default.ExpiryString = req.CA.Expiry
|
||||
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if req.CA.Backdate != "" {
|
||||
policy.Default.Backdate, err = time.ParseDuration(req.CA.Backdate)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
|
||||
if req.CA.PathLength != 0 && req.CA.PathLenZero {
|
||||
log.Infof("ignore invalid 'pathlenzero' value")
|
||||
} else {
|
||||
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
|
||||
}
|
||||
}
|
||||
|
||||
g := &csr.Generator{Validator: validator}
|
||||
csrPEM, key, err = g.ProcessRequest(req)
|
||||
if err != nil {
|
||||
log.Errorf("failed to process request: %v", err)
|
||||
key = nil
|
||||
return
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(key)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse private key: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create signer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
|
||||
cert, err = s.Sign(signReq)
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
// NewFromPEM creates a new root certificate from the key file passed in.
|
||||
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
|
||||
privData, err := helpers.ReadBytes(keyFile)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
priv, err := helpers.ParsePrivateKeyPEM(privData)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return NewFromSigner(req, priv)
|
||||
}
|
||||
|
||||
// RenewFromPEM re-creates a root certificate from the CA cert and key
|
||||
// files. The resulting root certificate will have the input CA certificate
|
||||
// as the template and have the same expiry length. E.g. the exsiting CA
|
||||
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
|
||||
// will be valid from now and expire in one year as well.
|
||||
func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
|
||||
caBytes, err := helpers.ReadBytes(caFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ca, err := helpers.ParseCertificatePEM(caBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
keyBytes, err := helpers.ReadBytes(keyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return RenewFromSigner(ca, key)
|
||||
}
|
||||
|
||||
// NewFromSigner creates a new root certificate from a crypto.Signer.
|
||||
func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
|
||||
policy := CAPolicy()
|
||||
if req.CA != nil {
|
||||
if req.CA.Expiry != "" {
|
||||
policy.Default.ExpiryString = req.CA.Expiry
|
||||
policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
|
||||
if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
|
||||
log.Infof("ignore invalid 'pathlenzero' value")
|
||||
} else {
|
||||
policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
|
||||
}
|
||||
}
|
||||
|
||||
csrPEM, err = csr.Generate(priv, req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
|
||||
if err != nil {
|
||||
log.Errorf("failed to create signer: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
signReq := signer.SignRequest{Request: string(csrPEM)}
|
||||
cert, err = s.Sign(signReq)
|
||||
return
|
||||
}
|
||||
|
||||
// RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer.
|
||||
// The resulting root certificate will have ca certificate
|
||||
// as the template and have the same expiry length. E.g. the exsiting CA
|
||||
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
|
||||
// will be valid from now and expire in one year as well.
|
||||
func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) {
|
||||
if !ca.IsCA {
|
||||
return nil, errors.New("input certificate is not a CA cert")
|
||||
}
|
||||
|
||||
// matching certificate public key vs private key
|
||||
switch {
|
||||
case ca.PublicKeyAlgorithm == x509.RSA:
|
||||
var rsaPublicKey *rsa.PublicKey
|
||||
var ok bool
|
||||
if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
case ca.PublicKeyAlgorithm == x509.ECDSA:
|
||||
var ecdsaPublicKey *ecdsa.PublicKey
|
||||
var ok bool
|
||||
if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch)
|
||||
}
|
||||
default:
|
||||
return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC)
|
||||
}
|
||||
|
||||
req := csr.ExtractCertificateRequest(ca)
|
||||
cert, _, err := NewFromSigner(req, priv)
|
||||
return cert, err
|
||||
|
||||
}
|
||||
|
||||
// CAPolicy contains the CA issuing policy as default policy.
|
||||
var CAPolicy = func() *config.Signing {
|
||||
return &config.Signing{
|
||||
Default: &config.SigningProfile{
|
||||
Usage: []string{"cert sign", "crl sign"},
|
||||
ExpiryString: "43800h",
|
||||
Expiry: 5 * helpers.OneYear,
|
||||
CAConstraint: config.CAConstraint{IsCA: true},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Update copies the CA certificate, updates the NotBefore and
|
||||
// NotAfter fields, and then re-signs the certificate.
|
||||
func Update(ca *x509.Certificate, priv crypto.Signer) (cert []byte, err error) {
|
||||
copy, err := x509.ParseCertificate(ca.Raw)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
validity := ca.NotAfter.Sub(ca.NotBefore)
|
||||
copy.NotBefore = time.Now().Round(time.Minute).Add(-5 * time.Minute)
|
||||
copy.NotAfter = copy.NotBefore.Add(validity)
|
||||
cert, err = x509.CreateCertificate(rand.Reader, copy, copy, priv.Public(), priv)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
|
||||
return
|
||||
}
|
39
vendor/github.com/cloudflare/cfssl/ocsp/BUILD
generated
vendored
Normal file
39
vendor/github.com/cloudflare/cfssl/ocsp/BUILD
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"ocsp.go",
|
||||
"responder.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/ocsp",
|
||||
importpath = "github.com/cloudflare/cfssl/ocsp",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/certdb/sql: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/jmhodges/clock: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",
|
||||
"//vendor/github.com/cloudflare/cfssl/ocsp/config:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
213
vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go
generated
vendored
Normal file
213
vendor/github.com/cloudflare/cfssl/ocsp/ocsp.go
generated
vendored
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
|
||||
Package ocsp exposes OCSP signing functionality, much like the signer
|
||||
package does for certificate signing. It also provies a basic OCSP
|
||||
responder stack for serving pre-signed OCSP responses.
|
||||
|
||||
*/
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"io/ioutil"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cferr "github.com/cloudflare/cfssl/errors"
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
// revocationReasonCodes is a map between string reason codes
|
||||
// to integers as defined in RFC 5280
|
||||
var revocationReasonCodes = map[string]int{
|
||||
"unspecified": ocsp.Unspecified,
|
||||
"keycompromise": ocsp.KeyCompromise,
|
||||
"cacompromise": ocsp.CACompromise,
|
||||
"affiliationchanged": ocsp.AffiliationChanged,
|
||||
"superseded": ocsp.Superseded,
|
||||
"cessationofoperation": ocsp.CessationOfOperation,
|
||||
"certificatehold": ocsp.CertificateHold,
|
||||
"removefromcrl": ocsp.RemoveFromCRL,
|
||||
"privilegewithdrawn": ocsp.PrivilegeWithdrawn,
|
||||
"aacompromise": ocsp.AACompromise,
|
||||
}
|
||||
|
||||
// StatusCode is a map between string statuses sent by cli/api
|
||||
// to ocsp int statuses
|
||||
var StatusCode = map[string]int{
|
||||
"good": ocsp.Good,
|
||||
"revoked": ocsp.Revoked,
|
||||
"unknown": ocsp.Unknown,
|
||||
}
|
||||
|
||||
// SignRequest represents the desired contents of a
|
||||
// specific OCSP response.
|
||||
type SignRequest struct {
|
||||
Certificate *x509.Certificate
|
||||
Status string
|
||||
Reason int
|
||||
RevokedAt time.Time
|
||||
Extensions []pkix.Extension
|
||||
// IssuerHash is the hashing function used to hash the issuer subject and public key
|
||||
// in the OCSP response. Valid values are crypto.SHA1, crypto.SHA256, crypto.SHA384,
|
||||
// and crypto.SHA512. If zero, the default is crypto.SHA1.
|
||||
IssuerHash crypto.Hash
|
||||
// If provided ThisUpdate will override the default usage of time.Now().Truncate(time.Hour)
|
||||
ThisUpdate *time.Time
|
||||
// If provided NextUpdate will override the default usage of ThisUpdate.Add(signerInterval)
|
||||
NextUpdate *time.Time
|
||||
}
|
||||
|
||||
// Signer represents a general signer of OCSP responses. It is
|
||||
// responsible for populating all fields in the OCSP response that
|
||||
// are not reflected in the SignRequest.
|
||||
type Signer interface {
|
||||
Sign(req SignRequest) ([]byte, error)
|
||||
}
|
||||
|
||||
// StandardSigner is the default concrete type of OCSP signer.
|
||||
// It represents a single responder (represented by a key and certificate)
|
||||
// speaking for a single issuer (certificate). It is assumed that OCSP
|
||||
// responses are issued at a regular interval, which is used to compute
|
||||
// the nextUpdate value based on the current time.
|
||||
type StandardSigner struct {
|
||||
issuer *x509.Certificate
|
||||
responder *x509.Certificate
|
||||
key crypto.Signer
|
||||
interval time.Duration
|
||||
}
|
||||
|
||||
// ReasonStringToCode tries to convert a reason string to an integer code
|
||||
func ReasonStringToCode(reason string) (reasonCode int, err error) {
|
||||
// default to 0
|
||||
if reason == "" {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
reasonCode, present := revocationReasonCodes[strings.ToLower(reason)]
|
||||
if !present {
|
||||
reasonCode, err = strconv.Atoi(reason)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if reasonCode >= ocsp.AACompromise || reasonCode <= ocsp.Unspecified {
|
||||
return 0, cferr.New(cferr.OCSPError, cferr.InvalidStatus)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NewSignerFromFile reads the issuer cert, the responder cert and the responder key
|
||||
// from PEM files, and takes an interval in seconds
|
||||
func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) {
|
||||
log.Debug("Loading issuer cert: ", issuerFile)
|
||||
issuerBytes, err := helpers.ReadBytes(issuerFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Loading responder cert: ", responderFile)
|
||||
responderBytes, err := ioutil.ReadFile(responderFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Debug("Loading responder key: ", keyFile)
|
||||
keyBytes, err := ioutil.ReadFile(keyFile)
|
||||
if err != nil {
|
||||
return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
|
||||
}
|
||||
|
||||
issuerCert, err := helpers.ParseCertificatePEM(issuerBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responderCert, err := helpers.ParseCertificatePEM(responderBytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := helpers.ParsePrivateKeyPEM(keyBytes)
|
||||
if err != nil {
|
||||
log.Debug("Malformed private key %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewSigner(issuerCert, responderCert, key, interval)
|
||||
}
|
||||
|
||||
// NewSigner simply constructs a new StandardSigner object from the inputs,
|
||||
// taking the interval in seconds
|
||||
func NewSigner(issuer, responder *x509.Certificate, key crypto.Signer, interval time.Duration) (Signer, error) {
|
||||
return &StandardSigner{
|
||||
issuer: issuer,
|
||||
responder: responder,
|
||||
key: key,
|
||||
interval: interval,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Sign is used with an OCSP signer to request the issuance of
|
||||
// an OCSP response.
|
||||
func (s StandardSigner) Sign(req SignRequest) ([]byte, error) {
|
||||
if req.Certificate == nil {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.ReadFailed)
|
||||
}
|
||||
|
||||
// Verify that req.Certificate is issued under s.issuer
|
||||
if bytes.Compare(req.Certificate.RawIssuer, s.issuer.RawSubject) != 0 {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch)
|
||||
}
|
||||
if req.Certificate.CheckSignatureFrom(s.issuer) != nil {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch)
|
||||
}
|
||||
|
||||
var thisUpdate, nextUpdate time.Time
|
||||
if req.ThisUpdate != nil {
|
||||
thisUpdate = *req.ThisUpdate
|
||||
} else {
|
||||
// Round thisUpdate times down to the nearest hour
|
||||
thisUpdate = time.Now().Truncate(time.Hour)
|
||||
}
|
||||
if req.NextUpdate != nil {
|
||||
nextUpdate = *req.NextUpdate
|
||||
} else {
|
||||
nextUpdate = thisUpdate.Add(s.interval)
|
||||
}
|
||||
|
||||
status, ok := StatusCode[req.Status]
|
||||
if !ok {
|
||||
return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus)
|
||||
}
|
||||
|
||||
// If the OCSP responder is the same as the issuer, there is no need to
|
||||
// include any certificate in the OCSP response, which decreases the byte size
|
||||
// of OCSP responses dramatically.
|
||||
certificate := s.responder
|
||||
if s.issuer == s.responder || bytes.Equal(s.issuer.Raw, s.responder.Raw) {
|
||||
certificate = nil
|
||||
}
|
||||
|
||||
template := ocsp.Response{
|
||||
Status: status,
|
||||
SerialNumber: req.Certificate.SerialNumber,
|
||||
ThisUpdate: thisUpdate,
|
||||
NextUpdate: nextUpdate,
|
||||
Certificate: certificate,
|
||||
ExtraExtensions: req.Extensions,
|
||||
IssuerHash: req.IssuerHash,
|
||||
}
|
||||
|
||||
if status == ocsp.Revoked {
|
||||
template.RevokedAt = req.RevokedAt
|
||||
template.RevocationReason = req.Reason
|
||||
}
|
||||
|
||||
return ocsp.CreateResponse(s.issuer, s.responder, template, s.key)
|
||||
}
|
349
vendor/github.com/cloudflare/cfssl/ocsp/responder.go
generated
vendored
Normal file
349
vendor/github.com/cloudflare/cfssl/ocsp/responder.go
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
// Package ocsp implements an OCSP responder based on a generic storage backend.
|
||||
// It provides a couple of sample implementations.
|
||||
// Because OCSP responders handle high query volumes, we have to be careful
|
||||
// about how much logging we do. Error-level logs are reserved for problems
|
||||
// internal to the server, that can be fixed by an administrator. Any type of
|
||||
// incorrect input from a user should be logged and Info or below. For things
|
||||
// that are logged on every request, Debug is the appropriate level.
|
||||
package ocsp
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/certdb"
|
||||
"github.com/cloudflare/cfssl/certdb/dbconf"
|
||||
"github.com/cloudflare/cfssl/certdb/sql"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
"github.com/jmhodges/clock"
|
||||
"golang.org/x/crypto/ocsp"
|
||||
)
|
||||
|
||||
var (
|
||||
malformedRequestErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x01}
|
||||
internalErrorErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x02}
|
||||
tryLaterErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x03}
|
||||
sigRequredErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x05}
|
||||
unauthorizedErrorResponse = []byte{0x30, 0x03, 0x0A, 0x01, 0x06}
|
||||
|
||||
// ErrNotFound indicates the request OCSP response was not found. It is used to
|
||||
// indicate that the responder should reply with unauthorizedErrorResponse.
|
||||
ErrNotFound = errors.New("Request OCSP Response not found")
|
||||
)
|
||||
|
||||
// Source represents the logical source of OCSP responses, i.e.,
|
||||
// the logic that actually chooses a response based on a request. In
|
||||
// order to create an actual responder, wrap one of these in a Responder
|
||||
// object and pass it to http.Handle. By default the Responder will set
|
||||
// the headers Cache-Control to "max-age=(response.NextUpdate-now), public, no-transform, must-revalidate",
|
||||
// Last-Modified to response.ThisUpdate, Expires to response.NextUpdate,
|
||||
// ETag to the SHA256 hash of the response, and Content-Type to
|
||||
// application/ocsp-response. If you want to override these headers,
|
||||
// or set extra headers, your source should return a http.Header
|
||||
// with the headers you wish to set. If you don't want to set any
|
||||
// extra headers you may return nil instead.
|
||||
type Source interface {
|
||||
Response(*ocsp.Request) ([]byte, http.Header, error)
|
||||
}
|
||||
|
||||
// An InMemorySource is a map from serialNumber -> der(response)
|
||||
type InMemorySource map[string][]byte
|
||||
|
||||
// Response looks up an OCSP response to provide for a given request.
|
||||
// InMemorySource looks up a response purely based on serial number,
|
||||
// without regard to what issuer the request is asking for.
|
||||
func (src InMemorySource) Response(request *ocsp.Request) ([]byte, http.Header, error) {
|
||||
response, present := src[request.SerialNumber.String()]
|
||||
if !present {
|
||||
return nil, nil, ErrNotFound
|
||||
}
|
||||
return response, nil, nil
|
||||
}
|
||||
|
||||
// DBSource represnts a source of OCSP responses backed by the certdb package.
|
||||
type DBSource struct {
|
||||
Accessor certdb.Accessor
|
||||
}
|
||||
|
||||
// NewDBSource creates a new DBSource type with an associated dbAccessor.
|
||||
func NewDBSource(dbAccessor certdb.Accessor) Source {
|
||||
return DBSource{
|
||||
Accessor: dbAccessor,
|
||||
}
|
||||
}
|
||||
|
||||
// Response implements cfssl.ocsp.responder.Source, which returns the
|
||||
// OCSP response in the Database for the given request with the expiration
|
||||
// date furthest in the future.
|
||||
func (src DBSource) Response(req *ocsp.Request) ([]byte, http.Header, error) {
|
||||
if req == nil {
|
||||
return nil, nil, errors.New("called with nil request")
|
||||
}
|
||||
|
||||
aki := hex.EncodeToString(req.IssuerKeyHash)
|
||||
sn := req.SerialNumber
|
||||
|
||||
if sn == nil {
|
||||
return nil, nil, errors.New("request contains no serial")
|
||||
}
|
||||
strSN := sn.String()
|
||||
|
||||
if src.Accessor == nil {
|
||||
log.Errorf("No DB Accessor")
|
||||
return nil, nil, errors.New("called with nil DB accessor")
|
||||
}
|
||||
records, err := src.Accessor.GetOCSP(strSN, aki)
|
||||
|
||||
// Response() logs when there are errors obtaining the OCSP response
|
||||
// and returns nil, false.
|
||||
if err != nil {
|
||||
log.Errorf("Error obtaining OCSP response: %s", err)
|
||||
return nil, nil, fmt.Errorf("failed to obtain OCSP response: %s", err)
|
||||
}
|
||||
|
||||
if len(records) == 0 {
|
||||
return nil, nil, ErrNotFound
|
||||
}
|
||||
|
||||
// Response() finds the OCSPRecord with the expiration date furthest in the future.
|
||||
cur := records[0]
|
||||
for _, rec := range records {
|
||||
if rec.Expiry.After(cur.Expiry) {
|
||||
cur = rec
|
||||
}
|
||||
}
|
||||
return []byte(cur.Body), nil, nil
|
||||
}
|
||||
|
||||
// NewSourceFromFile reads the named file into an InMemorySource.
|
||||
// The file read by this function must contain whitespace-separated OCSP
|
||||
// responses. Each OCSP response must be in base64-encoded DER form (i.e.,
|
||||
// PEM without headers or whitespace). Invalid responses are ignored.
|
||||
// This function pulls the entire file into an InMemorySource.
|
||||
func NewSourceFromFile(responseFile string) (Source, error) {
|
||||
fileContents, err := ioutil.ReadFile(responseFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
responsesB64 := regexp.MustCompile("\\s").Split(string(fileContents), -1)
|
||||
src := InMemorySource{}
|
||||
for _, b64 := range responsesB64 {
|
||||
// if the line/space is empty just skip
|
||||
if b64 == "" {
|
||||
continue
|
||||
}
|
||||
der, tmpErr := base64.StdEncoding.DecodeString(b64)
|
||||
if tmpErr != nil {
|
||||
log.Errorf("Base64 decode error %s on: %s", tmpErr, b64)
|
||||
continue
|
||||
}
|
||||
|
||||
response, tmpErr := ocsp.ParseResponse(der, nil)
|
||||
if tmpErr != nil {
|
||||
log.Errorf("OCSP decode error %s on: %s", tmpErr, b64)
|
||||
continue
|
||||
}
|
||||
|
||||
src[response.SerialNumber.String()] = der
|
||||
}
|
||||
|
||||
log.Infof("Read %d OCSP responses", len(src))
|
||||
return src, nil
|
||||
}
|
||||
|
||||
// NewSourceFromDB reads the given database configuration file
|
||||
// and creates a database data source for use with the OCSP responder
|
||||
func NewSourceFromDB(DBConfigFile string) (Source, error) {
|
||||
// Load DB from cofiguration file
|
||||
db, err := dbconf.DBFromConfig(DBConfigFile)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Create accesor
|
||||
accessor := sql.NewAccessor(db)
|
||||
src := NewDBSource(accessor)
|
||||
|
||||
return src, nil
|
||||
}
|
||||
|
||||
// A Responder object provides the HTTP logic to expose a
|
||||
// Source of OCSP responses.
|
||||
type Responder struct {
|
||||
Source Source
|
||||
clk clock.Clock
|
||||
}
|
||||
|
||||
// NewResponder instantiates a Responder with the give Source.
|
||||
func NewResponder(source Source) *Responder {
|
||||
return &Responder{
|
||||
Source: source,
|
||||
clk: clock.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func overrideHeaders(response http.ResponseWriter, headers http.Header) {
|
||||
for k, v := range headers {
|
||||
if len(v) == 1 {
|
||||
response.Header().Set(k, v[0])
|
||||
} else if len(v) > 1 {
|
||||
response.Header().Del(k)
|
||||
for _, e := range v {
|
||||
response.Header().Add(k, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A Responder can process both GET and POST requests. The mapping
|
||||
// from an OCSP request to an OCSP response is done by the Source;
|
||||
// the Responder simply decodes the request, and passes back whatever
|
||||
// response is provided by the source.
|
||||
// Note: The caller must use http.StripPrefix to strip any path components
|
||||
// (including '/') on GET requests.
|
||||
// Do not use this responder in conjunction with http.NewServeMux, because the
|
||||
// default handler will try to canonicalize path components by changing any
|
||||
// strings of repeated '/' into a single '/', which will break the base64
|
||||
// encoding.
|
||||
func (rs Responder) ServeHTTP(response http.ResponseWriter, request *http.Request) {
|
||||
// By default we set a 'max-age=0, no-cache' Cache-Control header, this
|
||||
// is only returned to the client if a valid authorized OCSP response
|
||||
// is not found or an error is returned. If a response if found the header
|
||||
// will be altered to contain the proper max-age and modifiers.
|
||||
response.Header().Add("Cache-Control", "max-age=0, no-cache")
|
||||
// Read response from request
|
||||
var requestBody []byte
|
||||
var err error
|
||||
switch request.Method {
|
||||
case "GET":
|
||||
base64Request, err := url.QueryUnescape(request.URL.Path)
|
||||
if err != nil {
|
||||
log.Debugf("Error decoding URL: %s", request.URL.Path)
|
||||
response.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
// url.QueryUnescape not only unescapes %2B escaping, but it additionally
|
||||
// turns the resulting '+' into a space, which makes base64 decoding fail.
|
||||
// So we go back afterwards and turn ' ' back into '+'. This means we
|
||||
// accept some malformed input that includes ' ' or %20, but that's fine.
|
||||
base64RequestBytes := []byte(base64Request)
|
||||
for i := range base64RequestBytes {
|
||||
if base64RequestBytes[i] == ' ' {
|
||||
base64RequestBytes[i] = '+'
|
||||
}
|
||||
}
|
||||
// In certain situations a UA may construct a request that has a double
|
||||
// slash between the host name and the base64 request body due to naively
|
||||
// constructing the request URL. In that case strip the leading slash
|
||||
// so that we can still decode the request.
|
||||
if len(base64RequestBytes) > 0 && base64RequestBytes[0] == '/' {
|
||||
base64RequestBytes = base64RequestBytes[1:]
|
||||
}
|
||||
requestBody, err = base64.StdEncoding.DecodeString(string(base64RequestBytes))
|
||||
if err != nil {
|
||||
log.Debugf("Error decoding base64 from URL: %s", string(base64RequestBytes))
|
||||
response.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
case "POST":
|
||||
requestBody, err = ioutil.ReadAll(request.Body)
|
||||
if err != nil {
|
||||
log.Errorf("Problem reading body of POST: %s", err)
|
||||
response.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
default:
|
||||
response.WriteHeader(http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
b64Body := base64.StdEncoding.EncodeToString(requestBody)
|
||||
log.Debugf("Received OCSP request: %s", b64Body)
|
||||
|
||||
// All responses after this point will be OCSP.
|
||||
// We could check for the content type of the request, but that
|
||||
// seems unnecessariliy restrictive.
|
||||
response.Header().Add("Content-Type", "application/ocsp-response")
|
||||
|
||||
// Parse response as an OCSP request
|
||||
// XXX: This fails if the request contains the nonce extension.
|
||||
// We don't intend to support nonces anyway, but maybe we
|
||||
// should return unauthorizedRequest instead of malformed.
|
||||
ocspRequest, err := ocsp.ParseRequest(requestBody)
|
||||
if err != nil {
|
||||
log.Debugf("Error decoding request body: %s", b64Body)
|
||||
response.WriteHeader(http.StatusBadRequest)
|
||||
response.Write(malformedRequestErrorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
// Look up OCSP response from source
|
||||
ocspResponse, headers, err := rs.Source.Response(ocspRequest)
|
||||
if err != nil {
|
||||
if err == ErrNotFound {
|
||||
log.Infof("No response found for request: serial %x, request body %s",
|
||||
ocspRequest.SerialNumber, b64Body)
|
||||
response.Write(unauthorizedErrorResponse)
|
||||
return
|
||||
}
|
||||
log.Infof("Error retrieving response for request: serial %x, request body %s, error: %s",
|
||||
ocspRequest.SerialNumber, b64Body, err)
|
||||
response.WriteHeader(http.StatusInternalServerError)
|
||||
response.Write(internalErrorErrorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
parsedResponse, err := ocsp.ParseResponse(ocspResponse, nil)
|
||||
if err != nil {
|
||||
log.Errorf("Error parsing response for serial %x: %s",
|
||||
ocspRequest.SerialNumber, err)
|
||||
response.Write(unauthorizedErrorResponse)
|
||||
return
|
||||
}
|
||||
|
||||
// Write OCSP response to response
|
||||
response.Header().Add("Last-Modified", parsedResponse.ThisUpdate.Format(time.RFC1123))
|
||||
response.Header().Add("Expires", parsedResponse.NextUpdate.Format(time.RFC1123))
|
||||
now := rs.clk.Now()
|
||||
maxAge := 0
|
||||
if now.Before(parsedResponse.NextUpdate) {
|
||||
maxAge = int(parsedResponse.NextUpdate.Sub(now) / time.Second)
|
||||
} else {
|
||||
// TODO(#530): we want max-age=0 but this is technically an authorized OCSP response
|
||||
// (despite being stale) and 5019 forbids attaching no-cache
|
||||
maxAge = 0
|
||||
}
|
||||
response.Header().Set(
|
||||
"Cache-Control",
|
||||
fmt.Sprintf(
|
||||
"max-age=%d, public, no-transform, must-revalidate",
|
||||
maxAge,
|
||||
),
|
||||
)
|
||||
responseHash := sha256.Sum256(ocspResponse)
|
||||
response.Header().Add("ETag", fmt.Sprintf("\"%X\"", responseHash))
|
||||
|
||||
if headers != nil {
|
||||
overrideHeaders(response, headers)
|
||||
}
|
||||
|
||||
// RFC 7232 says that a 304 response must contain the above
|
||||
// headers if they would also be sent for a 200 for the same
|
||||
// request, so we have to wait until here to do this
|
||||
if etag := request.Header.Get("If-None-Match"); etag != "" {
|
||||
if etag == fmt.Sprintf("\"%X\"", responseHash) {
|
||||
response.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
}
|
||||
response.WriteHeader(http.StatusOK)
|
||||
response.Write(ocspResponse)
|
||||
}
|
28
vendor/github.com/cloudflare/cfssl/revoke/BUILD
generated
vendored
Normal file
28
vendor/github.com/cloudflare/cfssl/revoke/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 = ["revoke.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/revoke",
|
||||
importpath = "github.com/cloudflare/cfssl/revoke",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/helpers:go_default_library",
|
||||
"//vendor/github.com/cloudflare/cfssl/log: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"],
|
||||
)
|
327
vendor/github.com/cloudflare/cfssl/revoke/revoke.go
generated
vendored
Normal file
327
vendor/github.com/cloudflare/cfssl/revoke/revoke.go
generated
vendored
Normal file
@@ -0,0 +1,327 @@
|
||||
// Package revoke provides functionality for checking the validity of
|
||||
// a cert. Specifically, the temporal validity of the certificate is
|
||||
// checked first, then any CRL and OCSP url in the cert is checked.
|
||||
package revoke
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/base64"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
neturl "net/url"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/ocsp"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/log"
|
||||
)
|
||||
|
||||
// HardFail determines whether the failure to check the revocation
|
||||
// status of a certificate (i.e. due to network failure) causes
|
||||
// verification to fail (a hard failure).
|
||||
var HardFail = false
|
||||
|
||||
// CRLSet associates a PKIX certificate list with the URL the CRL is
|
||||
// fetched from.
|
||||
var CRLSet = map[string]*pkix.CertificateList{}
|
||||
var crlLock = new(sync.Mutex)
|
||||
|
||||
// We can't handle LDAP certificates, so this checks to see if the
|
||||
// URL string points to an LDAP resource so that we can ignore it.
|
||||
func ldapURL(url string) bool {
|
||||
u, err := neturl.Parse(url)
|
||||
if err != nil {
|
||||
log.Warningf("error parsing url %s: %v", url, err)
|
||||
return false
|
||||
}
|
||||
if u.Scheme == "ldap" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// revCheck should check the certificate for any revocations. It
|
||||
// returns a pair of booleans: the first indicates whether the certificate
|
||||
// is revoked, the second indicates whether the revocations were
|
||||
// successfully checked.. This leads to the following combinations:
|
||||
//
|
||||
// false, false: an error was encountered while checking revocations.
|
||||
//
|
||||
// false, true: the certificate was checked successfully and
|
||||
// it is not revoked.
|
||||
//
|
||||
// true, true: the certificate was checked successfully and
|
||||
// it is revoked.
|
||||
//
|
||||
// true, false: failure to check revocation status causes
|
||||
// verification to fail
|
||||
func revCheck(cert *x509.Certificate) (revoked, ok bool) {
|
||||
for _, url := range cert.CRLDistributionPoints {
|
||||
if ldapURL(url) {
|
||||
log.Infof("skipping LDAP CRL: %s", url)
|
||||
continue
|
||||
}
|
||||
|
||||
if revoked, ok := certIsRevokedCRL(cert, url); !ok {
|
||||
log.Warning("error checking revocation via CRL")
|
||||
if HardFail {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
} else if revoked {
|
||||
log.Info("certificate is revoked via CRL")
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
|
||||
if revoked, ok := certIsRevokedOCSP(cert, HardFail); !ok {
|
||||
log.Warning("error checking revocation via OCSP")
|
||||
if HardFail {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
} else if revoked {
|
||||
log.Info("certificate is revoked via OCSP")
|
||||
return true, true
|
||||
}
|
||||
|
||||
return false, true
|
||||
}
|
||||
|
||||
// fetchCRL fetches and parses a CRL.
|
||||
func fetchCRL(url string) (*pkix.CertificateList, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if resp.StatusCode >= 300 {
|
||||
return nil, errors.New("failed to retrieve CRL")
|
||||
}
|
||||
|
||||
body, err := crlRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
return x509.ParseCRL(body)
|
||||
}
|
||||
|
||||
func getIssuer(cert *x509.Certificate) *x509.Certificate {
|
||||
var issuer *x509.Certificate
|
||||
var err error
|
||||
for _, issuingCert := range cert.IssuingCertificateURL {
|
||||
issuer, err = fetchRemote(issuingCert)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return issuer
|
||||
|
||||
}
|
||||
|
||||
// check a cert against a specific CRL. Returns the same bool pair
|
||||
// as revCheck.
|
||||
func certIsRevokedCRL(cert *x509.Certificate, url string) (revoked, ok bool) {
|
||||
crl, ok := CRLSet[url]
|
||||
if ok && crl == nil {
|
||||
ok = false
|
||||
crlLock.Lock()
|
||||
delete(CRLSet, url)
|
||||
crlLock.Unlock()
|
||||
}
|
||||
|
||||
var shouldFetchCRL = true
|
||||
if ok {
|
||||
if !crl.HasExpired(time.Now()) {
|
||||
shouldFetchCRL = false
|
||||
}
|
||||
}
|
||||
|
||||
issuer := getIssuer(cert)
|
||||
|
||||
if shouldFetchCRL {
|
||||
var err error
|
||||
crl, err = fetchCRL(url)
|
||||
if err != nil {
|
||||
log.Warningf("failed to fetch CRL: %v", err)
|
||||
return false, false
|
||||
}
|
||||
|
||||
// check CRL signature
|
||||
if issuer != nil {
|
||||
err = issuer.CheckCRLSignature(crl)
|
||||
if err != nil {
|
||||
log.Warningf("failed to verify CRL: %v", err)
|
||||
return false, false
|
||||
}
|
||||
}
|
||||
|
||||
crlLock.Lock()
|
||||
CRLSet[url] = crl
|
||||
crlLock.Unlock()
|
||||
}
|
||||
|
||||
for _, revoked := range crl.TBSCertList.RevokedCertificates {
|
||||
if cert.SerialNumber.Cmp(revoked.SerialNumber) == 0 {
|
||||
log.Info("Serial number match: intermediate is revoked.")
|
||||
return true, true
|
||||
}
|
||||
}
|
||||
|
||||
return false, true
|
||||
}
|
||||
|
||||
// VerifyCertificate ensures that the certificate passed in hasn't
|
||||
// expired and checks the CRL for the server.
|
||||
func VerifyCertificate(cert *x509.Certificate) (revoked, ok bool) {
|
||||
if !time.Now().Before(cert.NotAfter) {
|
||||
log.Infof("Certificate expired %s\n", cert.NotAfter)
|
||||
return true, true
|
||||
} else if !time.Now().After(cert.NotBefore) {
|
||||
log.Infof("Certificate isn't valid until %s\n", cert.NotBefore)
|
||||
return true, true
|
||||
}
|
||||
|
||||
return revCheck(cert)
|
||||
}
|
||||
|
||||
func fetchRemote(url string) (*x509.Certificate, error) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
in, err := remoteRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
p, _ := pem.Decode(in)
|
||||
if p != nil {
|
||||
return helpers.ParseCertificatePEM(in)
|
||||
}
|
||||
|
||||
return x509.ParseCertificate(in)
|
||||
}
|
||||
|
||||
var ocspOpts = ocsp.RequestOptions{
|
||||
Hash: crypto.SHA1,
|
||||
}
|
||||
|
||||
func certIsRevokedOCSP(leaf *x509.Certificate, strict bool) (revoked, ok bool) {
|
||||
var err error
|
||||
|
||||
ocspURLs := leaf.OCSPServer
|
||||
if len(ocspURLs) == 0 {
|
||||
// OCSP not enabled for this certificate.
|
||||
return false, true
|
||||
}
|
||||
|
||||
issuer := getIssuer(leaf)
|
||||
|
||||
if issuer == nil {
|
||||
return false, false
|
||||
}
|
||||
|
||||
ocspRequest, err := ocsp.CreateRequest(leaf, issuer, &ocspOpts)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, server := range ocspURLs {
|
||||
resp, err := sendOCSPRequest(server, ocspRequest, leaf, issuer)
|
||||
if err != nil {
|
||||
if strict {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// There wasn't an error fetching the OCSP status.
|
||||
ok = true
|
||||
|
||||
if resp.Status != ocsp.Good {
|
||||
// The certificate was revoked.
|
||||
revoked = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// sendOCSPRequest attempts to request an OCSP response from the
|
||||
// server. The error only indicates a failure to *fetch* the
|
||||
// certificate, and *does not* mean the certificate is valid.
|
||||
func sendOCSPRequest(server string, req []byte, leaf, issuer *x509.Certificate) (*ocsp.Response, error) {
|
||||
var resp *http.Response
|
||||
var err error
|
||||
if len(req) > 256 {
|
||||
buf := bytes.NewBuffer(req)
|
||||
resp, err = http.Post(server, "application/ocsp-request", buf)
|
||||
} else {
|
||||
reqURL := server + "/" + base64.StdEncoding.EncodeToString(req)
|
||||
resp, err = http.Get(reqURL)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, errors.New("failed to retrieve OSCP")
|
||||
}
|
||||
|
||||
body, err := ocspRead(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp.Body.Close()
|
||||
|
||||
switch {
|
||||
case bytes.Equal(body, ocsp.UnauthorizedErrorResponse):
|
||||
return nil, errors.New("OSCP unauthorized")
|
||||
case bytes.Equal(body, ocsp.MalformedRequestErrorResponse):
|
||||
return nil, errors.New("OSCP malformed")
|
||||
case bytes.Equal(body, ocsp.InternalErrorErrorResponse):
|
||||
return nil, errors.New("OSCP internal error")
|
||||
case bytes.Equal(body, ocsp.TryLaterErrorResponse):
|
||||
return nil, errors.New("OSCP try later")
|
||||
case bytes.Equal(body, ocsp.SigRequredErrorResponse):
|
||||
return nil, errors.New("OSCP signature required")
|
||||
}
|
||||
|
||||
return ocsp.ParseResponseForCert(body, leaf, issuer)
|
||||
}
|
||||
|
||||
var crlRead = ioutil.ReadAll
|
||||
|
||||
// SetCRLFetcher sets the function to use to read from the http response body
|
||||
func SetCRLFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
crlRead = fn
|
||||
}
|
||||
|
||||
var remoteRead = ioutil.ReadAll
|
||||
|
||||
// SetRemoteFetcher sets the function to use to read from the http response body
|
||||
func SetRemoteFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
remoteRead = fn
|
||||
}
|
||||
|
||||
var ocspRead = ioutil.ReadAll
|
||||
|
||||
// SetOCSPFetcher sets the function to use to read from the http response body
|
||||
func SetOCSPFetcher(fn func(io.Reader) ([]byte, error)) {
|
||||
ocspRead = fn
|
||||
}
|
36
vendor/github.com/cloudflare/cfssl/scan/BUILD
generated
vendored
Normal file
36
vendor/github.com/cloudflare/cfssl/scan/BUILD
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"broad.go",
|
||||
"connectivity.go",
|
||||
"pki.go",
|
||||
"scan_common.go",
|
||||
"tls_handshake.go",
|
||||
"tls_session.go",
|
||||
],
|
||||
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/scan",
|
||||
importpath = "github.com/cloudflare/cfssl/scan",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/cloudflare/cfssl/bundler: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/revoke: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"],
|
||||
)
|
84
vendor/github.com/cloudflare/cfssl/scan/broad.go
generated
vendored
Normal file
84
vendor/github.com/cloudflare/cfssl/scan/broad.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/bundler"
|
||||
)
|
||||
|
||||
// Broad contains scanners for large swaths of TLS hosts on the internet.
|
||||
var Broad = &Family{
|
||||
Description: "Large scale scans of TLS hosts",
|
||||
Scanners: map[string]*Scanner{
|
||||
"IntermediateCAs": {
|
||||
"Scans a CIDR IP range for unknown Intermediate CAs",
|
||||
intermediateCAScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func incrementBytes(bytes []byte) {
|
||||
lsb := len(bytes) - 1
|
||||
bytes[lsb]++
|
||||
if bytes[lsb] == 0 {
|
||||
incrementBytes(bytes[:lsb])
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
caBundleFile = "/etc/cfssl/ca-bundle.crt"
|
||||
intBundleFile = "/etc/cfssl/int-bundle.crt"
|
||||
numWorkers = 32
|
||||
timeout = time.Second
|
||||
)
|
||||
|
||||
// intermediateCAScan scans for new intermediate CAs not in the trust store.
|
||||
func intermediateCAScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
cidr, port, _ := net.SplitHostPort(addr)
|
||||
_, ipnet, err := net.ParseCIDR(cidr)
|
||||
if err != nil {
|
||||
return Skipped, nil, nil
|
||||
}
|
||||
b, err := bundler.NewBundler(caBundleFile, intBundleFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(numWorkers)
|
||||
dialer := &net.Dialer{Timeout: timeout}
|
||||
config := &tls.Config{InsecureSkipVerify: true}
|
||||
addrs := make(chan string)
|
||||
chains := make(chan []*x509.Certificate, numWorkers)
|
||||
go func() {
|
||||
for chain := range chains {
|
||||
b.Bundle(chain, nil, bundler.Force)
|
||||
}
|
||||
}()
|
||||
for i := 0; i < numWorkers; i++ {
|
||||
go func() {
|
||||
for addr := range addrs {
|
||||
conn, err := tls.DialWithDialer(dialer, Network, addr, config)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn.Close()
|
||||
if conn.ConnectionState().HandshakeComplete {
|
||||
chains <- conn.ConnectionState().PeerCertificates
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
for ip := ipnet.IP.To16(); ipnet.Contains(ip); incrementBytes(ip) {
|
||||
addrs <- net.JoinHostPort(ip.String(), port)
|
||||
}
|
||||
close(addrs)
|
||||
wg.Wait()
|
||||
close(chains)
|
||||
grade = Good
|
||||
return
|
||||
}
|
161
vendor/github.com/cloudflare/cfssl/scan/connectivity.go
generated
vendored
Normal file
161
vendor/github.com/cloudflare/cfssl/scan/connectivity.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
)
|
||||
|
||||
// Connectivity contains scanners testing basic connectivity to the host
|
||||
var Connectivity = &Family{
|
||||
Description: "Scans for basic connectivity with the host through DNS and TCP/TLS dials",
|
||||
Scanners: map[string]*Scanner{
|
||||
"DNSLookup": {
|
||||
"Host can be resolved through DNS",
|
||||
dnsLookupScan,
|
||||
},
|
||||
"CloudFlareStatus": {
|
||||
"Host is on CloudFlare",
|
||||
onCloudFlareScan,
|
||||
},
|
||||
"TCPDial": {
|
||||
"Host accepts TCP connection",
|
||||
tcpDialScan,
|
||||
},
|
||||
"TLSDial": {
|
||||
"Host can perform TLS handshake",
|
||||
tlsDialScan,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// dnsLookupScan tests that DNS resolution of the host returns at least one address
|
||||
func dnsLookupScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
addrs, err := net.LookupHost(hostname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(addrs) == 0 {
|
||||
err = errors.New("no addresses found for host")
|
||||
}
|
||||
|
||||
grade, output = Good, addrs
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
cfNets []*net.IPNet
|
||||
cfNetsErr error
|
||||
)
|
||||
|
||||
func initOnCloudFlareScan() ([]*net.IPNet, error) {
|
||||
// Propogate previous errors and don't attempt to re-download.
|
||||
if cfNetsErr != nil {
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
|
||||
// Don't re-download ranges if we already have them.
|
||||
if len(cfNets) > 0 {
|
||||
return cfNets, nil
|
||||
}
|
||||
|
||||
// Download CloudFlare CIDR ranges and parse them.
|
||||
v4resp, err := Client.Get("https://www.cloudflare.com/ips-v4")
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
defer v4resp.Body.Close()
|
||||
|
||||
v6resp, err := Client.Get("https://www.cloudflare.com/ips-v6")
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't download CloudFlare IPs: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
defer v6resp.Body.Close()
|
||||
|
||||
scanner := bufio.NewScanner(io.MultiReader(v4resp.Body, v6resp.Body))
|
||||
for scanner.Scan() {
|
||||
_, ipnet, err := net.ParseCIDR(scanner.Text())
|
||||
if err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't parse CIDR range: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
cfNets = append(cfNets, ipnet)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
cfNetsErr = fmt.Errorf("Couldn't read IP bodies: %v", err)
|
||||
return nil, cfNetsErr
|
||||
}
|
||||
|
||||
return cfNets, nil
|
||||
}
|
||||
|
||||
func onCloudFlareScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var cloudflareNets []*net.IPNet
|
||||
if cloudflareNets, err = initOnCloudFlareScan(); err != nil {
|
||||
grade = Skipped
|
||||
return
|
||||
}
|
||||
|
||||
_, addrs, err := dnsLookupScan(addr, hostname)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
cfStatus := make(map[string]bool)
|
||||
grade = Good
|
||||
for _, addr := range addrs.([]string) {
|
||||
ip := net.ParseIP(addr)
|
||||
for _, cfNet := range cloudflareNets {
|
||||
if cfNet.Contains(ip) {
|
||||
cfStatus[addr] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !cfStatus[addr] {
|
||||
cfStatus[addr] = false
|
||||
grade = Bad
|
||||
}
|
||||
}
|
||||
|
||||
output = cfStatus
|
||||
return
|
||||
}
|
||||
|
||||
// tcpDialScan tests that the host can be connected to through TCP.
|
||||
func tcpDialScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
conn, err := Dialer.Dial(Network, addr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
grade = Good
|
||||
return
|
||||
}
|
||||
|
||||
// tlsDialScan tests that the host can perform a TLS Handshake
|
||||
// and warns if the server's certificate can't be verified.
|
||||
func tlsDialScan(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
var conn *tls.Conn
|
||||
config := defaultTLSConfig(hostname)
|
||||
|
||||
if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
config.InsecureSkipVerify = false
|
||||
if conn, err = tls.DialWithDialer(Dialer, Network, addr, config); err != nil {
|
||||
grade = Warning
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
grade = Good
|
||||
return
|
||||
}
|
161
vendor/github.com/cloudflare/cfssl/scan/pki.go
generated
vendored
Normal file
161
vendor/github.com/cloudflare/cfssl/scan/pki.go
generated
vendored
Normal file
@@ -0,0 +1,161 @@
|
||||
package scan
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cloudflare/cfssl/helpers"
|
||||
"github.com/cloudflare/cfssl/revoke"
|
||||
)
|
||||
|
||||
// PKI contains scanners for the Public Key Infrastructure.
|
||||
var PKI = &Family{
|
||||
Description: "Scans for the Public Key Infrastructure",
|
||||
Scanners: map[string]*Scanner{
|
||||
"ChainExpiration": {
|
||||
"Host's chain hasn't expired and won't expire in the next 30 days",
|
||||
chainExpiration,
|
||||
},
|
||||
"ChainValidation": {
|
||||
"All certificates in host's chain are valid",
|
||||
chainValidation,
|
||||
},
|
||||
"MultipleCerts": {
|
||||
"Host serves same certificate chain across all IPs",
|
||||
multipleCerts,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// getChain is a helper function that retreives the host's certificate chain.
|
||||
func getChain(addr string, config *tls.Config) (chain []*x509.Certificate, err error) {
|
||||
var conn *tls.Conn
|
||||
conn, err = tls.DialWithDialer(Dialer, Network, addr, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
chain = conn.ConnectionState().PeerCertificates
|
||||
if len(chain) == 0 {
|
||||
err = fmt.Errorf("%s returned empty certificate chain", addr)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
type expiration time.Time
|
||||
|
||||
func (e expiration) String() string {
|
||||
return time.Time(e).Format("Jan 2 15:04:05 2006 MST")
|
||||
}
|
||||
|
||||
func chainExpiration(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
chain, err := getChain(addr, defaultTLSConfig(hostname))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
expirationTime := helpers.ExpiryTime(chain)
|
||||
output = expirationTime
|
||||
|
||||
if time.Now().After(expirationTime) {
|
||||
return
|
||||
}
|
||||
|
||||
// Warn if cert will expire in the next 30 days
|
||||
if time.Now().Add(time.Hour * 24 * 30).After(expirationTime) {
|
||||
grade = Warning
|
||||
return
|
||||
}
|
||||
|
||||
grade = Good
|
||||
return
|
||||
}
|
||||
|
||||
func chainValidation(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
chain, err := getChain(addr, defaultTLSConfig(hostname))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var warnings []string
|
||||
|
||||
for i := 0; i < len(chain)-1; i++ {
|
||||
cert, parent := chain[i], chain[i+1]
|
||||
|
||||
valid := helpers.ValidExpiry(cert)
|
||||
if !valid {
|
||||
warnings = append(warnings, fmt.Sprintf("Certificate for %s is valid for too long", cert.Subject.CommonName))
|
||||
}
|
||||
|
||||
revoked, ok := revoke.VerifyCertificate(cert)
|
||||
if !ok {
|
||||
warnings = append(warnings, fmt.Sprintf("couldn't check if %s is revoked", cert.Subject.CommonName))
|
||||
}
|
||||
if revoked {
|
||||
err = fmt.Errorf("%s is revoked", cert.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if !parent.IsCA {
|
||||
err = fmt.Errorf("%s is not a CA", parent.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if !bytes.Equal(cert.AuthorityKeyId, parent.SubjectKeyId) {
|
||||
err = fmt.Errorf("%s AuthorityKeyId differs from %s SubjectKeyId", cert.Subject.CommonName, parent.Subject.CommonName)
|
||||
return
|
||||
}
|
||||
|
||||
if err = cert.CheckSignatureFrom(parent); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch cert.SignatureAlgorithm {
|
||||
case x509.ECDSAWithSHA1:
|
||||
warnings = append(warnings, fmt.Sprintf("%s is signed by ECDSAWithSHA1", cert.Subject.CommonName))
|
||||
case x509.SHA1WithRSA:
|
||||
warnings = append(warnings, fmt.Sprintf("%s is signed by RSAWithSHA1", cert.Subject.CommonName))
|
||||
}
|
||||
}
|
||||
|
||||
if len(warnings) == 0 {
|
||||
grade = Good
|
||||
} else {
|
||||
grade = Warning
|
||||
output = warnings
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func multipleCerts(addr, hostname string) (grade Grade, output Output, err error) {
|
||||
config := defaultTLSConfig(hostname)
|
||||
|
||||
firstChain, err := getChain(addr, config)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
grade, _, err = multiscan(addr, func(addrport string) (g Grade, o Output, e error) {
|
||||
g = Good
|
||||
chain, e1 := getChain(addrport, config)
|
||||
if e1 != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !chain[0].Equal(firstChain[0]) {
|
||||
e = fmt.Errorf("%s not equal to %s", chain[0].Subject.CommonName, firstChain[0].Subject.CommonName)
|
||||
g = Bad
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
return
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user