Skip to content

Commit

Permalink
Generate new private keys for new certificates (#237)
Browse files Browse the repository at this point in the history
* Always generate new private keys by default

* Update readme
  • Loading branch information
mholt committed Jun 14, 2023
1 parent 25bb2af commit 232fade
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 13 deletions.
8 changes: 5 additions & 3 deletions README.md
Expand Up @@ -478,13 +478,15 @@ CertMagic emits events when possible things of interest happen. Set the [`OnEven
- `identifier`: The name on the certificate
- `remaining`: Time left on the certificate (if renewal)
- `issuer`: The previous or current issuer
- `storage_key`: The path to the cert resources within storage
- `storage_path`: The path to the folder containing the cert resources within storage
- `private_key_path`: The path to the private key file in storage
- `certificate_path`: The path to the public key file in storage
- `metadata_path`: The path to the metadata file in storage
- **`cert_failed`** An attempt to obtain a certificate failed
- `renewal`: Whether this is a renewal
- `identifier`: The name on the certificate
- `remaining`: Time left on the certificate (if renewal)
- `issuer`: The previous or current issuer
- `storage_key`: The path to the cert resources within storage
- `issuers`: The issuer(s) tried
- `error`: The (final) error message
- **`tls_get_certificate`** The GetCertificate phase of a TLS handshake is under way
- `client_hello`: The tls.ClientHelloInfo struct
Expand Down
38 changes: 28 additions & 10 deletions config.go
Expand Up @@ -95,6 +95,13 @@ type Config struct {
// turn until one succeeds.
Issuers []Issuer

// If true, private keys already existing in storage
// will be reused. Otherwise, a new key will be
// created for every new certificate to mitigate
// pinning and reduce the scope of key compromise.
// Default: false (do not reuse keys).
ReusePrivateKeys bool

// The source of new private keys for certificates;
// the default KeySource is StandardKeyGenerator.
KeySource KeyGenerator
Expand Down Expand Up @@ -527,9 +534,14 @@ func (cfg *Config) obtainCert(ctx context.Context, name string, interactive bool
}

// if storage has a private key already, use it; otherwise we'll generate our own
privKey, privKeyPEM, issuers, err := cfg.reusePrivateKey(ctx, name)
if err != nil {
return err
var privKey crypto.PrivateKey
var privKeyPEM []byte
var issuers []Issuer
if cfg.ReusePrivateKeys {
privKey, privKeyPEM, issuers, err = cfg.reusePrivateKey(ctx, name)
if err != nil {
return err
}
}
if privKey == nil {
privKey, err = cfg.KeySource.GenerateKey()
Expand Down Expand Up @@ -772,10 +784,17 @@ func (cfg *Config) renewCert(ctx context.Context, name string, force, interactiv
return fmt.Errorf("renewing certificate aborted by event handler: %w", err)
}

privateKey, err := PEMDecodePrivateKey(certRes.PrivateKeyPEM)
// reuse or generate new private key for CSR
var privateKey crypto.PrivateKey
if cfg.ReusePrivateKeys {
privateKey, err = PEMDecodePrivateKey(certRes.PrivateKeyPEM)
} else {
privateKey, err = cfg.KeySource.GenerateKey()
}
if err != nil {
return err
}

csr, err := cfg.generateCSR(privateKey, []string{name})
if err != nil {
return err
Expand Down Expand Up @@ -814,12 +833,11 @@ func (cfg *Config) renewCert(ctx context.Context, name string, force, interactiv
}
if err != nil {
cfg.emit(ctx, "cert_failed", map[string]any{
"renewal": true,
"identifier": name,
"remaining": timeLeft,
"issuers": issuerKeys,
"storage_key": certRes.NamesKey(),
"error": err,
"renewal": true,
"identifier": name,
"remaining": timeLeft,
"issuers": issuerKeys,
"error": err,
})

// only the error from the last issuer will be returned, but we logged the others
Expand Down

0 comments on commit 232fade

Please sign in to comment.