diff options
| -rw-r--r-- | handler.go | 71 | ||||
| -rw-r--r-- | type.go | 23 | 
2 files changed, 91 insertions, 3 deletions
| @@ -4,9 +4,13 @@ import (  	"context"  	"fmt" +	"encoding/json" +	"io/ioutil"  	"net/http"  	"github.com/golang/glog" +	"github.com/google/certificate-transparency-go/tls" +	"github.com/google/trillian"  )  // appHandler implements the http.Handler interface, and contains a reference @@ -31,7 +35,7 @@ func (a appHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {  	statusCode, err := a.handler(ctx, a.instance, w, r)  	if err != nil { -		glog.Warningf("handler error %s: %v", a.instance.prefix+a.endpoint, err) +		glog.Warningf("handler error %s/%s: %v", a.instance.prefix, a.endpoint, err)  		a.sendHTTPError(w, statusCode, err)  	}  } @@ -41,10 +45,71 @@ func (a appHandler) sendHTTPError(w http.ResponseWriter, statusCode int, err err  	http.Error(w, http.StatusText(statusCode), statusCode)  } -// addEntry adds an entry to the Trillian backend  func addEntry(ctx context.Context, i *instance, w http.ResponseWriter, r *http.Request) (int, error) {  	glog.Info("in addEntry") -	return http.StatusOK, nil // TODO +	var request AddEntryRequest +	if err := unpackRequest(r, &request); err != nil { +		return http.StatusBadRequest, err +	} + +	item, err := verifyAddEntryRequest(request) +	if err != nil { +		return http.StatusBadRequest, err +	} +	glog.Infof("got item: %s", item) + +	serializedItem, err := tls.Marshal(*item) +	if err != nil { +		return http.StatusInternalServerError, fmt.Errorf("tls marshal failed: %v", err) +	} +	trillianRequest := trillian.QueueLeafRequest{ +		LogId: i.logID, +		Leaf: &trillian.LogLeaf{ +			LeafValue: serializedItem, +			//TODO: add appendix here w/ chain + signature +		}, +	} + +	trillianResponse, err := i.client.QueueLeaf(ctx, &trillianRequest) +	if err != nil { +		return http.StatusInternalServerError, fmt.Errorf("backend QueueLeaf request failed: %v", err) +	} +	if trillianResponse == nil { +		return http.StatusInternalServerError, fmt.Errorf("missing QueueLeaf response") +	} +	// TODO: check that we got gRPC OK as specified in Trillian's API doc + +	queuedLeaf := trillianResponse.QueuedLeaf +	glog.Infof("Queued leaf: %v", queuedLeaf.Leaf.LeafValue) +	// TODO: respond with an SDI + +	return http.StatusOK, nil +} + +// verifyAddEntryRequest +func verifyAddEntryRequest(r AddEntryRequest) (*StItem, error) { +	item, err := StItemFromB64(r.Item) +	if err != nil { +		return nil, fmt.Errorf("failed decoding StItem: %v", err) +	} +	if item.Format != StFormatChecksumV1 { +		return nil, fmt.Errorf("invalid StItem format: %s", item.Format) +	} +	// TODO: verify checksum length +	// TODO: verify r.Signature and r.Certificate +	return item, nil +} + +// unpackRequest tries to unpack a json-encoded HTTP POST request into `unpack` +func unpackRequest(r *http.Request, unpack interface{}) error { +	body, err := ioutil.ReadAll(r.Body) +	if err != nil { +		return fmt.Errorf("failed reading request body: %v", err) +	} +	if err := json.Unmarshal(body, &unpack); err != nil { +		return fmt.Errorf("failed parsing json body: %v", err) +	} +	return nil  }  // getEntries provides with a list of entries from the Trillian backend @@ -55,6 +55,22 @@ func (i StItem) String() string {  	}  } +func StItemFromB64(s string) (*StItem, error) { +	b, err := base64.StdEncoding.DecodeString(s) +	if err != nil { +		return nil, fmt.Errorf("base64 decoding failed: %v", err) +	} + +	var item StItem +	extra, err := tls.Unmarshal(b, &item) +	if err != nil { +		return nil, fmt.Errorf("tls unmarshal failed: %v", err) +	} else if len(extra) > 0 { +		return nil, fmt.Errorf("tls unmarshal found extra data: %v", extra) +	} +	return &item, nil +} +  // ChecksumV1 associates a package name with an arbitrary checksum value  type ChecksumV1 struct {  	Package  []byte `tls:"minlen:0,maxlen:255"` @@ -75,3 +91,10 @@ func NewChecksumV1(name string, checksum []byte) (StItem, error) {  func (i ChecksumV1) String() string {  	return fmt.Sprintf("%v %v", string(i.Package), base64.StdEncoding.EncodeToString(i.Checksum))  } + +// AddEntryRequest is a collection of add-entry input parameters +type AddEntryRequest struct { +	Item        string `json:"item"` +	Signature   string `json:"signature"` +	Certificate string `json:"certificate"` +} | 
