diff --git a/internal/templates/funcmap.go b/internal/templates/funcmap.go index 01b6866d..76dd6e70 100644 --- a/internal/templates/funcmap.go +++ b/internal/templates/funcmap.go @@ -3,14 +3,19 @@ package templates import ( "errors" "text/template" + "time" "github.com/Masterminds/sprig/v3" + "go.step.sm/crypto/jose" ) -// GetFuncMap returns the list of functions provided by sprig. It changes the -// function "fail" to set the given string, this way we can report template -// errors directly to the template without having the wrapper that text/template -// adds. +// GetFuncMap returns the list of functions provided by sprig. It adds the +// function "toTime" and changes the function "fail". +// +// The "toTime" function receives a time or a Unix epoch and formats it to +// RFC3339 in UTC. The "fail" function sets the provided message, so that +// template errors are reported directly to the template without having the +// wrapper that text/template adds. // // sprig "env" and "expandenv" functions are removed to avoid the leak of // information. @@ -22,5 +27,31 @@ func GetFuncMap(failMessage *string) template.FuncMap { *failMessage = msg return "", errors.New(msg) } + m["toTime"] = toTime return m } + +func toTime(v any) string { + var t time.Time + switch date := v.(type) { + case time.Time: + t = date + case *time.Time: + t = *date + case int64: + t = time.Unix(date, 0) + case float64: // from json + t = time.Unix(int64(date), 0) + case int: + t = time.Unix(int64(date), 0) + case int32: + t = time.Unix(int64(date), 0) + case jose.NumericDate: + t = date.Time() + case *jose.NumericDate: + t = date.Time() + default: + t = time.Now() + } + return t.UTC().Format(time.RFC3339) +} diff --git a/internal/templates/funcmap_test.go b/internal/templates/funcmap_test.go index 155aed10..924b306f 100644 --- a/internal/templates/funcmap_test.go +++ b/internal/templates/funcmap_test.go @@ -3,6 +3,11 @@ package templates import ( "errors" "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.step.sm/crypto/jose" ) func Test_GetFuncMap_fail(t *testing.T) { @@ -20,3 +25,51 @@ func Test_GetFuncMap_fail(t *testing.T) { t.Errorf("fail() message = \"%s\", want \"the fail message\"", failMesage) } } + +func TestGetFuncMap_toTime(t *testing.T) { + now := time.Now() + numericDate := jose.NewNumericDate(now) + expected := now.UTC().Format(time.RFC3339) + loc, err := time.LoadLocation("America/Los_Angeles") + require.NoError(t, err) + + type args struct { + v any + } + tests := []struct { + name string + args args + want string + }{ + {"time", args{now}, expected}, + {"time pointer", args{&now}, expected}, + {"time UTC", args{now.UTC()}, expected}, + {"time with location", args{now.In(loc)}, expected}, + {"unix", args{now.Unix()}, expected}, + {"unix int", args{int(now.Unix())}, expected}, + {"unix int32", args{int32(now.Unix())}, expected}, + {"unix float64", args{float64(now.Unix())}, expected}, + {"unix float64", args{float64(now.Unix()) + 0.999}, expected}, + {"jose.NumericDate", args{*numericDate}, expected}, + {"jose.NumericDate pointer", args{numericDate}, expected}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var failMesage string + fns := GetFuncMap(&failMesage) + fn := fns["toTime"].(func(any) string) + assert.Equal(t, tt.want, fn(tt.args.v)) + }) + } + + t.Run("default", func(t *testing.T) { + var failMesage string + fns := GetFuncMap(&failMesage) + fn := fns["toTime"].(func(any) string) + want := time.Now() + got, err := time.Parse(time.RFC3339, fn(nil)) + require.NoError(t, err) + assert.WithinDuration(t, want, got, time.Second) + assert.Equal(t, time.UTC, got.Location()) + }) +} diff --git a/sshutil/certificate.go b/sshutil/certificate.go index 1bc59fba..a2367dd9 100644 --- a/sshutil/certificate.go +++ b/sshutil/certificate.go @@ -6,6 +6,7 @@ import ( "crypto/rand" "encoding/binary" "encoding/json" + "time" "github.com/pkg/errors" "go.step.sm/crypto/randutil" @@ -20,8 +21,8 @@ type Certificate struct { Type CertType `json:"type"` KeyID string `json:"keyId"` Principals []string `json:"principals"` - ValidAfter uint64 `json:"-"` - ValidBefore uint64 `json:"-"` + ValidAfter time.Time `json:"validAfter"` + ValidBefore time.Time `json:"validBefore"` CriticalOptions map[string]string `json:"criticalOptions"` Extensions map[string]string `json:"extensions"` Reserved []byte `json:"reserved"` @@ -62,8 +63,8 @@ func (c *Certificate) GetCertificate() *ssh.Certificate { CertType: uint32(c.Type), KeyId: c.KeyID, ValidPrincipals: c.Principals, - ValidAfter: c.ValidAfter, - ValidBefore: c.ValidBefore, + ValidAfter: toValidity(c.ValidAfter), + ValidBefore: toValidity(c.ValidBefore), Permissions: ssh.Permissions{ CriticalOptions: c.CriticalOptions, Extensions: c.Extensions, @@ -124,3 +125,10 @@ func CreateCertificate(cert *ssh.Certificate, signer ssh.Signer) (*ssh.Certifica return cert, nil } + +func toValidity(t time.Time) uint64 { + if t.IsZero() { + return 0 + } + return uint64(t.Unix()) +} diff --git a/sshutil/certificate_test.go b/sshutil/certificate_test.go index 7f67d685..be6cf9cd 100644 --- a/sshutil/certificate_test.go +++ b/sshutil/certificate_test.go @@ -10,7 +10,9 @@ import ( "io" "reflect" "testing" + "time" + "github.com/stretchr/testify/assert" "golang.org/x/crypto/ssh" ) @@ -71,6 +73,7 @@ func mustGeneratePublicKey(t *testing.T) ssh.PublicKey { } func TestNewCertificate(t *testing.T) { + now := time.Now().Truncate(time.Second) key := mustGeneratePublicKey(t) cr := CertificateRequest{ Key: key, @@ -100,8 +103,8 @@ func TestNewCertificate(t *testing.T) { Type: UserCert, KeyID: "jane@doe.com", Principals: []string{"jane"}, - ValidAfter: 0, - ValidBefore: 0, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: nil, Extensions: map[string]string{ "permit-X11-forwarding": "", @@ -121,8 +124,8 @@ func TestNewCertificate(t *testing.T) { Type: HostCert, KeyID: "foobar", Principals: []string{"foo.internal", "bar.internal"}, - ValidAfter: 0, - ValidBefore: 0, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: nil, Extensions: nil, Reserved: nil, @@ -136,8 +139,8 @@ func TestNewCertificate(t *testing.T) { Type: HostCert, KeyID: `foobar", "criticalOptions": {"foo": "bar"},"foo":"`, Principals: []string{"foo.internal", "bar.internal"}, - ValidAfter: 0, - ValidBefore: 0, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: nil, Extensions: nil, Reserved: nil, @@ -159,8 +162,8 @@ func TestNewCertificate(t *testing.T) { Type: UserCert, KeyID: "john@doe.com", Principals: []string{"john", "john@doe.com"}, - ValidAfter: 0, - ValidBefore: 0, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: nil, Extensions: map[string]string{ "login@github.com": "john", @@ -174,6 +177,38 @@ func TestNewCertificate(t *testing.T) { SignatureKey: nil, Signature: nil, }, false}, + {"file with dates", args{cr, []Option{WithTemplateFile("./testdata/date.tpl", TemplateData{ + TypeKey: UserCert, + KeyIDKey: "john@doe.com", + PrincipalsKey: []string{"john", "john@doe.com"}, + ExtensionsKey: DefaultExtensions(UserCert), + InsecureKey: TemplateData{ + "User": map[string]interface{}{"username": "john"}, + }, + WebhooksKey: TemplateData{ + "Test": map[string]interface{}{"validity": "16h"}, + }, + })}}, &Certificate{ + Nonce: nil, + Key: key, + Serial: 0, + Type: UserCert, + KeyID: "john@doe.com", + Principals: []string{"john", "john@doe.com"}, + ValidAfter: now, + ValidBefore: now.Add(16 * time.Hour), + CriticalOptions: nil, + Extensions: map[string]string{ + "permit-X11-forwarding": "", + "permit-agent-forwarding": "", + "permit-port-forwarding": "", + "permit-pty": "", + "permit-user-rc": "", + }, + Reserved: nil, + SignatureKey: nil, + Signature: nil, + }, false}, {"base64", args{cr, []Option{WithTemplateBase64(base64.StdEncoding.EncodeToString([]byte(DefaultTemplate)), CreateTemplateData(HostCert, "foo.internal", nil))}}, &Certificate{ Nonce: nil, Key: key, @@ -181,8 +216,8 @@ func TestNewCertificate(t *testing.T) { Type: HostCert, KeyID: "foo.internal", Principals: nil, - ValidAfter: 0, - ValidBefore: 0, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: nil, Extensions: nil, Reserved: nil, @@ -203,6 +238,15 @@ func TestNewCertificate(t *testing.T) { t.Errorf("NewCertificate() error = %v, wantErr %v", err, tt.wantErr) return } + if got != nil && tt.want != nil { + if assert.WithinDuration(t, tt.want.ValidAfter, got.ValidAfter, 2*time.Second) { + tt.want.ValidAfter = got.ValidAfter + } + if assert.WithinDuration(t, tt.want.ValidBefore, got.ValidBefore, 2*time.Second) { + tt.want.ValidBefore = got.ValidBefore + } + + } if !reflect.DeepEqual(got, tt.want) { t.Errorf("NewCertificate() = %v, want %v", got, tt.want) } @@ -212,6 +256,7 @@ func TestNewCertificate(t *testing.T) { func TestCertificate_GetCertificate(t *testing.T) { key := mustGeneratePublicKey(t) + now := time.Now() type fields struct { Nonce []byte @@ -220,8 +265,8 @@ func TestCertificate_GetCertificate(t *testing.T) { Type CertType KeyID string Principals []string - ValidAfter uint64 - ValidBefore uint64 + ValidAfter time.Time + ValidBefore time.Time CriticalOptions map[string]string Extensions map[string]string Reserved []byte @@ -240,8 +285,8 @@ func TestCertificate_GetCertificate(t *testing.T) { Type: UserCert, KeyID: "key-id", Principals: []string{"john"}, - ValidAfter: 1111, - ValidBefore: 2222, + ValidAfter: now, + ValidBefore: now.Add(time.Hour), CriticalOptions: map[string]string{"foo": "bar"}, Extensions: map[string]string{"login@github.com": "john"}, Reserved: []byte("reserved"), @@ -254,8 +299,8 @@ func TestCertificate_GetCertificate(t *testing.T) { CertType: ssh.UserCert, KeyId: "key-id", ValidPrincipals: []string{"john"}, - ValidAfter: 1111, - ValidBefore: 2222, + ValidAfter: uint64(now.Unix()), + ValidBefore: uint64(now.Add(time.Hour).Unix()), Permissions: ssh.Permissions{ CriticalOptions: map[string]string{"foo": "bar"}, Extensions: map[string]string{"login@github.com": "john"}, @@ -269,8 +314,8 @@ func TestCertificate_GetCertificate(t *testing.T) { Type: HostCert, KeyID: "key-id", Principals: []string{"foo.internal", "bar.internal"}, - ValidAfter: 1111, - ValidBefore: 2222, + ValidAfter: time.Time{}, + ValidBefore: time.Time{}, CriticalOptions: map[string]string{"foo": "bar"}, Extensions: nil, Reserved: []byte("reserved"), @@ -283,8 +328,8 @@ func TestCertificate_GetCertificate(t *testing.T) { CertType: ssh.HostCert, KeyId: "key-id", ValidPrincipals: []string{"foo.internal", "bar.internal"}, - ValidAfter: 1111, - ValidBefore: 2222, + ValidAfter: 0, + ValidBefore: 0, Permissions: ssh.Permissions{ CriticalOptions: map[string]string{"foo": "bar"}, Extensions: nil, diff --git a/sshutil/testdata/date.tpl b/sshutil/testdata/date.tpl new file mode 100644 index 00000000..5070d7bc --- /dev/null +++ b/sshutil/testdata/date.tpl @@ -0,0 +1,8 @@ +{ + "type": "{{ .Type }}", + "keyId": "{{ .KeyID }}", + "principals": {{ toJson .Principals }}, + "extensions": {{ toJson .Extensions }}, + "validAfter": {{ now | toJson }}, + "validBefore": {{ now | dateModify .Webhooks.Test.validity | toJson }} +} \ No newline at end of file diff --git a/x509util/certificate.go b/x509util/certificate.go index 918e28da..69eb5378 100644 --- a/x509util/certificate.go +++ b/x509util/certificate.go @@ -7,6 +7,7 @@ import ( "crypto/rand" "crypto/x509" "encoding/json" + "time" "github.com/pkg/errors" ) @@ -23,6 +24,8 @@ type Certificate struct { IPAddresses MultiIP `json:"ipAddresses"` URIs MultiURL `json:"uris"` SANs []SubjectAlternativeName `json:"sans"` + NotBefore time.Time `json:"notBefore"` + NotAfter time.Time `json:"notAfter"` Extensions []Extension `json:"extensions"` KeyUsage KeyUsage `json:"keyUsage"` ExtKeyUsage ExtKeyUsage `json:"extKeyUsage"` @@ -165,6 +168,10 @@ func (c *Certificate) GetCertificate() *x509.Certificate { e.Set(cert) } + // Validity bounds. + cert.NotBefore = c.NotBefore + cert.NotAfter = c.NotAfter + // Others. c.SerialNumber.Set(cert) c.SignatureAlgorithm.Set(cert) diff --git a/x509util/certificate_test.go b/x509util/certificate_test.go index 9e111eb1..5fc6b83d 100644 --- a/x509util/certificate_test.go +++ b/x509util/certificate_test.go @@ -112,6 +112,7 @@ func (b *badSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) ([] } func TestNewCertificate(t *testing.T) { + now := time.Now().UTC().Truncate(time.Second) cr, priv := createCertificateRequest(t, "commonName", []string{"foo.com", "root@foo.com"}) crBadSignateure, _ := createCertificateRequest(t, "fail", []string{"foo.com"}) crBadSignateure.PublicKey = priv.Public() @@ -195,12 +196,20 @@ func TestNewCertificate(t *testing.T) { TokenKey: map[string]interface{}{ "iss": "https://iss", "sub": "sub", + "nbf": now.Unix(), + }, + WebhooksKey: map[string]interface{}{ + "Test": map[string]interface{}{ + "notAfter": now.Add(10 * time.Hour).Format(time.RFC3339), + }, }, })}}, &Certificate{ Subject: Subject{CommonName: "commonName"}, SANs: []SubjectAlternativeName{{Type: DNSType, Value: "foo.com"}}, EmailAddresses: []string{"root@foo.com"}, URIs: []*url.URL{{Scheme: "https", Host: "iss", Fragment: "sub"}}, + NotBefore: now, + NotAfter: now.Add(10 * time.Hour), KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{ x509.ExtKeyUsageServerAuth, @@ -219,6 +228,8 @@ func TestNewCertificate(t *testing.T) { EmailAddresses: []string{"jane@doe.com"}, URIs: []*url.URL{{Scheme: "https", Host: "doe.com"}}, SANs: []SubjectAlternativeName{{Type: DNSType, Value: "www.doe.com"}}, + NotBefore: time.Unix(1234567890, 0).UTC(), + NotAfter: time.Unix(1234654290, 0).UTC(), Extensions: []Extension{{ID: []int{1, 2, 3, 4}, Critical: true, Value: []byte("extension")}}, KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}), @@ -309,6 +320,8 @@ func TestNewCertificateTemplate(t *testing.T) { (dict "type" "userPrincipalName" "value" .Token.upn) (dict "type" "1.2.3.4" "value" (printf "int:%s" .Insecure.User.id)) ) | toJson }}, + "notBefore": "{{ .Token.nbf | toTime }}", + "notAfter": {{ now | dateModify "24h" | toJson }}, {{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }} "keyUsage": ["keyEncipherment", "digitalSignature"], {{- else }} @@ -334,11 +347,13 @@ func TestNewCertificateTemplate(t *testing.T) { data.SetToken(map[string]any{ "upn": "foo@upn.com", "pi": "0123456789", + "nbf": time.Now().Unix(), }) iss, issPriv := createIssuerCertificate(t, "issuer") cr, priv := createCertificateRequest(t, "commonName", sans) + now := time.Now().Truncate(time.Second) cert, err := NewCertificate(cr, WithTemplate(tpl, data)) require.NoError(t, err) @@ -354,6 +369,9 @@ func TestNewCertificateTemplate(t *testing.T) { }, }, crt.Subject) + assert.WithinDuration(t, now, crt.NotBefore, 2*time.Second) + assert.WithinDuration(t, now.Add(24*time.Hour), crt.NotAfter, 2*time.Second) + // Create expected SAN extension var rawValues []asn1.RawValue for _, san := range []SubjectAlternativeName{ @@ -415,6 +433,7 @@ func TestNewCertificateTemplate(t *testing.T) { } func TestNewCertificateFromX509(t *testing.T) { + now := time.Now().UTC().Truncate(time.Second) priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) require.NoError(t, err) template := &x509.Certificate{ // similar template as the certificate request for TestNewCertificate @@ -500,11 +519,18 @@ func TestNewCertificateFromX509(t *testing.T) { "iss": "https://iss", "sub": "sub", }, + WebhooksKey: map[string]interface{}{ + "Test": map[string]interface{}{ + "notAfter": now.Add(10 * time.Hour).Format(time.RFC3339), + }, + }, })}}, &Certificate{ Subject: Subject{CommonName: "commonName"}, SANs: []SubjectAlternativeName{{Type: DNSType, Value: "foo.com"}}, EmailAddresses: []string{"root@foo.com"}, URIs: []*url.URL{{Scheme: "https", Host: "iss", Fragment: "sub"}}, + NotBefore: now, + NotAfter: now.Add(10 * time.Hour), KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{ x509.ExtKeyUsageServerAuth, @@ -523,6 +549,8 @@ func TestNewCertificateFromX509(t *testing.T) { EmailAddresses: []string{"jane@doe.com"}, URIs: []*url.URL{{Scheme: "https", Host: "doe.com"}}, SANs: []SubjectAlternativeName{{Type: DNSType, Value: "www.doe.com"}}, + NotBefore: time.Unix(1234567890, 0).UTC(), + NotAfter: time.Unix(1234654290, 0).UTC(), Extensions: []Extension{{ID: []int{1, 2, 3, 4}, Critical: true, Value: []byte("extension")}}, KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}), @@ -572,6 +600,7 @@ func TestNewCertificateFromX509(t *testing.T) { } func TestCertificate_GetCertificate(t *testing.T) { + now := time.Now() type fields struct { Version int Subject Subject @@ -582,6 +611,8 @@ func TestCertificate_GetCertificate(t *testing.T) { IPAddresses MultiIP URIs MultiURL SANs []SubjectAlternativeName + NotBefore time.Time + NotAfter time.Time Extensions []Extension KeyUsage KeyUsage ExtKeyUsage ExtKeyUsage @@ -618,6 +649,8 @@ func TestCertificate_GetCertificate(t *testing.T) { {Type: EmailType, Value: "admin@foo.com"}, {Type: URIType, Value: "mailto:admin@foo.com"}, }, + NotBefore: now, + NotAfter: time.Time{}, Extensions: []Extension{{ID: []int{1, 2, 3, 4}, Critical: true, Value: []byte("custom extension")}}, KeyUsage: KeyUsage(x509.KeyUsageDigitalSignature), ExtKeyUsage: ExtKeyUsage([]x509.ExtKeyUsage{ @@ -641,6 +674,8 @@ func TestCertificate_GetCertificate(t *testing.T) { Subject: pkix.Name{CommonName: "commonName", Organization: []string{"smallstep"}}, Issuer: pkix.Name{}, SerialNumber: big.NewInt(123), + NotBefore: now, + NotAfter: time.Time{}, DNSNames: []string{"foo.bar", "www.foo.bar"}, EmailAddresses: []string{"root@foo.com", "admin@foo.com"}, IPAddresses: []net.IP{net.ParseIP("::1"), net.ParseIP("127.0.0.1")}, @@ -680,6 +715,8 @@ func TestCertificate_GetCertificate(t *testing.T) { IPAddresses: tt.fields.IPAddresses, URIs: tt.fields.URIs, SANs: tt.fields.SANs, + NotBefore: tt.fields.NotBefore, + NotAfter: tt.fields.NotAfter, Extensions: tt.fields.Extensions, KeyUsage: tt.fields.KeyUsage, ExtKeyUsage: tt.fields.ExtKeyUsage, diff --git a/x509util/options_test.go b/x509util/options_test.go index 067d1322..80a284f8 100644 --- a/x509util/options_test.go +++ b/x509util/options_test.go @@ -249,6 +249,7 @@ func TestWithTemplateFile(t *testing.T) { rsa2048, _ := createRSACertificateRequest(t, 2048, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"}) rsa3072, _ := createRSACertificateRequest(t, 3072, "foo", []string{"foo.com", "foo@foo.com", "::1", "https://foo.com"}) + now := time.Now().UTC().Truncate(time.Second) data := TemplateData{ SANsKey: []SubjectAlternativeName{ {Type: "dns", Value: "foo.com"}, @@ -259,6 +260,12 @@ func TestWithTemplateFile(t *testing.T) { TokenKey: map[string]interface{}{ "iss": "https://iss", "sub": "sub", + "nbf": now.Unix(), + }, + WebhooksKey: map[string]interface{}{ + "Test": map[string]interface{}{ + "notAfter": now.Add(10 * time.Hour).Format(time.RFC3339), + }, }, } type args struct { @@ -278,6 +285,8 @@ func TestWithTemplateFile(t *testing.T) { "sans": [{"type":"dns","value":"foo.com"},{"type":"email","value":"root@foo.com"},{"type":"ip","value":"127.0.0.1"},{"type":"uri","value":"uri:foo:bar"}], "emailAddresses": ["foo@foo.com"], "uris": "https://iss#sub", + "notBefore": "` + now.Format(time.RFC3339) + `", + "notAfter": "` + now.Add(10*time.Hour).Format(time.RFC3339) + `", "keyUsage": ["digitalSignature"], "extKeyUsage": ["serverAuth", "clientAuth"] }`), @@ -288,6 +297,8 @@ func TestWithTemplateFile(t *testing.T) { "sans": [{"type":"dns","value":"foo.com"},{"type":"email","value":"root@foo.com"},{"type":"ip","value":"127.0.0.1"},{"type":"uri","value":"uri:foo:bar"}], "emailAddresses": ["foo@foo.com"], "uris": "https://iss#sub", + "notBefore": "` + now.Format(time.RFC3339) + `", + "notAfter": "` + now.Add(10*time.Hour).Format(time.RFC3339) + `", "keyUsage": ["keyEncipherment", "digitalSignature"], "extKeyUsage": ["serverAuth", "clientAuth"] }`), diff --git a/x509util/testdata/example.tpl b/x509util/testdata/example.tpl index 286edb5c..81c0637e 100644 --- a/x509util/testdata/example.tpl +++ b/x509util/testdata/example.tpl @@ -7,6 +7,8 @@ {{- if .Token }} "uris": "{{ .Token.iss }}#{{ .Token.sub }}", {{- end }} + "notBefore": "{{ dateInZone "2006-01-02T15:04:05Z07:00" .Token.nbf "UTC" }}", + "notAfter": "{{ .Webhooks.Test.notAfter }}", {{- if typeIs "*rsa.PublicKey" .Insecure.CR.PublicKey }} {{- if lt .Insecure.CR.PublicKey.Size 384 }} {{ fail "Key length must be at least 3072 bits" }} diff --git a/x509util/testdata/fullsimple.tpl b/x509util/testdata/fullsimple.tpl index 92b02f7b..1a879de1 100644 --- a/x509util/testdata/fullsimple.tpl +++ b/x509util/testdata/fullsimple.tpl @@ -8,6 +8,8 @@ "ipAddresses": "127.0.0.1", "uris": "https://doe.com", "sans": [{"type":"dns", "value":"www.doe.com"}], + "notBefore": "2009-02-13T23:31:30Z", + "notAfter": "2009-02-14T23:31:30Z", "extensions": [{"id":"1.2.3.4","critical":true,"value":"ZXh0ZW5zaW9u"}], "keyUsage": ["digitalSignature"], "extKeyUsage": ["serverAuth"],