forked from TrueCloudLab/certificates
Added RenewOrRekey function based on @maraino suggestion. RenewOrReky is called from Renew.
This commit is contained in:
parent
3813f57b1a
commit
8f504483ce
3 changed files with 19 additions and 92 deletions
|
@ -2,6 +2,7 @@ package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
@ -35,7 +36,7 @@ type Authority interface {
|
||||||
Root(shasum string) (*x509.Certificate, error)
|
Root(shasum string) (*x509.Certificate, error)
|
||||||
Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
|
Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) ([]*x509.Certificate, error)
|
||||||
Renew(peer *x509.Certificate) ([]*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)
|
LoadProvisionerByCertificate(*x509.Certificate) (provisioner.Interface, error)
|
||||||
LoadProvisionerByID(string) (provisioner.Interface, error)
|
LoadProvisionerByID(string) (provisioner.Interface, error)
|
||||||
GetProvisioners(cursor string, limit int) (provisioner.List, string, error)
|
GetProvisioners(cursor string, limit int) (provisioner.List, string, error)
|
||||||
|
|
12
api/rekey.go
12
api/rekey.go
|
@ -34,17 +34,17 @@ func (h *caHandler) Rekey(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := body.Validate(); err != nil {
|
|
||||||
WriteError(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
|
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
|
||||||
WriteError(w, errs.BadRequest("missing peer certificate"))
|
WriteError(w, errs.BadRequest("missing peer certificate"))
|
||||||
return
|
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 {
|
if err != nil {
|
||||||
WriteError(w, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Rekey"))
|
WriteError(w, errs.Wrap(http.StatusInternalServerError, err, "cahandler.Rekey"))
|
||||||
return
|
return
|
||||||
|
|
104
authority/tls.go
104
authority/tls.go
|
@ -2,6 +2,7 @@ package authority
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"crypto"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"encoding/asn1"
|
"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
|
// Renew creates a new Certificate identical to the old certificate, except
|
||||||
// with a validity window that begins 'now'.
|
// with a validity window that begins 'now'.
|
||||||
func (a *Authority) Renew(oldCert *x509.Certificate) ([]*x509.Certificate, error) {
|
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())}
|
opts := []interface{}{errs.WithKeyVal("serialNumber", oldCert.SerialNumber.String())}
|
||||||
|
|
||||||
// Check step provisioner extensions
|
// Check step provisioner extensions
|
||||||
if err := a.authorizeRenew(oldCert); err != nil {
|
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
|
// Durations
|
||||||
backdate := a.config.AuthorityConfig.Backdate.Duration
|
backdate := a.config.AuthorityConfig.Backdate.Duration
|
||||||
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
|
duration := oldCert.NotAfter.Sub(oldCert.NotBefore)
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
|
|
||||||
|
|
||||||
newCert := &x509.Certificate{
|
newCert := &x509.Certificate{
|
||||||
PublicKey: oldCert.PublicKey,
|
PublicKey: pk,
|
||||||
Issuer: a.x509Issuer.Subject,
|
Issuer: a.x509Issuer.Subject,
|
||||||
Subject: oldCert.Subject,
|
Subject: oldCert.Subject,
|
||||||
NotBefore: now.Add(-1 * backdate),
|
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)
|
leaf, err := x509util.NewLeafProfileWithTemplate(newCert, a.x509Issuer, a.x509Signer)
|
||||||
if err != nil {
|
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()
|
crtBytes, err := leaf.CreateCertificate()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err,
|
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)
|
serverCert, err := x509.ParseCertificate(crtBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errs.Wrap(http.StatusInternalServerError, err,
|
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 = a.db.StoreCertificate(serverCert); err != nil {
|
||||||
if err != db.ErrNotImplemented {
|
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...)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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...)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue