Skip to content

Commit 05f8a4b

Browse files
committed
Allow to retry with no tags when loading privatekeys
This function allows to retry the retrieval of a key without tags if the original uri didn't have one. This is used only in GetPublicKey and CreateSigner. It is not used in SearchKeys as we will need to remove duplicated keys.
1 parent 3a8464f commit 05f8a4b

File tree

2 files changed

+89
-5
lines changed

2 files changed

+89
-5
lines changed

kms/mackms/mackms.go

+27
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,30 @@ type keyAttributes struct {
5252
label string
5353
tag string
5454
hash []byte
55+
retry bool
5556
useSecureEnclave bool
5657
useBiometrics bool
5758
sigAlgorithm apiv1.SignatureAlgorithm
5859
keySize int
5960
}
6061

62+
// retryAttributes returns the original URI attributes used to get a private
63+
// key, but only if they are different that the ones set. It will return nil, if
64+
// they are the same. The only attribute that can change is the tag. This method
65+
// would return the tag empty if it was set using the default value.
66+
func (k *keyAttributes) retryAttributes() *keyAttributes {
67+
if !k.retry {
68+
fmt.Println("no retry")
69+
return nil
70+
}
71+
fmt.Println("retry")
72+
return &keyAttributes{
73+
label: k.label,
74+
hash: k.hash,
75+
retry: false,
76+
}
77+
}
78+
6179
type keySearchAttributes struct {
6280
label string
6381
tag string
@@ -715,6 +733,12 @@ func getPrivateKey(u *keyAttributes) (*security.SecKeyRef, error) {
715733

716734
var key cf.TypeRef
717735
if err := security.SecItemCopyMatching(query, &key); err != nil {
736+
// If not found retry without the tag if it wasn't set.
737+
if errors.Is(err, security.ErrNotFound) {
738+
if ru := u.retryAttributes(); ru != nil {
739+
return getPrivateKey(ru)
740+
}
741+
}
718742
return nil, fmt.Errorf("macOS SecItemCopyMatching failed: %w", err)
719743
}
720744
return security.NewSecKeyRef(key), nil
@@ -990,6 +1014,7 @@ func parseURI(rawuri string) (*keyAttributes, error) {
9901014
return &keyAttributes{
9911015
label: rawuri,
9921016
tag: DefaultTag,
1017+
retry: true,
9931018
}, nil
9941019
}
9951020

@@ -1006,6 +1031,7 @@ func parseURI(rawuri string) (*keyAttributes, error) {
10061031
return &keyAttributes{
10071032
label: k,
10081033
tag: DefaultTag,
1034+
retry: true,
10091035
}, nil
10101036
}
10111037
}
@@ -1025,6 +1051,7 @@ func parseURI(rawuri string) (*keyAttributes, error) {
10251051
label: label,
10261052
tag: tag,
10271053
hash: u.GetEncoded("hash"),
1054+
retry: !u.Has("tag"),
10281055
useSecureEnclave: u.GetBool("se"),
10291056
useBiometrics: u.GetBool("bio"),
10301057
}, nil

kms/mackms/mackms_test.go

+62-5
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ func TestMacKMS_GetPublicKey(t *testing.T) {
307307

308308
// Create private keys only
309309
r2 := createPrivateKeyOnly(t, "mackms:label=test-ecdsa", apiv1.ECDSAWithSHA256)
310-
r3 := createPrivateKeyOnly(t, "mackms:label=test-rsa", apiv1.SHA256WithRSA)
310+
r3 := createPrivateKeyOnly(t, "mackms:label=test-rsa;tag=", apiv1.SHA256WithRSA)
311311

312312
t.Cleanup(func() {
313313
assert.NoError(t, kms.DeleteKey(&apiv1.DeleteKeyRequest{
@@ -334,7 +334,8 @@ func TestMacKMS_GetPublicKey(t *testing.T) {
334334
{"ok", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: r1.Name}}, r1.PublicKey, assert.NoError},
335335
{"ok no tag", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "mackms:label=test-p256;tag="}}, r1.PublicKey, assert.NoError},
336336
{"ok private only ECDSA ", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "mackms:label=test-ecdsa"}}, r2.PublicKey, assert.NoError},
337-
{"ok private only RSA ", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: r3.Name}}, r3.PublicKey, assert.NoError},
337+
{"ok private only RSA", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: r3.Name}}, r3.PublicKey, assert.NoError},
338+
{"ok private only RSA with retry", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "mackms:label=test-rsa"}}, r3.PublicKey, assert.NoError},
338339
{"ok no uri", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "test-p256"}}, r1.PublicKey, assert.NoError},
339340
{"ok uri simple", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "mackms:test-p256"}}, r1.PublicKey, assert.NoError},
340341
{"ok uri label", &MacKMS{}, args{&apiv1.GetPublicKeyRequest{Name: "mackms:label=test-p256"}}, r1.PublicKey, assert.NoError},
@@ -541,11 +542,12 @@ func Test_parseURI(t *testing.T) {
541542
assertion assert.ErrorAssertionFunc
542543
}{
543544
{"ok", args{"mackms:label=the-label;tag=the-tag;hash=0102abcd"}, &keyAttributes{label: "the-label", tag: "the-tag", hash: []byte{1, 2, 171, 205}}, assert.NoError},
544-
{"ok label", args{"the-label"}, &keyAttributes{label: "the-label", tag: DefaultTag}, assert.NoError},
545-
{"ok label uri", args{"mackms:label=the-label"}, &keyAttributes{label: "the-label", tag: DefaultTag}, assert.NoError},
545+
{"ok label", args{"the-label"}, &keyAttributes{label: "the-label", tag: DefaultTag, retry: true}, assert.NoError},
546+
{"ok label uri", args{"mackms:label=the-label"}, &keyAttributes{label: "the-label", tag: DefaultTag, retry: true}, assert.NoError},
547+
{"ok label uri simple", args{"mackms:the-label"}, &keyAttributes{label: "the-label", tag: DefaultTag, retry: true}, assert.NoError},
546548
{"ok label empty tag", args{"mackms:label=the-label;tag="}, &keyAttributes{label: "the-label", tag: ""}, assert.NoError},
547549
{"ok label empty tag no equal", args{"mackms:label=the-label;tag"}, &keyAttributes{label: "the-label", tag: ""}, assert.NoError},
548-
{"fail parse", args{"mackms:::label=the-label"}, nil, assert.Error},
550+
{"fail parse", args{"mackms:%label=the-label"}, nil, assert.Error},
549551
{"fail missing label", args{"mackms:hash=0102abcd"}, nil, assert.Error},
550552
}
551553
for _, tt := range tests {
@@ -1306,3 +1308,58 @@ func TestMacKMS_SearchKeys(t *testing.T) {
13061308

13071309
assert.Equal(t, expectedHashes, hashes)
13081310
}
1311+
1312+
func Test_keyAttributes_retryAttributes(t *testing.T) {
1313+
type fields struct {
1314+
label string
1315+
tag string
1316+
hash []byte
1317+
retry bool
1318+
}
1319+
1320+
mustFields := func(s string) fields {
1321+
t.Helper()
1322+
u, err := parseURI(s)
1323+
require.NoError(t, err)
1324+
return fields{
1325+
label: u.label,
1326+
tag: u.tag,
1327+
hash: u.hash,
1328+
retry: u.retry,
1329+
}
1330+
}
1331+
1332+
tests := []struct {
1333+
name string
1334+
fields fields
1335+
want *keyAttributes
1336+
}{
1337+
{"with tag", mustFields("mackms:label=label;tag=tag"), nil},
1338+
{"with tag and hash", mustFields("mackms:label=label;hash=FF00;tag=tag"), nil},
1339+
{"with empty tag", mustFields("mackms:label=label;tag="), nil},
1340+
{"with no tag", mustFields("mackms:label=label;hash=FF00"), &keyAttributes{
1341+
label: "label",
1342+
hash: []byte{0xFF, 0x00},
1343+
}},
1344+
{"legacy name only", mustFields("label"), &keyAttributes{
1345+
label: "label",
1346+
}},
1347+
{"legacy with schema", mustFields("mackms:label"), &keyAttributes{
1348+
label: "label",
1349+
}},
1350+
}
1351+
for _, tt := range tests {
1352+
t.Run(tt.name, func(t *testing.T) {
1353+
k := &keyAttributes{
1354+
label: tt.fields.label,
1355+
tag: tt.fields.tag,
1356+
hash: tt.fields.hash,
1357+
retry: tt.fields.retry,
1358+
}
1359+
if tt.name == "with no tag" {
1360+
t.Log("foo")
1361+
}
1362+
assert.Equal(t, tt.want, k.retryAttributes())
1363+
})
1364+
}
1365+
}

0 commit comments

Comments
 (0)