remove unnecessary vendoring of cmd/cfssl

During dc9def6f93, which was a revert for
7a10073e4a we forgot to remove the extra
thing we started vendoring. So let's drop the cmd/cfssl

Change-Id: I308dc41cdb9b990f2b4ab8d59ad0445d5ac02e8c
This commit is contained in:
Davanum Srinivas
2019-04-11 16:50:41 -04:00
parent 9e83e6d1cd
commit 437a7333e3
265 changed files with 2 additions and 257197 deletions

View File

@@ -1,42 +0,0 @@
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/health: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"],
)

View File

@@ -1,231 +0,0 @@
// 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
}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,91 +0,0 @@
// 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)
}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,50 +0,0 @@
// 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)
}

View File

@@ -1,34 +0,0 @@
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"],
)

View File

@@ -1,6 +0,0 @@
package client
// SignResult is the result of signing a CSR.
type SignResult struct {
Certificate []byte `json:"certificate"`
}

View File

@@ -1,370 +0,0 @@
// 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() *http.Transport {
// Start with defaults from http.DefaultTransport
transport := &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
}
// Setup HTTPS client
tlsConfig := srv.TLSConfig
tlsConfig.BuildNameToCertificate()
transport.TLSClientConfig = tlsConfig
// Setup Proxy
if srv.proxy != nil {
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
}

View File

@@ -1,132 +0,0 @@
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
}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,93 +0,0 @@
// 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)
}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,102 +0,0 @@
// 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"},
}
}

View File

@@ -1,33 +0,0 @@
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"],
)

View File

@@ -1,319 +0,0 @@
// 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
}

View File

@@ -1,24 +0,0 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["health.go"],
importmap = "k8s.io/kubernetes/vendor/github.com/cloudflare/cfssl/api/health",
importpath = "github.com/cloudflare/cfssl/api/health",
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/cloudflare/cfssl/api: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"],
)

View File

@@ -1,26 +0,0 @@
package health
import (
"encoding/json"
"net/http"
"github.com/cloudflare/cfssl/api"
)
// Response contains the response to the /health API
type Response struct {
Healthy bool `json:"healthy"`
}
func healthHandler(w http.ResponseWriter, r *http.Request) error {
response := api.NewSuccessResponse(&Response{Healthy: true})
return json.NewEncoder(w).Encode(response)
}
// NewHealthCheck creates a new handler to serve health checks.
func NewHealthCheck() http.Handler {
return api.HTTPHandler{
Handler: api.HandlerFunc(healthHandler),
Methods: []string{"GET"},
}
}

View File

@@ -1,30 +0,0 @@
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"],
)

View File

@@ -1,121 +0,0 @@
// 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)
}

View File

@@ -1,30 +0,0 @@
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"],
)

View File

@@ -1,61 +0,0 @@
// 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"}}
}

View File

@@ -1,30 +0,0 @@
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"],
)

View File

@@ -1,113 +0,0 @@
// 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)
}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,137 +0,0 @@
// 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 response 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)
}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,76 +0,0 @@
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"},
}
}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,294 +0,0 @@
// 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)
}

View File

@@ -1,33 +0,0 @@
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"],
)

View File

@@ -1,186 +0,0 @@
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++
}
}

View File

@@ -1,843 +0,0 @@
// 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
}

View File

@@ -1,16 +0,0 @@
// 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

View File

@@ -17,11 +17,7 @@ filegroup(
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//vendor/github.com/cloudflare/cfssl/certdb/dbconf:all-srcs",
"//vendor/github.com/cloudflare/cfssl/certdb/sql:all-srcs",
],
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,57 +0,0 @@
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)
}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,352 +0,0 @@
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
}

View File

@@ -1,24 +0,0 @@
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"],
)

View File

@@ -1,166 +0,0 @@
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
}

View File

@@ -1,53 +0,0 @@
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"],
)

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,88 +0,0 @@
// 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}

View File

@@ -1,27 +0,0 @@
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"],
)

View File

@@ -1,89 +0,0 @@
// 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}

View File

@@ -1,199 +0,0 @@
// 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)
}

View File

@@ -1,147 +0,0 @@
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
MinTLSVersion string
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
Disable string
}
// 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.MinTLSVersion, "min-tls-version", "", "Minimum version of TLS to use, defaults to 1.0")
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)")
f.StringVar(&c.Disable, "disable", "", "endpoints to disable")
}
// 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 != "",
}
}

View File

@@ -1,33 +0,0 @@
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"],
)

