Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ go:
- 1.8

env:
- GOFLAGS=
- GOFLAGS=-race
- GOFLAGS= WITH_ETCD=true
- GOFLAGS=-race WITH_ETCD=true
- GOFLAGS= WITH_PKCS11=true
- GOFLAGS=-race WITH_PKCS11=true
- GOFLAGS=''
- GOFLAGS='-race'
- GOFLAGS='' WITH_ETCD=true
- GOFLAGS='-race' WITH_ETCD=true
- GOFLAGS='--tags pkcs11' WITH_PKCS11=true
- GOFLAGS='-race --tags pkcs11' WITH_PKCS11=true

matrix:
fast_finish: true
Expand Down Expand Up @@ -43,7 +43,7 @@ install:
- export PATH=$(pwd)/../protoc/bin:$PATH
# googleapis is not Go code, but it's required for .pb.go regeneration because of API dependencies.
- git clone https://github.com/googleapis/googleapis.git $GOPATH/src/github.com/googleapis/googleapis
- go get -d -t ./...
- go get ${GOFLAGS} -d -t ./...
- if [[ $TRAVIS_OS_NAME == "osx" ]]; then brew update > /dev/null && brew install mariadb && mysql.server start; fi
- go get -u github.com/client9/misspell/cmd/misspell
- go get -u github.com/fzipp/gocyclo
Expand Down
66 changes: 66 additions & 0 deletions cmd/createtree/keys/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package keys

import (
"fmt"
"strings"

"github.com/golang/protobuf/proto"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
)

// ProtoBuilder creates a protobuf message that describes a private key.
// It may use flags to obtain the required information, e.g. file paths.
type ProtoBuilder func() (proto.Message, error)

// protoBuilders is a map of key types to funcs that can create protobuf
// messages describing them. The "key type" is a human-friendly identifier;
// it does not have to be the name of the protobuf message.
var protoBuilders = make(map[string]ProtoBuilder)

// RegisterType registers a func that can create protobuf messages which describe
// a private key.
func RegisterType(protoType string, builder ProtoBuilder) {
protoBuilders[protoType] = builder
}

// New returns a protobuf message of the specified type that describes a private
// key. A ProtoBuilder must have been registered for this type using
// RegisterType() first.
func New(protoType string) (*any.Any, error) {
buildProto, ok := protoBuilders[protoType]
if !ok {
return nil, fmt.Errorf("key protobuf type must be one of: %s", strings.Join(RegisteredTypes(), ", "))
}

pb, err := buildProto()
if err != nil {
return nil, err
}

return ptypes.MarshalAny(pb)
}

// RegisteredTypes returns a list of protobuf message types that have been
// registered using RegisterType().
func RegisteredTypes() []string {
protoTypes := make([]string, 0, len(protoBuilders))
for protoType := range protoBuilders {
protoTypes = append(protoTypes, protoType)
}
return protoTypes
}
77 changes: 3 additions & 74 deletions cmd/createtree/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,17 @@ package main

import (
"context"
"encoding/json"
"errors"
"flag"
"fmt"
"io/ioutil"

"github.com/golang/glog"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/any"
"github.com/google/trillian"
"github.com/google/trillian/cmd"
"github.com/google/trillian/crypto/keys/der"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/cmd/createtree/keys"
"github.com/google/trillian/crypto/keyspb"
"github.com/google/trillian/crypto/sigpb"
"github.com/letsencrypt/pkcs11key"
"google.golang.org/grpc"
)

Expand All @@ -60,11 +55,7 @@ var (
displayName = flag.String("display_name", "", "Display name of the new tree")
description = flag.String("description", "", "Description of the new tree")
maxRootDuration = flag.Duration("max_root_duration", 0, "Interval after which a new signed root is produced despite no submissions; zero means never")

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.")
pemKeyPath = flag.String("pem_key_path", "", "Path to the private key PEM file")
pemKeyPassword = flag.String("pem_key_password", "", "Password of the private key PEM file")
pkcs11ConfigPath = flag.String("pkcs11_config_path", "", "Path to the PKCS #11 key configuration file")
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.")

configFile = flag.String("config", "", "Config file containing flags, file contents can be overridden by command line flags")
)
Expand Down Expand Up @@ -130,20 +121,12 @@ func newRequest() (*trillian.CreateTreeRequest, error) {
}}

