diff options
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/siglog_server/.gitignore | 1 | ||||
| -rw-r--r-- | cmd/siglog_server/README.md | 60 | ||||
| -rw-r--r-- | cmd/siglog_server/main.go | 176 | ||||
| -rw-r--r-- | cmd/tmp/README.md | 2 | ||||
| -rw-r--r-- | cmd/tmp/cosign/main.go | 56 | ||||
| -rw-r--r-- | cmd/tmp/keygen/main.go | 17 | ||||
| -rw-r--r-- | cmd/tmp/submit/main.go | 29 | 
7 files changed, 341 insertions, 0 deletions
| diff --git a/cmd/siglog_server/.gitignore b/cmd/siglog_server/.gitignore new file mode 100644 index 0000000..254defd --- /dev/null +++ b/cmd/siglog_server/.gitignore @@ -0,0 +1 @@ +server diff --git a/cmd/siglog_server/README.md b/cmd/siglog_server/README.md new file mode 100644 index 0000000..71bb3ac --- /dev/null +++ b/cmd/siglog_server/README.md @@ -0,0 +1,60 @@ +# Run Trillian + STFE locally +Trillian uses a database.  So, we will need to set that up.  It is documented +[here](https://github.com/google/trillian#mysql-setup), and how to check that it +is setup properly +[here](https://github.com/google/certificate-transparency-go/blob/master/trillian/docs/ManualDeployment.md#data-storage). + +Other than the database we need the Trillian log signer, Trillian log server, +and STFE server. +``` +$ go install github.com/google/trillian/cmd/trillian_log_signer +$ go install github.com/google/trillian/cmd/trillian_log_server +$ go install +``` + +Start Trillian log signer: +``` +trillian_log_signer --logtostderr -v 9 --force_master --rpc_endpoint=localhost:6961 --http_endpoint=localhost:6964 --num_sequencers 1 --sequencer_interval 100ms --batch_size 100 +``` + +Start Trillian log server: +``` +trillian_log_server --logtostderr -v 9 --rpc_endpoint=localhost:6962 --http_endpoint=localhost:6963 +``` + +As described in more detail +[here](https://github.com/google/certificate-transparency-go/blob/master/trillian/docs/ManualDeployment.md#trillian-services), +we need to provision a Merkle tree once: +``` +$ go install github.com/google/trillian/cmd/createtree +$ createtree --admin_server localhost:6962 +<tree id> +``` + +Hang on to `<tree id>`.  Our STFE server will use it when talking to the +Trillian log server to specify which Merkle tree we are working against. + +(If you take a look in the `Trees` table you will see that the tree has been +provisioned.) + +We will also need a public key-pair and log identifier for the STFE server. +``` +$ go install github.com/system-transparency/stfe/types/cmd/new-namespace +sk: <sk> +vk: <vk> +ed25519_v1: <namespace> +``` + +The log's identifier is `<namespace>` and contains the public verification key +`<vk>`.  The log's corresponding secret signing key is `<sk>`. + +Start STFE server: +``` +$ ./server --logtostderr -v 9 --http_endpoint localhost:6965 --log_rpc_server localhost:6962 --trillian_id <tree id> --key <sk> +``` + +If the log is responsive on, e.g., `GET http://localhost:6965/st/v1/get-latest-sth` you +may want to try running +`github.com/system-transparency/stfe/client/cmd/example.sh`.  You need to +configure the log's id though for verification to work (flag `log_id`, which +should be set to the `<namespace>` output above). diff --git a/cmd/siglog_server/main.go b/cmd/siglog_server/main.go new file mode 100644 index 0000000..368b0a7 --- /dev/null +++ b/cmd/siglog_server/main.go @@ -0,0 +1,176 @@ +// Package main provides an STFE server binary +package main + +import ( +	"context" +	"crypto" +	"crypto/ed25519" +	"encoding/hex" +	"flag" +	"fmt" +	"net/http" +	"os" +	"os/signal" +	"strings" +	"sync" +	"syscall" +	"time" + +	"github.com/golang/glog" +	"github.com/google/trillian" +	"github.com/prometheus/client_golang/prometheus/promhttp" +	stfe "github.com/system-transparency/stfe/pkg/instance" +	"github.com/system-transparency/stfe/pkg/state" +	trillianWrapper "github.com/system-transparency/stfe/pkg/trillian" +	"github.com/system-transparency/stfe/pkg/types" +	"google.golang.org/grpc" +) + +var ( +	httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") +	rpcBackend   = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") +	prefix       = flag.String("prefix", "", "a prefix that proceeds /st/v0/<endpoint>") +	trillianID   = flag.Int64("trillian_id", 0, "log identifier in the Trillian database") +	deadline     = flag.Duration("deadline", time.Second*10, "deadline for backend requests") +	key          = flag.String("key", "", "hex-encoded Ed25519 signing key") +	witnesses    = flag.String("witnesses", "", "comma-separated list of trusted witness verification keys in hex") +	maxRange     = flag.Int64("max_range", 10, "maximum number of entries that can be retrived in a single request") +	interval     = flag.Duration("interval", time.Second*30, "interval used to rotate the log's cosigned STH") +) + +func main() { +	flag.Parse() +	defer glog.Flush() + +	// wait for clean-up before exit +	var wg sync.WaitGroup +	defer wg.Wait() +	ctx, cancel := context.WithCancel(context.Background()) +	defer cancel() + +	glog.V(3).Infof("configuring stfe instance...") +	instance, err := setupInstanceFromFlags() +	if err != nil { +		glog.Errorf("setupInstance: %v", err) +		return +	} + +	glog.V(3).Infof("spawning state manager") +	go func() { +		wg.Add(1) +		defer wg.Done() +		instance.Stateman.Run(ctx) +		glog.Errorf("state manager shutdown") +		cancel() // must have state manager running +	}() + +	glog.V(3).Infof("spawning await") +	server := http.Server{Addr: *httpEndpoint} +	go await(ctx, func() { +		wg.Add(1) +		defer wg.Done() +		ctxInner, _ := context.WithTimeout(ctx, time.Second*60) +		glog.Infof("Shutting down HTTP server...") +		server.Shutdown(ctxInner) +		glog.V(3).Infof("HTTP server shutdown") +		glog.Infof("Shutting down spawned go routines...") +		cancel() +	}) + +	glog.Infof("Serving on %v/%v", *httpEndpoint, *prefix) +	if err = server.ListenAndServe(); err != http.ErrServerClosed { +		glog.Errorf("ListenAndServe: %v", err) +	} +} + +// SetupInstance sets up a new STFE instance from flags +func setupInstanceFromFlags() (*stfe.Instance, error) { +	var i stfe.Instance +	var err error + +	// Setup log configuration +	i.Signer, i.LogID, err = newLogIdentity(*key) +	if err != nil { +		return nil, fmt.Errorf("newLogIdentity: %v", err) +	} +	i.TreeID = *trillianID +	i.Prefix = *prefix +	i.MaxRange = *maxRange +	i.Deadline = *deadline +	i.Interval = *interval +	i.Witnesses, err = newWitnessMap(*witnesses) +	if err != nil { +		return nil, fmt.Errorf("newWitnessMap: %v", err) +	} + +	// Setup log client +	dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(i.Deadline)} +	conn, err := grpc.Dial(*rpcBackend, dialOpts...) +	if err != nil { +		return nil, fmt.Errorf("Dial: %v", err) +	} +	i.Client = &trillianWrapper.TrillianClient{ +		TreeID: i.TreeID, +		GRPC:   trillian.NewTrillianLogClient(conn), +	} + +	// Setup state manager +	i.Stateman, err = state.NewStateManagerSingle(i.Client, i.Signer, i.Interval, i.Deadline) +	if err != nil { +		return nil, fmt.Errorf("NewStateManager: %v", err) +	} + +	// Register HTTP endpoints +	mux := http.NewServeMux() +	http.Handle("/", mux) +	for _, handler := range i.Handlers() { +		glog.V(3).Infof("adding handler: %s", handler.Path()) +		mux.Handle(handler.Path(), handler) +	} +	glog.V(3).Infof("Adding prometheus handler on path: /metrics") +	http.Handle("/metrics", promhttp.Handler()) + +	return &i, nil +} + +func newLogIdentity(key string) (crypto.Signer, string, error) { +	buf, err := hex.DecodeString(key) +	if err != nil { +		return nil, "", fmt.Errorf("DecodeString: %v", err) +	} +	sk := crypto.Signer(ed25519.PrivateKey(buf)) +	vk := sk.Public().(ed25519.PublicKey) +	return sk, hex.EncodeToString([]byte(vk[:])), nil +} + +// newWitnessMap creates a new map of trusted witnesses +func newWitnessMap(witnesses string) (map[[types.HashSize]byte][types.VerificationKeySize]byte, error) { +	w := make(map[[types.HashSize]byte][types.VerificationKeySize]byte) +	if len(witnesses) > 0 { +		for _, witness := range strings.Split(witnesses, ",") { +			b, err := hex.DecodeString(witness) +			if err != nil { +				return nil, fmt.Errorf("DecodeString: %v", err) +			} + +			var vk [types.VerificationKeySize]byte +			if n := copy(vk[:], b); n != types.VerificationKeySize { +				return nil, fmt.Errorf("Invalid verification key size: %v", n) +			} +			w[*types.Hash(vk[:])] = vk +		} +	} +	return w, nil +} + +// await waits for a shutdown signal and then runs a clean-up function +func await(ctx context.Context, done func()) { +	sigs := make(chan os.Signal, 1) +	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) +	select { +	case <-sigs: +	case <-ctx.Done(): +	} +	glog.V(3).Info("received shutdown signal") +	done() +} diff --git a/cmd/tmp/README.md b/cmd/tmp/README.md new file mode 100644 index 0000000..30d5317 --- /dev/null +++ b/cmd/tmp/README.md @@ -0,0 +1,2 @@ +# Warning +These basic commands will be moved or replaced by proper tooling. diff --git a/cmd/tmp/cosign/main.go b/cmd/tmp/cosign/main.go new file mode 100644 index 0000000..a51f17d --- /dev/null +++ b/cmd/tmp/cosign/main.go @@ -0,0 +1,56 @@ +package main + +import ( +	"bytes" +	"crypto/ed25519" +	"encoding/hex" +	"flag" +	"fmt" +	"log" +	"net/http" + +	"github.com/system-transparency/stfe/pkg/types" +) + +var ( +	url = flag.String("url", "http://localhost:6965/st/v0", "base url") +	sk  = flag.String("sk", "e1d7c494dacb0ddf809a17e4528b01f584af22e3766fa740ec52a1711c59500d711090dd2286040b50961b0fe09f58aa665ccee5cb7ee042d819f18f6ab5046b", "hex key") +) + +func main() { +	priv, err := hex.DecodeString(*sk) +	if err != nil { +		log.Fatalf("DecodeString: %v", err) +	} +	sk := ed25519.PrivateKey(priv) +	vk := sk.Public().(ed25519.PublicKey) +	fmt.Printf("sk: %x\nvk: %x\n", sk, vk) + +	rsp, err := http.Get(*url + "/get-tree-head-to-sign") +	if err != nil { +		log.Fatalf("Get: %v", err) +	} +	var sth types.SignedTreeHead +	if err := sth.UnmarshalASCII(rsp.Body); err != nil { +		log.Fatalf("UnmarshalASCII: %v", err) +	} +	fmt.Printf("%+v\n", sth) + +	msg := sth.TreeHead.Marshal() +	sig := ed25519.Sign(sk, msg) +	sigident := &types.SigIdent{ +		KeyHash:   types.Hash(vk[:]), +		Signature: &[types.SignatureSize]byte{}, +	} +	copy(sigident.Signature[:], sig) + +	buf := bytes.NewBuffer(nil) +	if err := sigident.MarshalASCII(buf); err != nil { +		log.Fatalf("MarshalASCII: %v", err) +	} +	rsp, err = http.Post(*url+"/add-cosignature", "type/stfe", buf) +	if err != nil { +		log.Fatalf("Post: %v", err) +	} +	fmt.Printf("Status: %v\n", rsp.StatusCode) +} diff --git a/cmd/tmp/keygen/main.go b/cmd/tmp/keygen/main.go new file mode 100644 index 0000000..c1c1b58 --- /dev/null +++ b/cmd/tmp/keygen/main.go @@ -0,0 +1,17 @@ +package main + +import ( +	"crypto/ed25519" +	"crypto/rand" +	"fmt" +	"log" +) + +func main() { +	vk, sk, err := ed25519.GenerateKey(rand.Reader) +	if err != nil { +		log.Fatalf("GenerateKey: %v", err) +	} +	fmt.Printf("sk: %x\n", sk[:]) +	fmt.Printf("vk: %x\n", vk[:]) +} diff --git a/cmd/tmp/submit/main.go b/cmd/tmp/submit/main.go new file mode 100644 index 0000000..3dcaa97 --- /dev/null +++ b/cmd/tmp/submit/main.go @@ -0,0 +1,29 @@ +package main + +// go run . | bash + +import ( +	"crypto/ed25519" +	"crypto/rand" +	"fmt" + +	"github.com/system-transparency/stfe/pkg/types" +) + +func main() { +	checksum := [32]byte{} +	msg := types.Message{ +		ShardHint: 0, +		Checksum:  &checksum, +	} + +	vk, sk, err := ed25519.GenerateKey(rand.Reader) +	if err != nil { +		fmt.Printf("ed25519.GenerateKey: %v\n", err) +		return +	} +	sig := ed25519.Sign(sk, msg.Marshal()) +	//fmt.Printf("sk: %x\nvk: %x\n", sk[:], vk[:]) + +	fmt.Printf("echo \"shard_hint=%d\nchecksum=%x\nsignature_over_message=%x\nverification_key=%x\ndomain_hint=%s\" | curl --data-binary @- localhost:6965/st/v0/add-leaf\n", msg.ShardHint, msg.Checksum[:], sig, vk[:], "example.com") +} | 
