Skip to content

Commit

Permalink
Merge pull request #302 from smallstep/template-funcs
Browse files Browse the repository at this point in the history
Template funcs
  • Loading branch information
maraino committed Aug 3, 2023
2 parents efd553b + 4aa6694 commit 636f7a9
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 19 deletions.
6 changes: 1 addition & 5 deletions internal/templates/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,11 @@ import (
// results in invalid JSON, the template is invalid. When the template
// is valid, it can be used safely. A valid template can still result
// in invalid JSON when non-empty template data is provided.
func ValidateTemplate(data []byte) error {
func ValidateTemplate(data []byte, funcMap template.FuncMap) error {
if len(data) == 0 {
return nil
}

// get the default supported functions
var failMessage string
funcMap := GetFuncMap(&failMessage)

// prepare the template with our template functions
_, err := template.New("template").Funcs(funcMap).Parse(string(data))
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/templates/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ func TestValidateTemplate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := ValidateTemplate(tt.data)
var failMessage string
err := ValidateTemplate(tt.data, GetFuncMap(&failMessage))
if tt.err != nil {
assert.Error(t, err)
assert.EqualError(t, err, tt.err.Error())
Expand Down
1 change: 1 addition & 0 deletions kms/capi/capi_no_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package capi

import (
"context"

"github.com/pkg/errors"
"go.step.sm/crypto/kms/apiv1"
)
Expand Down
5 changes: 3 additions & 2 deletions kms/capi/ncrypt_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import (
"encoding/binary"
"errors"
"fmt"
"golang.org/x/sys/windows"
"unsafe"

"golang.org/x/sys/windows"
)

const (
Expand Down Expand Up @@ -152,7 +153,7 @@ type BCRYPT_PKCS1_PADDING_INFO struct {
pszAlgID *uint16
}

//CRYPTOAPI_BLOB -- https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa381414(v=vs.85)
// CRYPTOAPI_BLOB -- https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/aa381414(v=vs.85)
type CRYPTOAPI_BLOB struct {
len uint32
data uintptr
Expand Down
9 changes: 9 additions & 0 deletions kms/tpmkms/no_tpmkms.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@

package tpmkms

import (
"context"
"os"
"path/filepath"

"github.com/pkg/errors"
"go.step.sm/crypto/kms/apiv1"
)

func init() {
apiv1.Register(apiv1.TPMKMS, func(ctx context.Context, opts apiv1.Options) (apiv1.KeyManager, error) {
name := filepath.Base(os.Args[0])
Expand Down
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
2 changes: 1 addition & 1 deletion sshutil/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (e *TemplateError) Error() string {

// ValidateTemplate validates a text template.
func ValidateTemplate(text []byte) error {
return templates.ValidateTemplate(text)
return templates.ValidateTemplate(text, GetFuncMap())
}

// ValidateTemplateData validates that template data is
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
2 changes: 1 addition & 1 deletion x509util/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func (e *TemplateError) Error() string {

// ValidateTemplate validates a text template.
func ValidateTemplate(text []byte) error {
return templates.ValidateTemplate(text)
return templates.ValidateTemplate(text, GetFuncMap())
}

// ValidateTemplateData validates that template data is
Expand Down

0 comments on commit 636f7a9

Please sign in to comment.