forked from TrueCloudLab/certificates
Add support for lifetime.
This commit is contained in:
parent
ae4b8f58b8
commit
7958f6ebb5
3 changed files with 91 additions and 3 deletions
|
@ -172,8 +172,9 @@ func (s *StepCAS) createCertificate(cr *x509.CertificateRequest, lifetime time.D
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := s.client.Sign(&api.SignRequest{
|
resp, err := s.client.Sign(&api.SignRequest{
|
||||||
CsrPEM: api.CertificateRequest{CertificateRequest: cr},
|
CsrPEM: api.CertificateRequest{CertificateRequest: cr},
|
||||||
OTT: token,
|
OTT: token,
|
||||||
|
NotAfter: s.lifetime(lifetime),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -203,3 +204,13 @@ func (s *StepCAS) revokeToken(subject string) (string, error) {
|
||||||
|
|
||||||
return "", errors.New("stepCAS does not have any provisioner configured")
|
return "", errors.New("stepCAS does not have any provisioner configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *StepCAS) lifetime(d time.Duration) api.TimeDuration {
|
||||||
|
if s.x5c != nil {
|
||||||
|
d = s.x5c.Lifetime(d)
|
||||||
|
}
|
||||||
|
var td api.TimeDuration
|
||||||
|
td.SetDuration(d)
|
||||||
|
println(td.String(), d.String())
|
||||||
|
return td
|
||||||
|
}
|
||||||
|
|
|
@ -17,6 +17,12 @@ import (
|
||||||
|
|
||||||
const defaultValidity = 5 * time.Minute
|
const defaultValidity = 5 * time.Minute
|
||||||
|
|
||||||
|
// timeNow returns the current time.
|
||||||
|
// This method is used for unit testing purposes.
|
||||||
|
var timeNow = func() time.Time {
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
type x5cIssuer struct {
|
type x5cIssuer struct {
|
||||||
caURL *url.URL
|
caURL *url.URL
|
||||||
certFile string
|
certFile string
|
||||||
|
@ -58,6 +64,18 @@ func (i *x5cIssuer) RevokeToken(subject string) (string, error) {
|
||||||
return i.createToken(aud, subject, nil)
|
return i.createToken(aud, subject, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *x5cIssuer) Lifetime(d time.Duration) time.Duration {
|
||||||
|
cert, err := pemutil.ReadCertificate(i.certFile, pemutil.WithFirstBlock())
|
||||||
|
if err != nil {
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
now := timeNow()
|
||||||
|
if now.Add(d + time.Minute).After(cert.NotAfter) {
|
||||||
|
return cert.NotAfter.Sub(now) - time.Minute
|
||||||
|
}
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error) {
|
||||||
signer, err := newX5CSigner(i.certFile, i.keyFile)
|
signer, err := newX5CSigner(i.certFile, i.keyFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -86,7 +104,7 @@ func (i *x5cIssuer) createToken(aud, sub string, sans []string) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultClaims(iss, sub, aud, id string) jose.Claims {
|
func defaultClaims(iss, sub, aud, id string) jose.Claims {
|
||||||
now := time.Now()
|
now := timeNow()
|
||||||
return jose.Claims{
|
return jose.Claims{
|
||||||
ID: id,
|
ID: id,
|
||||||
Issuer: iss,
|
Issuer: iss,
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.step.sm/crypto/jose"
|
"go.step.sm/crypto/jose"
|
||||||
)
|
)
|
||||||
|
@ -25,6 +26,17 @@ func (b noneSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts)
|
||||||
return digest, nil
|
return digest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fakeTime(t *testing.T) {
|
||||||
|
t.Helper()
|
||||||
|
tmp := timeNow
|
||||||
|
t.Cleanup(func() {
|
||||||
|
timeNow = tmp
|
||||||
|
})
|
||||||
|
timeNow = func() time.Time {
|
||||||
|
return testX5CCrt.NotBefore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_x5cIssuer_SignToken(t *testing.T) {
|
func Test_x5cIssuer_SignToken(t *testing.T) {
|
||||||
caURL, err := url.Parse("https://ca.smallstep.com")
|
caURL, err := url.Parse("https://ca.smallstep.com")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -154,6 +166,53 @@ func Test_x5cIssuer_RevokeToken(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_x5cIssuer_Lifetime(t *testing.T) {
|
||||||
|
fakeTime(t)
|
||||||
|
caURL, err := url.Parse("https://ca.smallstep.com")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// With a leeway of 1m the max duration will be 59m.
|
||||||
|
maxDuration := testX5CCrt.NotAfter.Sub(timeNow()) - time.Minute
|
||||||
|
|
||||||
|
type fields struct {
|
||||||
|
caURL *url.URL
|
||||||
|
certFile string
|
||||||
|
keyFile string
|
||||||
|
issuer string
|
||||||
|
}
|
||||||
|
type args struct {
|
||||||
|
d time.Duration
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
fields fields
|
||||||
|
args args
|
||||||
|
want time.Duration
|
||||||
|
}{
|
||||||
|
{"ok 0s", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{0}, 0},
|
||||||
|
{"ok 1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{time.Minute}, time.Minute},
|
||||||
|
{"ok max-1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration - time.Minute}, maxDuration - time.Minute},
|
||||||
|
{"ok max", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration}, maxDuration},
|
||||||
|
{"ok max+1m", fields{caURL, testX5CPath, testX5CKeyPath, "X5C"}, args{maxDuration + time.Minute}, maxDuration},
|
||||||
|
{"ok fail", fields{caURL, testX5CPath + ".missing", testX5CKeyPath, "X5C"}, args{maxDuration + time.Minute}, maxDuration + time.Minute},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
i := &x5cIssuer{
|
||||||
|
caURL: tt.fields.caURL,
|
||||||
|
certFile: tt.fields.certFile,
|
||||||
|
keyFile: tt.fields.keyFile,
|
||||||
|
issuer: tt.fields.issuer,
|
||||||
|
}
|
||||||
|
if got := i.Lifetime(tt.args.d); got != tt.want {
|
||||||
|
t.Errorf("x5cIssuer.Lifetime() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Test_newJoseSigner(t *testing.T) {
|
func Test_newJoseSigner(t *testing.T) {
|
||||||
mustSigner := func(args ...interface{}) crypto.Signer {
|
mustSigner := func(args ...interface{}) crypto.Signer {
|
||||||
if err := args[len(args)-1]; err != nil {
|
if err := args[len(args)-1]; err != nil {
|
||||||
|
|
Loading…
Reference in a new issue