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
6 changes: 3 additions & 3 deletions client/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ import (

"github.com/google/trillian"
tcrypto "github.com/google/trillian/crypto"
"github.com/google/trillian/crypto/keys"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/merkle/rfc6962"
"github.com/google/trillian/testonly"
)

func TestVerifyRootErrors(t *testing.T) {
// Test setup
key, err := keys.NewFromPrivatePEM(testonly.DemoPrivateKey, testonly.DemoPrivateKeyPass)
key, err := pem.UnmarshalPrivateKey(testonly.DemoPrivateKey, testonly.DemoPrivateKeyPass)
if err != nil {
t.Fatalf("Failed to open test key, err=%v", err)
}
signer := tcrypto.NewSHA256Signer(key)
pk, err := keys.NewFromPublicPEM(testonly.DemoPublicKey)
pk, err := pem.UnmarshalPublicKey(testonly.DemoPublicKey)
if err != nil {
t.Fatalf("Failed to load public key, err=%v", err)
}
Expand Down
9 changes: 5 additions & 4 deletions cmd/createtree/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ import (
"github.com/golang/protobuf/ptypes/any"
"github.com/google/trillian"
"github.com/google/trillian/cmd"
"github.com/google/trillian/crypto/keys"
"github.com/google/trillian/crypto/keys/der"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/crypto/keyspb"
"github.com/google/trillian/crypto/sigpb"
"github.com/letsencrypt/pkcs11key"
Expand Down Expand Up @@ -180,16 +181,16 @@ func newPK(keyFormat string) (*any.Any, error) {
if *pemKeyPath == "" {
return nil, errors.New("empty pem_key_path")
}
pemSigner, err := keys.NewFromPrivatePEMFile(
pemSigner, err := pem.ReadPrivateKeyFile(
*pemKeyPath, *pemKeyPassword)
if err != nil {
return nil, err
}
der, err := keys.MarshalPrivateKey(pemSigner)
keyDER, err := der.MarshalPrivateKey(pemSigner)
if err != nil {
return nil, err
}
return ptypes.MarshalAny(&keyspb.PrivateKey{Der: der})
return ptypes.MarshalAny(&keyspb.PrivateKey{Der: keyDER})
case "PKCS11ConfigFile":
if *pkcs11ConfigPath == "" {
return nil, errors.New("empty PKCS11 config file path")
Expand Down
7 changes: 4 additions & 3 deletions cmd/createtree/pem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ package main
import (
"testing"

"github.com/google/trillian/crypto/keys"
"github.com/google/trillian/crypto/keys/der"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/crypto/keyspb"
)

Expand Down Expand Up @@ -64,12 +65,12 @@ func TestWithPEMKeyFile(t *testing.T) {
func TestWithPrivateKey(t *testing.T) {
pemPath, pemPassword := "../../testdata/log-rpc-server.privkey.pem", "towel"

key, err := keys.NewFromPrivatePEMFile(pemPath, pemPassword)
key, err := pem.ReadPrivateKeyFile(pemPath, pemPassword)
if err != nil {
t.Fatalf("Error reading test private key file: %v", err)
}

keyDER, err := keys.MarshalPrivateKey(key)
keyDER, err := der.MarshalPrivateKey(key)
if err != nil {
t.Fatalf("Error marshaling test private key to DER: %v", err)
}
Expand Down
26 changes: 21 additions & 5 deletions crypto/keys/default_signer_factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,25 @@ import (
"sync"

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

// SignerFactory gets and creates cryptographic signers.
// This may be done by loading a key from a file, interfacing with a HSM, or
// sending requests to a remote key management service, to give a few examples.
type SignerFactory interface {
// NewSigner uses the information in the provided protobuf message to obtain and return a crypto.Signer.
NewSigner(context.Context, proto.Message) (crypto.Signer, error)

// Generate creates a new private key based on a key specification.
// It returns a proto that describes how to access that key.
// This proto can be passed to NewSigner() to get a crypto.Signer.
Generate(context.Context, *keyspb.Specification) (proto.Message, error)
}

// DefaultSignerFactory produces a crypto.Signer from a protobuf message describing a key.
// It can also generate new private keys.
// It implements keys.SignerFactory.
Expand All @@ -37,11 +53,11 @@ type DefaultSignerFactory struct {
func (f *DefaultSignerFactory) NewSigner(ctx context.Context, pb proto.Message) (crypto.Signer, error) {
switch privateKey := pb.(type) {
case *keyspb.PEMKeyFile:
return NewFromPrivatePEMFile(privateKey.GetPath(), privateKey.GetPassword())
return pem.ReadPrivateKeyFile(privateKey.GetPath(), privateKey.GetPassword())
case *keyspb.PrivateKey:
return NewFromPrivateDER(privateKey.GetDer())
return der.UnmarshalPrivateKey(privateKey.GetDer())
case *keyspb.PKCS11Config:
return NewFromPKCS11Config(f.pkcs11Module, privateKey)
return pkcs11.FromConfig(f.pkcs11Module, privateKey)
}

return nil, fmt.Errorf("unsupported private key protobuf type: %T", pb)
Expand All @@ -55,12 +71,12 @@ func (f *DefaultSignerFactory) Generate(ctx context.Context, spec *keyspb.Specif
return nil, fmt.Errorf("error generating key: %v", err)
}

der, err := MarshalPrivateKey(key)
keyDER, 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
return &keyspb.PrivateKey{Der: keyDER}, nil
}

// SetPKCS11Module sets the PKCS#11 module used to load PKCS#11 keys.
Expand Down
6 changes: 4 additions & 2 deletions crypto/keys/default_signer_factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ package keys
import (
"testing"

"github.com/google/trillian/crypto/keys/der"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/crypto/keyspb"
)

func TestDefaultSignerFactory(t *testing.T) {
key, err := NewFromPrivatePEMFile("../../testdata/log-rpc-server.privkey.pem", "towel")
key, err := pem.ReadPrivateKeyFile("../../testdata/log-rpc-server.privkey.pem", "towel")
if err != nil {
t.Fatalf("Failed to load private key: %v", err)
}

keyDER, err := MarshalPrivateKey(key)
keyDER, err := der.MarshalPrivateKey(key)
if err != nil {
t.Fatalf("Failed to marshal private key to DER: %v", err)
}
Expand Down
78 changes: 78 additions & 0 deletions crypto/keys/der/der.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// 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 der

import (
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"fmt"

"github.com/google/trillian/crypto/keyspb"
)

// FromProto takes a PrivateKey protobuf message and returns the private key contained within.
func FromProto(pb *keyspb.PrivateKey) (crypto.Signer, error) {
return UnmarshalPrivateKey(pb.GetDer())
}

// UnmarshalPrivateKey reads a DER-encoded private key.
func UnmarshalPrivateKey(keyDER []byte) (crypto.Signer, error) {
key1, err1 := x509.ParseECPrivateKey(keyDER)
if err1 == nil {
return key1, nil
}

key2, err2 := x509.ParsePKCS8PrivateKey(keyDER)
if err2 == nil {
switch key2 := key2.(type) {
case *ecdsa.PrivateKey:
return key2, nil
case *rsa.PrivateKey:
return key2, nil
}
return nil, fmt.Errorf("der: unsupported private key type: %T", key2)
}

key3, err3 := x509.ParsePKCS1PrivateKey(keyDER)
if err3 == nil {
return key3, nil
}

return nil, fmt.Errorf("der: could not parse private key as SEC1 (%v), PKCS8 (%v) or PKCS1 (%v)", err1, err2, err3)
}

// UnmarshalPublicKey reads a DER-encoded public key.
func UnmarshalPublicKey(keyDER []byte) (crypto.PublicKey, error) {
key, err := x509.ParsePKIXPublicKey(keyDER)
if err != nil {
return nil, fmt.Errorf("der: could not parse public key as PKIX (%v)", err)
}

return key, nil
}

// MarshalPrivateKey serializes an RSA or ECDSA private key as DER.
func MarshalPrivateKey(key crypto.Signer) ([]byte, error) {
switch key := key.(type) {
case *ecdsa.PrivateKey:
return x509.MarshalECPrivateKey(key)
case *rsa.PrivateKey:
return x509.MarshalPKCS1PrivateKey(key), nil
}

return nil, fmt.Errorf("der: unsupported key type: %T", key)
}
16 changes: 16 additions & 0 deletions crypto/keys/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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 provides access to public and private keys for signing and verification of signatures.
package keys
76 changes: 76 additions & 0 deletions crypto/keys/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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 (
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"fmt"

"github.com/google/trillian/crypto/keyspb"
)

const (
// DefaultRsaKeySizeInBits is the size of an RSA key generated by this package, in bits, if not overridden.
DefaultRsaKeySizeInBits = 2048

// MinRsaKeySizeInBits is the smallest RSA key that this package will generate.
MinRsaKeySizeInBits = 2048
)

// NewFromSpec generates a new private key based on a key specification.
// If an RSA key is specified, the key size must be at least MinRsaKeySizeInBits.
func NewFromSpec(spec *keyspb.Specification) (crypto.Signer, error) {
switch params := spec.GetParams().(type) {
case *keyspb.Specification_EcdsaParams:
curve := ECDSACurveFromParams(params.EcdsaParams)
if curve == nil {
return nil, fmt.Errorf("unsupported ECDSA curve: %s", params.EcdsaParams.GetCurve())
}

return ecdsa.GenerateKey(curve, rand.Reader)
case *keyspb.Specification_RsaParams:
bits := int(params.RsaParams.GetBits())
if bits == 0 {
bits = DefaultRsaKeySizeInBits
}
if bits < MinRsaKeySizeInBits {
return nil, fmt.Errorf("minimum RSA key size is %v bits, got %v bits", MinRsaKeySizeInBits, bits)
}

return rsa.GenerateKey(rand.Reader, bits)
default:
return nil, fmt.Errorf("unsupported keygen params type: %T", params)
}
}

// ECDSACurveFromParams returns the curve specified by the given parameters.
// Returns nil if the curve is not supported.
func ECDSACurveFromParams(params *keyspb.Specification_ECDSA) elliptic.Curve {
switch params.GetCurve() {
case keyspb.Specification_ECDSA_DEFAULT_CURVE:
return elliptic.P256()
case keyspb.Specification_ECDSA_P256:
return elliptic.P256()
case keyspb.Specification_ECDSA_P384:
return elliptic.P384()
case keyspb.Specification_ECDSA_P521:
return elliptic.P521()
}
return nil
}
Loading