2019-03-08 03:30:17 +00:00
package provisioner
2018-10-05 21:48:36 +00:00
import (
2019-03-11 20:25:19 +00:00
"crypto/x509"
2018-10-05 21:48:36 +00:00
"crypto/x509/pkix"
2019-12-20 21:30:05 +00:00
"fmt"
2018-10-05 21:48:36 +00:00
"net"
2019-03-11 20:25:19 +00:00
"net/url"
2019-12-20 21:30:05 +00:00
"strings"
2018-10-05 21:48:36 +00:00
"testing"
2019-03-11 20:25:19 +00:00
"time"
2019-08-27 00:52:49 +00:00
"github.com/pkg/errors"
"github.com/smallstep/assert"
"github.com/smallstep/cli/crypto/pemutil"
2018-10-05 21:48:36 +00:00
)
2019-03-11 20:25:19 +00:00
func Test_emailOnlyIdentity_Valid ( t * testing . T ) {
uri , err := url . Parse ( "https://example.com/1.0/getUser" )
if err != nil {
t . Fatal ( err )
}
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
e emailOnlyIdentity
args args
wantErr bool
2018-10-05 21:48:36 +00:00
} {
2019-03-11 20:25:19 +00:00
{ "ok" , "name@smallstep.com" , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "name@smallstep.com" } } } , false } ,
{ "DNSNames" , "name@smallstep.com" , args { & x509 . CertificateRequest { DNSNames : [ ] string { "foo.bar.zar" } } } , true } ,
{ "IPAddresses" , "name@smallstep.com" , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { net . IPv4 ( 127 , 0 , 0 , 1 ) } } } , true } ,
{ "URIs" , "name@smallstep.com" , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { uri } } } , true } ,
{ "no-emails" , "name@smallstep.com" , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { } } } , true } ,
{ "empty-email" , "" , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "" } } } , true } ,
{ "multiple-emails" , "name@smallstep.com" , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "name@smallstep.com" , "foo@smallstep.com" } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . e . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "emailOnlyIdentity.Valid() error = %v, wantErr %v" , err , tt . wantErr )
}
} )
2018-10-05 21:48:36 +00:00
}
2019-03-11 20:25:19 +00:00
}
2018-10-05 21:48:36 +00:00
2019-08-27 00:52:49 +00:00
func Test_defaultPublicKeyValidator_Valid ( t * testing . T ) {
2019-12-20 21:30:05 +00:00
_shortRSA , err := pemutil . Read ( "./testdata/certs/short-rsa.csr" )
2019-08-27 00:52:49 +00:00
assert . FatalError ( t , err )
shortRSA , ok := _shortRSA . ( * x509 . CertificateRequest )
assert . Fatal ( t , ok )
2019-12-20 21:30:05 +00:00
_rsa , err := pemutil . Read ( "./testdata/certs/rsa.csr" )
2019-08-27 00:52:49 +00:00
assert . FatalError ( t , err )
rsaCSR , ok := _rsa . ( * x509 . CertificateRequest )
assert . Fatal ( t , ok )
2019-12-20 21:30:05 +00:00
_ecdsa , err := pemutil . Read ( "./testdata/certs/ecdsa.csr" )
2019-08-27 00:52:49 +00:00
assert . FatalError ( t , err )
ecdsaCSR , ok := _ecdsa . ( * x509 . CertificateRequest )
assert . Fatal ( t , ok )
2019-12-20 21:30:05 +00:00
_ed25519 , err := pemutil . Read ( "./testdata/certs/ed25519.csr" )
2019-08-27 00:52:49 +00:00
assert . FatalError ( t , err )
2020-01-10 18:58:49 +00:00
ed25519CSR , ok := _ed25519 . ( * x509 . CertificateRequest )
2019-08-27 00:52:49 +00:00
assert . Fatal ( t , ok )
v := defaultPublicKeyValidator { }
tests := [ ] struct {
name string
csr * x509 . CertificateRequest
err error
} {
{
"fail/unrecognized-key-type" ,
& x509 . CertificateRequest { PublicKey : "foo" } ,
errors . New ( "unrecognized public key of type 'string' in CSR" ) ,
} ,
{
"fail/rsa/too-short" ,
shortRSA ,
errors . New ( "rsa key in CSR must be at least 2048 bits (256 bytes)" ) ,
} ,
{
"ok/rsa" ,
rsaCSR ,
nil ,
} ,
{
"ok/ecdsa" ,
ecdsaCSR ,
nil ,
} ,
{
"ok/ed25519" ,
2020-01-10 18:58:49 +00:00
ed25519CSR ,
2019-08-27 00:52:49 +00:00
nil ,
} ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := v . Valid ( tt . csr ) ; err != nil {
if assert . NotNil ( t , tt . err ) {
assert . HasPrefix ( t , err . Error ( ) , tt . err . Error ( ) )
}
} else {
assert . Nil ( t , tt . err )
}
} )
}
}
2019-03-11 20:25:19 +00:00
func Test_commonNameValidator_Valid ( t * testing . T ) {
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v commonNameValidator
args args
wantErr bool
} {
{ "ok" , "foo.bar.zar" , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "foo.bar.zar" } } } , false } ,
2020-04-20 19:29:23 +00:00
{ "empty" , "" , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "" } } } , false } ,
2019-03-11 20:25:19 +00:00
{ "wrong" , "foo.bar.zar" , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "example.com" } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "commonNameValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
2018-10-05 21:48:36 +00:00
}
} )
}
2019-07-15 22:52:36 +00:00
}
func Test_commonNameSliceValidator_Valid ( t * testing . T ) {
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v commonNameSliceValidator
args args
wantErr bool
} {
{ "ok" , [ ] string { "foo.bar.zar" } , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "foo.bar.zar" } } } , false } ,
{ "ok" , [ ] string { "example.com" , "foo.bar.zar" } , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "foo.bar.zar" } } } , false } ,
2020-04-20 19:29:23 +00:00
{ "empty" , [ ] string { "" } , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "" } } } , false } ,
2019-07-15 22:52:36 +00:00
{ "wrong" , [ ] string { "foo.bar.zar" } , args { & x509 . CertificateRequest { Subject : pkix . Name { CommonName : "example.com" } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "commonNameSliceValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
}
} )
}
2019-08-23 19:09:16 +00:00
}
func Test_emailAddressesValidator_Valid ( t * testing . T ) {
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v emailAddressesValidator
args args
wantErr bool
} {
{ "ok0" , [ ] string { } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { } } } , false } ,
{ "ok1" , [ ] string { "max@smallstep.com" } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "max@smallstep.com" } } } , false } ,
{ "ok2" , [ ] string { "max@step.com" , "mike@step.com" } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "max@step.com" , "mike@step.com" } } } , false } ,
{ "ok3" , [ ] string { "max@step.com" , "mike@step.com" } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "mike@step.com" , "max@step.com" } } } , false } ,
{ "fail1" , [ ] string { "max@step.com" } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "mike@step.com" } } } , true } ,
{ "fail2" , [ ] string { "mike@step.com" } , args { & x509 . CertificateRequest { EmailAddresses : [ ] string { "max@step.com" , "mike@step.com" } } } , true } ,
{ "fail3" , [ ] string { "mike@step.com" , "max@step.com" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "mike@step.com" , "mex@step.com" } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "dnsNamesValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
}
} )
}
2018-10-05 21:48:36 +00:00
}
2019-03-11 20:25:19 +00:00
func Test_dnsNamesValidator_Valid ( t * testing . T ) {
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v dnsNamesValidator
args args
wantErr bool
2018-10-05 21:48:36 +00:00
} {
2019-03-11 20:25:19 +00:00
{ "ok0" , [ ] string { } , args { & x509 . CertificateRequest { DNSNames : [ ] string { } } } , false } ,
{ "ok1" , [ ] string { "foo.bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "foo.bar.zar" } } } , false } ,
{ "ok2" , [ ] string { "foo.bar.zar" , "bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "foo.bar.zar" , "bar.zar" } } } , false } ,
{ "ok3" , [ ] string { "foo.bar.zar" , "bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "bar.zar" , "foo.bar.zar" } } } , false } ,
{ "fail1" , [ ] string { "foo.bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "bar.zar" } } } , true } ,
{ "fail2" , [ ] string { "foo.bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "bar.zar" , "foo.bar.zar" } } } , true } ,
{ "fail3" , [ ] string { "foo.bar.zar" , "bar.zar" } , args { & x509 . CertificateRequest { DNSNames : [ ] string { "foo.bar.zar" , "zar.bar" } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "dnsNamesValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
}
} )
2018-10-05 21:48:36 +00:00
}
2019-03-11 20:25:19 +00:00
}
func Test_ipAddressesValidator_Valid ( t * testing . T ) {
ip1 := net . IPv4 ( 10 , 3 , 2 , 1 )
ip2 := net . IPv4 ( 10 , 3 , 2 , 2 )
ip3 := net . IPv4 ( 10 , 3 , 2 , 3 )
2018-10-05 21:48:36 +00:00
2019-03-11 20:25:19 +00:00
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v ipAddressesValidator
args args
wantErr bool
} {
{ "ok0" , [ ] net . IP { } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { } } } , false } ,
{ "ok1" , [ ] net . IP { ip1 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip1 } } } , false } ,
{ "ok2" , [ ] net . IP { ip1 , ip2 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip1 , ip2 } } } , false } ,
{ "ok3" , [ ] net . IP { ip1 , ip2 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip2 , ip1 } } } , false } ,
{ "fail1" , [ ] net . IP { ip1 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip2 } } } , true } ,
{ "fail2" , [ ] net . IP { ip1 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip2 , ip1 } } } , true } ,
{ "fail3" , [ ] net . IP { ip1 , ip2 } , args { & x509 . CertificateRequest { IPAddresses : [ ] net . IP { ip1 , ip3 } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "ipAddressesValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
2018-10-05 21:48:36 +00:00
}
} )
}
}
2020-06-23 18:10:45 +00:00
func Test_urisValidator_Valid ( t * testing . T ) {
u1 , err := url . Parse ( "https://ca.smallstep.com" )
assert . FatalError ( t , err )
u2 , err := url . Parse ( "https://google.com/index.html" )
assert . FatalError ( t , err )
2020-06-24 16:58:40 +00:00
u3 , err := url . Parse ( "urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959" )
2020-06-23 18:10:45 +00:00
assert . FatalError ( t , err )
fu , err := url . Parse ( "https://unexpected.com" )
assert . FatalError ( t , err )
type args struct {
req * x509 . CertificateRequest
}
tests := [ ] struct {
name string
v urisValidator
args args
wantErr bool
} {
{ "ok0" , [ ] * url . URL { } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { } } } , false } ,
{ "ok1" , [ ] * url . URL { u1 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u1 } } } , false } ,
{ "ok2" , [ ] * url . URL { u1 , u2 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u2 , u1 } } } , false } ,
{ "ok3" , [ ] * url . URL { u2 , u1 , u3 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u3 , u2 , u1 } } } , false } ,
{ "fail1" , [ ] * url . URL { u1 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u2 } } } , true } ,
{ "fail2" , [ ] * url . URL { u1 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u2 , u1 } } } , true } ,
{ "fail3" , [ ] * url . URL { u1 , u2 } , args { & x509 . CertificateRequest { URIs : [ ] * url . URL { u1 , fu } } } , true } ,
}
for _ , tt := range tests {
t . Run ( tt . name , func ( t * testing . T ) {
if err := tt . v . Valid ( tt . args . req ) ; ( err != nil ) != tt . wantErr {
t . Errorf ( "urisValidator.Valid() error = %v, wantErr %v" , err , tt . wantErr )
}
} )
}
}
2020-06-24 16:58:40 +00:00
func Test_defaultSANsValidator_Valid ( t * testing . T ) {
type test struct {
csr * x509 . CertificateRequest
expectedSANs [ ] string
err error
}
tests := map [ string ] func ( ) test {
"fail/dnsNamesValidator" : func ( ) test {
return test {
csr : & x509 . CertificateRequest { DNSNames : [ ] string { "foo" , "bar" } } ,
expectedSANs : [ ] string { "foo" } ,
err : errors . New ( "certificate request does not contain the valid DNS names" ) ,
}
} ,
"fail/emailAddressesValidator" : func ( ) test {
return test {
csr : & x509 . CertificateRequest { EmailAddresses : [ ] string { "max@fx.com" , "mariano@fx.com" } } ,
expectedSANs : [ ] string { "dcow@fx.com" } ,
err : errors . New ( "certificate request does not contain the valid Email Addresses" ) ,
}
} ,
"fail/ipAddressesValidator" : func ( ) test {
return test {
csr : & x509 . CertificateRequest { IPAddresses : [ ] net . IP { net . ParseIP ( "1.1.1.1" ) , net . ParseIP ( "127.0.0.1" ) } } ,
expectedSANs : [ ] string { "127.0.0.1" } ,
err : errors . New ( "IP Addresses claim failed" ) ,
}
} ,
"fail/urisValidator" : func ( ) test {
u1 , err := url . Parse ( "https://google.com" )
assert . FatalError ( t , err )
u2 , err := url . Parse ( "urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959" )
assert . FatalError ( t , err )
return test {
csr : & x509 . CertificateRequest { URIs : [ ] * url . URL { u1 , u2 } } ,
expectedSANs : [ ] string { "urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959" } ,
err : errors . New ( "URIs claim failed" ) ,
}
} ,
"ok" : func ( ) test {
u1 , err := url . Parse ( "https://google.com" )
assert . FatalError ( t , err )
u2 , err := url . Parse ( "urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959" )
assert . FatalError ( t , err )
return test {
csr : & x509 . CertificateRequest {
DNSNames : [ ] string { "foo" , "bar" } ,
EmailAddresses : [ ] string { "max@fx.com" , "mariano@fx.com" } ,
IPAddresses : [ ] net . IP { net . ParseIP ( "1.1.1.1" ) , net . ParseIP ( "127.0.0.1" ) } ,
URIs : [ ] * url . URL { u1 , u2 } ,
} ,
expectedSANs : [ ] string { "foo" , "127.0.0.1" , "max@fx.com" , "mariano@fx.com" , "https://google.com" , "1.1.1.1" , "bar" , "urn:uuid:ddfe62ba-7e99-4bc1-83b3-8f57fe3e9959" } ,
}
} ,
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
if err := defaultSANsValidator ( tt . expectedSANs ) . Valid ( tt . csr ) ; err != nil {
if assert . NotNil ( t , tt . err , fmt . Sprintf ( "expected no error, but got err = %s" , err . Error ( ) ) ) {
assert . True ( t , strings . Contains ( err . Error ( ) , tt . err . Error ( ) ) ,
fmt . Sprintf ( "want err = %s, but got err = %s" , tt . err . Error ( ) , err . Error ( ) ) )
}
} else {
assert . Nil ( t , tt . err , fmt . Sprintf ( "expected err = %s, but not <nil>" , tt . err ) )
}
} )
}
}
func Test_ExtraExtsEnforcer_Enforce ( t * testing . T ) {
e1 := pkix . Extension { Id : [ ] int { 1 , 2 , 3 , 4 , 5 } , Critical : false , Value : [ ] byte ( "foo" ) }
e2 := pkix . Extension { Id : [ ] int { 2 , 2 , 2 } , Critical : false , Value : [ ] byte ( "bar" ) }
stepExt := pkix . Extension { Id : stepOIDProvisioner , Critical : false , Value : [ ] byte ( "baz" ) }
2020-06-25 06:25:15 +00:00
fakeStepExt := pkix . Extension { Id : stepOIDProvisioner , Critical : false , Value : [ ] byte ( "zap" ) }
2020-06-24 16:58:40 +00:00
type test struct {
cert * x509 . Certificate
check func ( * x509 . Certificate )
}
tests := map [ string ] func ( ) test {
"ok/empty-exts" : func ( ) test {
return test {
cert : & x509 . Certificate { } ,
check : func ( cert * x509 . Certificate ) {
assert . Equals ( t , len ( cert . ExtraExtensions ) , 0 )
} ,
}
} ,
"ok/no-step-provisioner-ext" : func ( ) test {
return test {
cert : & x509 . Certificate { ExtraExtensions : [ ] pkix . Extension { e1 , e2 } } ,
check : func ( cert * x509 . Certificate ) {
assert . Equals ( t , len ( cert . ExtraExtensions ) , 0 )
} ,
}
} ,
"ok/step-provisioner-ext" : func ( ) test {
return test {
2020-06-25 06:25:15 +00:00
cert : & x509 . Certificate { ExtraExtensions : [ ] pkix . Extension { e1 , stepExt , fakeStepExt , e2 } } ,
2020-06-24 16:58:40 +00:00
check : func ( cert * x509 . Certificate ) {
assert . Equals ( t , len ( cert . ExtraExtensions ) , 1 )
assert . Equals ( t , cert . ExtraExtensions [ 0 ] , stepExt )
} ,
}
} ,
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
ExtraExtsEnforcer { } . Enforce ( tt . cert )
tt . check ( tt . cert )
} )
}
}
2019-03-11 20:25:19 +00:00
func Test_validityValidator_Valid ( t * testing . T ) {
2019-12-20 21:30:05 +00:00
type test struct {
cert * x509 . Certificate
opts Options
vv * validityValidator
err error
2019-03-11 20:25:19 +00:00
}
2019-12-20 21:30:05 +00:00
tests := map [ string ] func ( ) test {
"fail/notAfter-past" : func ( ) test {
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotAfter : time . Now ( ) . Add ( - 5 * time . Minute ) } ,
opts : Options { } ,
err : errors . New ( "notAfter cannot be in the past" ) ,
}
} ,
"fail/notBefore-after-notAfter" : func ( ) test {
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotBefore : time . Now ( ) . Add ( 10 * time . Minute ) ,
NotAfter : time . Now ( ) . Add ( 5 * time . Minute ) } ,
opts : Options { } ,
err : errors . New ( "notAfter cannot be before notBefore" ) ,
}
} ,
"fail/duration-too-short" : func ( ) test {
n := now ( )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotBefore : n ,
NotAfter : n . Add ( 3 * time . Minute ) } ,
opts : Options { } ,
err : errors . New ( "is less than the authorized minimum certificate duration of " ) ,
}
} ,
"ok/duration-exactly-min" : func ( ) test {
n := now ( )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotBefore : n ,
NotAfter : n . Add ( 5 * time . Minute ) } ,
opts : Options { } ,
}
} ,
"fail/duration-too-great" : func ( ) test {
n := now ( )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotBefore : n ,
NotAfter : n . Add ( 24 * time . Hour + time . Second ) } ,
err : errors . New ( "is more than the authorized maximum certificate duration of " ) ,
}
} ,
"ok/duration-exactly-max" : func ( ) test {
n := time . Now ( )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : & x509 . Certificate { NotBefore : n ,
NotAfter : n . Add ( 24 * time . Hour ) } ,
}
} ,
"ok/duration-exact-min-with-backdate" : func ( ) test {
now := time . Now ( )
cert := & x509 . Certificate { NotBefore : now , NotAfter : now . Add ( 5 * time . Minute ) }
time . Sleep ( time . Second )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : cert ,
opts : Options { Backdate : time . Second } ,
}
} ,
"ok/duration-exact-max-with-backdate" : func ( ) test {
backdate := time . Second
now := time . Now ( )
cert := & x509 . Certificate { NotBefore : now , NotAfter : now . Add ( 24 * time . Hour + backdate ) }
time . Sleep ( backdate )
return test {
vv : & validityValidator { 5 * time . Minute , 24 * time . Hour } ,
cert : cert ,
opts : Options { Backdate : backdate } ,
}
} ,
2019-03-11 20:25:19 +00:00
}
2019-12-20 21:30:05 +00:00
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
if err := tt . vv . Valid ( tt . cert , tt . opts ) ; err != nil {
if assert . NotNil ( t , tt . err , fmt . Sprintf ( "expected no error, but got err = %s" , err . Error ( ) ) ) {
assert . True ( t , strings . Contains ( err . Error ( ) , tt . err . Error ( ) ) ,
fmt . Sprintf ( "want err = %s, but got err = %s" , tt . err . Error ( ) , err . Error ( ) ) )
}
} else {
assert . Nil ( t , tt . err , fmt . Sprintf ( "expected err = %s, but not <nil>" , tt . err ) )
}
} )
2018-10-05 21:48:36 +00:00
}
2019-12-20 21:30:05 +00:00
}
2020-05-17 17:29:28 +00:00
func Test_forceCN_Option ( t * testing . T ) {
type test struct {
so Options
fcn forceCNOption
cert * x509 . Certificate
valid func ( * x509 . Certificate )
err error
}
tests := map [ string ] func ( ) test {
"ok/CN-not-forced" : func ( ) test {
return test {
fcn : forceCNOption { false } ,
so : Options { } ,
cert : & x509 . Certificate {
Subject : pkix . Name { } ,
DNSNames : [ ] string { "acme.example.com" , "step.example.com" } ,
} ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . Subject . CommonName , "" )
} ,
}
} ,
"ok/CN-forced-and-set" : func ( ) test {
return test {
fcn : forceCNOption { true } ,
so : Options { } ,
cert : & x509 . Certificate {
Subject : pkix . Name {
CommonName : "Some Common Name" ,
} ,
DNSNames : [ ] string { "acme.example.com" , "step.example.com" } ,
} ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . Subject . CommonName , "Some Common Name" )
} ,
}
} ,
"ok/CN-forced-and-not-set" : func ( ) test {
return test {
fcn : forceCNOption { true } ,
so : Options { } ,
cert : & x509 . Certificate {
Subject : pkix . Name { } ,
DNSNames : [ ] string { "acme.example.com" , "step.example.com" } ,
} ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . Subject . CommonName , "acme.example.com" )
} ,
}
} ,
"fail/CN-forced-and-empty-DNSNames" : func ( ) test {
return test {
fcn : forceCNOption { true } ,
so : Options { } ,
cert : & x509 . Certificate {
Subject : pkix . Name { } ,
DNSNames : [ ] string { } ,
} ,
err : errors . New ( "Cannot force CN, DNSNames is empty" ) ,
}
} ,
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
2020-07-21 02:01:43 +00:00
if err := tt . fcn . Modify ( tt . cert , tt . so ) ; err != nil {
2020-05-17 17:29:28 +00:00
if assert . NotNil ( t , tt . err ) {
assert . HasPrefix ( t , err . Error ( ) , tt . err . Error ( ) )
}
} else {
if assert . Nil ( t , tt . err ) {
2020-07-21 02:01:43 +00:00
tt . valid ( tt . cert )
2020-05-17 17:29:28 +00:00
}
}
} )
}
}
2019-12-20 21:30:05 +00:00
func Test_profileDefaultDuration_Option ( t * testing . T ) {
type test struct {
so Options
pdd profileDefaultDuration
cert * x509 . Certificate
valid func ( * x509 . Certificate )
}
tests := map [ string ] func ( ) test {
"ok/notBefore-notAfter-duration-empty" : func ( ) test {
return test {
pdd : profileDefaultDuration ( 0 ) ,
so : Options { } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
n := now ( )
assert . True ( t , n . After ( cert . NotBefore ) )
assert . True ( t , n . Add ( - 1 * time . Minute ) . Before ( cert . NotBefore ) )
assert . True ( t , n . Add ( 24 * time . Hour ) . After ( cert . NotAfter ) )
assert . True ( t , n . Add ( 24 * time . Hour ) . Add ( - 1 * time . Minute ) . Before ( cert . NotAfter ) )
} ,
2019-03-11 20:25:19 +00:00
}
2019-12-20 21:30:05 +00:00
} ,
"ok/notBefore-set" : func ( ) test {
nb := time . Now ( ) . Add ( 5 * time . Minute ) . UTC ( )
return test {
pdd : profileDefaultDuration ( 0 ) ,
so : Options { NotBefore : NewTimeDuration ( nb ) } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , nb )
assert . Equals ( t , cert . NotAfter , nb . Add ( 24 * time . Hour ) )
} ,
2018-10-05 21:48:36 +00:00
}
2019-12-20 21:30:05 +00:00
} ,
"ok/duration-set" : func ( ) test {
d := 4 * time . Hour
return test {
pdd : profileDefaultDuration ( d ) ,
so : Options { Backdate : time . Second } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
n := now ( )
assert . True ( t , n . After ( cert . NotBefore ) , fmt . Sprintf ( "expected now = %s to be after cert.NotBefore = %s" , n , cert . NotBefore ) )
assert . True ( t , n . Add ( - 1 * time . Minute ) . Before ( cert . NotBefore ) )
assert . True ( t , n . Add ( d ) . After ( cert . NotAfter ) )
assert . True ( t , n . Add ( d ) . Add ( - 1 * time . Minute ) . Before ( cert . NotAfter ) )
} ,
}
} ,
"ok/notAfter-set" : func ( ) test {
na := now ( ) . Add ( 10 * time . Minute ) . UTC ( )
return test {
pdd : profileDefaultDuration ( 0 ) ,
so : Options { NotAfter : NewTimeDuration ( na ) } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
n := now ( )
2020-06-16 19:16:43 +00:00
assert . True ( t , n . Add ( 3 * time . Second ) . After ( cert . NotBefore ) , fmt . Sprintf ( "expected now = %s to be after cert.NotBefore = %s" , n . Add ( 3 * time . Second ) , cert . NotBefore ) )
2019-12-20 21:30:05 +00:00
assert . True ( t , n . Add ( - 1 * time . Minute ) . Before ( cert . NotBefore ) )
assert . Equals ( t , cert . NotAfter , na )
} ,
}
} ,
"ok/notBefore-and-notAfter-set" : func ( ) test {
nb := time . Now ( ) . Add ( 5 * time . Minute ) . UTC ( )
na := time . Now ( ) . Add ( 10 * time . Minute ) . UTC ( )
d := 4 * time . Hour
return test {
pdd : profileDefaultDuration ( d ) ,
so : Options { NotBefore : NewTimeDuration ( nb ) , NotAfter : NewTimeDuration ( na ) } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , nb )
assert . Equals ( t , cert . NotAfter , na )
} ,
}
} ,
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
2020-07-21 02:01:43 +00:00
assert . FatalError ( t , tt . pdd . Modify ( tt . cert , tt . so ) , "unexpected error" )
time . Sleep ( 1 * time . Nanosecond )
tt . valid ( tt . cert )
2018-10-05 21:48:36 +00:00
} )
}
}
2019-09-05 01:31:09 +00:00
2020-06-25 06:25:15 +00:00
func Test_newProvisionerExtension_Option ( t * testing . T ) {
type test struct {
cert * x509 . Certificate
valid func ( * x509 . Certificate )
}
tests := map [ string ] func ( ) test {
"ok/one-element" : func ( ) test {
return test {
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
if assert . Len ( t , 1 , cert . ExtraExtensions ) {
ext := cert . ExtraExtensions [ 0 ]
assert . Equals ( t , ext . Id , stepOIDProvisioner )
}
} ,
}
} ,
"ok/prepend" : func ( ) test {
return test {
cert : & x509 . Certificate { ExtraExtensions : [ ] pkix . Extension { { Id : stepOIDProvisioner , Critical : true } , { Id : [ ] int { 1 , 2 , 3 } } } } ,
valid : func ( cert * x509 . Certificate ) {
if assert . Len ( t , 3 , cert . ExtraExtensions ) {
ext := cert . ExtraExtensions [ 0 ]
assert . Equals ( t , ext . Id , stepOIDProvisioner )
assert . False ( t , ext . Critical )
}
} ,
}
} ,
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
2020-07-21 02:01:43 +00:00
assert . FatalError ( t , newProvisionerExtensionOption ( TypeJWK , "foo" , "bar" , "baz" , "zap" ) . Modify ( tt . cert , Options { } ) )
tt . valid ( tt . cert )
2020-06-25 06:25:15 +00:00
} )
}
}
2019-09-05 01:31:09 +00:00
func Test_profileLimitDuration_Option ( t * testing . T ) {
2020-01-06 22:34:59 +00:00
n , fn := mockNow ( )
defer fn ( )
2019-09-05 01:31:09 +00:00
type test struct {
pld profileLimitDuration
so Options
cert * x509 . Certificate
valid func ( * x509 . Certificate )
err error
}
tests := map [ string ] func ( ) test {
2020-06-16 19:16:43 +00:00
"fail/notBefore-before-active-window" : func ( ) test {
d , err := ParseTimeDuration ( "6h" )
2019-09-05 01:31:09 +00:00
assert . FatalError ( t , err )
return test {
2020-06-16 19:16:43 +00:00
pld : profileLimitDuration { def : 4 * time . Hour , notBefore : n . Add ( 8 * time . Hour ) } ,
2019-09-05 01:31:09 +00:00
so : Options { NotBefore : d } ,
cert : new ( x509 . Certificate ) ,
2020-06-16 19:16:43 +00:00
err : errors . New ( "requested certificate notBefore (" ) ,
2019-09-05 01:31:09 +00:00
}
} ,
"fail/requested-notAfter-after-limit" : func ( ) test {
d , err := ParseTimeDuration ( "4h" )
assert . FatalError ( t , err )
return test {
pld : profileLimitDuration { def : 4 * time . Hour , notAfter : n . Add ( 6 * time . Hour ) } ,
so : Options { NotBefore : NewTimeDuration ( n . Add ( 3 * time . Hour ) ) , NotAfter : d } ,
cert : new ( x509 . Certificate ) ,
2020-06-16 19:16:43 +00:00
err : errors . New ( "requested certificate notAfter (" ) ,
2019-09-05 01:31:09 +00:00
}
} ,
"ok/valid-notAfter-requested" : func ( ) test {
d , err := ParseTimeDuration ( "2h" )
assert . FatalError ( t , err )
return test {
pld : profileLimitDuration { def : 4 * time . Hour , notAfter : n . Add ( 6 * time . Hour ) } ,
2020-01-06 22:34:59 +00:00
so : Options { NotBefore : NewTimeDuration ( n . Add ( 3 * time . Hour ) ) , NotAfter : d , Backdate : 1 * time . Minute } ,
2019-09-05 01:31:09 +00:00
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , n . Add ( 3 * time . Hour ) )
assert . Equals ( t , cert . NotAfter , n . Add ( 5 * time . Hour ) )
} ,
}
} ,
"ok/valid-notAfter-nil-limit-over-default" : func ( ) test {
return test {
pld : profileLimitDuration { def : 1 * time . Hour , notAfter : n . Add ( 6 * time . Hour ) } ,
2020-01-06 22:34:59 +00:00
so : Options { NotBefore : NewTimeDuration ( n . Add ( 3 * time . Hour ) ) , Backdate : 1 * time . Minute } ,
2019-09-05 01:31:09 +00:00
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , n . Add ( 3 * time . Hour ) )
assert . Equals ( t , cert . NotAfter , n . Add ( 4 * time . Hour ) )
} ,
}
} ,
"ok/valid-notAfter-nil-limit-under-default" : func ( ) test {
return test {
pld : profileLimitDuration { def : 4 * time . Hour , notAfter : n . Add ( 6 * time . Hour ) } ,
2020-01-06 22:34:59 +00:00
so : Options { NotBefore : NewTimeDuration ( n . Add ( 3 * time . Hour ) ) , Backdate : 1 * time . Minute } ,
2019-09-05 01:31:09 +00:00
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , n . Add ( 3 * time . Hour ) )
assert . Equals ( t , cert . NotAfter , n . Add ( 6 * time . Hour ) )
} ,
}
} ,
2020-01-06 22:34:59 +00:00
"ok/over-limit-with-backdate" : func ( ) test {
return test {
pld : profileLimitDuration { def : 24 * time . Hour , notAfter : n . Add ( 6 * time . Hour ) } ,
so : Options { Backdate : 1 * time . Minute } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , n . Add ( - time . Minute ) )
assert . Equals ( t , cert . NotAfter , n . Add ( 6 * time . Hour ) )
} ,
}
} ,
"ok/under-limit-with-backdate" : func ( ) test {
return test {
pld : profileLimitDuration { def : 24 * time . Hour , notAfter : n . Add ( 30 * time . Hour ) } ,
so : Options { Backdate : 1 * time . Minute } ,
cert : new ( x509 . Certificate ) ,
valid : func ( cert * x509 . Certificate ) {
assert . Equals ( t , cert . NotBefore , n . Add ( - time . Minute ) )
assert . Equals ( t , cert . NotAfter , n . Add ( 24 * time . Hour ) )
} ,
}
} ,
2019-09-05 01:31:09 +00:00
}
for name , run := range tests {
t . Run ( name , func ( t * testing . T ) {
tt := run ( )
2020-07-21 02:01:43 +00:00
if err := tt . pld . Modify ( tt . cert , tt . so ) ; err != nil {
2019-09-05 01:31:09 +00:00
if assert . NotNil ( t , tt . err ) {
assert . HasPrefix ( t , err . Error ( ) , tt . err . Error ( ) )
}
} else {
if assert . Nil ( t , tt . err ) {
2020-07-21 02:01:43 +00:00
tt . valid ( tt . cert )
2019-09-05 01:31:09 +00:00
}
}
} )
}
}