Skip to content
Snippets Groups Projects
Unverified Commit 8b972796 authored by Bob Callaway's avatar Bob Callaway Committed by GitHub
Browse files

block to return for insertion until leaf has been added (#139)

parent 68c5f36d
No related branches found
No related tags found
No related merge requests found
...@@ -20,6 +20,7 @@ import ( ...@@ -20,6 +20,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/go-openapi/swag"
"github.com/projectrekor/rekor/cmd/cli/app/format" "github.com/projectrekor/rekor/cmd/cli/app/format"
"github.com/projectrekor/rekor/pkg/generated/client/entries" "github.com/projectrekor/rekor/pkg/generated/client/entries"
"github.com/projectrekor/rekor/pkg/generated/models" "github.com/projectrekor/rekor/pkg/generated/models"
...@@ -30,11 +31,12 @@ import ( ...@@ -30,11 +31,12 @@ import (
type uploadCmdOutput struct { type uploadCmdOutput struct {
Location string Location string
Index int64
} }
func (u *uploadCmdOutput) String() string { func (u *uploadCmdOutput) String() string {
if u.Location != "" { if u.Location != "" {
return fmt.Sprintf("Created entry at: %v%v\n", viper.GetString("rekor_server"), u.Location) return fmt.Sprintf("Created entry at index %d, available at: %v%v\n", u.Index, viper.GetString("rekor_server"), u.Location)
} }
return "Entry already exists.\n" return "Entry already exists.\n"
} }
...@@ -90,8 +92,14 @@ var uploadCmd = &cobra.Command{ ...@@ -90,8 +92,14 @@ var uploadCmd = &cobra.Command{
} }
} }
var newIndex int64
for _, entry := range resp.Payload {
newIndex = swag.Int64Value(entry.LogIndex)
}
return &uploadCmdOutput{ return &uploadCmdOutput{
Location: string(resp.Location), Location: string(resp.Location),
Index: newIndex,
}, nil }, nil
}), }),
} }
......
...@@ -22,6 +22,7 @@ import ( ...@@ -22,6 +22,7 @@ import (
"time" "time"
"github.com/google/trillian" "github.com/google/trillian"
"github.com/google/trillian/client"
"github.com/google/trillian/crypto/keyspb" "github.com/google/trillian/crypto/keyspb"
radix "github.com/mediocregopher/radix/v4" radix "github.com/mediocregopher/radix/v4"
"github.com/projectrekor/rekor/pkg/log" "github.com/projectrekor/rekor/pkg/log"
...@@ -45,6 +46,7 @@ type API struct { ...@@ -45,6 +46,7 @@ type API struct {
logClient trillian.TrillianLogClient logClient trillian.TrillianLogClient
logID int64 logID int64
pubkey *keyspb.PublicKey pubkey *keyspb.PublicKey
verifier *client.LogVerifier
} }
func NewAPI() (*API, error) { func NewAPI() (*API, error) {
...@@ -74,11 +76,16 @@ func NewAPI() (*API, error) { ...@@ -74,11 +76,16 @@ func NewAPI() (*API, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
verifier, err := client.NewLogVerifierFromTree(t)
if err != nil {
return nil, err
}
return &API{ return &API{
logClient: logClient, logClient: logClient,
logID: tLogID, logID: tLogID,
pubkey: t.PublicKey, pubkey: t.PublicKey,
verifier: verifier,
}, nil }, nil
} }
...@@ -101,12 +108,3 @@ func ConfigureAPI() { ...@@ -101,12 +108,3 @@ func ConfigureAPI() {
} }
} }
} }
func NewTrillianClient(ctx context.Context) TrillianClient {
return TrillianClient{
client: api.logClient,
logID: api.logID,
context: ctx,
pubkey: api.pubkey,
}
}
...@@ -113,8 +113,8 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo ...@@ -113,8 +113,8 @@ func CreateLogEntryHandler(params entries.CreateLogEntryParams) middleware.Respo
logEntry := models.LogEntry{ logEntry := models.LogEntry{
uuid: models.LogEntryAnon{ uuid: models.LogEntryAnon{
//LogIndex is not given here because it is always returned as 0 LogIndex: swag.Int64(queuedLeaf.LeafIndex),
Body: queuedLeaf.GetLeafValue(), Body: queuedLeaf.GetLeafValue(),
}, },
} }
......
...@@ -28,16 +28,25 @@ import ( ...@@ -28,16 +28,25 @@ import (
"github.com/google/trillian/client" "github.com/google/trillian/client"
"github.com/google/trillian/crypto/keyspb" "github.com/google/trillian/crypto/keyspb"
"github.com/google/trillian/crypto/sigpb" "github.com/google/trillian/crypto/sigpb"
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/types" "github.com/google/trillian/types"
) )
type TrillianClient struct { type TrillianClient struct {
client trillian.TrillianLogClient client trillian.TrillianLogClient
logID int64 logID int64
context context.Context context context.Context
pubkey *keyspb.PublicKey pubkey *keyspb.PublicKey
verifier *client.LogVerifier
}
func NewTrillianClient(ctx context.Context) TrillianClient {
return TrillianClient{
client: api.logClient,
logID: api.logID,
context: ctx,
pubkey: api.pubkey,
verifier: api.verifier,
}
} }
type Response struct { type Response struct {
...@@ -76,6 +85,44 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response { ...@@ -76,6 +85,44 @@ func (t *TrillianClient) addLeaf(byteValue []byte) *Response {
} }
resp, err := t.client.QueueLeaf(t.context, rqst) resp, err := t.client.QueueLeaf(t.context, rqst)
// check for error
if err != nil || (resp.QueuedLeaf.Status != nil && resp.QueuedLeaf.Status.Code != int32(codes.OK)) {
return &Response{
status: status.Code(err),
err: err,
getAddResult: resp,
}
}
root, err := t.root()
if err != nil {
return &Response{
status: status.Code(err),
err: err,
getAddResult: resp,
}
}
logClient := client.New(t.logID, t.client, t.verifier, root)
if err := logClient.WaitForInclusion(t.context, byteValue); err != nil {
return &Response{
status: status.Code(err),
err: err,
getAddResult: resp,
}
}
leafResp := t.getLeafByHash([][]byte{resp.QueuedLeaf.Leaf.MerkleLeafHash})
if leafResp.err != nil {
return &Response{
status: status.Code(leafResp.err),
err: leafResp.err,
getAddResult: resp,
}
}
//overwrite queued leaf that doesn't have index set
resp.QueuedLeaf.Leaf = leafResp.getLeafResult.Leaves[0]
return &Response{ return &Response{
status: status.Code(err), status: status.Code(err),
err: err, err: err,
...@@ -136,11 +183,9 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response { ...@@ -136,11 +183,9 @@ func (t *TrillianClient) getProofByHash(hashValue []byte) *Response {
TreeSize: int64(root.TreeSize), TreeSize: int64(root.TreeSize),
}) })
v := merkle.NewLogVerifier(rfc6962.DefaultHasher)
if resp != nil { if resp != nil {
for _, proof := range resp.Proof { for _, proof := range resp.Proof {
if err := v.VerifyInclusionProof(proof.LeafIndex, int64(root.TreeSize), proof.GetHashes(), root.RootHash, hashValue); err != nil { if err := t.verifier.VerifyInclusionByHash(&root, hashValue, proof); err != nil {
return &Response{ return &Response{
status: status.Code(err), status: status.Code(err),
err: err, err: err,
......
...@@ -9,9 +9,17 @@ import ( ...@@ -9,9 +9,17 @@ import (
"strconv" "strconv"
"strings" "strings"
"testing" "testing"
"time"
) )
func getUUIDFromUploadOutput(t *testing.T, out string) string {
t.Helper()
// Output looks like "Created entry at index X, available at $URL/UUID", so grab the UUID:
urlTokens := strings.Split(strings.TrimSpace(out), " ")
url := urlTokens[len(urlTokens)-1]
splitUrl := strings.Split(url, "/")
return splitUrl[len(splitUrl)-1]
}
func TestDuplicates(t *testing.T) { func TestDuplicates(t *testing.T) {
artifactPath := filepath.Join(t.TempDir(), "artifact") artifactPath := filepath.Join(t.TempDir(), "artifact")
sigPath := filepath.Join(t.TempDir(), "signature.asc") sigPath := filepath.Join(t.TempDir(), "signature.asc")
...@@ -59,9 +67,6 @@ func TestUploadVerifyRekord(t *testing.T) { ...@@ -59,9 +67,6 @@ func TestUploadVerifyRekord(t *testing.T) {
out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath) out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
outputContains(t, out, "Created entry at") outputContains(t, out, "Created entry at")
// We have to wait some time for the log to get signed and included.
time.Sleep(3 * time.Second)
// Now we should be able to verify it. // Now we should be able to verify it.
out = runCli(t, "verify", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath) out = runCli(t, "verify", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
outputContains(t, out, "Inclusion Proof:") outputContains(t, out, "Inclusion Proof:")
...@@ -88,9 +93,6 @@ func TestUploadVerifyRpm(t *testing.T) { ...@@ -88,9 +93,6 @@ func TestUploadVerifyRpm(t *testing.T) {
out := runCli(t, "upload", "--type=rpm", "--artifact", rpmPath, "--public-key", pubPath) out := runCli(t, "upload", "--type=rpm", "--artifact", rpmPath, "--public-key", pubPath)
outputContains(t, out, "Created entry at") outputContains(t, out, "Created entry at")
// We have to wait some time for the log to get signed and included.
time.Sleep(3 * time.Second)
// Now we should be able to verify it. // Now we should be able to verify it.
out = runCli(t, "verify", "--type=rpm", "--artifact", rpmPath, "--public-key", pubPath) out = runCli(t, "verify", "--type=rpm", "--artifact", rpmPath, "--public-key", pubPath)
outputContains(t, out, "Inclusion Proof:") outputContains(t, out, "Inclusion Proof:")
...@@ -117,13 +119,7 @@ func TestGet(t *testing.T) { ...@@ -117,13 +119,7 @@ func TestGet(t *testing.T) {
out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath) out := runCli(t, "upload", "--artifact", artifactPath, "--signature", sigPath, "--public-key", pubPath)
outputContains(t, out, "Created entry at") outputContains(t, out, "Created entry at")
// Wait a second for the entry to be added. uuid := getUUIDFromUploadOutput(t, out)
time.Sleep(1 * time.Second)
// Output looks like "Created entry at $URL/UUID", so grab the UUID:
url := strings.Split(strings.TrimSpace(out), " ")[3]
splitUrl := strings.Split(url, "/")
uuid := splitUrl[len(splitUrl)-1]
out = runCli(t, "get", "--format=json", "--uuid", uuid) out = runCli(t, "get", "--format=json", "--uuid", uuid)
// The output here should be in JSON with this structure: // The output here should be in JSON with this structure:
...@@ -172,13 +168,7 @@ func TestMinisign(t *testing.T) { ...@@ -172,13 +168,7 @@ func TestMinisign(t *testing.T) {
"--public-key", pubPath, "--pki-format", "minisign") "--public-key", pubPath, "--pki-format", "minisign")
outputContains(t, out, "Created entry at") outputContains(t, out, "Created entry at")
// Output looks like "Created entry at $URL/UUID", so grab the UUID: uuid := getUUIDFromUploadOutput(t, out)
url := strings.Split(strings.TrimSpace(out), " ")[3]
splitUrl := strings.Split(url, "/")
uuid := splitUrl[len(splitUrl)-1]
// Wait and check it.
time.Sleep(3 * time.Second)
out = runCli(t, "verify", "--artifact", artifactPath, "--signature", sigPath, out = runCli(t, "verify", "--artifact", artifactPath, "--signature", sigPath,
"--public-key", pubPath, "--pki-format", "minisign") "--public-key", pubPath, "--pki-format", "minisign")
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment