Mariano Cano 1 month ago committed by GitHub
commit 1278d65cd4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -88,6 +88,39 @@ func generateToken(sub, iss, aud string, sans []string, iat time.Time, jwk *jose
return jose.Signed(sig).Claims(claims).CompactSerialize()
}
func generateCustomToken(sub, iss, aud string, jwk *jose.JSONWebKey, extraHeaders, extraClaims map[string]any) (string, error) {
so := new(jose.SignerOptions)
so.WithType("JWT")
so.WithHeader("kid", jwk.KeyID)
for k, v := range extraHeaders {
so.WithHeader(jose.HeaderKey(k), v)
}
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, so)
if err != nil {
return "", err
}
id, err := randutil.ASCII(64)
if err != nil {
return "", err
}
iat := time.Now()
claims := jose.Claims{
ID: id,
Subject: sub,
Issuer: iss,
IssuedAt: jose.NewNumericDate(iat),
NotBefore: jose.NewNumericDate(iat),
Expiry: jose.NewNumericDate(iat.Add(5 * time.Minute)),
Audience: []string{aud},
}
return jose.Signed(sig).Claims(claims).Claims(extraClaims).CompactSerialize()
}
func TestAuthority_authorizeToken(t *testing.T) {
a := testAuthority(t)
@ -491,7 +524,7 @@ func TestAuthority_authorizeSign(t *testing.T) {
}
} else {
if assert.Nil(t, tc.err) {
assert.Equals(t, 10, len(got)) // number of provisioner.SignOptions returned
assert.Equals(t, 11, len(got)) // number of provisioner.SignOptions returned
}
}
})

