diff --git a/kms/apiv1/requests.go b/kms/apiv1/requests.go index eb55f8ed..394dd0ac 100644 --- a/kms/apiv1/requests.go +++ b/kms/apiv1/requests.go @@ -179,18 +179,19 @@ type CreateKeyResponse struct { } // SearchKeysRequest is the request for the SearchKeys method. It takes -// a single Query string with the attributes to match when searching the +// a Query string with the attributes to match when searching the // KMS. type SearchKeysRequest struct { Query string } -// SearchKeyResult is a single results returned from the SearchKeys +// SearchKeyResult is a single result returned from the SearchKeys // method. type SearchKeyResult CreateKeyResponse // SearchKeysResponse is the response for the SearchKeys method. It -// wraps a slice of SearchKeyResponse structs. +// wraps a slice of SearchKeyResult structs. The Results slice can +// be empty in case no key was found for the search query. type SearchKeysResponse struct { Results []SearchKeyResult } diff --git a/kms/mackms/mackms.go b/kms/mackms/mackms.go index db7ce941..9398075d 100644 --- a/kms/mackms/mackms.go +++ b/kms/mackms/mackms.go @@ -555,6 +555,18 @@ func (*MacKMS) DeleteCertificate(req *apiv1.DeleteCertificateRequest) error { return nil } +// SearchKeys searches for keys according to the query URI in the request. +// +// - "" will return all keys managed by the KMS (using the default tag) +// - "mackms:" will return all keys managed by the KMS (using the default tag) +// - "mackms:label=my-label" will return all keys using label "my-label" (and the default tag) +// - "mackms:hash=the-hash" will return all keys having hash "hash" (and the default tag; generally one result) +// - "mackms:tag=my-tag" will search for all keys with "my-tag" +// +// # Experimental +// +// Notice: This API is EXPERIMENTAL and may be changed or removed in a later +// release. func (k *MacKMS) SearchKeys(req *apiv1.SearchKeysRequest) (*apiv1.SearchKeysResponse, error) { if req.Query == "" { return nil, fmt.Errorf("searchKeysRequest 'query' cannot be empty") @@ -586,7 +598,7 @@ func (k *MacKMS) SearchKeys(req *apiv1.SearchKeysRequest) (*apiv1.SearchKeysResp } // obtain the public key by requesting it, as the current - // representation of the key are just the attributes. + // representation of the key includes just the attributes. pub, err := k.GetPublicKey(&apiv1.GetPublicKeyRequest{ Name: name.String(), }) @@ -724,7 +736,10 @@ func getPrivateKeys(u *keyAttributes) ([]*security.SecKeychainItemRef, error) { var result cf.TypeRef err = security.SecItemCopyMatching(query, &result) if err != nil { - return nil, fmt.Errorf("failed matching: %w", err) + if errors.Is(err, security.ErrNotFound) { + return []*security.SecKeychainItemRef{}, nil + } + return nil, fmt.Errorf("macOS SecItemCopyMatching failed: %w", err) } array := cf.NewArrayRef(result) @@ -1041,7 +1056,7 @@ func parseSearchURI(rawuri string) (*keyAttributes, error) { } // When rawuri is a mackms uri. - u, err := uri.ParseWithScheme(Scheme, rawuri) + u, err := uri.Parse(rawuri) if err != nil { return nil, err } @@ -1066,11 +1081,9 @@ func parseSearchURI(rawuri string) (*keyAttributes, error) { tag = DefaultTag } return &keyAttributes{ - label: label, - tag: tag, - hash: u.GetEncoded("hash"), - useSecureEnclave: u.GetBool("se"), - useBiometrics: u.GetBool("bio"), + label: label, + tag: tag, + hash: u.GetEncoded("hash"), }, nil } diff --git a/kms/mackms/mackms_test.go b/kms/mackms/mackms_test.go index d233dc52..6bf27402 100644 --- a/kms/mackms/mackms_test.go +++ b/kms/mackms/mackms_test.go @@ -1239,7 +1239,15 @@ func TestMacKMS_SearchKeys(t *testing.T) { require.NoError(t, err) tag := fmt.Sprintf("com.smallstep.crypto.test.%s", name) // unique tag per test execution + // initialize MacKMS k := &MacKMS{} + + // search by tag; expect 0 keys before the test + got, err := k.SearchKeys(&apiv1.SearchKeysRequest{Query: fmt.Sprintf("mackms:tag=%s", tag)}) + require.NoError(t, err) + require.NotNil(t, got) + require.Len(t, got.Results, 0) + key1, err := k.CreateKey(&apiv1.CreateKeyRequest{Name: fmt.Sprintf("mackms:name=test-step-1;label=test-step-1;tag=%s;se=false", tag)}) require.NoError(t, err) key2, err := k.CreateKey(&apiv1.CreateKeyRequest{Name: fmt.Sprintf("mackms:name=test-step-2;label=test-step-2;tag=%s;se=false", tag)}) @@ -1258,7 +1266,7 @@ func TestMacKMS_SearchKeys(t *testing.T) { }) // search by tag - got, err := k.SearchKeys(&apiv1.SearchKeysRequest{Query: fmt.Sprintf("mackms:tag=%s", tag)}) + got, err = k.SearchKeys(&apiv1.SearchKeysRequest{Query: fmt.Sprintf("mackms:tag=%s", tag)}) require.NoError(t, err) require.NotNil(t, got) require.Len(t, got.Results, 2)