Handle "too many objects" in pkcs11helper. (#4972)

Previously we were relying on a "more" boolean returned from
FindObjects. But according to
https://pkg.go.dev/github.com/miekg/pkcs11?tab=doc#Ctx.FindObjects,

> The returned boolean value is deprecated and should be ignored.

Instead, we ask for more objects than we need and error if we get more
than 1.

Add a test, and in the process split up the relevant test  into
multiple smaller test cases.
This commit is contained in:
Jacob Hoffman-Andrews 2020-07-22 18:57:28 -07:00 committed by GitHub
parent 12d8674130
commit 4ba537f293
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 59 additions and 20 deletions

View File

@ -182,6 +182,8 @@ func Sign(ctx PKCtx, session pkcs11.SessionHandle, object pkcs11.ObjectHandle, k
return signature, nil
}
var ErrNoObject = errors.New("no objects found matching provided template")
// FindObject looks up a PKCS#11 object handle based on the provided template.
// In the case where zero or more than one objects are found to match the
// template an error is returned.
@ -189,19 +191,19 @@ func FindObject(ctx PKCtx, session pkcs11.SessionHandle, tmpl []*pkcs11.Attribut
if err := ctx.FindObjectsInit(session, tmpl); err != nil {
return 0, err
}
handles, more, err := ctx.FindObjects(session, 1)
handles, _, err := ctx.FindObjects(session, 2)
if err != nil {
return 0, err
}
if len(handles) == 0 {
return 0, errors.New("no objects found matching provided template")
}
if more {
return 0, errors.New("more than one object matches provided template")
}
if err := ctx.FindObjectsFinal(session); err != nil {
return 0, err
}
if len(handles) == 0 {
return 0, ErrNoObject
}
if len(handles) > 1 {
return 0, fmt.Errorf("too many objects (%d) that match the provided template", len(handles))
}
return handles[0], nil
}

View File

@ -2,6 +2,7 @@ package pkcs11helpers
import (
"errors"
"strings"
"testing"
"github.com/letsencrypt/boulder/test"
@ -113,8 +114,17 @@ func TestRSAPublicKey(t *testing.T) {
test.AssertNotError(t, err, "rsaPub failed with valid attributes")
}
func TestFindObject(t *testing.T) {
func findObjectsFinalOK(pkcs11.SessionHandle) error {
return nil
}
func findObjectsInitOK(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return nil
}
func TestFindObjectFailsOnFailedInit(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsFinalFunc = findObjectsFinalOK
// test FindObject fails when FindObjectsInit fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
@ -122,30 +132,51 @@ func TestFindObject(t *testing.T) {
}
_, err := FindObject(ctx, 0, nil)
test.AssertError(t, err, "FindObject didn't fail when FindObjectsInit failed")
}
func TestFindObjectFailsOnFailedFindObjects(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsInitFunc = findObjectsInitOK
ctx.FindObjectsFinalFunc = findObjectsFinalOK
// test FindObject fails when FindObjects fails
ctx.FindObjectsInitFunc = func(pkcs11.SessionHandle, []*pkcs11.Attribute) error {
return nil
}
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return nil, false, errors.New("broken")
}
_, err = FindObject(ctx, 0, nil)
_, err := FindObject(ctx, 0, nil)
test.AssertError(t, err, "FindObject didn't fail when FindObjects failed")
}
func TestFindObjectFailsOnNoHandles(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsInitFunc = findObjectsInitOK
ctx.FindObjectsFinalFunc = findObjectsFinalOK
// test FindObject fails when no handles are returned
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return []pkcs11.ObjectHandle{}, false, nil
}
_, err = FindObject(ctx, 0, nil)
test.AssertError(t, err, "FindObject didn't fail when FindObjects returns no handles")
_, err := FindObject(ctx, 0, nil)
test.AssertEquals(t, err, ErrNoObject)
}
func TestFindObjectFailsOnMultipleHandles(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsInitFunc = findObjectsInitOK
ctx.FindObjectsFinalFunc = findObjectsFinalOK
// test FindObject fails when multiple handles are returned
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return []pkcs11.ObjectHandle{1}, true, nil
return []pkcs11.ObjectHandle{1, 2, 3}, false, nil
}
_, err = FindObject(ctx, 0, nil)
_, err := FindObject(ctx, 0, nil)
test.AssertError(t, err, "FindObject didn't fail when FindObjects returns multiple handles")
test.Assert(t, strings.HasPrefix(err.Error(), "too many objects"), "FindObject failed with wrong error")
}
func TestFindObjectFailsOnFinalizeFailure(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsInitFunc = findObjectsInitOK
// test FindObject fails when FindObjectsFinal fails
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
@ -154,13 +185,19 @@ func TestFindObject(t *testing.T) {
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
return errors.New("broken")
}
_, err = FindObject(ctx, 0, nil)
_, err := FindObject(ctx, 0, nil)
test.AssertError(t, err, "FindObject didn't fail when FindObjectsFinal fails")
}
// test FindObject works
ctx.FindObjectsFinalFunc = func(pkcs11.SessionHandle) error {
return nil
func TestFindObjectSucceeds(t *testing.T) {
ctx := MockCtx{}
ctx.FindObjectsInitFunc = findObjectsInitOK
ctx.FindObjectsFinalFunc = findObjectsFinalOK
ctx.FindObjectsFunc = func(pkcs11.SessionHandle, int) ([]pkcs11.ObjectHandle, bool, error) {
return []pkcs11.ObjectHandle{1}, false, nil
}
// test FindObject works
handle, err := FindObject(ctx, 0, nil)
test.AssertNotError(t, err, "FindObject failed when everything worked as expected")
test.AssertEquals(t, handle, pkcs11.ObjectHandle(1))