Skip to content

Commit f525de8

Browse files
authored
Specify public key for inactive shards in shard config (sigstore#746)
* Specify public key for each inactive shard in config Signed-off-by: Priya Wadhwa <priya@chainguard.dev> * Updated the integration test Signed-off-by: Priya Wadhwa <priya@chainguard.dev> * Add debugging to the sharding test Signed-off-by: Priya Wadhwa <priya@chainguard.dev> * Add debugging Signed-off-by: Priya Wadhwa <priya@chainguard.dev>
1 parent 035b262 commit f525de8

File tree

8 files changed

+282
-30
lines changed

8 files changed

+282
-30
lines changed

openapi.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ paths:
9393
operationId: getPublicKey
9494
tags:
9595
- pubkey
96+
parameters:
97+
- in: query
98+
name: treeID
99+
type: string
100+
pattern: '^[0-9]+$'
101+
description: The tree ID of the tree you wish to get a public key for
96102
produces:
97103
- application/x-pem-file
98104
responses:

pkg/api/public_key.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,20 @@ limitations under the License.
1717
package api
1818

1919
import (
20+
"net/http"
21+
2022
"github.com/go-openapi/runtime/middleware"
23+
"github.com/go-openapi/swag"
2124
"github.com/sigstore/rekor/pkg/generated/restapi/operations/pubkey"
2225
)
2326

2427
func GetPublicKeyHandler(params pubkey.GetPublicKeyParams) middleware.Responder {
25-
return pubkey.NewGetPublicKeyOK().WithPayload(api.pubkey)
28+
ctx := params.HTTPRequest.Context()
29+
treeID := swag.StringValue(params.TreeID)
30+
tc := NewTrillianClient(ctx)
31+
pk, err := tc.ranges.PublicKey(api.pubkey, treeID)
32+
if err != nil {
33+
return handleRekorAPIError(params, http.StatusBadRequest, err, "")
34+
}
35+
return pubkey.NewGetPublicKeyOK().WithPayload(pk)
2636
}

pkg/generated/client/pubkey/get_public_key_parameters.go

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/generated/restapi/operations/pubkey/get_public_key_parameters.go

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/generated/restapi/operations/pubkey/get_public_key_urlbuilder.go

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sharding/ranges.go

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
package sharding
1717

1818
import (
19+
"encoding/base64"
1920
"errors"
2021
"fmt"
2122
"io/ioutil"
23+
"strconv"
2224
"strings"
2325

2426
"github.com/ghodss/yaml"
@@ -33,8 +35,10 @@ type LogRanges struct {
3335
type Ranges []LogRange
3436

3537
type LogRange struct {
36-
TreeID int64 `yaml:"treeID"`
37-
TreeLength int64 `yaml:"treeLength"`
38+
TreeID int64 `yaml:"treeID"`
39+
TreeLength int64 `yaml:"treeLength"`
40+
EncodedPublicKey string `yaml:"encodedPublicKey"`
41+
decodedPublicKey string
3842
}
3943

4044
func NewLogRanges(path string, treeID uint) (LogRanges, error) {
@@ -54,6 +58,14 @@ func NewLogRanges(path string, treeID uint) (LogRanges, error) {
5458
if err := yaml.Unmarshal(contents, &ranges); err != nil {
5559
return LogRanges{}, err
5660
}
61+
for i, r := range ranges {
62+
decoded, err := base64.StdEncoding.DecodeString(r.EncodedPublicKey)
63+
if err != nil {
64+
return LogRanges{}, err
65+
}
66+
r.decodedPublicKey = string(decoded)
67+
ranges[i] = r
68+
}
5769
return LogRanges{
5870
inactive: ranges,
5971
active: int64(treeID),
@@ -119,3 +131,30 @@ func (l *LogRanges) String() string {
119131
ranges = append(ranges, fmt.Sprintf("active=%d", l.active))
120132
return strings.Join(ranges, ",")
121133
}
134+
135+
// PublicKey returns the associated public key for the given Tree ID
136+
// and returns the active public key by default
137+
func (l *LogRanges) PublicKey(activePublicKey, treeID string) (string, error) {
138+
// if no tree ID is specified, assume the active tree
139+
if treeID == "" {
140+
return activePublicKey, nil
141+
}
142+
tid, err := strconv.Atoi(treeID)
143+
if err != nil {
144+
return "", err
145+
}
146+
147+
for _, i := range l.inactive {
148+
if int(i.TreeID) == tid {
149+
if i.decodedPublicKey != "" {
150+
return i.decodedPublicKey, nil
151+
}
152+
// assume the active public key if one wasn't provided
153+
return activePublicKey, nil
154+
}
155+
}
156+
if tid == int(l.active) {
157+
return activePublicKey, nil
158+
}
159+
return "", fmt.Errorf("%d is not a valid tree ID and doesn't have an associated public key", tid)
160+
}

pkg/sharding/ranges_test.go

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ func TestNewLogRanges(t *testing.T) {
2626
contents := `
2727
- treeID: 0001
2828
treeLength: 3
29+
encodedPublicKey: c2hhcmRpbmcK
2930
- treeID: 0002
3031
treeLength: 4`
3132
file := filepath.Join(t.TempDir(), "sharding-config")
@@ -36,8 +37,10 @@ func TestNewLogRanges(t *testing.T) {
3637
expected := LogRanges{
3738
inactive: []LogRange{
3839
{
39-
TreeID: 1,
40-
TreeLength: 3,
40+
TreeID: 1,
41+
TreeLength: 3,
42+
EncodedPublicKey: "c2hhcmRpbmcK",
43+
decodedPublicKey: "sharding\n",
4144
}, {
4245
TreeID: 2,
4346
TreeLength: 4,
@@ -94,3 +97,62 @@ func TestLogRanges_ResolveVirtualIndex(t *testing.T) {
9497
}
9598
}
9699
}
100+
101+
func TestPublicKey(t *testing.T) {
102+
ranges := LogRanges{
103+
active: 45,
104+
inactive: []LogRange{
105+
{
106+
TreeID: 10,
107+
TreeLength: 10,
108+
decodedPublicKey: "sharding",
109+
}, {
110+
TreeID: 20,
111+
TreeLength: 20,
112+
},
113+
},
114+
}
115+
activePubKey := "activekey"
116+
tests := []struct {
117+
description string
118+
treeID string
119+
expectedPubKey string
120+
shouldErr bool
121+
}{
122+
{
123+
description: "empty tree ID",
124+
expectedPubKey: "activekey",
125+
}, {
126+
description: "tree id with decoded public key",
127+
treeID: "10",
128+
expectedPubKey: "sharding",
129+
}, {
130+
description: "tree id without decoded public key",
131+
treeID: "20",
132+
expectedPubKey: "activekey",
133+
}, {
134+
description: "invalid tree id",
135+
treeID: "34",
136+
shouldErr: true,
137+
}, {
138+
description: "pass in active tree id",
139+
treeID: "45",
140+
expectedPubKey: "activekey",
141+
},
142+
}
143+
144+
for _, test := range tests {
145+
t.Run(test.description, func(t *testing.T) {
146+
got, err := ranges.PublicKey(activePubKey, test.treeID)
147+
if err != nil && !test.shouldErr {
148+
t.Fatal(err)
149+
}
150+
if test.shouldErr {
151+
return
152+
}
153+
if got != test.expectedPubKey {
154+
t.Fatalf("got %s doesn't match expected %s", got, test.expectedPubKey)
155+
}
156+
})
157+
}
158+
}

0 commit comments

Comments
 (0)