@ -19,8 +19,9 @@ import (
// jwtPayload extends jwt.Claims with step attributes.
type jwtPayload struct {
jose.Claims
SANs []string `json:"sans,omitempty"`
Step *stepPayload `json:"step,omitempty"`
SANs []string `json:"sans,omitempty"`
Step *stepPayload `json:"step,omitempty"`
Confirmation *cnfPayload `json:"cnf,omitempty"`
}
type stepPayload struct {
@ -28,6 +29,10 @@ type stepPayload struct {
RA *RAInfo `json:"ra,omitempty"`
}
type cnfPayload struct {
Kid string `json:"kid,omitempty"`
}
// JWK is the default provisioner, an entity that can sign tokens necessary for
// signature requests.
type JWK struct {
@ -183,6 +188,12 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
}
}
// Check the fingerprint of the certificate request if given.
var fingerprint string
if claims.Confirmation != nil {
fingerprint = claims.Confirmation.Kid
}
return []SignOption{
self,
templateOptions,
@ -190,6 +201,7 @@ func (p *JWK) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
newProvisionerExtensionOption(TypeJWK, p.Name, p.Key.KeyID).WithControllerOptions(p.ctl),
profileDefaultDuration(p.ctl.Claimer.DefaultTLSCertDuration()),
// validators
fingerprintValidator(fingerprint),
commonNameSliceValidator(append([]string{claims.Subject}, claims.SANs...)),
defaultPublicKeyValidator{},
newDefaultSANsValidator(ctx, claims.SANs),
@ -229,6 +241,11 @@ func (p *JWK) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
sshCertOptionsValidator(SignSSHOptions{KeyID: claims.Subject}),
}
// Check the fingerprint of the certificate request if given.
if claims.Confirmation != nil && claims.Confirmation.Kid != "" {
signOptions = append(signOptions, sshFingerprintValidator(claims.Confirmation.Kid))
}
// Default template attributes.
certType := sshutil.UserCert
keyID := claims.Subject

@ -13,7 +13,9 @@ import (
"testing"
"time"
"go.step.sm/crypto/fingerprint"
"go.step.sm/crypto/jose"
"golang.org/x/crypto/ssh"
"github.com/smallstep/assert"
"github.com/smallstep/certificates/api/render"
@ -247,6 +249,9 @@ func TestJWK_AuthorizeSign(t *testing.T) {
t2, err := generateToken("subject", p1.Name, testAudiences.Sign[0], "name@smallstep.com", []string{}, time.Now(), key1)
assert.FatalError(t, err)
t3, err := generateCustomToken("subject", p1.Name, testAudiences.Sign[0], key1, nil, map[string]any{"cnf": map[string]any{"kid": "fingerprint"}})
assert.FatalError(t, err)
// invalid signature
failSig := t1[0 : len(t1)-2]
@ -254,12 +259,13 @@ func TestJWK_AuthorizeSign(t *testing.T) {
token string
}
tests := []struct {
name string
prov *JWK
args args
code int
err error
sans []string
name string
prov *JWK
args args
code int
err error
sans []string
fingerprint string
}{
{
name: "fail-signature",
@ -284,6 +290,15 @@ func TestJWK_AuthorizeSign(t *testing.T) {
err: nil,
sans: []string{"subject"},
},
{
name: "ok-cnf",
prov: p1,
args: args{t3},
code: http.StatusOK,
err: nil,
sans: []string{"subject"},
fingerprint: "fingerprint",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@ -297,7 +312,7 @@ func TestJWK_AuthorizeSign(t *testing.T) {
}
} else {
if assert.NotNil(t, got) {
assert.Equals(t, 10, len(got))
assert.Equals(t, 11, len(got))
for _, o := range got {
switch v := o.(type) {
case *JWK:
@ -321,6 +336,8 @@ func TestJWK_AuthorizeSign(t *testing.T) {
case *x509NamePolicyValidator:
assert.Equals(t, nil, v.policyEngine)
case *WebhookController:
case fingerprintValidator:
assert.Equals(t, tt.fingerprint, string(v))
default:
assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v))
}
@ -393,17 +410,6 @@ func TestJWK_AuthorizeSSHSign(t *testing.T) {
jwk, err := decryptJSONWebKey(p1.EncryptedKey)
assert.FatalError(t, err)
iss, aud := p1.Name, testAudiences.SSHSign[0]
t1, err := generateSimpleSSHUserToken(iss, aud, jwk)
assert.FatalError(t, err)
t2, err := generateSimpleSSHHostToken(iss, aud, jwk)
assert.FatalError(t, err)
// invalid signature
failSig := t1[0 : len(t1)-2]
key, err := generateJSONWebKey()
assert.FatalError(t, err)
@ -417,6 +423,39 @@ func TestJWK_AuthorizeSSHSign(t *testing.T) {
rsa1024, err := rsa.GenerateKey(rand.Reader, 1024)
assert.FatalError(t, err)
// Calculate fingerprint
sshPub, err := ssh.NewPublicKey(pub)
assert.FatalError(t, err)
fp, err := fingerprint.New(sshPub.Marshal(), crypto.SHA256, fingerprint.Base64RawURLFingerprint)
assert.FatalError(t, err)
iss, aud := p1.Name, testAudiences.SSHSign[0]
t1, err := generateSimpleSSHUserToken(iss, aud, jwk)
assert.FatalError(t, err)
t2, err := generateSimpleSSHHostToken(iss, aud, jwk)
assert.FatalError(t, err)
t3, err := generateCustomToken("sub", iss, aud, jwk, nil, map[string]any{
"step": map[string]any{
"ssh": map[string]any{"certType": "host", "principals": []string{"smallstep.com"}},
},
"cnf": map[string]any{"kid": fp},
})
assert.FatalError(t, err)
t4, err := generateCustomToken("sub", iss, aud, jwk, nil, map[string]any{
"step": map[string]any{
"ssh": map[string]any{"certType": "host", "principals": []string{"smallstep.com"}},
},
"cnf": map[string]any{"kid": "bad-fingerprint"},
})
assert.FatalError(t, err)
// invalid signature
failSig := t1[0 : len(t1)-2]
userDuration := p1.ctl.Claimer.DefaultUserSSHCertDuration()
hostDuration := p1.ctl.Claimer.DefaultHostSSHCertDuration()
expectedUserOptions := &SignSSHOptions{
@ -451,9 +490,11 @@ func TestJWK_AuthorizeSSHSign(t *testing.T) {
{"host-type", p1, args{t2, SignSSHOptions{CertType: "host"}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-principals", p1, args{t2, SignSSHOptions{Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-options", p1, args{t2, SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"host-cnf", p1, args{t3, SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusOK, false, false},
{"fail-sshCA-disabled", p2, args{"foo", SignSSHOptions{}, pub}, expectedUserOptions, http.StatusUnauthorized, true, false},
{"fail-signature", p1, args{failSig, SignSSHOptions{}, pub}, nil, http.StatusUnauthorized, true, false},
{"rail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true},
{"fail-rsa1024", p1, args{t1, SignSSHOptions{}, rsa1024.Public()}, expectedUserOptions, http.StatusOK, false, true},
{"fail-cnf", p1, args{t4, SignSSHOptions{CertType: "host", Principals: []string{"smallstep.com"}}, pub}, expectedHostOptions, http.StatusUnauthorized, false, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {

@ -5,7 +5,10 @@ import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rsa"
"crypto/sha256"
"crypto/subtle"
"crypto/x509"
"encoding/base64"
"encoding/json"
"net"
"net/http"
@ -492,3 +495,21 @@ func (o *provisionerExtensionOption) Modify(cert *x509.Certificate, _ SignOption
cert.ExtraExtensions = append(cert.ExtraExtensions, ext)
return nil
}
// fingerprintValidator is a CertificateRequestValidator that checks the
// fingerprint of the certificate with the provided one.
type fingerprintValidator string
func (s fingerprintValidator) Valid(cr *x509.CertificateRequest) error {
if s != "" {
expected, err := base64.RawURLEncoding.DecodeString(string(s))
if err != nil {
return errs.ForbiddenErr(err, "error decoding fingerprint")
}
sum := sha256.Sum256(cr.Raw)
if subtle.ConstantTimeCompare(expected, sum[:]) != 1 {
return errs.Forbidden("certificate request fingerprint does not match %q", s)
}
}
return nil
}

@ -2,6 +2,9 @@ package provisioner
import (
"crypto/rsa"
"crypto/sha256"
"crypto/subtle"
"encoding/base64"
"encoding/binary"
"encoding/json"
"fmt"
@ -44,6 +47,13 @@ type SSHCertOptionsValidator interface {
Valid(got SignSSHOptions) error
}
// SSHPublicKeyValidator is the interface used to validate the public key of an
// SSH certificate.
type SSHPublicKeyValidator interface {
SignOption
Valid(got ssh.PublicKey) error
}
// SignSSHOptions contains the options that can be passed to the SignSSH method.
type SignSSHOptions struct {
CertType string `json:"certType"`
@ -419,6 +429,24 @@ func (v *sshNamePolicyValidator) Valid(cert *ssh.Certificate, _ SignSSHOptions)
}
}
// sshFingerprintValidator is a SSHPublicKeyValidator that checks the
// fingerprint of the public key with the provided one.
type sshFingerprintValidator string
func (s sshFingerprintValidator) Valid(key ssh.PublicKey) error {
if s != "" {
expected, err := base64.RawURLEncoding.DecodeString(string(s))
if err != nil {
return errs.ForbiddenErr(err, "error decoding fingerprint")
}
sum := sha256.Sum256(key.Marshal())
if subtle.ConstantTimeCompare(expected, sum[:]) != 1 {
return errs.Forbidden("ssh public key fingerprint does not match %q", s)
}
}
return nil
}
// sshCertTypeUInt32
func sshCertTypeUInt32(ct string) uint32 {
switch ct {

@ -51,6 +51,7 @@ func signSSHCertificate(key crypto.PublicKey, opts SignSSHOptions, signOpts []Si
var mods []SSHCertModifier
var certOptions []sshutil.Option
var validators []SSHCertValidator
var keyValidators []SSHPublicKeyValidator
for _, op := range signOpts {
switch o := op.(type) {
@ -71,11 +72,19 @@ func signSSHCertificate(key crypto.PublicKey, opts SignSSHOptions, signOpts []Si
}
// call webhooks
case *WebhookController:
case sshFingerprintValidator:
keyValidators = append(keyValidators, o)
default:
return nil, fmt.Errorf("signSSH: invalid extra option type %T", o)
}
}
for _, v := range keyValidators {
if err := v.Valid(pub); err != nil {
return nil, err
}
}
// Simulated certificate request with request options.
cr := sshutil.CertificateRequest{
Type: opts.CertType,

@ -765,6 +765,37 @@ func generateToken(sub, iss, aud, email string, sans []string, iat time.Time, jw
return jose.Signed(sig).Claims(claims).CompactSerialize()
}
func generateCustomToken(sub, iss, aud string, jwk *jose.JSONWebKey, extraHeaders, extraClaims map[string]any) (string, error) {
so := new(jose.SignerOptions)
so.WithType("JWT")
so.WithHeader("kid", jwk.KeyID)
for k, v := range extraHeaders {
so.WithHeader(jose.HeaderKey(k), v)
}
sig, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.ES256, Key: jwk.Key}, so)
if err != nil {
return "", err
}
id, err := randutil.ASCII(64)
if err != nil {
return "", err
}
iat := time.Now()
claims := jose.Claims{
ID: id,
Subject: sub,
Issuer: iss,
IssuedAt: jose.NewNumericDate(iat),
NotBefore: jose.NewNumericDate(iat),
Expiry: jose.NewNumericDate(iat.Add(5 * time.Minute)),
Audience: []string{aud},
}
return jose.Signed(sig).Claims(claims).Claims(extraClaims).CompactSerialize()
}
func generateOIDCToken(sub, iss, aud, email, preferredUsername string, iat time.Time, jwk *jose.JSONWebKey, tokOpts ...tokOption) (string, error) {
so := new(jose.SignerOptions)
so.WithType("JWT")

@ -21,9 +21,10 @@ import (
// x5cPayload extends jwt.Claims with step attributes.
type x5cPayload struct {
jose.Claims
SANs []string `json:"sans,omitempty"`
Step *stepPayload `json:"step,omitempty"`
chains [][]*x509.Certificate
SANs []string `json:"sans,omitempty"`
Step *stepPayload `json:"step,omitempty"`
Confirmation *cnfPayload `json:"cnf,omitempty"`
chains [][]*x509.Certificate
}
// X5C is the default provisioner, an entity that can sign tokens necessary for
@ -233,6 +234,12 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
}
}
// Check the fingerprint of the certificate request if given.
var fingerprint string
if claims.Confirmation != nil {
fingerprint = claims.Confirmation.Kid
}
return []SignOption{
self,
templateOptions,
@ -243,6 +250,7 @@ func (p *X5C) AuthorizeSign(ctx context.Context, token string) ([]SignOption, er
x5cLeaf.NotBefore, x5cLeaf.NotAfter,
},
// validators
fingerprintValidator(fingerprint),
commonNameValidator(claims.Subject),
newDefaultSANsValidator(ctx, claims.SANs),
defaultPublicKeyValidator{},
@ -285,6 +293,11 @@ func (p *X5C) AuthorizeSSHSign(_ context.Context, token string) ([]SignOption, e
sshCertOptionsValidator(SignSSHOptions{KeyID: claims.Subject}),
}
// Check the fingerprint of the certificate request if given.
if claims.Confirmation != nil && claims.Confirmation.Kid != "" {
signOptions = append(signOptions, sshFingerprintValidator(claims.Confirmation.Kid))
}
// Default template attributes.
certType := sshutil.UserCert
keyID := claims.Subject

@ -3,6 +3,7 @@ package provisioner
import (
"context"
"crypto/x509"
"encoding/base64"
"errors"
"fmt"
"net/http"
@ -413,11 +414,12 @@ func TestX5C_AuthorizeSign(t *testing.T) {
assert.FatalError(t, err)
type test struct {
p *X5C
token string
code int
err error
sans []string
p *X5C
token string
code int
err error
sans []string
fingerprint string
}
tests := map[string]func(*testing.T) test{
"fail/invalid-token": func(t *testing.T) test {
@ -456,13 +458,36 @@ func TestX5C_AuthorizeSign(t *testing.T) {
sans: []string{"127.0.0.1", "foo", "max@smallstep.com"},
}
},
"ok/cnf": func(t *testing.T) test {
p, err := generateX5C(nil)
assert.FatalError(t, err)
x5c := make([]string, len(certs))
for i, cert := range certs {
x5c[i] = base64.StdEncoding.EncodeToString(cert.Raw)
}
extraHeaders := map[string]any{"x5c": x5c}
extraClaims := map[string]any{
"sans": []string{"127.0.0.1", "foo", "max@smallstep.com"},
"cnf": map[string]any{"kid": "fingerprint"},
}
tok, err := generateCustomToken("foo", p.GetName(), testAudiences.Sign[0], jwk, extraHeaders, extraClaims)
assert.FatalError(t, err)
return test{
p: p,
token: tok,
sans: []string{"127.0.0.1", "foo", "max@smallstep.com"},
fingerprint: "fingerprint",
}
},
}
for name, tt := range tests {
t.Run(name, func(t *testing.T) {
tc := tt(t)
ctx := NewContextWithMethod(context.Background(), SignIdentityMethod)
if opts, err := tc.p.AuthorizeSign(ctx, tc.token); err != nil {
if assert.NotNil(t, tc.err) {
if assert.NotNil(t, tc.err, err.Error()) {
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tc.code)
@ -472,7 +497,7 @@ func TestX5C_AuthorizeSign(t *testing.T) {
} else {
if assert.Nil(t, tc.err) {
if assert.NotNil(t, opts) {
assert.Equals(t, 10, len(opts))
assert.Equals(t, 11, len(opts))
for _, o := range opts {
switch v := o.(type) {
case *X5C:
@ -502,6 +527,8 @@ func TestX5C_AuthorizeSign(t *testing.T) {
assert.Len(t, 0, v.webhooks)
assert.Equals(t, linkedca.Webhook_X509, v.certType)
assert.Len(t, 2, v.options)
case fingerprintValidator:
assert.Equals(t, tc.fingerprint, string(v))
default:
assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v))
}
@ -627,11 +654,13 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
_, fn := mockNow()
defer fn()
type test struct {
p *X5C
token string
claims *x5cPayload
code int
err error
p *X5C
token string
claims *x5cPayload
fingerprint string
count int
code int
err error
}
tests := map[string]func(*testing.T) test{
"fail/sshCA-disabled": func(t *testing.T) test {
@ -719,7 +748,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
Audience: []string{testAudiences.SSHSign[0]},
},
Step: &stepPayload{SSH: &SignSSHOptions{
CertType: SSHHostCert,
CertType: SSHUserCert,
KeyID: "foo",
Principals: []string{"max", "mariano", "alan"},
ValidAfter: TimeDuration{d: 5 * time.Minute},
@ -732,6 +761,7 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
p: p,
claims: claims,
token: tok,
count: 12,
}
},
"ok/without-claims": func(t *testing.T) test {
@ -759,6 +789,42 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
p: p,
claims: claims,
token: tok,
count: 10,
}
},
"ok/cnf": func(t *testing.T) test {
p, err := generateX5C(nil)
assert.FatalError(t, err)
id, err := randutil.ASCII(64)
assert.FatalError(t, err)
now := time.Now()
claims := &x5cPayload{
Claims: jose.Claims{
ID: id,
Subject: "foo",
Issuer: p.GetName(),
IssuedAt: jose.NewNumericDate(now),
NotBefore: jose.NewNumericDate(now),
Expiry: jose.NewNumericDate(now.Add(5 * time.Minute)),
Audience: []string{testAudiences.SSHSign[0]},
},
Step: &stepPayload{SSH: &SignSSHOptions{
CertType: SSHHostCert,
Principals: []string{"host.smallstep.com"},
}},
Confirmation: &cnfPayload{
Kid: "fingerprint",
},
}
tok, err := generateX5CSSHToken(x5cJWK, claims, withX5CHdr(x5cCerts))
assert.FatalError(t, err)
return test{
p: p,
claims: claims,
token: tok,
fingerprint: "fingerprint",
count: 11,
}
},
}
@ -808,16 +874,14 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
assert.Len(t, 0, v.webhooks)
assert.Equals(t, linkedca.Webhook_SSH, v.certType)
assert.Len(t, 2, v.options)
case sshFingerprintValidator:
assert.Equals(t, tc.fingerprint, string(v))
default:
assert.FatalError(t, fmt.Errorf("unexpected sign option of type %T", v))
}
tot++
}
if tc.claims.Step.SSH.CertType != "" {
assert.Equals(t, tot, 12)
} else {
assert.Equals(t, tot, 10)
}
assert.Equals(t, tc.count, tot)
}
}
}

@ -154,12 +154,16 @@ func (a *Authority) SignSSH(ctx context.Context, key ssh.PublicKey, opts provisi
func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisioner.SignSSHOptions, signOpts ...provisioner.SignOption) (*ssh.Certificate, provisioner.Interface, error) {
var (
certOptions []sshutil.Option
mods []provisioner.SSHCertModifier
validators []provisioner.SSHCertValidator
certOptions []sshutil.Option
mods []provisioner.SSHCertModifier
validators []provisioner.SSHCertValidator
keyValidators []provisioner.SSHPublicKeyValidator
)
// Validate given options.
// Validate given key and options
if key == nil {
return nil, nil, errs.BadRequest("ssh public key cannot be nil")
}
if err := opts.Validate(); err != nil {
return nil, nil, err
}
@ -183,6 +187,10 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi
case provisioner.SSHCertModifier:
mods = append(mods, o)
// validate the ssh public key
case provisioner.SSHPublicKeyValidator:
keyValidators = append(keyValidators, o)
// validate the ssh.Certificate
case provisioner.SSHCertValidator:
validators = append(validators, o)
@ -202,6 +210,16 @@ func (a *Authority) signSSH(ctx context.Context, key ssh.PublicKey, opts provisi
}
}
// Validate public key
for _, v := range keyValidators {
if err := v.Valid(key); err != nil {
return nil, nil, errs.ApplyOptions(
errs.ForbiddenErr(err, err.Error()),
errs.WithKeyVal("signOptions", signOpts),
)
}
}
// Simulated certificate request with request options.
cr := sshutil.CertificateRequest{
Type: opts.CertType,

@ -15,16 +15,17 @@ import (
"fmt"
"net/http"
"reflect"
"strings"
"testing"
"time"
"go.step.sm/crypto/fingerprint"
"go.step.sm/crypto/jose"
"go.step.sm/crypto/keyutil"
"go.step.sm/crypto/minica"
"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"
@ -239,6 +240,11 @@ func (e *testEnforcer) Enforce(cert *x509.Certificate) error {
return nil
}
func assertHasPrefix(t *testing.T, s, p string, msg ...interface{}) bool {
t.Helper()
return assert.True(t, strings.HasPrefix(s, p), "%q is not a prefix of %q", p, s)
}
func TestAuthority_SignWithContext(t *testing.T) {
pub, priv, err := keyutil.GenerateDefaultKeyPair()
require.NoError(t, err)
@ -418,7 +424,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 +453,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 +482,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 +500,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 +525,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 +545,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
},
}
@ -595,12 +601,49 @@ ZYtQ9Ot36qc=
code: http.StatusForbidden,
}
},
"fail with cnf": func(t *testing.T) *signTest {
csr := getCSR(t, priv)
auth := testAuthority(t)
auth.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
auth.db = &db.MockAuthDB{
MUseToken: func(id, tok string) (bool, error) {
return true, nil
},
MStoreCertificate: func(crt *x509.Certificate) error {
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
assert.Equal(t, crt.DNSNames, []string{"test.smallstep.com"})
return nil
},
}
// Create a token with cnf
tok, err := generateCustomToken("smallstep test", "step-cli", testAudiences.Sign[0], key, nil, map[string]any{
"sans": []string{"test.smallstep.com"},
"cnf": map[string]any{"kid": "bad-fingerprint"},
})
require.NoError(t, err)
opts, err := auth.Authorize(ctx, tok)
require.NoError(t, err)
return &signTest{
auth: auth,
csr: csr,
extraOpts: opts,
signOpts: signOpts,
notBefore: signOpts.NotBefore.Time().Truncate(time.Second),
notAfter: signOpts.NotAfter.Time().Truncate(time.Second),
err: errors.New(`certificate request fingerprint does not match "bad-fingerprint"`),
code: http.StatusForbidden,
}
},
"ok": func(t *testing.T) *signTest {
csr := getCSR(t, priv)
_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 +677,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 +711,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 +745,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 +782,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 +807,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 +828,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 +861,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
},
@ -842,6 +885,44 @@ ZYtQ9Ot36qc=
extensionsCount: 6,
}
},
"ok with cnf": func(t *testing.T) *signTest {
csr := getCSR(t, priv)
fingerprint, err := fingerprint.New(csr.Raw, crypto.SHA256, fingerprint.Base64RawURLFingerprint)
require.NoError(t, err)
auth := testAuthority(t)
auth.config.AuthorityConfig.Template = a.config.AuthorityConfig.Template
auth.db = &db.MockAuthDB{
MUseToken: func(id, tok string) (bool, error) {
return true, nil
},
MStoreCertificate: func(crt *x509.Certificate) error {
assert.Equal(t, crt.Subject.CommonName, "smallstep test")
assert.Equal(t, crt.DNSNames, []string{"test.smallstep.com"})
return nil
},
}
// Create a token with cnf
tok, err := generateCustomToken("smallstep test", "step-cli", testAudiences.Sign[0], key, nil, map[string]any{
"sans": []string{"test.smallstep.com"},
"cnf": map[string]any{"kid": fingerprint},
})
require.NoError(t, err)
opts, err := auth.Authorize(ctx, tok)
require.NoError(t, err)
return &signTest{
auth: auth,
csr: csr,
extraOpts: opts,
signOpts: signOpts,
notBefore: signOpts.NotBefore.Time().Truncate(time.Second),
notAfter: signOpts.NotAfter.Time().Truncate(time.Second),
extensionsCount: 6,
}
},
}
for name, genTestCase := range tests {
@ -853,26 +934,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 +962,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 +984,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 +994,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 +1005,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 +1151,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 +1173,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 +1216,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 +1245,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 +1356,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 +1378,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 +1387,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 +1432,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 +1461,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 +1499,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 +1569,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 +1609,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 +1649,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 +1785,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)

Loading…
Cancel
Save