github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/server/admin/admin_server.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 admin
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"fmt"
    21  
    22  	"github.com/golang/glog"
    23  	"github.com/golang/protobuf/ptypes"
    24  	"github.com/google/trillian"
    25  	"github.com/google/trillian/crypto/keys/der"
    26  	"github.com/google/trillian/extension"
    27  	"github.com/google/trillian/merkle/hashers"
    28  	"github.com/google/trillian/storage"
    29  	"github.com/google/trillian/trees"
    30  	"google.golang.org/genproto/protobuf/field_mask"
    31  	"google.golang.org/grpc/codes"
    32  	"google.golang.org/grpc/status"
    33  
    34  	_ "github.com/google/trillian/merkle/rfc6962" // Make hashers available
    35  )
    36  
    37  // Server is an implementation of trillian.TrillianAdminServer.
    38  type Server struct {
    39  	registry         extension.Registry
    40  	allowedTreeTypes []trillian.TreeType
    41  }
    42  
    43  // New returns a trillian.TrillianAdminServer implementation.
    44  // registry is the extension.Registry used by the Server.
    45  // allowedTreeTypes defines which tree types may be created through this server,
    46  // with nil meaning unrestricted.
    47  func New(registry extension.Registry, allowedTreeTypes []trillian.TreeType) *Server {
    48  	return &Server{
    49  		registry:         registry,
    50  		allowedTreeTypes: allowedTreeTypes,
    51  	}
    52  }
    53  
    54  // IsHealthy returns nil if the server is healthy, error otherwise.
    55  // TODO(Martin2112): This method (and the one in the log server) should probably have ctx as a param
    56  func (s *Server) IsHealthy() error {
    57  	return s.registry.AdminStorage.CheckDatabaseAccessible(context.Background())
    58  }
    59  
    60  // ListTrees implements trillian.TrillianAdminServer.ListTrees.
    61  func (s *Server) ListTrees(ctx context.Context, req *trillian.ListTreesRequest) (*trillian.ListTreesResponse, error) {
    62  	// TODO(codingllama): This needs access control
    63  	resp, err := storage.ListTrees(ctx, s.registry.AdminStorage, req.GetShowDeleted())
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	for _, tree := range resp {
    68  		redact(tree)
    69  	}
    70  	return &trillian.ListTreesResponse{Tree: resp}, nil
    71  }
    72  
    73  // GetTree implements trillian.TrillianAdminServer.GetTree.
    74  func (s *Server) GetTree(ctx context.Context, req *trillian.GetTreeRequest) (*trillian.Tree, error) {
    75  	tree, err := storage.GetTree(ctx, s.registry.AdminStorage, req.GetTreeId())
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	return redact(tree), nil
    80  }
    81  
    82  // CreateTree implements trillian.TrillianAdminServer.CreateTree.
    83  func (s *Server) CreateTree(ctx context.Context, req *trillian.CreateTreeRequest) (*trillian.Tree, error) {
    84  	tree := req.GetTree()
    85  	if tree == nil {
    86  		return nil, status.Errorf(codes.InvalidArgument, "a tree is required")
    87  	}
    88  	if err := s.validateAllowedTreeType(tree.TreeType); err != nil {
    89  		return nil, status.Error(codes.InvalidArgument, err.Error())
    90  	}
    91  	switch tree.TreeType {
    92  	case trillian.TreeType_LOG, trillian.TreeType_PREORDERED_LOG:
    93  		if _, err := hashers.NewLogHasher(tree.HashStrategy); err != nil {
    94  			return nil, status.Errorf(codes.InvalidArgument, "failed to create hasher for tree: %v", err.Error())
    95  		}
    96  	case trillian.TreeType_MAP:
    97  		if _, err := hashers.NewMapHasher(tree.HashStrategy); err != nil {
    98  			return nil, status.Errorf(codes.InvalidArgument, "failed to create hasher for tree: %v", err.Error())
    99  		}
   100  	default:
   101  		return nil, status.Errorf(codes.InvalidArgument, "invalid tree type: %v", tree.TreeType)
   102  	}
   103  
   104  	// If a key specification was provided, generate a new key.
   105  	if req.KeySpec != nil {
   106  		if tree.PrivateKey != nil {
   107  			return nil, status.Errorf(codes.InvalidArgument, "the tree.private_key and key_spec fields are mutually exclusive")
   108  		}
   109  		if tree.PublicKey != nil {
   110  			return nil, status.Errorf(codes.InvalidArgument, "the tree.public_key and key_spec fields are mutually exclusive")
   111  		}
   112  		if s.registry.NewKeyProto == nil {
   113  			return nil, status.Errorf(codes.FailedPrecondition, "key generation is not enabled")
   114  		}
   115  
   116  		keyProto, err := s.registry.NewKeyProto(ctx, req.KeySpec)
   117  		if err != nil {
   118  			return nil, status.Errorf(codes.InvalidArgument, "failed to generate private key: %v", err.Error())
   119  		}
   120  
   121  		tree.PrivateKey, err = ptypes.MarshalAny(keyProto)
   122  		if err != nil {
   123  			return nil, status.Errorf(codes.Internal, "failed to marshal private key: %v", err.Error())
   124  		}
   125  	}
   126  
   127  	if tree.PrivateKey == nil {
   128  		return nil, status.Errorf(codes.InvalidArgument, "tree.private_key or key_spec is required")
   129  	}
   130  
   131  	// Check that the tree.PrivateKey is valid by trying to get a signer.
   132  	signer, err := trees.Signer(ctx, tree)
   133  	if err != nil {
   134  		return nil, status.Errorf(codes.InvalidArgument, "failed to create signer for tree: %v", err.Error())
   135  	}
   136  
   137  	// Derive the public key that corresponds to the private key for this tree.
   138  	// The caller may have provided the public key, but for safety we shouldn't rely on it being correct.
   139  	publicKey, err := der.ToPublicProto(signer.Public())
   140  	if err != nil {
   141  		return nil, status.Errorf(codes.InvalidArgument, "failed to marshal public key: %v", err.Error())
   142  	}
   143  
   144  	// If a public key was provided, check that it matches the one we derived. If it doesn't, this indicates a mistake by the caller.
   145  	if tree.PublicKey != nil && !bytes.Equal(tree.PublicKey.Der, publicKey.Der) {
   146  		return nil, status.Error(codes.InvalidArgument, "the public and private keys are not a pair")
   147  	}
   148  
   149  	// If no public key was provided, use the DER that we just marshaled.
   150  	if tree.PublicKey == nil {
   151  		tree.PublicKey = publicKey
   152  	}
   153  
   154  	// Clear generated fields, storage must set those
   155  	tree.TreeId = 0
   156  	tree.CreateTime = nil
   157  	tree.UpdateTime = nil
   158  	tree.Deleted = false
   159  	tree.DeleteTime = nil
   160  
   161  	createdTree, err := storage.CreateTree(ctx, s.registry.AdminStorage, tree)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	return redact(createdTree), nil
   166  }
   167  
   168  func (s *Server) validateAllowedTreeType(tt trillian.TreeType) error {
   169  	if s.allowedTreeTypes == nil {
   170  		return nil // All types OK
   171  	}
   172  	for _, allowedType := range s.allowedTreeTypes {
   173  		if tt == allowedType {
   174  			return nil
   175  		}
   176  	}
   177  	return fmt.Errorf("tree type %s not allowed by this server", tt)
   178  }
   179  
   180  // UpdateTree implements trillian.TrillianAdminServer.UpdateTree.
   181  func (s *Server) UpdateTree(ctx context.Context, req *trillian.UpdateTreeRequest) (*trillian.Tree, error) {
   182  	tree := req.GetTree()
   183  	mask := req.GetUpdateMask()
   184  	if tree == nil {
   185  		return nil, status.Errorf(codes.InvalidArgument, "a tree is required")
   186  	}
   187  	// Apply the mask to a couple of empty trees just to check that the paths are correct.
   188  	if err := applyUpdateMask(&trillian.Tree{}, &trillian.Tree{}, mask); err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	updatedTree, err := storage.UpdateTree(ctx, s.registry.AdminStorage, tree.TreeId, func(other *trillian.Tree) {
   193  		if err := applyUpdateMask(tree, other, mask); err != nil {
   194  			// Should never happen (famous last words).
   195  			glog.Errorf("Error applying mask on tree update: %v", err)
   196  		}
   197  	})
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	return redact(updatedTree), nil
   202  }
   203  
   204  func applyUpdateMask(from, to *trillian.Tree, mask *field_mask.FieldMask) error {
   205  	if mask == nil || len(mask.Paths) == 0 {
   206  		return status.Errorf(codes.InvalidArgument, "an update_mask is required")
   207  	}
   208  	for _, path := range mask.Paths {
   209  		switch path {
   210  		case "tree_state":
   211  			to.TreeState = from.TreeState
   212  		case "tree_type":
   213  			to.TreeType = from.TreeType
   214  		case "display_name":
   215  			to.DisplayName = from.DisplayName
   216  		case "description":
   217  			to.Description = from.Description
   218  		case "storage_settings":
   219  			to.StorageSettings = from.StorageSettings
   220  		case "max_root_duration":
   221  			to.MaxRootDuration = from.MaxRootDuration
   222  		case "private_key":
   223  			to.PrivateKey = from.PrivateKey
   224  		default:
   225  			return status.Errorf(codes.InvalidArgument, "invalid update_mask path: %q", path)
   226  		}
   227  	}
   228  	return nil
   229  }
   230  
   231  // DeleteTree implements trillian.TrillianAdminServer.DeleteTree.
   232  func (s *Server) DeleteTree(ctx context.Context, req *trillian.DeleteTreeRequest) (*trillian.Tree, error) {
   233  	tree, err := storage.SoftDeleteTree(ctx, s.registry.AdminStorage, req.GetTreeId())
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  	return redact(tree), nil
   238  }
   239  
   240  // UndeleteTree implements trillian.TrillianAdminServer.UndeleteTree.
   241  func (s *Server) UndeleteTree(ctx context.Context, req *trillian.UndeleteTreeRequest) (*trillian.Tree, error) {
   242  	tree, err := storage.UndeleteTree(ctx, s.registry.AdminStorage, req.GetTreeId())
   243  	if err != nil {
   244  		return nil, err
   245  	}
   246  	return redact(tree), nil
   247  }
   248  
   249  // redact removes sensitive information from t. Returns t for convenience.
   250  func redact(t *trillian.Tree) *trillian.Tree {
   251  	t.PrivateKey = nil
   252  	return t
   253  }