Merge branch 'master' into herman/remote-management-helm

This commit is contained in:
Herman Slatman 2022-10-13 23:36:50 +02:00
commit da5d2b405c
No known key found for this signature in database
GPG key ID: F4D8A44EA0A75A4F
10 changed files with 194 additions and 78 deletions

View file

@ -2774,3 +2774,97 @@ func Test_doStepAttestationFormat(t *testing.T) {
})
}
}
func Test_doStepAttestationFormat_noCAIntermediate(t *testing.T) {
ctx := context.Background()
// This CA simulates a YubiKey v5.2.4, where the attestation intermediate in
// the CA does not have the basic constraint extension. With the current
// validation of the certificate the test case below returns an error. If
// we change the validation to support this use case, the test case below
// should change.
//
// See https://github.com/Yubico/yubikey-manager/issues/522
ca, err := minica.New(minica.WithIntermediateTemplate(`{"subject": {{ toJson .Subject }}}`))
if err != nil {
t.Fatal(err)
}
caRoot := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: ca.Root.Raw})
makeLeaf := func(signer crypto.Signer, serialNumber []byte) *x509.Certificate {
leaf, err := ca.Sign(&x509.Certificate{
Subject: pkix.Name{CommonName: "attestation cert"},
PublicKey: signer.Public(),
ExtraExtensions: []pkix.Extension{
{Id: oidYubicoSerialNumber, Value: serialNumber},
},
})
if err != nil {
t.Fatal(err)
}
return leaf
}
signer, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatal(err)
}
serialNumber, err := asn1.Marshal(1234)
if err != nil {
t.Fatal(err)
}
leaf := makeLeaf(signer, serialNumber)
jwk, err := jose.GenerateJWK("EC", "P-256", "ES256", "sig", "", 0)
if err != nil {
t.Fatal(err)
}
keyAuth, err := KeyAuthorization("token", jwk)
if err != nil {
t.Fatal(err)
}
keyAuthSum := sha256.Sum256([]byte(keyAuth))
sig, err := signer.Sign(rand.Reader, keyAuthSum[:], crypto.SHA256)
if err != nil {
t.Fatal(err)
}
cborSig, err := cbor.Marshal(sig)
if err != nil {
t.Fatal(err)
}
type args struct {
ctx context.Context
prov Provisioner
ch *Challenge
jwk *jose.JSONWebKey
att *AttestationObject
}
tests := []struct {
name string
args args
want *stepAttestationData
wantErr bool
}{
{"fail no intermediate", args{ctx, mustAttestationProvisioner(t, caRoot), &Challenge{Token: "token"}, jwk, &AttestationObject{
Format: "step",
AttStatement: map[string]interface{}{
"x5c": []interface{}{leaf.Raw, ca.Intermediate.Raw},
"alg": -7,
"sig": cborSig,
},
}}, nil, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := doStepAttestationFormat(tt.args.ctx, tt.args.prov, tt.args.ch, tt.args.jwk, tt.args.att)
if (err != nil) != tt.wantErr {
t.Errorf("doStepAttestationFormat() error = %#v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("doStepAttestationFormat() = %v, want %v", got, tt.want)
}
})
}
}

View file

@ -241,9 +241,10 @@ func TestUnimplementedMethods(t *testing.T) {
default:
t.Errorf("unexpected method %s", tt.method)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), http.StatusUnauthorized)
}
assert.Equals(t, err.Error(), msg)
})
}

View file