if *privateKeyFormat != "" {
pk, err := newPK(*privateKeyFormat)
pk, err := keys.New(*privateKeyFormat)
if err != nil {
return nil, err
}
ctr.Tree.PrivateKey = pk
} else {
// Cannot continue if options specifying a key were provided but
// privateKeyType is not set, as there's no way to know what protobuf
// message type was intended.
if *pemKeyPath != "" || *pemKeyPassword != "" || *pkcs11ConfigPath != "" {
return nil, errors.New("must specify private key format")
}

// If no key flags were provided at all, get Trillian to generate a key.
ctr.KeySpec = &keyspb.Specification{}

switch sigpb.DigitallySigned_SignatureAlgorithm(sa) {
Expand All @@ -163,60 +146,6 @@ func newRequest() (*trillian.CreateTreeRequest, error) {
return ctr, nil
}

func newPK(keyFormat string) (*any.Any, error) {
switch keyFormat {
case "PEMKeyFile":
if *pemKeyPath == "" {
return nil, errors.New("empty pem_key_path")
}
if *pemKeyPassword == "" {
return nil, fmt.Errorf("empty password for PEM key file %q", *pemKeyPath)
}
pemKey := &keyspb.PEMKeyFile{
Path: *pemKeyPath,
Password: *pemKeyPassword,
}
return ptypes.MarshalAny(pemKey)
case "PrivateKey":
if *pemKeyPath == "" {
return nil, errors.New("empty pem_key_path")
}
pemSigner, err := pem.ReadPrivateKeyFile(
*pemKeyPath, *pemKeyPassword)
if err != nil {
return nil, err
}
keyDER, err := der.MarshalPrivateKey(pemSigner)
if err != nil {
return nil, err
}
return ptypes.MarshalAny(&keyspb.PrivateKey{Der: keyDER})
case "PKCS11ConfigFile":
if *pkcs11ConfigPath == "" {
return nil, errors.New("empty PKCS11 config file path")
}
configBytes, err := ioutil.ReadFile(*pkcs11ConfigPath)
if err != nil {
return nil, err
}
var config pkcs11key.Config
if err = json.Unmarshal(configBytes, &config); err != nil {
return nil, err
}
pubKeyBytes, err := ioutil.ReadFile(config.PublicKeyPath)
if err != nil {
return nil, err
}
return ptypes.MarshalAny(&keyspb.PKCS11Config{
TokenLabel: config.TokenLabel,
Pin: config.PIN,
PublicKey: string(pubKeyBytes),
})
default:
return nil, fmt.Errorf("unknown private key type: %v", keyFormat)
}
}

func main() {
flag.Parse()

Expand Down
7 changes: 5 additions & 2 deletions cmd/createtree/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ func TestCreateTree(t *testing.T) {

runTest(t, []*testCase{
{
desc: "validOpts",
desc: "validOpts",
// runTest sets mandatory options, so no need to provide a setFlags func.
wantTree: defaultTree,
},
{
Expand All @@ -82,7 +83,8 @@ func TestCreateTree(t *testing.T) {
wantTree: &nonDefaultTree,
},
{
desc: "defaultOptsOnly",
desc: "mandatoryOptsNotSet",
// Undo the flags set by runTest, so that mandatory options are no longer set.
setFlags: resetFlags,
wantErr: true,
},
Expand Down Expand Up @@ -154,6 +156,7 @@ func runTest(t *testing.T, tests []*testCase) {
}
}

// resetFlags sets all flags to their default values.
func resetFlags() {
flag.Visit(func(f *flag.Flag) {
f.Value.Set(f.DefValue)
Expand Down
69 changes: 69 additions & 0 deletions cmd/createtree/pem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
"errors"
"flag"
"fmt"

"github.com/golang/protobuf/proto"
"github.com/google/trillian/cmd/createtree/keys"
"github.com/google/trillian/crypto/keys/der"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/crypto/keyspb"
)

var (
pemKeyPath = flag.String("pem_key_path", "", "Path to the private key PEM file")
pemKeyPass = flag.String("pem_key_password", "", "Password of the private key PEM file")
)

func init() {
keys.RegisterType("PEMKeyFile", pemKeyFileProtoFromFlags)
keys.RegisterType("PrivateKey", privateKeyProtoFromFlags)
}

func pemKeyFileProtoFromFlags() (proto.Message, error) {
if *pemKeyPath == "" {
return nil, errors.New("empty pem_key_path")
}
if *pemKeyPass == "" {
return nil, fmt.Errorf("empty password for PEM key file %q", *pemKeyPath)
}

return &keyspb.PEMKeyFile{
Path: *pemKeyPath,
Password: *pemKeyPass,
}, nil
}

func privateKeyProtoFromFlags() (proto.Message, error) {
if *pemKeyPath == "" {
return nil, errors.New("empty pem_key_path")
}

key, err := pem.ReadPrivateKeyFile(*pemKeyPath, *pemKeyPass)
if err != nil {
return nil, fmt.Errorf("error reading reading private key file: %v", err)
}

der, err := der.MarshalPrivateKey(key)
if err != nil {
return nil, fmt.Errorf("error marshaling private key as DER: %v", err)
}

return &keyspb.PrivateKey{Der: der}, nil
}
12 changes: 6 additions & 6 deletions cmd/createtree/pem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestWithPEMKeyFile(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PEMKeyFile"
*pemKeyPath = ""
*pemKeyPassword = pemPassword
*pemKeyPass = pemPassword
},
wantErr: true,
},
Expand All @@ -46,7 +46,7 @@ func TestWithPEMKeyFile(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PEMKeyFile"
*pemKeyPath = pemPath
*pemKeyPassword = ""
*pemKeyPass = ""
},
wantErr: true,
},
Expand All @@ -55,7 +55,7 @@ func TestWithPEMKeyFile(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PEMKeyFile"
*pemKeyPath = pemPath
*pemKeyPassword = pemPassword
*pemKeyPass = pemPassword
},
wantTree: &wantTree,
},
Expand Down Expand Up @@ -86,7 +86,7 @@ func TestWithPrivateKey(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PrivateKey"
*pemKeyPath = ""
*pemKeyPassword = pemPassword
*pemKeyPass = pemPassword
},
wantErr: true,
},
Expand All @@ -95,7 +95,7 @@ func TestWithPrivateKey(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PrivateKey"
*pemKeyPath = pemPath
*pemKeyPassword = ""
*pemKeyPass = ""
},
wantErr: true,
},
Expand All @@ -104,7 +104,7 @@ func TestWithPrivateKey(t *testing.T) {
setFlags: func() {
*privateKeyFormat = "PrivateKey"
*pemKeyPath = pemPath
*pemKeyPassword = pemPassword
*pemKeyPass = pemPassword
},
wantTree: &wantTree,
},
Expand Down
Loading