From a97ea87caab68d9c35ac13d8b458c8cb94a3bc75 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Thu, 7 Mar 2019 15:14:18 -0800 Subject: [PATCH] Move options to provisioner so we can set the duration of the cert. --- api/api.go | 11 +++++------ api/api_test.go | 7 +++---- authority/provisioner/jwk.go | 23 +++-------------------- authority/provisioner/oidc.go | 1 + authority/provisioner/sign_options.go | 24 ++++++++++++++++++++---- authority/tls.go | 13 +++---------- 6 files changed, 35 insertions(+), 44 deletions(-) diff --git a/api/api.go b/api/api.go index 15b82be3..a92b7902 100644 --- a/api/api.go +++ b/api/api.go @@ -18,7 +18,6 @@ import ( "github.com/go-chi/chi" "github.com/pkg/errors" - "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/logging" "github.com/smallstep/cli/crypto/tlsutil" @@ -29,7 +28,7 @@ type Authority interface { Authorize(ott string) ([]provisioner.SignOption, error) GetTLSOptions() *tlsutil.TLSOptions Root(shasum string) (*x509.Certificate, error) - Sign(cr *x509.CertificateRequest, signOpts authority.SignOptions, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) + Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) Renew(peer *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) GetProvisioners(cursor string, limit int) (provisioner.List, string, error) GetEncryptedKey(kid string) (string, error) @@ -166,7 +165,7 @@ type ProvisionersResponse struct { NextCursor string `json:"nextCursor"` } -// ProvisionerKeyResponse is the response object that returns the encryptoed key +// ProvisionerKeyResponse is the response object that returns the encrypted key // of a provisioner. type ProvisionerKeyResponse struct { Key string `json:"key"` @@ -267,18 +266,18 @@ func (h *caHandler) Sign(w http.ResponseWriter, r *http.Request) { return } - signOpts := authority.SignOptions{ + opts := provisioner.Options{ NotBefore: body.NotBefore, NotAfter: body.NotAfter, } - extraOpts, err := h.Authority.Authorize(body.OTT) + signOpts, err := h.Authority.Authorize(body.OTT) if err != nil { WriteError(w, Unauthorized(err)) return } - cert, root, err := h.Authority.Sign(body.CsrPEM.CertificateRequest, signOpts, extraOpts...) + cert, root, err := h.Authority.Sign(body.CsrPEM.CertificateRequest, opts, signOpts...) if err != nil { WriteError(w, Forbidden(err)) return diff --git a/api/api_test.go b/api/api_test.go index eac09577..80879ef5 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -24,7 +24,6 @@ import ( "time" "github.com/go-chi/chi" - "github.com/smallstep/certificates/authority" "github.com/smallstep/certificates/authority/provisioner" "github.com/smallstep/certificates/logging" "github.com/smallstep/cli/crypto/tlsutil" @@ -414,7 +413,7 @@ type mockAuthority struct { authorize func(ott string) ([]provisioner.SignOption, error) getTLSOptions func() *tlsutil.TLSOptions root func(shasum string) (*x509.Certificate, error) - sign func(cr *x509.CertificateRequest, signOpts authority.SignOptions, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) + sign func(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) renew func(cert *x509.Certificate) (*x509.Certificate, *x509.Certificate, error) getProvisioners func(nextCursor string, limit int) (provisioner.List, string, error) getEncryptedKey func(kid string) (string, error) @@ -443,9 +442,9 @@ func (m *mockAuthority) Root(shasum string) (*x509.Certificate, error) { return m.ret1.(*x509.Certificate), m.err } -func (m *mockAuthority) Sign(cr *x509.CertificateRequest, signOpts authority.SignOptions, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { +func (m *mockAuthority) Sign(cr *x509.CertificateRequest, opts provisioner.Options, signOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { if m.sign != nil { - return m.sign(cr, signOpts, extraOpts...) + return m.sign(cr, opts, signOpts...) } return m.ret1.(*x509.Certificate), m.ret2.(*x509.Certificate), m.err } diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index a585731c..3c8d07a8 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -105,16 +105,14 @@ func (p *JWK) Authorize(token string) ([]SignOption, error) { return nil, err } - signOps := []SignOption{ + return []SignOption{ commonNameValidator(claims.Subject), dnsNamesValidator(dnsNames), ipAddressesValidator(ips), - // profileWithOption(x509util.WithNotBeforeAfterDuration(so.NotBefore, so.NotAfter, p.Claims.DefaultTLSCertDuration())), + profileDefaultDuration(p.Claims.DefaultTLSCertDuration()), newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID), newValidityValidator(p.Claims.MinTLSCertDuration(), p.Claims.MaxTLSCertDuration()), - } - - return signOps, nil + }, nil } // AuthorizeRenewal returns an error if the renewal is disabled. @@ -130,18 +128,3 @@ func (p *JWK) AuthorizeRenewal(cert *x509.Certificate) error { func (p *JWK) AuthorizeRevoke(token string) error { return errors.New("not implemented") } - -// // getTLSApps returns a list of modifiers and validators that will be applied to -// // the certificate. -// func (p *JWT) getTLSApps(so SignOptions) ([]x509util.WithOption, []certClaim, error) { -// c := p.Claims -// return []x509util.WithOption{ -// x509util.WithNotBeforeAfterDuration(so.NotBefore, so.NotAfter, c.DefaultTLSCertDuration()), -// withProvisionerOID(p.Name, p.Key.KeyID), -// }, []certClaim{ -// &certTemporalClaim{ -// min: c.MinTLSCertDuration(), -// max: c.MaxTLSCertDuration(), -// }, -// }, nil -// } diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index b28b7617..c31d3095 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -156,6 +156,7 @@ func (o *OIDC) Authorize(token string) ([]SignOption, error) { return []SignOption{ emailOnlyIdentity(claims.Email), + profileDefaultDuration(o.Claims.DefaultTLSCertDuration()), newProvisionerExtensionOption(TypeOIDC, o.Name, o.ClientID), newValidityValidator(o.Claims.MinTLSCertDuration(), o.Claims.MaxTLSCertDuration()), }, nil diff --git a/authority/provisioner/sign_options.go b/authority/provisioner/sign_options.go index ba34c864..068ffa93 100644 --- a/authority/provisioner/sign_options.go +++ b/authority/provisioner/sign_options.go @@ -12,6 +12,12 @@ import ( "github.com/smallstep/cli/crypto/x509util" ) +// Options contains the options that can be passed to the Sign method. +type Options struct { + NotAfter time.Time `json:"notAfter"` + NotBefore time.Time `json:"notBefore"` +} + // SignOption is the interface used to collect all extra options used in the // Sign method. type SignOption interface{} @@ -29,19 +35,29 @@ type CertificateRequestValidator interface { Valid(req *x509.CertificateRequest) error } -// ProfileWithOption is the interface used to add custom options to the profile +// ProfileModifier is the interface used to add custom options to the profile // constructor. The options are used to modify the final certificate. -type ProfileWithOption interface { +type ProfileModifier interface { SignOption - Option() x509util.WithOption + Option(so SignOption) x509util.WithOption } +// profileWithOption is a wrapper against x509util.WithOption to conform the +// interface. type profileWithOption x509util.WithOption -func (v profileWithOption) Option() x509util.WithOption { +func (v profileWithOption) Option(Options) x509util.WithOption { return x509util.WithOption(v) } +// profileDefaultDuration is a wrapper against x509util.WithOption to conform the +// interface. +type profileDefaultDuration time.Duration + +func (v profileDefaultDuration) Option(so Options) x509util.WithOption { + return x509util.WithNotBeforeAfterDuration(so.NotBefore, so.NotAfter, time.Duration(v)) +} + // emailOnlyIdentity is a CertificateRequestValidator that checks that the only // SAN provided is the given email address. type emailOnlyIdentity string diff --git a/authority/tls.go b/authority/tls.go index c1639a59..1c9c7897 100644 --- a/authority/tls.go +++ b/authority/tls.go @@ -23,13 +23,6 @@ func (a *Authority) GetTLSOptions() *tlsutil.TLSOptions { return a.config.TLS } -// SignOptions contains the options that can be passed to the Authority.Sign -// method. -type SignOptions struct { - NotAfter time.Time `json:"notAfter"` - NotBefore time.Time `json:"notBefore"` -} - var ( stepOIDRoot = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 37476, 9000, 64} stepOIDProvisioner = append(asn1.ObjectIdentifier(nil), append(stepOIDRoot, 1)...) @@ -97,7 +90,7 @@ func withDefaultASN1DN(def *x509util.ASN1DN) x509util.WithOption { } // Sign creates a signed certificate from a certificate signing request. -func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts SignOptions, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { +func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts provisioner.Options, extraOpts ...provisioner.SignOption) (*x509.Certificate, *x509.Certificate, error) { var ( errContext = context{"csr": csr, "signOptions": signOpts} mods = []x509util.WithOption{} @@ -111,8 +104,8 @@ func (a *Authority) Sign(csr *x509.CertificateRequest, signOpts SignOptions, ext if err := k.Valid(csr); err != nil { return nil, nil, err } - case provisioner.ProfileWithOption: - mods = append(mods, k.Option()) + case provisioner.ProfileModifier: + mods = append(mods, k.Option(signOpts)) default: return nil, nil, &apiError{errors.Errorf("sign: invalid extra option type %T", k), http.StatusInternalServerError, errContext}