From 44e4fb0f4e9e9ff9bf6e31c68b626fea2eb7403a Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Thu, 22 Oct 2020 20:03:57 +0200 Subject: Added start on get-proof-by-hash code path If the provided tree size is (mostly) valid the Trillian back-end is asked to provide an inclusion proof, which is then placed in an InclusionProofV1 structure and returned as a JSON object. --- handler.go | 37 +++++++++++++++++++++++++++++++++++ type.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/handler.go b/handler.go index 4d2ace8..57adaf1 100644 --- a/handler.go +++ b/handler.go @@ -169,6 +169,43 @@ func getAnchors(ctx context.Context, i *instance, w http.ResponseWriter, r *http // getProofByHash provides an inclusion proof based on a given leaf hash func getProofByHash(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) { glog.Info("in getProofByHash") + request, err := NewGetProofByHashRequest(r) + if err != nil { + return http.StatusBadRequest, err + } + + trillianRequest := trillian.GetInclusionProofByHashRequest{ + LogId: i.logID, + LeafHash: request.Hash, + TreeSize: request.TreeSize, + OrderBySequence: true, + } + trillianResponse, err := i.client.GetInclusionProofByHash(ctx, &trillianRequest) + if err != nil { + return http.StatusInternalServerError, fmt.Errorf("failed fetching inclusion proof from Trillian backend: %v", err) + } + // TODO: check the returned tree size in response? + + // Santity check + if len(trillianResponse.Proof) == 0 { + return http.StatusNotFound, fmt.Errorf("get-proof-by-hash backend returned no proof") + } + // TODO: verify that proof is valid? + + w.Header().Set("Content-Type", "application/json") + data, err := NewGetProofByHashResponse(uint64(request.TreeSize), trillianResponse.Proof[0]) + if err != nil { + return http.StatusInternalServerError, fmt.Errorf("failed creating get-proof-by-hash response: %v", err) + } + json, err := json.Marshal(data) + if err != nil { + return http.StatusInternalServerError, fmt.Errorf("failed json-encoding GetProofByHashResponse: %v", err) + } + _, err = w.Write(json) + if err != nil { + return http.StatusInternalServerError, fmt.Errorf("failed writing get-entries response: %v", err) + } + return http.StatusOK, nil // TODO } diff --git a/type.go b/type.go index 11fafe1..10ec2bd 100644 --- a/type.go +++ b/type.go @@ -95,6 +95,31 @@ func (i ChecksumV1) String() string { return fmt.Sprintf("%v %v", string(i.Package), base64.StdEncoding.EncodeToString(i.Checksum)) } +type NodeHash struct { + Data []byte `tls:"minlen:32,maxlen:255"` +} + +type InclusionProofV1 struct { + LogID []byte `tls:"minlen:2,maxlen:127"` + TreeSize uint64 + LeafIndex uint64 + InclusionPath []NodeHash `tls:"minlen:1,maxlen:65535"` +} + +func NewInclusionProofV1(logID []byte, treeSize uint64, proof *trillian.Proof) InclusionProofV1 { + inclusionPath := make([]NodeHash, 0, len(proof.Hashes)) + for _, hash := range proof.Hashes { + inclusionPath = append(inclusionPath, NodeHash{ Data: hash }) + } + + return InclusionProofV1{ + LogID: logID, + TreeSize: treeSize, + LeafIndex: uint64(proof.LeafIndex), + InclusionPath: inclusionPath, + } +} + // AddEntryRequest is a collection of add-entry input parameters type AddEntryRequest struct { Item string `json:"item"` @@ -155,3 +180,43 @@ func NewGetEntriesResponse(leaves []*trillian.LogLeaf) (GetEntriesResponse, erro } return GetEntriesResponse{entries}, nil } + +type GetProofByHashRequest struct { + Hash []byte + TreeSize int64 +} + +func NewGetProofByHashRequest(httpRequest *http.Request) (*GetProofByHashRequest, error) { + var r GetProofByHashRequest + var err error + + r.TreeSize, err = strconv.ParseInt(httpRequest.FormValue("tree_size"), 10, 64) + if err != nil { + return nil, fmt.Errorf("bad tree_size parameter: %v", err) + } + if r.TreeSize < 0 { + return nil, fmt.Errorf("bad tree_size parameter: negative value") + } + // TODO: check that tree size is not past STH.tree_size + + r.Hash, err = base64.StdEncoding.DecodeString(httpRequest.FormValue("hash")) + if err != nil { + return nil, fmt.Errorf("bad hash parameter: %v", err) + } + return &r, nil +} + +type GetProofByHashResponse struct { + InclusionProof string `json:"inclusion_proof"` +} + +func NewGetProofByHashResponse(treeSize uint64, inclusionProof *trillian.Proof) (*GetProofByHashResponse, error) { + item := NewInclusionProofV1([]byte("TODO: add log ID"), treeSize, inclusionProof) + b, err := tls.Marshal(item) + if err != nil { + return nil, fmt.Errorf("tls marshal failed: %v", err) + } + return &GetProofByHashResponse{ + InclusionProof: base64.StdEncoding.EncodeToString(b), + }, nil +} -- cgit v1.2.3