mirror of
https://github.com/caddyserver/caddy.git
synced 2025-02-02 22:27:10 +01:00
allow customizable CSR key ID/name and key parameters
This commit is contained in:
parent
5b09e7df3d
commit
f49d2c5b02
2 changed files with 51 additions and 13 deletions
|
@ -24,6 +24,7 @@ import (
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
|
||||||
"github.com/caddyserver/caddy/v2"
|
"github.com/caddyserver/caddy/v2"
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -177,6 +178,29 @@ func (a *adminAPI) handleCACerts(w http.ResponseWriter, r *http.Request) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
type csrRequest struct {
|
type csrRequest struct {
|
||||||
|
// Custom name assigned to the CSR key. If empty, UUID is generated and assigned.
|
||||||
|
ID string `json:"id,omitempty"`
|
||||||
|
|
||||||
|
// Customization knobs of the generated/loaded key, if desired.
|
||||||
|
// If empty, sane defaults will be managed internally without exposing their details
|
||||||
|
// to the user. At the moment, the default parameters are:
|
||||||
|
// {
|
||||||
|
// "type": "EC",
|
||||||
|
// "curve": "P-256"
|
||||||
|
// }
|
||||||
|
Key *struct {
|
||||||
|
// The key type to be used for signing the CSR. The possible types are:
|
||||||
|
// EC, RSA, and OKP.
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// The curve to use with key types EC and OKP.
|
||||||
|
// If the Type is OKP, then acceptable curves are: Ed25519, or X25519
|
||||||
|
// If the Type is EC, then acceptable curves are: P-256, P-384, or P-521
|
||||||
|
Curve string `json:"curve,omitempty"`
|
||||||
|
|
||||||
|
// Only used with RSA keys and accepts minimum of 2048.
|
||||||
|
Size int `json:"size,omitempty"`
|
||||||
|
} `json:"key,omitempty"`
|
||||||
// SANs is a list of subject alternative names for the certificate.
|
// SANs is a list of subject alternative names for the certificate.
|
||||||
SANs []string `json:"sans"`
|
SANs []string `json:"sans"`
|
||||||
}
|
}
|
||||||
|
@ -205,8 +229,13 @@ func (a *adminAPI) handleCSRGeneration(w http.ResponseWriter, r *http.Request) e
|
||||||
Err: fmt.Errorf("failed to decode CSR request: %v", err),
|
Err: fmt.Errorf("failed to decode CSR request: %v", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
csrReq.ID = strings.TrimSpace(csrReq.ID)
|
||||||
|
if len(csrReq.ID) == 0 {
|
||||||
|
csrReq.ID = uuid.New().String()
|
||||||
|
}
|
||||||
|
|
||||||
// Generate the CSR
|
// Generate the CSR
|
||||||
csr, err := ca.generateCSR(csrReq.SANs)
|
csr, err := ca.generateCSR(csrReq)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return caddy.APIError{
|
return caddy.APIError{
|
||||||
HTTPStatus: http.StatusInternalServerError,
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
@ -227,6 +256,8 @@ func (a *adminAPI) handleCSRGeneration(w http.ResponseWriter, r *http.Request) e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.Header().Set("Content-Type", "application/pkcs10")
|
w.Header().Set("Content-Type", "application/pkcs10")
|
||||||
|
w.Header().Set("content-disposition", fmt.Sprintf(`attachment; filename="%s"`, csrReq.ID))
|
||||||
|
|
||||||
if _, err := w.Write(bs); err != nil {
|
if _, err := w.Write(bs); err != nil {
|
||||||
return caddy.APIError{
|
return caddy.APIError{
|
||||||
HTTPStatus: http.StatusInternalServerError,
|
HTTPStatus: http.StatusInternalServerError,
|
||||||
|
|
|
@ -396,8 +396,8 @@ func (ca CA) storageKeyIntermediateKey() string {
|
||||||
return path.Join(ca.storageKeyCAPrefix(), "intermediate.key")
|
return path.Join(ca.storageKeyCAPrefix(), "intermediate.key")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca CA) storageKeyCSRKey() string {
|
func (ca CA) storageKeyCSRKey(id string) string {
|
||||||
return path.Join(ca.storageKeyCAPrefix(), "csr.key")
|
return path.Join(ca.storageKeyCAPrefix(), id+".csr.key")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca CA) newReplacer() *caddy.Replacer {
|
func (ca CA) newReplacer() *caddy.Replacer {
|
||||||
|
@ -427,34 +427,41 @@ func (ca CA) installRoot() error {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ca CA) generateCSR(sans []string) (csr *x509.CertificateRequest, err error) {
|
func (ca CA) generateCSR(csrReq csrRequest) (csr *x509.CertificateRequest, err error) {
|
||||||
var signer crypto.Signer
|
var signer crypto.Signer
|
||||||
csrKeyPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyCSRKey())
|
csrKeyPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyCSRKey(csrReq.ID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return nil, fmt.Errorf("loading csr key: %v", err)
|
return nil, fmt.Errorf("loading csr key '%s': %v", csrReq.ID, err)
|
||||||
|
}
|
||||||
|
if csrReq.Key == nil {
|
||||||
|
signer, err = keyutil.GenerateDefaultSigner()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
signer, err = keyutil.GenerateSigner(csrReq.Key.Type, csrReq.Key.Curve, csrReq.Key.Size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
signer, err = keyutil.GenerateDefaultSigner()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
csrKeyPEM, err = certmagic.PEMEncodePrivateKey(signer)
|
csrKeyPEM, err = certmagic.PEMEncodePrivateKey(signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("encoding csr key: %v", err)
|
return nil, fmt.Errorf("encoding csr key: %v", err)
|
||||||
}
|
}
|
||||||
if err := ca.storage.Store(ca.ctx, ca.storageKeyCSRKey(), csrKeyPEM); err != nil {
|
if err := ca.storage.Store(ca.ctx, ca.storageKeyCSRKey(csrReq.ID), csrKeyPEM); err != nil {
|
||||||
return nil, fmt.Errorf("saving csr key: %v", err)
|
return nil, fmt.Errorf("saving csr key: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if signer == nil {
|
if signer == nil {
|
||||||
signer, err = certmagic.PEMDecodePrivateKey(csrKeyPEM)
|
signer, err = certmagic.PEMDecodePrivateKey(csrKeyPEM)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("decoding root key: %v", err)
|
return nil, fmt.Errorf("decoding csr key: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
csr, err = x509util.CreateCertificateRequest("", sans, signer)
|
csr, err = x509util.CreateCertificateRequest("", csrReq.SANs, signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue