From 02c4f9817def5d28ea8ee844ced75562f813719e Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Tue, 21 Jul 2020 11:41:36 -0700 Subject: [PATCH] Set full token payload instead of only the known properties. --- authority/provisioner/aws.go | 4 +++- authority/provisioner/azure.go | 6 ++++-- authority/provisioner/gcp.go | 4 +++- authority/provisioner/jwk.go | 4 +++- authority/provisioner/k8sSA.go | 4 +++- authority/provisioner/oidc.go | 4 +++- authority/provisioner/options.go | 15 +++++++++++++++ authority/provisioner/x5c.go | 4 +++- x509util/certificate_test.go | 6 +++--- x509util/templates.go | 10 ++++++++++ 10 files changed, 50 insertions(+), 11 deletions(-) diff --git a/authority/provisioner/aws.go b/authority/provisioner/aws.go index 9d41f3e2..327467a7 100644 --- a/authority/provisioner/aws.go +++ b/authority/provisioner/aws.go @@ -281,8 +281,10 @@ func (p *AWS) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Template options data := x509util.NewTemplateData() - data.SetToken(payload) data.SetCommonName(payload.Claims.Subject) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } // Enforce known CN and default DNS and IP if configured. // By default we'll accept the CN and SANs in the CSR. diff --git a/authority/provisioner/azure.go b/authority/provisioner/azure.go index b1870e9f..865eee91 100644 --- a/authority/provisioner/azure.go +++ b/authority/provisioner/azure.go @@ -259,7 +259,7 @@ func (p *Azure) authorizeToken(token string) (*azurePayload, string, string, err // AuthorizeSign validates the given token and returns the sign options that // will be used on certificate creation. func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, error) { - payload, name, group, err := p.authorizeToken(token) + _, name, group, err := p.authorizeToken(token) if err != nil { return nil, errs.Wrap(http.StatusInternalServerError, err, "azure.AuthorizeSign") } @@ -280,8 +280,10 @@ func (p *Azure) AuthorizeSign(ctx context.Context, token string) ([]SignOption, // Template options data := x509util.NewTemplateData() - data.SetToken(payload) data.SetCommonName(name) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } // Enforce known common name and default DNS if configured. // By default we'll accept the CN and SANs in the CSR. diff --git a/authority/provisioner/gcp.go b/authority/provisioner/gcp.go index 6a9afd1c..f083b759 100644 --- a/authority/provisioner/gcp.go +++ b/authority/provisioner/gcp.go @@ -220,8 +220,10 @@ func (p *GCP) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Template options data := x509util.NewTemplateData() - data.SetToken(claims) data.SetCommonName(ce.InstanceName) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } // Enforce known common name and default DNS if configured. // By default we we'll accept the CN and SANs in the CSR. diff --git a/authority/provisioner/jwk.go b/authority/provisioner/jwk.go index 04db81c5..68b104ce 100644 --- a/authority/provisioner/jwk.go +++ b/authority/provisioner/jwk.go @@ -155,7 +155,9 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Certificate templates data := x509util.CreateTemplateData(claims.Subject, claims.SANs) - data.SetToken(claims) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } templateOptions, err := TemplateOptions(p.Options, data) if err != nil { diff --git a/authority/provisioner/k8sSA.go b/authority/provisioner/k8sSA.go index f9d1eeb0..15e6569c 100644 --- a/authority/provisioner/k8sSA.go +++ b/authority/provisioner/k8sSA.go @@ -213,8 +213,10 @@ func (p *K8sSA) AuthorizeSign(ctx context.Context, token string) ([]SignOption, // Add some values to use in custom templates. data := x509util.NewTemplateData() - data.SetToken(claims) data.SetCommonName(claims.ServiceAccountName) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } // Certificate templates: on K8sSA the default template is the certificate // request. diff --git a/authority/provisioner/oidc.go b/authority/provisioner/oidc.go index 574c307d..eaac13a9 100644 --- a/authority/provisioner/oidc.go +++ b/authority/provisioner/oidc.go @@ -318,7 +318,9 @@ func (o *OIDC) AuthorizeSign(ctx context.Context, token string) ([]SignOption, e } data := x509util.CreateTemplateData(claims.Subject, sans) - data.SetToken(claims) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } // Use the default template unless no-templates are configured and email is // an admin, in that case we will use the CR template. diff --git a/authority/provisioner/options.go b/authority/provisioner/options.go index 21ad56f3..f3df716f 100644 --- a/authority/provisioner/options.go +++ b/authority/provisioner/options.go @@ -6,6 +6,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certificates/x509util" + "github.com/smallstep/cli/jose" ) // CertificateOptions is an interface that returns a list of options passed when @@ -106,3 +107,17 @@ func CustomTemplateOptions(o *ProvisionerOptions, data x509util.TemplateData, de } }), nil } + +// unsafeParseSigned parses the given token and returns all the claims without +// verifying the signature of the token. +func unsafeParseSigned(s string) (map[string]interface{}, error) { + token, err := jose.ParseSigned(s) + if err != nil { + return nil, err + } + claims := make(map[string]interface{}) + if err = token.UnsafeClaimsWithoutVerification(&claims); err != nil { + return nil, err + } + return claims, nil +} diff --git a/authority/provisioner/x5c.go b/authority/provisioner/x5c.go index 5712c7ed..8ec1ddae 100644 --- a/authority/provisioner/x5c.go +++ b/authority/provisioner/x5c.go @@ -197,7 +197,9 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er // Certificate templates data := x509util.CreateTemplateData(claims.Subject, claims.SANs) - data.SetToken(claims) + if v, err := unsafeParseSigned(token); err == nil { + data.SetToken(v) + } templateOptions, err := TemplateOptions(p.Options, data) if err != nil { diff --git a/x509util/certificate_test.go b/x509util/certificate_test.go index a84f6eeb..fb987752 100644 --- a/x509util/certificate_test.go +++ b/x509util/certificate_test.go @@ -147,9 +147,9 @@ func TestNewCertificate(t *testing.T) { SANsKey: []SubjectAlternativeName{ {Type: "dns", Value: "foo.com"}, }, - TokenKey: map[string]string{ - "Issuer": "https://iss", - "Subject": "sub", + TokenKey: map[string]interface{}{ + "iss": "https://iss", + "sub": "sub", }, })}}, &Certificate{ Subject: Subject{CommonName: "commonName"}, diff --git a/x509util/templates.go b/x509util/templates.go index 7f82d159..b252e832 100644 --- a/x509util/templates.go +++ b/x509util/templates.go @@ -44,10 +44,12 @@ func CreateTemplateData(commonName string, sans []string) TemplateData { } } +// Set sets a key-value pair in the template data. func (t TemplateData) Set(key string, v interface{}) { t[key] = v } +// SetInsecure sets a key-value pair in the insecure template data. func (t TemplateData) SetInsecure(key string, v interface{}) { if m, ok := t[InsecureKey].(TemplateData); ok { m[key] = v @@ -56,28 +58,36 @@ func (t TemplateData) SetInsecure(key string, v interface{}) { } } +// SetSubject sets the given subject in the template data. func (t TemplateData) SetSubject(v Subject) { t.Set(SubjectKey, v) } +// SetCommonName sets the given common name in the subject in the template data. func (t TemplateData) SetCommonName(cn string) { s, _ := t[SubjectKey].(Subject) s.CommonName = cn t[SubjectKey] = s } +// SetSANs sets the given SANs in the template data. func (t TemplateData) SetSANs(sans []string) { t.Set(SANsKey, CreateSANs(sans)) } +// SetToken sets the given token in the template data. func (t TemplateData) SetToken(v interface{}) { t.Set(TokenKey, v) } +// SetUserData sets the given user provided object in the insecure template +// data. func (t TemplateData) SetUserData(v interface{}) { t.SetInsecure(UserKey, v) } +// SetCertificateRequest sets the given certificate request in the insecure +// template data. func (t TemplateData) SetCertificateRequest(cr *x509.CertificateRequest) { t.SetInsecure(CertificateRequestKey, newCertificateRequest(cr)) }