Added RenewOrRekey function based on @maraino suggestion. RenewOrReky is called from Renew.

This commit is contained in:
dharanikumar-s 2020-07-03 15:58:15 +05:30
parent 3813f57b1a
commit 8f504483ce
3 changed files with 19 additions and 92 deletions

View file

@ -2,6 +2,7 @@ package api
import (
"context"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/rsa"
@ -35,7 +36,7 @@ type Authority interface {
Root(shasum string) (*x509.Certificate, error)
Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
Renew(peer *x509.Certificate) ([]*x509.Certificate, error)
Rekey(peer *x509.Certificate, csr *x509.CertificateRequest) ([]*x509.Certificate, error)
RenewOrRekey(peer *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error)
LoadProvisionerByCertificate(*x509.Certificate) (provisioner.Interface, error)
LoadProvisionerByID(string) (provisioner.Interface, error)
GetProvisioners(cursor string, limit int) (provisioner.List, string, error)

View file

@ -34,17 +34,17 @@ func (h *caHandler) Rekey(w http.ResponseWriter, r *http.Request) {
return
}
if err := body.Validate(); err != nil {
WriteError(w, err)
return
}
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
WriteError(w, errs.BadRequest("missing peer certificate"))
return
}
certChain, err := h.Authority.Rekey(r.TLS.PeerCertificates[0],body.CsrPEM.CertificateRequest)
if err := body.Validate(); err != nil {
WriteError(w, err)
return
}
certChain, err := h.Authority.RenewOrRekey(r.TLS.PeerCertificates[0],body.CsrPEM.CertificateRequest.PublicKey)
if err != nil {
WriteError(w, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Rekey"))
return

View file

@ -2,6 +2,7 @@ package authority
import (
"context"
"crypto"
"crypto/tls"
"crypto/x509"
"encoding/asn1"
@ -135,20 +136,28 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Opti
// Renew creates a new Certificate identical to the old certificate, except
// with a validity window that begins 'now'.
func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error) {
return a.RenewOrRekey(oldCert, oldCert.PublicKey)
}
// Rekey is similar to renew except that the certificate will be renewed with new key.
// Function does rekeying if a new public key is passed as pk else if same key is passed, certificate will be just renewed.
func (a *Authority) RenewOrRekey(oldCert *x509.Certificate, pk crypto.PublicKey) ([]*x509.Certificate, error) {
opts := []interface{}{errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String())}
// Check step provisioner extensions
if err := a.authorizeRenew(oldCert); err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew", opts...)
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.RenewOrRekey", opts...)
}
// Durations
backdate := a.config.AuthorityConfig.Backdate.Duration
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
now := time.Now().UTC()
newCert := &x509.Certificate{
PublicKey: oldCert.PublicKey,
PublicKey: pk,
Issuer: a.x509Issuer.Subject,
Subject: oldCert.Subject,
NotBefore: now.Add(-1 * backdate),
@ -191,106 +200,23 @@ func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error
leaf, err := x509util.NewLeafProfileWithTemplate(newCert, a.x509Issuer, a.x509Signer)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew", opts...)
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.RenewOrRekey", opts...)
}
crtBytes, err := leaf.CreateCertificate()
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err,
"authority.Renew; error renewing certificate from existing server certificate", opts...)
"authority.RenewOrRenew; error renewing certificate from existing server certificate", opts...)
}
serverCert, err := x509.ParseCertificate(crtBytes)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err,
"authority.Renew; error parsing new server certificate", opts...)
"authority.RenewOrRekey; error parsing new server certificate", opts...)
}
if err = a.db.StoreCertificate(serverCert); err != nil {
if err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew; error storing certificate in db", opts...)
}
}
return []*x509.Certificate{serverCert, a.x509Issuer}, nil
}
// Rekey is similar to renew except that the certificate will be renewed with new key from csr argument.
func (a *Authority) Rekey(oldCert *x509.Certificate, csr *x509.CertificateRequest) ([]*x509.Certificate, error) {
opts := []interface{}{errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String())}
// Check step provisioner extensions
if err := a.authorizeRenew(oldCert); err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew", opts...)
}
// Durations
backdate := a.config.AuthorityConfig.Backdate.Duration
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
now := time.Now().UTC()
newCert := &x509.Certificate{
PublicKey: csr.PublicKey,
Issuer: a.x509Issuer.Subject,
Subject: oldCert.Subject,
NotBefore: now.Add(-1 * backdate),
NotAfter: now.Add(duration - backdate),
KeyUsage: oldCert.KeyUsage,
UnhandledCriticalExtensions: oldCert.UnhandledCriticalExtensions,
ExtKeyUsage: oldCert.ExtKeyUsage,
UnknownExtKeyUsage: oldCert.UnknownExtKeyUsage,
BasicConstraintsValid: oldCert.BasicConstraintsValid,
IsCA: oldCert.IsCA,
MaxPathLen: oldCert.MaxPathLen,
MaxPathLenZero: oldCert.MaxPathLenZero,
OCSPServer: oldCert.OCSPServer,
IssuingCertificateURL: oldCert.IssuingCertificateURL,
PermittedDNSDomainsCritical: oldCert.PermittedDNSDomainsCritical,
PermittedEmailAddresses: oldCert.PermittedEmailAddresses,
DNSNames: oldCert.DNSNames,
EmailAddresses: oldCert.EmailAddresses,
IPAddresses: oldCert.IPAddresses,
URIs: oldCert.URIs,
PermittedDNSDomains: oldCert.PermittedDNSDomains,
ExcludedDNSDomains: oldCert.ExcludedDNSDomains,
PermittedIPRanges: oldCert.PermittedIPRanges,
ExcludedIPRanges: oldCert.ExcludedIPRanges,
ExcludedEmailAddresses: oldCert.ExcludedEmailAddresses,
PermittedURIDomains: oldCert.PermittedURIDomains,
ExcludedURIDomains: oldCert.ExcludedURIDomains,
CRLDistributionPoints: oldCert.CRLDistributionPoints,
PolicyIdentifiers: oldCert.PolicyIdentifiers,
}
// Copy all extensions except for Authority Key Identifier. This one might
// be different if we rotate the intermediate certificate and it will cause
// a TLS bad certificate error.
for _, ext := range oldCert.Extensions {
if !ext.Id.Equal(oidAuthorityKeyIdentifier) {
newCert.ExtraExtensions = append(newCert.ExtraExtensions, ext)
}
}
leaf, err := x509util.NewLeafProfileWithTemplate(newCert, a.x509Issuer, a.x509Signer)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew", opts...)
}
crtBytes, err := leaf.CreateCertificate()
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err,
"authority.Renew; error renewing certificate from existing server certificate", opts...)
}
serverCert, err := x509.ParseCertificate(crtBytes)
if err != nil {
return nil, errs.Wrap(http.StatusInternalServerError, err,
"authority.Renew; error parsing new server certificate", opts...)
}
if err = a.db.StoreCertificate(serverCert); err != nil {
if err != db.ErrNotImplemented {
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.Renew; error storing certificate in db", opts...)
return nil, errs.Wrap(http.StatusInternalServerError, err, "authority.RenewOrRekey; error storing certificate in db", opts...)
}
}