diff --git a/cmd/inclusion.go b/cmd/inclusion.go new file mode 100644 index 0000000000000000000000000000000000000000..6f1b39169fe7b260701be1af3c4db05341ae7fa7 --- /dev/null +++ b/cmd/inclusion.go @@ -0,0 +1,76 @@ +/* +Copyright © 2020 NAME HERE <EMAIL ADDRESS> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +package cmd + +import ( + "context" + "fmt" + "io/ioutil" + "log" + "os" + "time" + + "github.com/google/trillian" + "github.com/spf13/cobra" + "github.com/spf13/viper" + "google.golang.org/grpc" +) + +// inclusionCmd represents the inclusion command +var inclusionCmd = &cobra.Command{ + Use: "inclusion", + Short: "Rekor CLI", + Long: `Rekor interacts with a transparency log + +For more information, visit [domain]`, + Run: func(cmd *cobra.Command, args []string) { + logRpcServer := viper.GetString("log_rpc_server") + tLogID := viper.GetInt64("tlog_id") + linkfile := viper.GetString("linkfile") + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + // Set up and test connection to rpc server + conn, err := grpc.DialContext(ctx, logRpcServer, grpc.WithInsecure()) + if err != nil { + fmt.Println("Failed to connect to log server:", err) + } + defer conn.Close() + + jsonFile, err := os.Open(linkfile) + + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + byteValue, _ := ioutil.ReadAll(jsonFile) + defer jsonFile.Close() + + tLogClient := trillian.NewTrillianLogClient(conn) + server := serverInstance(tLogClient, tLogID) + + resp := &Response{} + + resp, err = server.getInclusion(byteValue, tLogID) + log.Printf("Server PUT Response: %s", resp) + }, +} + +func init() { + rootCmd.AddCommand(inclusionCmd) +} diff --git a/cmd/log_server.go b/cmd/log_server.go index 7e90c602d1ce032b7100e94201da86b81e85ba12..5673634c3e32dd413a809f1245069136d3022796 100644 --- a/cmd/log_server.go +++ b/cmd/log_server.go @@ -19,20 +19,32 @@ package cmd import ( "context" "fmt" + "log" + "time" + "github.com/google/trillian" + "github.com/google/trillian/client" + "github.com/google/trillian/merkle" "github.com/google/trillian/merkle/rfc6962" + "github.com/google/trillian/types" "google.golang.org/grpc/codes" - "log" + "google.golang.org/grpc/status" ) type server struct { + lc *client.LogClient client trillian.TrillianLogClient logID int64 ctx context.Context } type Response struct { - status string + status string + leafhash string +} + +type InclusionResponse struct { + status string leafhash string } @@ -43,6 +55,70 @@ func serverInstance(client trillian.TrillianLogClient, tLogID int64) *server { } } +func (s *server) root() (types.LogRootV1, error) { + rqst := &trillian.GetLatestSignedLogRootRequest{ + LogId: s.logID, + } + resp, err := s.client.GetLatestSignedLogRoot(context.Background(), rqst) + if err != nil { + return types.LogRootV1{}, err + } + var root types.LogRootV1 + if err := root.UnmarshalBinary(resp.SignedLogRoot.LogRoot); err != nil { + return types.LogRootV1{}, err + } + return root, nil +} + +func (s *server) getInclusion(byteValue []byte, tLogID int64) (*Response, error) { + + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + + root, err := s.root() + if err != nil { + return &Response{}, err + } + + log.Printf("[server:wait] Root hash: %x", root.RootHash) + + hasher := rfc6962.DefaultHasher + leafHash := hasher.HashLeaf(byteValue) + + resp, err := s.client.GetInclusionProofByHash(ctx, + &trillian.GetInclusionProofByHashRequest{ + LogId: tLogID, + LeafHash: leafHash, + TreeSize: int64(root.TreeSize), + }) + if err != nil { + fmt.Println("one") + return nil, status.Errorf(codes.Internal, "failed to get inclusion proof: %v", err) + } + if err != nil { + fmt.Println("two") + return &Response{}, err + } + if len(resp.Proof) < 1 { + fmt.Println("three") + return &Response{}, nil + } + + v := merkle.NewLogVerifier(rfc6962.DefaultHasher) + for i, proof := range resp.Proof { + hashes := proof.GetHashes() + for j, hash := range hashes { + log.Printf("Proof[%d],hash[%d] == %x\n", i, j, hash) + } + if err := v.VerifyInclusionProof(proof.LeafIndex, int64(root.TreeSize), hashes, root.RootHash, leafHash); err != nil { + return &Response{}, err + } + } + return &Response{ + status: "ok", + }, nil +} + func (s *server) addLeaf(byteValue []byte, tLogID int64) (*Response, error) { leaf := &trillian.LogLeaf{