github.com/caddyserver/caddy/v2/modules/caddypki
No package summary is available.
Package
Files: 7. Third party imports: 7. Imports from organisation: 1. Tests: 0. Benchmarks: 0.
Constants
const (
// DefaultCAID is the default CA ID.
DefaultCAID = "local"
defaultCAName = "Caddy Local Authority"
defaultRootCommonName = "{pki.ca.name} - {time.now.year} ECC Root"
defaultIntermediateCommonName = "{pki.ca.name} - ECC Intermediate"
defaultRootLifetime = 24 * time.Hour * 30 * 12 * 10
defaultIntermediateLifetime = 24 * time.Hour * 7
)
// adminPKIEndpointBase is the base admin endpoint under which all PKI admin endpoints exist.
const adminPKIEndpointBase = "/pki/"
const renewalWindowRatio = 0.2 // TODO: make configurable
Vars
var (
_ caddy.AdminRouter = (*adminAPI)(nil)
_ caddy.Provisioner = (*adminAPI)(nil)
)
Types
AuthorityConfig
AuthorityConfig is used to help a CA configure the underlying signing authority.
type AuthorityConfig struct {
SignWithRoot bool
// TODO: should we just embed the underlying authority.Config struct type?
DB *db.AuthDB
AuthConfig *authority.AuthConfig
}
CA
CA describes a certificate authority, which consists of root/signing certificates and various settings pertaining to the issuance of certificates and trusting them.
type CA struct {
// The user-facing name of the certificate authority.
Name string `json:"name,omitempty"`
// The name to put in the CommonName field of the
// root certificate.
RootCommonName string `json:"root_common_name,omitempty"`
// The name to put in the CommonName field of the
// intermediate certificates.
IntermediateCommonName string `json:"intermediate_common_name,omitempty"`
// The lifetime for the intermediate certificates
IntermediateLifetime caddy.Duration `json:"intermediate_lifetime,omitempty"`
// Whether Caddy will attempt to install the CA's root
// into the system trust store, as well as into Java
// and Mozilla Firefox trust stores. Default: true.
InstallTrust *bool `json:"install_trust,omitempty"`
// The root certificate to use; if null, one will be generated.
Root *KeyPair `json:"root,omitempty"`
// The intermediate (signing) certificate; if null, one will be generated.
Intermediate *KeyPair `json:"intermediate,omitempty"`
// Optionally configure a separate storage module associated with this
// issuer, instead of using Caddy's global/default-configured storage.
// This can be useful if you want to keep your signing keys in a
// separate location from your leaf certificates.
StorageRaw json.RawMessage `json:"storage,omitempty" caddy:"namespace=caddy.storage inline_key=module"`
// The unique config-facing ID of the certificate authority.
// Since the ID is set in JSON config via object key, this
// field is exported only for purposes of config generation
// and module provisioning.
ID string `json:"-"`
storage certmagic.Storage
root, inter *x509.Certificate
interKey any // TODO: should we just store these as crypto.Signer?
mu *sync.RWMutex
rootCertPath string // mainly used for logging purposes if trusting
log *zap.Logger
ctx caddy.Context
}
KeyPair
KeyPair represents a public-private key pair, where the public key is also called a certificate.
type KeyPair struct {
// The certificate. By default, this should be the path to
// a PEM file unless format is something else.
Certificate string `json:"certificate,omitempty"`
// The private key. By default, this should be the path to
// a PEM file unless format is something else.
PrivateKey string `json:"private_key,omitempty"`
// The format in which the certificate and private
// key are provided. Default: pem_file
Format string `json:"format,omitempty"`
}
PKI
PKI provides Public Key Infrastructure facilities for Caddy.
This app can define certificate authorities (CAs) which are capable of signing certificates. Other modules can be configured to use the CAs defined by this app for issuing certificates or getting key information needed for establishing trust.
type PKI struct {
// The certificate authorities to manage. Each CA is keyed by an
// ID that is used to uniquely identify it from other CAs.
// At runtime, the GetCA() method should be used instead to ensure
// the default CA is provisioned if it hadn't already been.
// The default CA ID is "local".
CAs map[string]*CA `json:"certificate_authorities,omitempty"`
ctx caddy.Context
log *zap.Logger
}
adminAPI
adminAPI is a module that serves PKI endpoints to retrieve information about the CAs being managed by Caddy.
type adminAPI struct {
ctx caddy.Context
log *zap.Logger
pkiApp *PKI
}
caInfo
caInfo is the response structure for the CA info API endpoint.
type caInfo struct {
ID string `json:"id"`
Name string `json:"name"`
RootCN string `json:"root_common_name"`
IntermediateCN string `json:"intermediate_common_name"`
RootCert string `json:"root_certificate"`
IntermediateCert string `json:"intermediate_certificate"`
}
Functions
func (*CA) NewAuthority
NewAuthority returns a new Smallstep-powered signing authority for this CA. Note that we receive *CA (a pointer) in this method to ensure the closure within it, which executes at a later time, always has the only copy of the CA so it can access the latest, renewed certificates since NewAuthority was called. See #4517 and #4669.
func (ca *CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authority, error) {
// get the root certificate and the issuer cert+key
rootCert := ca.RootCertificate()
// set up the signer; cert/key which signs the leaf certs
var signerOption authority.Option
if authorityConfig.SignWithRoot {
// if we're signing with root, we can just pass the
// cert/key directly, since it's unlikely to expire
// while Caddy is running (long lifetime)
var issuerCert *x509.Certificate
var issuerKey any
issuerCert = rootCert
var err error
issuerKey, err = ca.RootKey()
if err != nil {
return nil, fmt.Errorf("loading signing key: %v", err)
}
signerOption = authority.WithX509Signer(issuerCert, issuerKey.(crypto.Signer))
} else {
// if we're signing with intermediate, we need to make
// sure it's always fresh, because the intermediate may
// renew while Caddy is running (medium lifetime)
signerOption = authority.WithX509SignerFunc(func() ([]*x509.Certificate, crypto.Signer, error) {
issuerCert := ca.IntermediateCertificate()
issuerKey := ca.IntermediateKey().(crypto.Signer)
ca.log.Debug("using intermediate signer",
zap.String("serial", issuerCert.SerialNumber.String()),
zap.String("not_before", issuerCert.NotBefore.String()),
zap.String("not_after", issuerCert.NotAfter.String()))
return []*x509.Certificate{issuerCert}, issuerKey, nil
})
}
opts := []authority.Option{
authority.WithConfig(&authority.Config{
AuthorityConfig: authorityConfig.AuthConfig,
}),
signerOption,
authority.WithX509RootCerts(rootCert),
}
// Add a database if we have one
if authorityConfig.DB != nil {
opts = append(opts, authority.WithDatabase(*authorityConfig.DB))
}
auth, err := authority.NewEmbedded(opts...)
if err != nil {
return nil, fmt.Errorf("initializing certificate authority: %v", err)
}
return auth, nil
}
Cognitive complexity: 14
, Cyclomatic complexity: 5
func (*PKI) GetCA
GetCA retrieves a CA by ID. If the ID is the default CA ID, and it hasn't been provisioned yet, it will be provisioned.
func (p *PKI) GetCA(ctx caddy.Context, id string) (*CA, error) {
ca, ok := p.CAs[id]
if !ok {
// for anything other than the default CA ID, error out if it wasn't configured
if id != DefaultCAID {
return nil, fmt.Errorf("no certificate authority configured with id: %s", id)
}
// for the default CA ID, provision it, because we want it to "just work"
err := p.ProvisionDefaultCA(ctx)
if err != nil {
return nil, fmt.Errorf("failed to provision default CA: %s", err)
}
ca = p.CAs[id]
}
return ca, nil
}
Cognitive complexity: 6
, Cyclomatic complexity: 4
func (*PKI) ProvisionDefaultCA
ProvisionDefaultCA sets up the default CA.
func (p *PKI) ProvisionDefaultCA(ctx caddy.Context) error {
if p.CAs == nil {
p.CAs = make(map[string]*CA)
}
p.CAs[DefaultCAID] = new(CA)
return p.CAs[DefaultCAID].Provision(ctx, DefaultCAID, p.log)
}
Cognitive complexity: 2
, Cyclomatic complexity: 2
func (*PKI) Start
Start starts the PKI app.
func (p *PKI) Start() error {
// install roots to trust store, if not disabled
for _, ca := range p.CAs {
if ca.InstallTrust != nil && !*ca.InstallTrust {
ca.log.Info("root certificate trust store installation disabled; unconfigured clients may show warnings",
zap.String("path", ca.rootCertPath))
continue
}
if err := ca.installRoot(); err != nil {
// could be some system dependencies that are missing;
// shouldn't totally prevent startup, but we should log it
ca.log.Error("failed to install root certificate",
zap.Error(err),
zap.String("certificate_file", ca.rootCertPath))
}
}
// see if root/intermediates need renewal...
p.renewCerts()
// ...and keep them renewed
go p.maintenance()
return nil
}
Cognitive complexity: 7
, Cyclomatic complexity: 5
func (*PKI) Stop
Stop stops the PKI app.
func (p *PKI) Stop() error {
return nil
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (*adminAPI) Provision
Provision sets up the adminAPI module.
func (a *adminAPI) Provision(ctx caddy.Context) error {
a.ctx = ctx
a.log = ctx.Logger(a) // TODO: passing in 'a' is a hack until the admin API is officially extensible (see #5032)
// Avoid initializing PKI if it wasn't configured.
// We intentionally ignore the error since it's not
// fatal if the PKI app is not explicitly configured.
pkiApp, err := ctx.AppIfConfigured("pki")
if err == nil {
a.pkiApp = pkiApp.(*PKI)
}
return nil
}
Cognitive complexity: 2
, Cyclomatic complexity: 2
func (*adminAPI) Routes
Routes returns the admin routes for the PKI app.
func (a *adminAPI) Routes() []caddy.AdminRoute {
return []caddy.AdminRoute{
{
Pattern: adminPKIEndpointBase,
Handler: caddy.AdminHandlerFunc(a.handleAPIEndpoints),
},
}
}
Cognitive complexity: 2
, Cyclomatic complexity: 1
func (CA) IntermediateCertificate
IntermediateCertificate returns the CA's intermediate certificate (public key).
func (ca CA) IntermediateCertificate() *x509.Certificate {
ca.mu.RLock()
defer ca.mu.RUnlock()
return ca.inter
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (CA) IntermediateKey
IntermediateKey returns the CA's intermediate private key.
func (ca CA) IntermediateKey() any {
ca.mu.RLock()
defer ca.mu.RUnlock()
return ca.interKey
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (CA) RootCertificate
RootCertificate returns the CA's root certificate (public key).
func (ca CA) RootCertificate() *x509.Certificate {
ca.mu.RLock()
defer ca.mu.RUnlock()
return ca.root
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (CA) RootKey
RootKey returns the CA's root private key. Since the root key is not cached in memory long-term, it needs to be loaded from storage, which could yield an error.
func (ca CA) RootKey() (any, error) {
_, rootKey, err := ca.loadOrGenRoot()
return rootKey, err
}
Cognitive complexity: 0
, Cyclomatic complexity: 1
func (KeyPair) Load
Load loads the certificate and key.
func (kp KeyPair) Load() (*x509.Certificate, crypto.Signer, error) {
switch kp.Format {
case "", "pem_file":
certData, err := os.ReadFile(kp.Certificate)
if err != nil {
return nil, nil, err
}
cert, err := pemDecodeSingleCert(certData)
if err != nil {
return nil, nil, err
}
var key crypto.Signer
if kp.PrivateKey != "" {
keyData, err := os.ReadFile(kp.PrivateKey)
if err != nil {
return nil, nil, err
}
key, err = certmagic.PEMDecodePrivateKey(keyData)
if err != nil {
return nil, nil, err
}
}
return cert, key, nil
default:
return nil, nil, fmt.Errorf("unsupported format: %s", kp.Format)
}
}
Cognitive complexity: 13
, Cyclomatic complexity: 8
func (adminAPI) CaddyModule
CaddyModule returns the Caddy module information.
func (adminAPI) CaddyModule() caddy.ModuleInfo {
return caddy.ModuleInfo{
ID: "admin.api.pki",
New: func() caddy.Module { return new(adminAPI) },
}
}
Cognitive complexity: 2
, Cyclomatic complexity: 1
Private functions
func cmdTrust
cmdTrust (fl caddycmd.Flags) (int, error)
References: caddycmd.DetermineAdminAPIAddress, fmt.Errorf, path.Join.
func cmdUntrust
cmdUntrust (fl caddycmd.Flags) (int, error)
References: caddycmd.DetermineAdminAPIAddress, fmt.Errorf, os.Stat, truststore.Uninstall, truststore.UninstallFile, truststore.WithDebug, truststore.WithFirefox, truststore.WithJava.
func generateIntermediate
generateIntermediate (commonName string, rootCrt *x509.Certificate, rootKey crypto.Signer, lifetime time.Duration) (*x509.Certificate, crypto.Signer, error)
References: x509util.CreateCertificate, x509util.DefaultIntermediateTemplate.
func generateRoot
generateRoot (commonName string) (*x509.Certificate, crypto.Signer, error)
References: x509util.CreateCertificate, x509util.DefaultRootTemplate.
func init
init ()
func needsRenewal
needsRenewal (cert *x509.Certificate) bool
References: time.Duration, time.Now.
func newCert
newCert (commonName,templateName string, lifetime time.Duration) (*x509.Certificate, crypto.Signer, error)
References: keyutil.GenerateDefaultSigner, time.Now, time.Second, x509util.CreateCertificateRequest, x509util.CreateTemplateData, x509util.NewCertificate, x509util.WithTemplate.
func pemDecodeSingleCert
pemDecodeSingleCert (pemDER []byte) (*x509.Certificate, error)
References: fmt.Errorf, pem.Decode, x509.ParseCertificate.
func pemEncode
pemEncode (blockType string, b []byte) ([]byte, error)
References: bytes.Buffer, pem.Block, pem.Encode.
func pemEncodeCert
pemEncodeCert (der []byte) ([]byte, error)
func rootAndIntermediatePEM
rootAndIntermediatePEM (ca *CA) ([]byte, error)
func rootCertFromAdmin
rootCertFromAdmin makes the API request to fetch the root certificate for the named CA via admin API.
rootCertFromAdmin (adminAddr string, caID string) (*x509.Certificate, error)
References: caddycmd.AdminAPIRequest, fmt.Errorf, http.Header, http.MethodGet, json.NewDecoder, path.Join, pem.Decode, x509.ParseCertificate.
func trusted
trusted (cert *x509.Certificate) bool
References: x509.VerifyOptions.
func maintenance
maintenance ()
References: debug.Stack, log.Printf, time.Minute, time.NewTicker.
func renewCerts
renewCerts ()
References: zap.Error, zap.String.
func renewCertsForCA
renewCertsForCA (ca *CA) error
References: fmt.Errorf, time.Until, zap.Duration, zap.String, zap.Time.
func getCAFromAPIRequestPath
getCAFromAPIRequestPath (r *http.Request) (*CA, error)
References: fmt.Errorf, http.StatusBadRequest, http.StatusInternalServerError, http.StatusNotFound, strings.Split.
func handleAPIEndpoints
handleAPIEndpoints routes API requests within adminPKIEndpointBase.
handleAPIEndpoints (w http.ResponseWriter, r *http.Request) error
References: fmt.Errorf, http.StatusNotFound, strings.Split, strings.TrimPrefix.
func handleCACerts
handleCACerts returns the certificate chain for a particular CA by its ID. If the CA ID is the default, then the CA will be provisioned if it has not already been. Other CA IDs will return an error if they have not been previously provisioned.
handleCACerts (w http.ResponseWriter, r *http.Request) error
References: fmt.Errorf, http.MethodGet, http.StatusInternalServerError, http.StatusMethodNotAllowed.
func handleCAInfo
handleCAInfo returns information about a particular CA by its ID. If the CA ID is the default, then the CA will be provisioned if it has not already been. Other CA IDs will return an error if they have not been previously provisioned.
handleCAInfo (w http.ResponseWriter, r *http.Request) error
References: fmt.Errorf, http.MethodGet, http.StatusInternalServerError, http.StatusMethodNotAllowed, json.Marshal.
func genIntermediate
genIntermediate (rootCert *x509.Certificate, rootKey crypto.Signer) (*x509.Certificate, crypto.Signer, error)
References: certmagic.PEMEncodePrivateKey, fmt.Errorf, time.Duration.
func genRoot
genRoot () (*x509.Certificate, crypto.Signer, error)
References: certmagic.PEMEncodePrivateKey, fmt.Errorf.
func installRoot
installRoot installs this CA's root certificate into the local trust store(s) if it is not already trusted. The CA must already be provisioned.
installRoot () error
References: truststore.Install, truststore.WithDebug, truststore.WithFirefox, truststore.WithJava, zap.String.
func loadOrGenIntermediate
loadOrGenIntermediate (rootCert *x509.Certificate, rootKey crypto.Signer) (*x509.Certificate, crypto.Signer, error)
References: certmagic.PEMDecodePrivateKey, errors.Is, fmt.Errorf, fs.ErrNotExist.
func loadOrGenRoot
loadOrGenRoot () (*x509.Certificate, crypto.Signer, error)
References: certmagic.PEMDecodePrivateKey, errors.Is, fmt.Errorf, fs.ErrNotExist.
func newReplacer
newReplacer () *caddy.Replacer
func storageKeyCAPrefix
storageKeyCAPrefix () string
References: certmagic.StorageKeys, path.Join.
func storageKeyIntermediateCert
storageKeyIntermediateCert () string
References: path.Join.
func storageKeyIntermediateKey
storageKeyIntermediateKey () string
References: path.Join.
func storageKeyRootCert
storageKeyRootCert () string
References: path.Join.
func storageKeyRootKey
storageKeyRootKey () string
References: path.Join.