Skip to content

Commit

Permalink
Add methods to get the templates functions
Browse files Browse the repository at this point in the history
step-ca fails to add a template with ASN.1 functions because they are
not defined in the list of functions supported. This commit will add
a function that has all the supported methods so you can create
a provisioner with a template using this methods.
  • Loading branch information
maraino committed Aug 3, 2023
1 parent efd553b commit c1d883c
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 9 deletions.
15 changes: 13 additions & 2 deletions sshutil/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,24 @@ func (o *Options) apply(cr CertificateRequest, opts []Option) (*Options, error)
// Option is the type used as a variadic argument in NewCertificate.
type Option func(cr CertificateRequest, o *Options) error

// GetFuncMap returns the list of functions used by the templates. It will
// return all the functions supported by "sprig.TxtFuncMap()" but exclude "env"
// and "expandenv", removed to avoid the leak of information.
func GetFuncMap() template.FuncMap {
return getFuncMap(new(TemplateError))
}

func getFuncMap(err *TemplateError) template.FuncMap {
return templates.GetFuncMap(&err.Message)
}

// WithTemplate is an options that executes the given template text with the
// given data.
func WithTemplate(text string, data TemplateData) Option {
return func(cr CertificateRequest, o *Options) error {
terr := new(TemplateError)
funcMap := templates.GetFuncMap(&terr.Message)

funcMap := getFuncMap(terr)
// Parse template
tmpl, err := template.New("template").Funcs(funcMap).Parse(text)
if err != nil {
return errors.Wrapf(err, "error parsing template")
Expand Down
17 changes: 17 additions & 0 deletions sshutil/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ import (
"testing"
)

func TestGetFuncMap(t *testing.T) {
ok := []string{"fail", "contains", "split"}
fail := []string{"env", "expandenv"}

funcMap := GetFuncMap()
for _, name := range ok {
if _, ok := funcMap[name]; !ok {
t.Errorf("GetFuncMap() does not contain the function %s", name)
}
}
for _, name := range fail {
if _, ok := funcMap[name]; ok {
t.Errorf("GetFuncMap() contains the function %s", name)
}
}
}

func TestWithTemplate(t *testing.T) {
key := mustGeneratePublicKey(t)
cr := CertificateRequest{
Expand Down
35 changes: 28 additions & 7 deletions x509util/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,39 @@ func (o *Options) apply(cr *x509.CertificateRequest, opts []Option) (*Options, e
// Option is the type used as a variadic argument in NewCertificate.
type Option func(cr *x509.CertificateRequest, o *Options) error

// GetFuncMap returns the list of functions used by the templates. It will
// return all the functions supported by "sprig.TxtFuncMap()" but exclude "env"
// and "expandenv", removed to avoid the leak of information. It will also add
// the following functions to encode data using ASN.1:
//
// - asn1Enc: encodes the given string to ASN.1. By default, it will use the
// PrintableString format but it can be change using the suffix ":<format>".
// Supported formats are: "printable", "utf8", "ia5", "numeric", "int", "oid",
// "utc", "generalized", and "raw".
// - asn1Marshal: encodes the given string with the given params using Go's
// asn1.MarshalWithParams.
// - asn1Seq: encodes a sequence of the given ASN.1 data.
// - asn1Set: encodes a set of the given ASN.1 data.
func GetFuncMap() template.FuncMap {
return getFuncMap(new(TemplateError))
}

func getFuncMap(err *TemplateError) template.FuncMap {
funcMap := templates.GetFuncMap(&err.Message)
// asn1 methods
funcMap["asn1Enc"] = asn1Encode
funcMap["asn1Marshal"] = asn1Marshal
funcMap["asn1Seq"] = asn1Sequence
funcMap["asn1Set"] = asn1Set
return funcMap
}

// WithTemplate is an options that executes the given template text with the
// given data.
func WithTemplate(text string, data TemplateData) Option {
return func(cr *x509.CertificateRequest, o *Options) error {
terr := new(TemplateError)
funcMap := templates.GetFuncMap(&terr.Message)
// asn1 methods
funcMap["asn1Enc"] = asn1Encode
funcMap["asn1Marshal"] = asn1Marshal
funcMap["asn1Seq"] = asn1Sequence
funcMap["asn1Set"] = asn1Set

funcMap := getFuncMap(terr)
// Parse template
tmpl, err := template.New("template").Funcs(funcMap).Parse(text)
if err != nil {
Expand Down
20 changes: 20 additions & 0 deletions x509util/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ func createRSACertificateRequest(t *testing.T, bits int, commonName string, sans
return cr, priv
}

func TestGetFuncMap(t *testing.T) {
ok := []string{
"fail", "contains", "split", // generic sprig functions
"asn1Enc", "asn1Marshal", "asn1Seq", "asn1Set", // custom functions
}
fail := []string{"env", "expandenv"}

funcMap := GetFuncMap()
for _, name := range ok {
if _, ok := funcMap[name]; !ok {
t.Errorf("GetFuncMap() does not contain the function %s", name)
}
}
for _, name := range fail {
if _, ok := funcMap[name]; ok {
t.Errorf("GetFuncMap() contains the function %s", name)
}
}
}

func TestWithTemplate(t *testing.T) {
cr, _ := createCertificateRequest(t, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
crRSA, _ := createRSACertificateRequest(t, 2048, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"})
Expand Down

0 comments on commit c1d883c

Please sign in to comment.