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 }