github.com/bartle-stripe/trillian@v1.2.1/cmd/createtree/main.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package main contains the implementation and entry point for the createtree
    16  // command.
    17  //
    18  // Example usage:
    19  // $ ./createtree --admin_server=host:port
    20  //
    21  // The command outputs the tree ID of the created tree to stdout, or an error to
    22  // stderr in case of failure. The output is minimal to allow for easy usage in
    23  // automated scripts.
    24  //
    25  // Several flags are provided to configure the create tree, most of which try to
    26  // assume reasonable defaults. Multiple types of private keys may be supported;
    27  // one has only to set the appropriate --private_key_format value and supply the
    28  // corresponding flags for the chosen key type.
    29  package main
    30  
    31  import (
    32  	"context"
    33  	"errors"
    34  	"flag"
    35  	"fmt"
    36  	"time"
    37  
    38  	"github.com/golang/glog"
    39  	"github.com/golang/protobuf/ptypes"
    40  	"github.com/google/trillian"
    41  	"github.com/google/trillian/client"
    42  	"github.com/google/trillian/client/rpcflags"
    43  	"github.com/google/trillian/cmd"
    44  	"github.com/google/trillian/cmd/createtree/keys"
    45  	"github.com/google/trillian/crypto/keyspb"
    46  	"github.com/google/trillian/crypto/sigpb"
    47  	"google.golang.org/grpc"
    48  )
    49  
    50  var (
    51  	adminServerAddr = flag.String("admin_server", "", "Address of the gRPC Trillian Admin Server (host:port)")
    52  	rpcDeadline     = flag.Duration("rpc_deadline", time.Second*10, "Deadline for RPC requests")
    53  
    54  	treeState          = flag.String("tree_state", trillian.TreeState_ACTIVE.String(), "State of the new tree")
    55  	treeType           = flag.String("tree_type", trillian.TreeType_LOG.String(), "Type of the new tree")
    56  	hashStrategy       = flag.String("hash_strategy", trillian.HashStrategy_RFC6962_SHA256.String(), "Hash strategy (aka preimage protection) of the new tree")
    57  	hashAlgorithm      = flag.String("hash_algorithm", sigpb.DigitallySigned_SHA256.String(), "Hash algorithm of the new tree")
    58  	signatureAlgorithm = flag.String("signature_algorithm", sigpb.DigitallySigned_ECDSA.String(), "Signature algorithm of the new tree")
    59  	displayName        = flag.String("display_name", "", "Display name of the new tree")
    60  	description        = flag.String("description", "", "Description of the new tree")
    61  	maxRootDuration    = flag.Duration("max_root_duration", 0, "Interval after which a new signed root is produced despite no submissions; zero means never")
    62  	privateKeyFormat   = flag.String("private_key_format", "", "Type of protobuf message to send the key as (PrivateKey, PEMKeyFile, or PKCS11ConfigFile). If empty, a key will be generated for you by Trillian.")
    63  
    64  	configFile = flag.String("config", "", "Config file containing flags, file contents can be overridden by command line flags")
    65  
    66  	errAdminAddrNotSet = errors.New("empty --admin_server, please provide the Admin server host:port")
    67  )
    68  
    69  // TODO(Martin2112): Pass everything needed into this and don't refer to flags.
    70  func createTree(ctx context.Context) (*trillian.Tree, error) {
    71  	if *adminServerAddr == "" {
    72  		return nil, errAdminAddrNotSet
    73  	}
    74  
    75  	req, err := newRequest()
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	dialOpts, err := rpcflags.NewClientDialOptionsFromFlags()
    81  	if err != nil {
    82  		return nil, fmt.Errorf("failed to determine dial options: %v", err)
    83  	}
    84  
    85  	conn, err := grpc.Dial(*adminServerAddr, dialOpts...)
    86  	if err != nil {
    87  		return nil, fmt.Errorf("failed to dial %v: %v", *adminServerAddr, err)
    88  	}
    89  	defer conn.Close()
    90  
    91  	adminClient := trillian.NewTrillianAdminClient(conn)
    92  	mapClient := trillian.NewTrillianMapClient(conn)
    93  	logClient := trillian.NewTrillianLogClient(conn)
    94  
    95  	return client.CreateAndInitTree(ctx, req, adminClient, mapClient, logClient)
    96  }
    97  
    98  func newRequest() (*trillian.CreateTreeRequest, error) {
    99  	ts, ok := trillian.TreeState_value[*treeState]
   100  	if !ok {
   101  		return nil, fmt.Errorf("unknown TreeState: %v", *treeState)
   102  	}
   103  
   104  	tt, ok := trillian.TreeType_value[*treeType]
   105  	if !ok {
   106  		return nil, fmt.Errorf("unknown TreeType: %v", *treeType)
   107  	}
   108  
   109  	hs, ok := trillian.HashStrategy_value[*hashStrategy]
   110  	if !ok {
   111  		return nil, fmt.Errorf("unknown HashStrategy: %v", *hashStrategy)
   112  	}
   113  
   114  	ha, ok := sigpb.DigitallySigned_HashAlgorithm_value[*hashAlgorithm]
   115  	if !ok {
   116  		return nil, fmt.Errorf("unknown HashAlgorithm: %v", *hashAlgorithm)
   117  	}
   118  
   119  	sa, ok := sigpb.DigitallySigned_SignatureAlgorithm_value[*signatureAlgorithm]
   120  	if !ok {
   121  		return nil, fmt.Errorf("unknown SignatureAlgorithm: %v", *signatureAlgorithm)
   122  	}
   123  
   124  	ctr := &trillian.CreateTreeRequest{Tree: &trillian.Tree{
   125  		TreeState:          trillian.TreeState(ts),
   126  		TreeType:           trillian.TreeType(tt),
   127  		HashStrategy:       trillian.HashStrategy(hs),
   128  		HashAlgorithm:      sigpb.DigitallySigned_HashAlgorithm(ha),
   129  		SignatureAlgorithm: sigpb.DigitallySigned_SignatureAlgorithm(sa),
   130  		DisplayName:        *displayName,
   131  		Description:        *description,
   132  		MaxRootDuration:    ptypes.DurationProto(*maxRootDuration),
   133  	}}
   134  	glog.Infof("Creating tree %+v", ctr.Tree)
   135  
   136  	if *privateKeyFormat != "" {
   137  		pk, err := keys.New(*privateKeyFormat)
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  		ctr.Tree.PrivateKey = pk
   142  	} else {
   143  		ctr.KeySpec = &keyspb.Specification{}
   144  
   145  		switch sigpb.DigitallySigned_SignatureAlgorithm(sa) {
   146  		case sigpb.DigitallySigned_ECDSA:
   147  			ctr.KeySpec.Params = &keyspb.Specification_EcdsaParams{
   148  				EcdsaParams: &keyspb.Specification_ECDSA{},
   149  			}
   150  		case sigpb.DigitallySigned_RSA:
   151  			ctr.KeySpec.Params = &keyspb.Specification_RsaParams{
   152  				RsaParams: &keyspb.Specification_RSA{},
   153  			}
   154  		default:
   155  			return nil, fmt.Errorf("unsupported signature algorithm: %v", sa)
   156  		}
   157  	}
   158  
   159  	return ctr, nil
   160  }
   161  
   162  func main() {
   163  	flag.Parse()
   164  	defer glog.Flush()
   165  
   166  	if *configFile != "" {
   167  		if err := cmd.ParseFlagFile(*configFile); err != nil {
   168  			glog.Exitf("Failed to load flags from config file %q: %s", *configFile, err)
   169  		}
   170  	}
   171  
   172  	ctx, cancel := context.WithTimeout(context.Background(), *rpcDeadline)
   173  	defer cancel()
   174  	tree, err := createTree(ctx)
   175  	if err != nil {
   176  		glog.Exitf("Failed to create tree: %v", err)
   177  	}
   178  
   179  	// DO NOT change the output format, scripts are meant to depend on it.
   180  	// If you really want to change it, provide an output_format flag and
   181  	// keep the default as-is.
   182  	fmt.Println(tree.TreeId)
   183  }