View File

@@ -1,105 +0,0 @@
//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}

View File

@@ -1,33 +0,0 @@
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"],
)

View File

@@ -1,165 +0,0 @@
// 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 Certificates
// 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}

View File

@@ -1,27 +0,0 @@
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"],
)

View File

@@ -1,82 +0,0 @@
//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}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,99 +0,0 @@
// 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}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,82 +0,0 @@
// 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}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,110 +0,0 @@
// 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,
}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,50 +0,0 @@
// 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}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,112 +0,0 @@
// 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}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,62 +0,0 @@
// 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}

View File

@@ -1,29 +0,0 @@
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"],
)

View File

@@ -1,93 +0,0 @@
// 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}

View File

@@ -1,27 +0,0 @@
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"],
)

View File

@@ -1,49 +0,0 @@
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"
}
]
}
`,
}

View File

@@ -1,48 +0,0 @@
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,
}

View File

@@ -1,30 +0,0 @@
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"],
)

View File

@@ -1,66 +0,0 @@
// 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,
}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,123 +0,0 @@
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}

View File

@@ -1,31 +0,0 @@
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"],
)

View File

@@ -1,120 +0,0 @@
// 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}

View File

@@ -1,51 +0,0 @@
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/health: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"],
)

View File

@@ -1,13 +0,0 @@
## 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
```

View File

@@ -1,389 +0,0 @@
// 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/health"
"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] [-min-tls-version version] [-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] [-disable endpoint[,endpoint]]
Flags:
`
// Flags used by 'cfssl serve'
var serverFlags = []string{"address", "port", "min-tls-version", "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", "disable"}
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.
// Attempting 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
},
"health": func() (http.Handler, error) {
return health.NewHealthCheck(), nil
},
}
// registerHandlers instantiates various handlers and associate them to corresponding endpoints.
func registerHandlers() {
disabled := make(map[string]bool)
if conf.Disable != "" {
for _, endpoint := range strings.Split(conf.Disable, ",") {
disabled[endpoint] = true
}
}
for path, getHandler := range endpoints {
log.Debugf("getHandler for %s", path)
if _, ok := disabled[path]; ok {
log.Infof("endpoint '%s' is explicitly disabled", path)
} else 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))
tlscfg := tls.Config{}
if conf.MinTLSVersion != "" {
tlscfg.MinVersion = helpers.StringTLSVersion(conf.MinTLSVersion)
}
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)
}
tlscfg.ClientAuth = tls.RequireAndVerifyClientCert
tlscfg.ClientCAs = clientPool
server := http.Server{
Addr: addr,
TLSConfig: &tlscfg,
}
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)
server := http.Server{
Addr: addr,
TLSConfig: &tlscfg,
}
return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile)
}
// 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
}

View File

@@ -1,33 +0,0 @@
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"],
)

View File

@@ -1,181 +0,0 @@
// 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}

View File

@@ -1,27 +0,0 @@
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"],
)

View File

@@ -1,42 +0,0 @@
// 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, 2, "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}

View File

@@ -1,7 +0,0 @@
// +build !release
package version
func init() {
version.Revision = "dev"
}

View File

@@ -1,55 +0,0 @@
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"],
tags = ["manual"],
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"],
)

View File

@@ -1,87 +0,0 @@
/*
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)
}
}

View File

@@ -1,31 +0,0 @@
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"],
tags = ["manual"],
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"],
)

View File

@@ -1,211 +0,0 @@
// 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)
}
}
}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,108 +0,0 @@
// 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
}

View File

@@ -1,32 +0,0 @@
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"],
)

View File

@@ -1,249 +0,0 @@
// 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 existing 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 existing 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
}

View File

@@ -1,39 +0,0 @@
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"],
)

View File

@@ -1,215 +0,0 @@
/*
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)
}
err := req.Certificate.CheckSignatureFrom(s.issuer)
if err != nil {
return nil, cferr.Wrap(cferr.OCSPError, cferr.VerifyFailed, err)
}
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)
}

View File

@@ -1,349 +0,0 @@
// 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)
}

View File

@@ -1,28 +0,0 @@
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"],
)

View File

@@ -1,327 +0,0 @@
// 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
}

View File

@@ -1,40 +0,0 @@
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",
"//vendor/github.com/cloudflare/cfssl/scan/crypto/tls: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/scan/crypto/tls:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -1,84 +0,0 @@
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
}

Some files were not shown because too many files have changed in this diff Show More