|
|
|
@ -15,6 +15,7 @@ import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
@ -24,11 +25,11 @@ import (
|
|
|
|
|
"go.step.sm/crypto/pemutil"
|
|
|
|
|
"go.step.sm/crypto/x509util"
|
|
|
|
|
|
|
|
|
|
sassert "github.com/smallstep/assert"
|
|
|
|
|
"github.com/smallstep/certificates/api/render"
|
|
|
|
|
"github.com/smallstep/certificates/authority/config"
|
|
|
|
|
"github.com/smallstep/certificates/authority/policy"
|
|
|
|
|
"github.com/smallstep/certificates/authority/provisioner"
|
|
|
|
|
"github.com/smallstep/certificates/cas/apiv1"
|
|
|
|
|
"github.com/smallstep/certificates/cas/softcas"
|
|
|
|
|
"github.com/smallstep/certificates/db"
|
|
|
|
|
"github.com/smallstep/certificates/errs"
|
|
|
|
@ -223,6 +224,15 @@ func generateSubjectKeyID(pub crypto.PublicKey) ([]byte, error) {
|
|
|
|
|
return hash[:], nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func assertHasPrefix(t *testing.T, s, p string) bool {
|
|
|
|
|
if strings.HasPrefix(s, p) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
t.Helper()
|
|
|
|
|
t.Errorf("'%s' is not a prefix of '%s'", p, s)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type basicConstraints struct {
|
|
|
|
|
IsCA bool `asn1:"optional"`
|
|
|
|
|
MaxPathLen int `asn1:"optional,default:-1"`
|
|
|
|
@ -418,7 +428,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
testAuthority.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -447,7 +457,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
testAuthority.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -476,7 +486,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
testAuthority.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -494,7 +504,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
aa := testAuthority(t)
|
|
|
|
|
aa.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -519,7 +529,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
}))
|
|
|
|
|
aa.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -539,7 +549,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
aa.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
fmt.Println(crt.Subject)
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -600,7 +610,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
_a := testAuthority(t)
|
|
|
|
|
_a.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -634,7 +644,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
_a := testAuthority(t)
|
|
|
|
|
_a.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -668,7 +678,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
testAuthority.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -702,7 +712,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
testAuthority.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -739,7 +749,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
_a.config.AuthorityConfig.Template = &ASN1DN{}
|
|
|
|
|
_a.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject, pkix.Name{})
|
|
|
|
|
assert.Equal(t, crt.Subject, pkix.Name{})
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -764,8 +774,8 @@ ZYtQ9Ot36qc=
|
|
|
|
|
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
|
|
|
|
aa.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
sassert.Equals(t, crt.CRLDistributionPoints, []string{"http://ca.example.org/leaf.crl"})
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.CRLDistributionPoints, []string{"http://ca.example.org/leaf.crl"})
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -785,7 +795,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
aa.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
|
|
|
|
|
aa.db = &db.MockAuthDB{
|
|
|
|
|
MStoreCertificate: func(crt *x509.Certificate) error {
|
|
|
|
|
sassert.Equals(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
@ -818,13 +828,13 @@ ZYtQ9Ot36qc=
|
|
|
|
|
MStoreCertificateChain: func(prov provisioner.Interface, certs ...*x509.Certificate) error {
|
|
|
|
|
p, ok := prov.(attProvisioner)
|
|
|
|
|
if assert.True(t, ok) {
|
|
|
|
|
sassert.Equals(t, &provisioner.AttestationData{
|
|
|
|
|
assert.Equal(t, &provisioner.AttestationData{
|
|
|
|
|
PermanentIdentifier: "1234567890",
|
|
|
|
|
}, p.AttestationData())
|
|
|
|
|
}
|
|
|
|
|
if assert.Len(t, certs, 2) {
|
|
|
|
|
sassert.Equals(t, certs[0].Subject.CommonName, "smallstep test")
|
|
|
|
|
sassert.Equals(t, certs[1].Subject.CommonName, "smallstep Intermediate CA")
|
|
|
|
|
assert.Equal(t, certs[0].Subject.CommonName, "smallstep test")
|
|
|
|
|
assert.Equal(t, certs[1].Subject.CommonName, "smallstep Intermediate CA")
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
},
|
|
|
|
@ -853,26 +863,26 @@ ZYtQ9Ot36qc=
|
|
|
|
|
if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) {
|
|
|
|
|
assert.Nil(t, certChain)
|
|
|
|
|
var sc render.StatusCodedError
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
sassert.Equals(t, sc.StatusCode(), tc.code)
|
|
|
|
|
sassert.HasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
require.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
assert.Equal(t, sc.StatusCode(), tc.code)
|
|
|
|
|
assertHasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
|
|
|
|
|
var ctxErr *errs.Error
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["csr"], tc.csr)
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["signOptions"], tc.signOpts)
|
|
|
|
|
require.True(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
assert.Equal(t, ctxErr.Details["csr"], tc.csr)
|
|
|
|
|
assert.Equal(t, ctxErr.Details["signOptions"], tc.signOpts)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
leaf := certChain[0]
|
|
|
|
|
intermediate := certChain[1]
|
|
|
|
|
if assert.Nil(t, tc.err) {
|
|
|
|
|
sassert.Equals(t, leaf.NotBefore, tc.notBefore)
|
|
|
|
|
sassert.Equals(t, leaf.NotAfter, tc.notAfter)
|
|
|
|
|
assert.Equal(t, leaf.NotBefore, tc.notBefore)
|
|
|
|
|
assert.Equal(t, leaf.NotAfter, tc.notAfter)
|
|
|
|
|
tmplt := a.config.AuthorityConfig.Template
|
|
|
|
|
if tc.csr.Subject.CommonName == "" {
|
|
|
|
|
sassert.Equals(t, leaf.Subject, pkix.Name{})
|
|
|
|
|
assert.Equal(t, leaf.Subject, pkix.Name{})
|
|
|
|
|
} else {
|
|
|
|
|
sassert.Equals(t, leaf.Subject.String(),
|
|
|
|
|
assert.Equal(t, leaf.Subject.String(),
|
|
|
|
|
pkix.Name{
|
|
|
|
|
Country: []string{tmplt.Country},
|
|
|
|
|
Organization: []string{tmplt.Organization},
|
|
|
|
@ -881,18 +891,18 @@ ZYtQ9Ot36qc=
|
|
|
|
|
Province: []string{tmplt.Province},
|
|
|
|
|
CommonName: "smallstep test",
|
|
|
|
|
}.String())
|
|
|
|
|
sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com"})
|
|
|
|
|
assert.Equal(t, leaf.DNSNames, []string{"test.smallstep.com"})
|
|
|
|
|
}
|
|
|
|
|
sassert.Equals(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
sassert.Equals(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
|
|
|
|
|
assert.Equal(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
assert.Equal(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
assert.Equal(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
assert.Equal(t, leaf.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
|
|
|
|
|
|
|
|
|
|
issuer := getDefaultIssuer(a)
|
|
|
|
|
subjectKeyID, err := generateSubjectKeyID(pub)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
assert.Equal(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
|
|
|
|
|
// Verify Provisioner OID
|
|
|
|
|
found := 0
|
|
|
|
@ -903,9 +913,9 @@ ZYtQ9Ot36qc=
|
|
|
|
|
val := stepProvisionerASN1{}
|
|
|
|
|
_, err := asn1.Unmarshal(ext.Value, &val)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, val.Type, provisionerTypeJWK)
|
|
|
|
|
sassert.Equals(t, val.Name, []byte(p.Name))
|
|
|
|
|
sassert.Equals(t, val.CredentialID, []byte(p.Key.KeyID))
|
|
|
|
|
assert.Equal(t, val.Type, provisionerTypeJWK)
|
|
|
|
|
assert.Equal(t, val.Name, []byte(p.Name))
|
|
|
|
|
assert.Equal(t, val.CredentialID, []byte(p.Key.KeyID))
|
|
|
|
|
|
|
|
|
|
// Basic Constraints
|
|
|
|
|
case ext.Id.Equal(asn1.ObjectIdentifier([]int{2, 5, 29, 19})):
|
|
|
|
@ -913,7 +923,7 @@ ZYtQ9Ot36qc=
|
|
|
|
|
_, err := asn1.Unmarshal(ext.Value, &val)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.False(t, val.IsCA, false)
|
|
|
|
|
sassert.Equals(t, val.MaxPathLen, 0)
|
|
|
|
|
assert.Equal(t, val.MaxPathLen, 0)
|
|
|
|
|
|
|
|
|
|
// SAN extension
|
|
|
|
|
case ext.Id.Equal(asn1.ObjectIdentifier([]int{2, 5, 29, 17})):
|
|
|
|
@ -924,10 +934,10 @@ ZYtQ9Ot36qc=
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sassert.Equals(t, found, 1)
|
|
|
|
|
assert.Equal(t, found, 1)
|
|
|
|
|
realIntermediate, err := x509.ParseCertificate(issuer.Raw)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, intermediate, realIntermediate)
|
|
|
|
|
assert.Equal(t, intermediate, realIntermediate)
|
|
|
|
|
assert.Len(t, leaf.Extensions, tc.extensionsCount)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1070,19 +1080,19 @@ func TestAuthority_Renew(t *testing.T) {
|
|
|
|
|
if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) {
|
|
|
|
|
assert.Nil(t, certChain)
|
|
|
|
|
var sc render.StatusCodedError
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
sassert.Equals(t, sc.StatusCode(), tc.code)
|
|
|
|
|
sassert.HasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
require.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
assert.Equal(t, sc.StatusCode(), tc.code)
|
|
|
|
|
assertHasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
|
|
|
|
|
var ctxErr *errs.Error
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String())
|
|
|
|
|
require.True(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
assert.Equal(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String())
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
leaf := certChain[0]
|
|
|
|
|
intermediate := certChain[1]
|
|
|
|
|
if assert.Nil(t, tc.err) {
|
|
|
|
|
sassert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore))
|
|
|
|
|
assert.Equal(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore))
|
|
|
|
|
|
|
|
|
|
assert.True(t, leaf.NotBefore.After(now.Add(-2*time.Minute)))
|
|
|
|
|
assert.True(t, leaf.NotBefore.Before(now.Add(time.Minute)))
|
|
|
|
@ -1092,30 +1102,30 @@ func TestAuthority_Renew(t *testing.T) {
|
|
|
|
|
assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Hour)))
|
|
|
|
|
|
|
|
|
|
tmplt := a.config.AuthorityConfig.Template
|
|
|
|
|
sassert.Equals(t, leaf.RawSubject, tc.cert.RawSubject)
|
|
|
|
|
sassert.Equals(t, leaf.Subject.Country, []string{tmplt.Country})
|
|
|
|
|
sassert.Equals(t, leaf.Subject.Organization, []string{tmplt.Organization})
|
|
|
|
|
sassert.Equals(t, leaf.Subject.Locality, []string{tmplt.Locality})
|
|
|
|
|
sassert.Equals(t, leaf.Subject.StreetAddress, []string{tmplt.StreetAddress})
|
|
|
|
|
sassert.Equals(t, leaf.Subject.Province, []string{tmplt.Province})
|
|
|
|
|
sassert.Equals(t, leaf.Subject.CommonName, tmplt.CommonName)
|
|
|
|
|
|
|
|
|
|
sassert.Equals(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
|
|
|
|
|
sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
sassert.Equals(t, leaf.ExtKeyUsage,
|
|
|
|
|
assert.Equal(t, leaf.RawSubject, tc.cert.RawSubject)
|
|
|
|
|
assert.Equal(t, leaf.Subject.Country, []string{tmplt.Country})
|
|
|
|
|
assert.Equal(t, leaf.Subject.Organization, []string{tmplt.Organization})
|
|
|
|
|
assert.Equal(t, leaf.Subject.Locality, []string{tmplt.Locality})
|
|
|
|
|
assert.Equal(t, leaf.Subject.StreetAddress, []string{tmplt.StreetAddress})
|
|
|
|
|
assert.Equal(t, leaf.Subject.Province, []string{tmplt.Province})
|
|
|
|
|
assert.Equal(t, leaf.Subject.CommonName, tmplt.CommonName)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
assert.Equal(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
assert.Equal(t, leaf.ExtKeyUsage,
|
|
|
|
|
[]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
|
|
|
|
|
sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"})
|
|
|
|
|
assert.Equal(t, leaf.DNSNames, []string{"test.smallstep.com", "test"})
|
|
|
|
|
|
|
|
|
|
subjectKeyID, err := generateSubjectKeyID(leaf.PublicKey)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
assert.Equal(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
|
|
|
|
|
// We did not change the intermediate before renewing.
|
|
|
|
|
authIssuer := getDefaultIssuer(tc.auth)
|
|
|
|
|
if issuer.SerialNumber == authIssuer.SerialNumber {
|
|
|
|
|
sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
// Compare extensions: they can be in a different order
|
|
|
|
|
for _, ext1 := range tc.cert.Extensions {
|
|
|
|
|
//skip SubjectKeyIdentifier
|
|
|
|
@ -1135,7 +1145,7 @@ func TestAuthority_Renew(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// We did change the intermediate before renewing.
|
|
|
|
|
sassert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId)
|
|
|
|
|
// Compare extensions: they can be in a different order
|
|
|
|
|
for _, ext1 := range tc.cert.Extensions {
|
|
|
|
|
//skip SubjectKeyIdentifier
|
|
|
|
@ -1164,7 +1174,7 @@ func TestAuthority_Renew(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
realIntermediate, err := x509.ParseCertificate(authIssuer.Raw)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, intermediate, realIntermediate)
|
|
|
|
|
assert.Equal(t, intermediate, realIntermediate)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
@ -1275,19 +1285,19 @@ func TestAuthority_Rekey(t *testing.T) {
|
|
|
|
|
if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) {
|
|
|
|
|
assert.Nil(t, certChain)
|
|
|
|
|
var sc render.StatusCodedError
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
sassert.Equals(t, sc.StatusCode(), tc.code)
|
|
|
|
|
sassert.HasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
require.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
assert.Equal(t, sc.StatusCode(), tc.code)
|
|
|
|
|
assertHasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
|
|
|
|
|
var ctxErr *errs.Error
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String())
|
|
|
|
|
require.True(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
assert.Equal(t, ctxErr.Details["serialNumber"], tc.cert.SerialNumber.String())
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
leaf := certChain[0]
|
|
|
|
|
intermediate := certChain[1]
|
|
|
|
|
if assert.Nil(t, tc.err) {
|
|
|
|
|
sassert.Equals(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore))
|
|
|
|
|
assert.Equal(t, leaf.NotAfter.Sub(leaf.NotBefore), tc.cert.NotAfter.Sub(cert.NotBefore))
|
|
|
|
|
|
|
|
|
|
assert.True(t, leaf.NotBefore.After(now.Add(-2*time.Minute)))
|
|
|
|
|
assert.True(t, leaf.NotBefore.Before(now.Add(time.Minute)))
|
|
|
|
@ -1297,7 +1307,7 @@ func TestAuthority_Rekey(t *testing.T) {
|
|
|
|
|
assert.True(t, leaf.NotAfter.Before(expiry.Add(time.Hour)))
|
|
|
|
|
|
|
|
|
|
tmplt := a.config.AuthorityConfig.Template
|
|
|
|
|
sassert.Equals(t, leaf.Subject.String(),
|
|
|
|
|
assert.Equal(t, leaf.Subject.String(),
|
|
|
|
|
pkix.Name{
|
|
|
|
|
Country: []string{tmplt.Country},
|
|
|
|
|
Organization: []string{tmplt.Organization},
|
|
|
|
@ -1306,32 +1316,32 @@ func TestAuthority_Rekey(t *testing.T) {
|
|
|
|
|
Province: []string{tmplt.Province},
|
|
|
|
|
CommonName: tmplt.CommonName,
|
|
|
|
|
}.String())
|
|
|
|
|
sassert.Equals(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
assert.Equal(t, leaf.Issuer, intermediate.Subject)
|
|
|
|
|
|
|
|
|
|
sassert.Equals(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
sassert.Equals(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
sassert.Equals(t, leaf.ExtKeyUsage,
|
|
|
|
|
assert.Equal(t, leaf.SignatureAlgorithm, x509.ECDSAWithSHA256)
|
|
|
|
|
assert.Equal(t, leaf.PublicKeyAlgorithm, x509.ECDSA)
|
|
|
|
|
assert.Equal(t, leaf.ExtKeyUsage,
|
|
|
|
|
[]x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth})
|
|
|
|
|
sassert.Equals(t, leaf.DNSNames, []string{"test.smallstep.com", "test"})
|
|
|
|
|
assert.Equal(t, leaf.DNSNames, []string{"test.smallstep.com", "test"})
|
|
|
|
|
|
|
|
|
|
// Test Public Key and SubjectKeyId
|
|
|
|
|
expectedPK := tc.pk
|
|
|
|
|
if tc.pk == nil {
|
|
|
|
|
expectedPK = cert.PublicKey
|
|
|
|
|
}
|
|
|
|
|
sassert.Equals(t, leaf.PublicKey, expectedPK)
|
|
|
|
|
assert.Equal(t, leaf.PublicKey, expectedPK)
|
|
|
|
|
|
|
|
|
|
subjectKeyID, err := generateSubjectKeyID(expectedPK)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
assert.Equal(t, leaf.SubjectKeyId, subjectKeyID)
|
|
|
|
|
if tc.pk == nil {
|
|
|
|
|
sassert.Equals(t, leaf.SubjectKeyId, cert.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.SubjectKeyId, cert.SubjectKeyId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We did not change the intermediate before renewing.
|
|
|
|
|
authIssuer := getDefaultIssuer(tc.auth)
|
|
|
|
|
if issuer.SerialNumber == authIssuer.SerialNumber {
|
|
|
|
|
sassert.Equals(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.AuthorityKeyId, issuer.SubjectKeyId)
|
|
|
|
|
// Compare extensions: they can be in a different order
|
|
|
|
|
for _, ext1 := range tc.cert.Extensions {
|
|
|
|
|
//skip SubjectKeyIdentifier
|
|
|
|
@ -1351,7 +1361,7 @@ func TestAuthority_Rekey(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// We did change the intermediate before renewing.
|
|
|
|
|
sassert.Equals(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId)
|
|
|
|
|
assert.Equal(t, leaf.AuthorityKeyId, authIssuer.SubjectKeyId)
|
|
|
|
|
// Compare extensions: they can be in a different order
|
|
|
|
|
for _, ext1 := range tc.cert.Extensions {
|
|
|
|
|
//skip SubjectKeyIdentifier
|
|
|
|
@ -1380,7 +1390,7 @@ func TestAuthority_Rekey(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
realIntermediate, err := x509.ParseCertificate(authIssuer.Raw)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
sassert.Equals(t, intermediate, realIntermediate)
|
|
|
|
|
assert.Equal(t, intermediate, realIntermediate)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
@ -1418,7 +1428,7 @@ func TestAuthority_GetTLSOptions(t *testing.T) {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
opts := tc.auth.GetTLSOptions()
|
|
|
|
|
sassert.Equals(t, opts, tc.opts)
|
|
|
|
|
assert.Equal(t, opts, tc.opts)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -1488,9 +1498,9 @@ func TestAuthority_Revoke(t *testing.T) {
|
|
|
|
|
err: errors.New("authority.Revoke; no persistence layer configured"),
|
|
|
|
|
code: http.StatusNotImplemented,
|
|
|
|
|
checkErrDetails: func(err *errs.Error) {
|
|
|
|
|
sassert.Equals(t, err.Details["token"], raw)
|
|
|
|
|
sassert.Equals(t, err.Details["tokenID"], "44")
|
|
|
|
|
sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
assert.Equal(t, err.Details["token"], raw)
|
|
|
|
|
assert.Equal(t, err.Details["tokenID"], "44")
|
|
|
|
|
assert.Equal(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -1528,9 +1538,9 @@ func TestAuthority_Revoke(t *testing.T) {
|
|
|
|
|
err: errors.New("authority.Revoke: force"),
|
|
|
|
|
code: http.StatusInternalServerError,
|
|
|
|
|
checkErrDetails: func(err *errs.Error) {
|
|
|
|
|
sassert.Equals(t, err.Details["token"], raw)
|
|
|
|
|
sassert.Equals(t, err.Details["tokenID"], "44")
|
|
|
|
|
sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
assert.Equal(t, err.Details["token"], raw)
|
|
|
|
|
assert.Equal(t, err.Details["tokenID"], "44")
|
|
|
|
|
assert.Equal(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -1568,9 +1578,9 @@ func TestAuthority_Revoke(t *testing.T) {
|
|
|
|
|
err: errors.New("certificate with serial number 'sn' is already revoked"),
|
|
|
|
|
code: http.StatusBadRequest,
|
|
|
|
|
checkErrDetails: func(err *errs.Error) {
|
|
|
|
|
sassert.Equals(t, err.Details["token"], raw)
|
|
|
|
|
sassert.Equals(t, err.Details["tokenID"], "44")
|
|
|
|
|
sassert.Equals(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
assert.Equal(t, err.Details["token"], raw)
|
|
|
|
|
assert.Equal(t, err.Details["tokenID"], "44")
|
|
|
|
|
assert.Equal(t, err.Details["provisionerID"], "step-cli:4UELJx8e0aS9m0CH3fZ0EB7D5aUPICb759zALHFejvc")
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
@ -1704,17 +1714,17 @@ func TestAuthority_Revoke(t *testing.T) {
|
|
|
|
|
if err := tc.auth.Revoke(tc.ctx, tc.opts); err != nil {
|
|
|
|
|
if assert.NotNil(t, tc.err, fmt.Sprintf("unexpected error: %s", err)) {
|
|
|
|
|
var sc render.StatusCodedError
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
sassert.Equals(t, sc.StatusCode(), tc.code)
|
|
|
|
|
sassert.HasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
require.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
|
|
|
|
|
assert.Equal(t, sc.StatusCode(), tc.code)
|
|
|
|
|
assertHasPrefix(t, err.Error(), tc.err.Error())
|
|
|
|
|
|
|
|
|
|
var ctxErr *errs.Error
|
|
|
|
|
sassert.Fatal(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["serialNumber"], tc.opts.Serial)
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["reasonCode"], tc.opts.ReasonCode)
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["reason"], tc.opts.Reason)
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["MTLS"], tc.opts.MTLS)
|
|
|
|
|
sassert.Equals(t, ctxErr.Details["context"], provisioner.RevokeMethod.String())
|
|
|
|
|
require.True(t, errors.As(err, &ctxErr), "error is not of type *errs.Error")
|
|
|
|
|
assert.Equal(t, ctxErr.Details["serialNumber"], tc.opts.Serial)
|
|
|
|
|
assert.Equal(t, ctxErr.Details["reasonCode"], tc.opts.ReasonCode)
|
|
|
|
|
assert.Equal(t, ctxErr.Details["reason"], tc.opts.Reason)
|
|
|
|
|
assert.Equal(t, ctxErr.Details["MTLS"], tc.opts.MTLS)
|
|
|
|
|
assert.Equal(t, ctxErr.Details["context"], provisioner.RevokeMethod.String())
|
|
|
|
|
|
|
|
|
|
if tc.checkErrDetails != nil {
|
|
|
|
|
tc.checkErrDetails(ctxErr)
|
|
|
|
@ -1952,3 +1962,39 @@ func TestAuthority_CRL(t *testing.T) {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type notImplementedCAS struct{}
|
|
|
|
|
|
|
|
|
|
func (notImplementedCAS) CreateCertificate(req *apiv1.CreateCertificateRequest) (*apiv1.CreateCertificateResponse, error) {
|
|
|
|
|
return nil, apiv1.NotImplementedError{}
|
|
|
|
|
}
|
|
|
|
|
func (notImplementedCAS) RenewCertificate(req *apiv1.RenewCertificateRequest) (*apiv1.RenewCertificateResponse, error) {
|
|
|
|
|
return nil, apiv1.NotImplementedError{}
|
|
|
|
|
}
|
|
|
|
|
func (notImplementedCAS) RevokeCertificate(req *apiv1.RevokeCertificateRequest) (*apiv1.RevokeCertificateResponse, error) {
|
|
|
|
|
return nil, apiv1.NotImplementedError{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestAuthority_GetX509Signer(t *testing.T) {
|
|
|
|
|
auth := testAuthority(t)
|
|
|
|
|
require.IsType(t, &softcas.SoftCAS{}, auth.x509CAService)
|
|
|
|
|
signer := auth.x509CAService.(*softcas.SoftCAS).Signer
|
|
|
|
|
require.NotNil(t, signer)
|
|
|
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
|
name string
|
|
|
|
|
authority *Authority
|
|
|
|
|
want crypto.Signer
|
|
|
|
|
assertion assert.ErrorAssertionFunc
|
|
|
|
|
}{
|
|
|
|
|
{"ok", auth, signer, assert.NoError},
|
|
|
|
|
{"fail", testAuthority(t, WithX509CAService(notImplementedCAS{})), nil, assert.Error},
|
|
|
|
|
}
|
|
|
|
|
for _, tt := range tests {
|
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
|
got, err := tt.authority.GetX509Signer()
|
|
|
|
|
tt.assertion(t, err)
|
|
|
|
|
assert.Equal(t, tt.want, got)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|