Skip to content

Commit ebc1d7a

Browse files
authored
Refactor rekor-cli loginfo (sigstore#734)
This refactors the loginfo file in preparation for also getting info for inactive shards and verifying them as well. Signed-off-by: Priya Wadhwa <priya@chainguard.dev>
1 parent 2ab7705 commit ebc1d7a

File tree

1 file changed

+91
-67
lines changed

1 file changed

+91
-67
lines changed

cmd/rekor-cli/app/log_info.go

Lines changed: 91 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/go-openapi/swag"
2929
"github.com/google/trillian/merkle/logverifier"
3030
"github.com/google/trillian/merkle/rfc6962"
31+
rclient "github.com/sigstore/rekor/pkg/generated/client"
3132
"github.com/spf13/cobra"
3233
"github.com/spf13/viper"
3334

@@ -81,89 +82,112 @@ var logInfoCmd = &cobra.Command{
8182
logInfo := result.GetPayload()
8283

8384
sth := util.SignedCheckpoint{}
84-
if err := sth.UnmarshalText([]byte(*logInfo.SignedTreeHead)); err != nil {
85+
signedTreeHead := swag.StringValue(logInfo.SignedTreeHead)
86+
if err := sth.UnmarshalText([]byte(signedTreeHead)); err != nil {
8587
return nil, err
8688
}
8789

88-
publicKey := viper.GetString("rekor_server_public_key")
89-
if publicKey == "" {
90-
// fetch key from server
91-
keyResp, err := rekorClient.Pubkey.GetPublicKey(nil)
92-
if err != nil {
93-
return nil, err
94-
}
95-
publicKey = keyResp.Payload
96-
}
97-
98-
block, _ := pem.Decode([]byte(publicKey))
99-
if block == nil {
100-
return nil, errors.New("failed to decode public key of server")
101-
}
102-
103-
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
104-
if err != nil {
90+
if err := verifyTree(rekorClient, signedTreeHead, serverURL); err != nil {
10591
return nil, err
10692
}
10793

108-
verifier, err := signature.LoadVerifier(pub, crypto.SHA256)
109-
if err != nil {
110-
return nil, err
111-
}
112-
113-
if !sth.Verify(verifier) {
114-
return nil, errors.New("signature on tree head did not verify")
115-
}
116-
11794
cmdOutput := &logInfoCmdOutput{
11895
TreeSize: swag.Int64Value(logInfo.TreeSize),
11996
RootHash: swag.StringValue(logInfo.RootHash),
12097
TimestampNanos: sth.GetTimestamp(),
12198
TreeID: swag.StringValue(logInfo.TreeID),
12299
}
100+
return cmdOutput, nil
101+
}),
102+
}
123103

124-
oldState := state.Load(serverURL)
125-
if oldState != nil {
126-
persistedSize := oldState.Size
127-
if persistedSize < sth.Size {
128-
log.CliLogger.Infof("Found previous log state, proving consistency between %d and %d", oldState.Size, sth.Size)
129-
params := tlog.NewGetLogProofParams()
130-
firstSize := int64(persistedSize)
131-
params.FirstSize = &firstSize
132-
params.LastSize = int64(sth.Size)
133-
proof, err := rekorClient.Tlog.GetLogProof(params)
134-
if err != nil {
135-
return nil, err
136-
}
137-
hashes := [][]byte{}
138-
for _, h := range proof.Payload.Hashes {
139-
b, _ := hex.DecodeString(h)
140-
hashes = append(hashes, b)
141-
}
142-
v := logverifier.New(rfc6962.DefaultHasher)
143-
if err := v.VerifyConsistencyProof(firstSize, int64(sth.Size), oldState.Hash,
144-
sth.Hash, hashes); err != nil {
145-
return nil, err
146-
}
147-
log.CliLogger.Infof("Consistency proof valid!")
148-
} else if persistedSize == sth.Size {
149-
if !bytes.Equal(oldState.Hash, sth.Hash) {
150-
return nil, errors.New("root hash returned from server does not match previously persisted state")
151-
}
152-
log.CliLogger.Infof("Persisted log state matches the current state of the log")
153-
} else if persistedSize > sth.Size {
154-
return nil, fmt.Errorf("current size of tree reported from server %d is less than previously persisted state %d", sth.Size, persistedSize)
155-
}
156-
} else {
157-
log.CliLogger.Infof("No previous log state stored, unable to prove consistency")
104+
func verifyTree(rekorClient *rclient.Rekor, signedTreeHead, serverURL string) error {
105+
oldState := state.Load(serverURL)
106+
sth := util.SignedCheckpoint{}
107+
if err := sth.UnmarshalText([]byte(signedTreeHead)); err != nil {
108+
return err
109+
}
110+
verifier, err := loadVerifier(rekorClient)
111+
if err != nil {
112+
return err
113+
}
114+
if !sth.Verify(verifier) {
115+
return errors.New("signature on tree head did not verify")
116+
}
117+
118+
if err := proveConsistency(rekorClient, oldState, sth); err != nil {
119+
return err
120+
}
121+
122+
if viper.GetBool("store_tree_state") {
123+
if err := state.Dump(serverURL, &sth); err != nil {
124+
log.CliLogger.Infof("Unable to store previous state: %v", err)
158125
}
126+
}
127+
return nil
128+
}
159129

160-
if viper.GetBool("store_tree_state") {
161-
if err := state.Dump(serverURL, &sth); err != nil {
162-
log.CliLogger.Infof("Unable to store previous state: %v", err)
163-
}
130+
func proveConsistency(rekorClient *rclient.Rekor, oldState *util.SignedCheckpoint, sth util.SignedCheckpoint) error {
131+
if oldState == nil {
132+
log.CliLogger.Infof("No previous log state stored, unable to prove consistency")
133+
return nil
134+
}
135+
persistedSize := oldState.Size
136+
switch {
137+
case persistedSize < sth.Size:
138+
log.CliLogger.Infof("Found previous log state, proving consistency between %d and %d", oldState.Size, sth.Size)
139+
params := tlog.NewGetLogProofParams()
140+
firstSize := int64(persistedSize)
141+
params.FirstSize = &firstSize
142+
params.LastSize = int64(sth.Size)
143+
proof, err := rekorClient.Tlog.GetLogProof(params)
144+
if err != nil {
145+
return err
164146
}
165-
return cmdOutput, nil
166-
}),
147+
hashes := [][]byte{}
148+
for _, h := range proof.Payload.Hashes {
149+
b, _ := hex.DecodeString(h)
150+
hashes = append(hashes, b)
151+
}
152+
v := logverifier.New(rfc6962.DefaultHasher)
153+
if err := v.VerifyConsistencyProof(firstSize, int64(sth.Size), oldState.Hash,
154+
sth.Hash, hashes); err != nil {
155+
return err
156+
}
157+
log.CliLogger.Infof("Consistency proof valid!")
158+
case persistedSize == sth.Size:
159+
if !bytes.Equal(oldState.Hash, sth.Hash) {
160+
return errors.New("root hash returned from server does not match previously persisted state")
161+
}
162+
log.CliLogger.Infof("Persisted log state matches the current state of the log")
163+
default:
164+
return fmt.Errorf("current size of tree reported from server %d is less than previously persisted state %d", sth.Size, persistedSize)
165+
}
166+
return nil
167+
}
168+
169+
func loadVerifier(rekorClient *rclient.Rekor) (signature.Verifier, error) {
170+
publicKey := viper.GetString("rekor_server_public_key")
171+
if publicKey == "" {
172+
// fetch key from server
173+
keyResp, err := rekorClient.Pubkey.GetPublicKey(nil)
174+
if err != nil {
175+
return nil, err
176+
}
177+
publicKey = keyResp.Payload
178+
}
179+
180+
block, _ := pem.Decode([]byte(publicKey))
181+
if block == nil {
182+
return nil, errors.New("failed to decode public key of server")
183+
}
184+
185+
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
186+
if err != nil {
187+
return nil, err
188+
}
189+
190+
return signature.LoadVerifier(pub, crypto.SHA256)
167191
}
168192

169193
func init() {

0 commit comments

Comments
 (0)