@ -218,9 +218,10 @@ func TestSSHPOP_authorizeToken(t *testing.T) {
t.Run(name, func(t *testing.T) {
tc := tt(t)
if claims, err := tc.p.authorizeToken(tc.token, testAudiences.Sign, true); err != nil {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
if assert.NotNil(t, tc.err) {
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
@ -289,9 +290,10 @@ func TestSSHPOP_AuthorizeSSHRevoke(t *testing.T) {
t.Run(name, func(t *testing.T) {
tc := tt(t)
if err := tc.p.AuthorizeSSHRevoke(context.Background(), tc.token); err != nil {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
if assert.NotNil(t, tc.err) {
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
@ -370,9 +372,10 @@ func TestSSHPOP_AuthorizeSSHRenew(t *testing.T) {
tc := tt(t)
if cert, err := tc.p.AuthorizeSSHRenew(context.Background(), tc.token); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -452,9 +455,10 @@ func TestSSHPOP_AuthorizeSSHRekey(t *testing.T) {
tc := tt(t)
if cert, opts, err := tc.p.AuthorizeSSHRekey(context.Background(), tc.token); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {

View file

@ -389,9 +389,10 @@ lgsqsR63is+0YQ==
tc := tt(t)
if claims, err := tc.p.authorizeToken(tc.token, testAudiences.Sign); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -460,9 +461,10 @@ func TestX5C_AuthorizeSign(t *testing.T) {
tc := tt(t)
if opts, err := tc.p.AuthorizeSign(context.Background(), tc.token); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCoder interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -547,9 +549,10 @@ func TestX5C_AuthorizeRevoke(t *testing.T) {
tc := tt(t)
if err := tc.p.AuthorizeRevoke(context.Background(), tc.token); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -597,9 +600,10 @@ func TestX5C_AuthorizeRenew(t *testing.T) {
NotAfter: now.Add(time.Hour),
}); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -758,9 +762,10 @@ func TestX5C_AuthorizeSSHSign(t *testing.T) {
tc := tt(t)
if opts, err := tc.p.AuthorizeSSHSign(context.Background(), tc.token); err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCoder interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {

View file

@ -58,9 +58,10 @@ func TestGetEncryptedKey(t *testing.T) {
ek, err := tc.a.GetEncryptedKey(tc.kid)
if err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -108,9 +109,10 @@ func TestGetProvisioners(t *testing.T) {
ps, next, err := tc.a.GetProvisioners("", 0)
if err != nil {
if assert.NotNil(t, tc.err) {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
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)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {

View file

@ -774,8 +774,8 @@ func TestAuthority_GetSSHBastion(t *testing.T) {
t.Errorf("Authority.GetSSHBastion() error = %v, wantErr %v", err, tt.wantErr)
return
} else if err != nil {
_, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Authority.GetSSHBastion() = %v, want %v", got, tt.want)
@ -865,8 +865,9 @@ func TestAuthority_GetSSHHosts(t *testing.T) {
if err != nil {
if assert.NotNil(t, tc.err) {
var sc render.StatusCodedError
assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tc.code)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {
@ -1092,8 +1093,9 @@ func TestAuthority_RekeySSH(t *testing.T) {
if err != nil {
if assert.NotNil(t, tc.err) {
var sc render.StatusCodedError
assert.Fatal(t, errors.As(err, &sc), "error does not implement StatusCodedError interface")
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tc.code)
}
assert.HasPrefix(t, err.Error(), tc.err.Error())
}
} else {

View file

@ -519,9 +519,10 @@ func TestClient_Renew(t *testing.T) {
t.Errorf("Client.Renew() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, err.Error(), tt.err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -587,9 +588,10 @@ func TestClient_RenewWithToken(t *testing.T) {
t.Errorf("Client.RenewWithToken() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, err.Error(), tt.err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -656,9 +658,10 @@ func TestClient_Rekey(t *testing.T) {
t.Errorf("Client.Renew() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, err.Error(), tt.err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -777,9 +780,10 @@ func TestClient_ProvisionerKey(t *testing.T) {
t.Errorf("Client.ProvisionerKey() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, tt.err.Error(), err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -836,9 +840,10 @@ func TestClient_Roots(t *testing.T) {
if got != nil {
t.Errorf("Client.Roots() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, err.Error(), tt.err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -894,9 +899,10 @@ func TestClient_Federation(t *testing.T) {
if got != nil {
t.Errorf("Client.Federation() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, tt.err.Error(), err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -956,9 +962,10 @@ func TestClient_SSHRoots(t *testing.T) {
if got != nil {
t.Errorf("Client.SSHKeys() = %v, want nil", got)
}
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, tt.err.Error(), err.Error())
default:
if !reflect.DeepEqual(got, tt.response) {
@ -1118,9 +1125,10 @@ func TestClient_SSHBastion(t *testing.T) {
t.Errorf("Client.SSHBastion() = %v, want nil", got)
}
if tt.responseCode != 200 {
sc, ok := err.(render.StatusCodedError)
assert.Fatal(t, ok, "error does not implement StatusCodedError interface")
var sc render.StatusCodedError
if assert.True(t, errors.As(err, &sc), "error does not implement StatusCodedError interface") {
assert.Equals(t, sc.StatusCode(), tt.responseCode)
}
assert.HasPrefix(t, err.Error(), tt.err.Error())
}
default:

View file

@ -143,8 +143,9 @@ func (e *Error) UnmarshalJSON(data []byte) error {
// Format implements the fmt.Formatter interface.
func (e *Error) Format(f fmt.State, c rune) {
if err, ok := e.Err.(fmt.Formatter); ok {
err.Format(f, c)
var fe fmt.Formatter
if errors.As(e.Err, &fe) {
fe.Format(f, c)
return
}
fmt.Fprint(f, e.Err.Error())
@ -253,7 +254,8 @@ func NewError(status int, err error, format string, args ...interface{}) error {
return err
}
msg := fmt.Sprintf(format, args...)
if _, ok := err.(log.StackTracedError); !ok {
var ste log.StackTracedError
if !errors.As(err, &ste) {
err = errors.Wrap(err, msg)
}
return &Error{
@ -268,17 +270,13 @@ func NewError(status int, err error, format string, args ...interface{}) error {
func NewErr(status int, err error, opts ...Option) error {
var e *Error
if !errors.As(err, &e) {
if sc, ok := err.(render.StatusCodedError); ok {
e = &Error{Status: sc.StatusCode(), Err: err}
} else {
cause := errors.Cause(err)
if sc, ok := cause.(render.StatusCodedError); ok {
e = &Error{Status: sc.StatusCode(), Err: err}
var ste render.StatusCodedError
if errors.As(err, &ste) {
e = &Error{Status: ste.StatusCode(), Err: err}
} else {
e = &Error{Status: status, Err: err}
}
}
}
for _, o := range opts {
o(e)
}

2
go.mod
View file

@ -142,7 +142,7 @@ require (
go.opencensus.io v0.23.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 // indirect
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 // indirect
golang.org/x/text v0.3.8 // indirect
google.golang.org/appengine v1.6.7 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

2
go.sum
View file

@ -1060,6 +1060,8 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=